Formatting and Styles¶
cplots separates what a plot shows from how it looks:
- Formatting belongs to one plot: axis labels, limits, scales, legend, size. You set it with chainable methods.
- Styles are visual settings shared across plots: fonts, colours, palette.
They layer from a global default, through
withblocks, down to each figure and plot.
Formatting a plot¶
Every method returns a new plot and leaves the original unchanged, so one plot can serve as a base for several variants:
| Method | Sets |
|---|---|
.axes(xlabel=, ylabel=, xlim=, ylim=, xscale=, yscale=, aspect=, secondary_x=, secondary_y=) |
labels, limits, scales ("linear", "log", "symlog"), aspect="equal", a secondary top x-axis / right y-axis (SecondaryAxisSpec) |
.title(text) |
panel title |
.legend(show=True, loc=, ncol=, frame=, outside=, title=) |
legend; .legend(False) hides it |
.xticks(values=, labels=, count=, minor=, format=), .yticks(...) |
tick positions and labels, approximate tick count, minor ticks, label format such as ".2f" or ".0e" |
.grid(on=True) |
background grid |
.colorbar(**fields) |
colourbar settings of colour-mapped plots (loc, label, lim, ...) |
.latex(on=True) |
pass labels to the backend as raw LaTeX |
.size(w, h) |
figure size in inches |
.layout(engine=) |
matplotlib layout engine: "constrained" (default), "tight" or None |
.paper("PRD") |
journal size and font: "PRD", "PRD-2col", "MNRAS", "A4" |
.style(style, **fields) |
a style for this plot |
Constructor arguments use the same names (xlabel=, ylabel=, xscale=,
style=, ...). They act as defaults, and the methods above override them. The
older spellings still work for now but emit a DeprecationWarning:
| Old | New |
|---|---|
x_label, y_label, x_scale, y_scale |
xlabel, ylabel, xscale, yscale |
theme |
style |
label (power spectra) |
labels |
z_label, value_label (phase portraits) |
clabel |
c_lim |
clim |
cbar_loc, cbar_label_loc, colorbar_pad, colorbar_scale |
colorbar={"loc": ..., "label_loc": ..., "pad": ..., "scale": ...} |
width_ratios, height_ratios (Figure) |
widths, heights |
height_ratio (with_residuals) |
heights |
labels (PhasePortrait axis names) |
axis_labels |
Ticks¶
Repeated calls update only the arguments you pass, so
.yticks(count=4).yticks(format=".1e") keeps both. format is a format spec
shared by Python and d3 (".2f", ".1e", ".0%"). altair has no minor ticks
and warns if you set minor.
plot.spec() returns the backend-agnostic specification with every override
applied, which helps with testing and debugging.
Styles¶
A cplots.Style is a partial set of visual settings. Every field is optional,
and an unset field (None) inherits from the layer below it:
| Field | Meaning |
|---|---|
font_family, font_size |
base font |
label_size, title_size, tick_size |
per-element font sizes (points) |
background |
figure/axes background ("none" is transparent) |
foreground |
axes, ticks, labels and text colour |
palette |
colours cycled across traces |
linewidth, grid, legend_frame |
line and frame defaults |
backend_options |
per-backend extras, e.g. {"matplotlib": {"axes.spines.top": False}} |
Built-in styles: cplots.DEFAULT (applied to every plot, see below),
cplots.PUBLICATION (serif, white) and cplots.DARK (transparent background,
white foreground, neon palette).
The default style¶
Every plot starts from cplots.DEFAULT: Computer Modern text and math
(CMU Serif, falling back to DejaVu Serif when it isn't installed), the
FiveThirtyEight palette (cplots.DEFAULT_PALETTE), 10 pt text, 1.5 pt lines,
a white background and boxed axes with inward major and minor ticks on all four
sides. Colour-mapped plots default to magma (cplots.DEFAULT_COLORMAP).
cplots.set_style(...) layers on top of DEFAULT; pass base=None to start
from the backends' own defaults instead:
cplots.set_style(font_size=9) # the cplots look, smaller text
cplots.set_style(base=None) # plain matplotlib / plotly / altair defaults
cplots.set_style(None) # back to DEFAULT
PUBLICATION, DARK and your own styles are layered on top of DEFAULT, so
they keep whatever they don't set: .style(cplots.DARK) changes the colours and
font family but keeps the inward ticks, the 1.5 pt lines and the Computer Modern
math from DEFAULT.
The cascade¶
Styles are resolved when the plot renders, from lowest to highest priority:
- Global:
cplots.DEFAULT, plus anything set withcplots.set_style(...) - Context:
with cplots.style(...):(nested blocks merge; thread- and async-safe) - Figure:
Figure(style=...)orfigure.style(...) - Plot:
XYPlot(..., style=...)orplot.style(...)
cplots.set_style(cplots.PUBLICATION) # every plot from now on
with cplots.style(cplots.DARK, font_size=14): # just for this talk's slides
pk.show()
pk.style(palette=("#000000", "#d62728")).show() # this plot only
Only the fields that are set get applied, through matplotlib.rc_context for
that one render, so nothing leaks into later figures and your global rcParams
are never modified. Because DEFAULT is always applied, its settings win over
your own matplotlib style sheet or rcParams; call cplots.set_style(base=None)
to let those through instead.
Backend support¶
Every feature above works on matplotlib. When a backend can't render a feature,
it emits a single cplots.UnsupportedFeatureWarning naming it, rather than
silently ignoring it. For example, altair cannot draw aspect="equal" or shared
axes, and plotly has no symlog scale. To silence these warnings: