Skillversitas

Styling with rcParams and Stylesheets

Setting fonts, grid lines, figure sizes, and color cycles per call gets repetitive fast; the right layer for project-wide appearance is rcParams - the configuration dictionary that matplotlib reads for every default. Stylesheets package a set of rcParams under a name so a whole project shares one look with a single line, and rc_context applies a style temporarily without touching the global state. This chapter is the last one most figures need: how to make "our charts" look like "our charts" everywhere.

rcParams Directly

import matplotlib.pyplot as plt

plt.rcParams["figure.figsize"] = (8, 5)
plt.rcParams["figure.dpi"] = 110
plt.rcParams["axes.grid"] = True
plt.rcParams["grid.alpha"] = 0.3
plt.rcParams["grid.linestyle"] = ":"
plt.rcParams["font.size"] = 11
plt.rcParams["axes.spines.top"] = False
plt.rcParams["axes.spines.right"] = False
plt.rcParams["axes.prop_cycle"] = plt.cycler(
    color=["#2563eb", "#f59e0b", "#10b981", "#ef4444"])

x = [0, 1, 2, 3, 4]
fig, ax = plt.subplots()
ax.plot(x, [v * v for v in x])
plt.show()

Every keyword argument any artist accepts has an rcParams equivalent (axes.grid, lines.linewidth, font.family, pdf.fonttype), and the full list is available in plt.rcParams. Set them once at startup (a notebook cell, an app's init, a test fixture) and every figure inherits them. plt.rcParams mutates global state - change it before creating figures, and reset with plt.rcParams.update(plt.rcParamsDefault) when needed.

Named Styles and Stylesheets

import matplotlib.pyplot as plt

print(plt.style.available)
plt.style.use("ggplot")        # or "fivethirtyeight", "dark_background", ...
# in recent versions: "seaborn-v0_8-whitegrid", "seaborn-v0_8-darkgrid", ...

x = [0, 1, 2, 3]
fig, ax = plt.subplots()
ax.plot(x, [1, 3, 2, 4])
plt.show()

plt.style.use("default")       # back to the factory look

A stylesheet is just a named collection of rcParams. The built-ins cover common looks; for a house style, write your own file:

# mystyle.mplstyle
figure.figsize: 8, 5
axes.grid: True
grid.alpha: 0.3
grid.linestyle: :
font.size: 11
axes.spines.top: False
axes.spines.right: False
axes.prop_cycle: cycler('color', ['2563EB', 'F59E0B', '10B981', 'EF4444'])
plt.style.use("path/to/mystyle.mplstyle")   # load by file path

Shipping the file in the repository means every notebook and every report generator renders identically - the style is code, versioned and reviewable like the rest.

Temporary Overrides with rc_context

import matplotlib.pyplot as plt

x = [0, 1, 2, 3, 4]
fig, (ax1, ax2) = plt.subplots(1, 2)

ax1.plot(x, [v * v for v in x])      # normal style

with plt.rc_context({"axes.grid": False, "font.size": 14,
                     "axes.prop_cycle": plt.cycler(color=["black"])}):
    ax2.plot(x, [v * v for v in x])  # this figure only
plt.show()

rc_context is a context manager: parameters set inside are restored on exit. Use it for the one panel that needs to differ (a monochrome inset, a dense small-multiple), or in tests where a global style would leak between cases.

How the Layers Stack

  1. Built-in defaults.
  2. The active style sheet (style.use) - overrides defaults.
  3. Global rcParams changes - override the style.
  4. rc_context - overrides everything, temporarily.
  5. Explicit keyword arguments on any call - always win.

The order is the design: a stylesheet sets the house look, rcParams sets project-specific constants, and the occasional explicit argument handles the one-off. When output looks wrong, walk the list from the top and find which layer is actually in charge.

Summary

Define the house look once: a named or file-based stylesheet for the global appearance, rcParams for project constants, rc_context for temporary deviations, and explicit keywords for one-offs. Keep the style file in version control, and when a figure looks off, remember the five layers - the explicit argument is always the one that wins.