Styles and rcParams
Decide how your charts look once, in one place
plt.rcParamsplt.style.useplt.style.contextrc_context.mplstyleplt.rcdefaultsWatch it happen
Play it through, or step back and forth yourself.
len(plt.rcParams)about a thousand of themplt.rcParams["lines.linewidth"]2.0 hereplt.rcParams["figure.dpi"]110 hereplt.rcParams["font.size"]10plt.rcParams["axes.prop_cycle"]the paletteEvery colour, font size, line width and grid setting comes from rcParams — a dict of about a thousand defaults matplotlib consults as it draws. Nothing is hardcoded; you're always overriding something.
The idea
Every colour, font size, line width, tick length and grid setting matplotlib uses comes from rcParams — a dict of roughly a thousand defaults it consults as it draws. Nothing about a chart's appearance is hardcoded; you are always overriding something.
plt.rcParams["lines.linewidth"] # 2.0 in this lab
plt.rcParams["figure.dpi"] # 110
plt.rcParams["font.size"] # 10
plt.rcParams["axes.prop_cycle"] # the palette from lesson 11Which means styling belongs in one place, set once, rather than repeated as keyword arguments on every call. plt.rcParams["axes.grid"] = True at the top of a notebook beats ax.grid(True) forty times, and it can't drift out of sync with itself.
plt.rcParams.update({
"axes.spines.top": False,
"axes.spines.right": False,
"axes.titlelocation": "left",
"legend.frameon": False,
"figure.figsize": (7, 4),
})
plt.rcdefaults() # back to matplotlib stockStyle sheets
A style sheet is a named bundle of rcParams. Twenty-six ship with matplotlib:
plt.style.available # 26 names
plt.style.use("ggplot") # global — everything from here onWorth knowing by name: ggplot and seaborn-v0_8-* (grey panel, white grid), fivethirtyeight (bold, thick lines, for slides), grayscale (for print), and tableau-colorblind10 (a safer palette, from lesson 11).
Prefer the scoped form
with plt.style.context("ggplot"):
fig, ax = plt.subplots()
ax.plot(days, delhi)
# everything is back to normal hereplt.style.use is global mutable state. Set it in cell 3 and wonder in cell 40 why your colours changed — that's a real afternoon. The context manager scopes it to the block. There's also mpl.rc_context({...}) for individual parameters:
import matplotlib as mpl
with mpl.rc_context({"lines.linewidth": 5}):
... # thick lines in here, 2.0 again outside
A house style
For anything ongoing, write your own .mplstyle file and put it in version control:
# chai.mplstyle
figure.figsize: 7, 4
figure.dpi: 110
axes.prop_cycle: cycler('color', ['ff7d0c', '66aaf9', '74dfa2'])
axes.spines.top: False
axes.spines.right: False
axes.titlelocation: left
axes.grid: True
grid.alpha: 0.25
font.size: 10
legend.frameon: Falseplt.style.use("chai.mplstyle")
plt.style.use(["seaborn-v0_8-white", "chai.mplstyle"]) # layered, in orderOne file now decides how every chart in the project looks. Changing the brand colour is a one-line diff instead of a search through nine notebooks, and every chart in the report matches without anyone having to remember to make it match.
The order things win in
Three layers, and later beats earlier:
- The style sheet — the project-wide baseline.
- Your rcParams — this notebook is different.
- The keyword argument on the call — this one line is the point.
That's why color= on a single call always wins, and why it should be reserved for the series you're actually talking about. If you find yourself passing the same color= to every call, that belongs one layer up.
Fonts
plt.rcParams["font.family"] = "DejaVu Sans". Two things bite here: a font that exists on your laptop may not exist on the server, and matplotlib falls back silently with only a warning. And PDF or SVG output embeds the font, so a figure that renders correctly for you may not for a reader — which is one more reason to test the actual saved file rather than the on-screen preview.
Practice
Write it yourself. The answer is there when you want it.
Putting the kettle on…
Starting up…
Write it yourself
not gradedPrint how many styles are available, ignoring the private ones. Then print the axes face colour before, inside and after a style.context block, to prove the change is scoped. Open an rc_context setting a fat line width and a grid on, and inside it plot both cities with a left-aligned title and a legend — no per-call styling anywhere. Print the line width from inside the block. Finish with fig.
Your turn
3 exercises. Write the code yourself, then press Check — a nudge and the answer are there if you want them.
How many style sheets ship with matplotlib, ignoring the private ones that start with _? Return the count.
Read plt.rcParams["axes.facecolor"] inside a ggplot style context and after it, and return the two values as a list — the point being that the context puts things back.
Using mpl.rc_context, draw one line with lines.linewidth set to 5 and another outside the block at the default. Return [inside_width, outside_width].
