Plot style#
Figure style (decision D27b).
Two things live here, and they act at two different moments.
PATH and context() are the style sheet – colours,
fonts, line widths, figure size. Those are matplotlib rcParams, so they
have to be active before a figure is created; they cannot be applied
to a line that is already drawn. The sheet ships with the package and is
never applied at import time – importing a library must not mutate
the user’s matplotlib state:
import matplotlib.pyplot as plt
import comnumpy.style
plt.style.use(comnumpy.style.PATH) # global, explicit
with comnumpy.style.context(): # or scoped
...
apply() is the per-axis convention: what an error-rate figure
of this library looks like, what an IQ plane looks like. It runs after
the drawing, on an axis the caller filled themselves:
fig, ax = plt.subplots()
line, = ax.semilogy(snr_dB, ser, "o", fillstyle="none", label="16-QAM")
ax.semilogy(snr_dB, ser_theory, "-", color=line.get_color())
style.apply(ax, "error_rate")
That is the whole point of the split: the reader sees the two matplotlib calls that draw the curves, and the library is left with the part that is a house convention rather than a plotting decision.
Colors come from the Okabe-Ito colorblind-safe palette, and no
information is carried by color alone (decision D27c): semantic tables
such as comnumpy.ofdm.allocation.CARRIER_STYLE pair each color
with a glyph and a hatch.
- context()[source]#
Context manager applying the comnumpy style locally.
- Returns:
contextlib.AbstractContextManager – The matplotlib style context for
with comnumpy.style.context():.
- use() None[source]#
Activate the style sheet for every figure created from now on.
One line at the top of a script, after the imports and before the first figure – the colours and the figure size are rcParams, so a figure already created keeps the ones that were active when it was:
import comnumpy.style as style style.use()
Explicit on purpose: importing this package must not change the user’s matplotlib state behind their back (decision D27b). Use
context()instead to scope the change to a block.
- apply(ax: Axes, kind: str, *, legend: bool | None = None) Axes[source]#
Give an axis the house look for one kind of figure.
What it does#
Three things, and deliberately no more:
fills the labels that are still empty. A label the caller has already set is never overwritten –
ax.set_ylabel("BER")followed byapply(ax, "error_rate")keeps"BER". The defaults are inKINDS;turns on the grid, on both decades when the corresponding axis is logarithmic and on the major ticks otherwise;
adds a legend when the axis carries labelled artists and does not have one yet.
kind="iq"additionally sets an equal aspect ratio, because a constellation read on unequal axes is a different constellation.What it does not do#
It never touches the data and never changes a scale. Whether a curve is drawn with
plotorsemilogy, with markers or without, in which colour, is the caller’s statement about their measurement, and it stays visible in the caller’s code. This function decorates what is already there.The colours, fonts, line widths and figure size are not here either: those are rcParams, they have to be active before the figure exists, and they come from the style sheet – see
PATHandcontext().- param ax:
The axis to decorate, already drawn on.
- type ax:
matplotlib.axes.Axes
- param kind:
One of the keys of
KINDS:"error_rate","iq","time"or"spectrum".- type kind:
str
- param legend:
Force the legend on or off. The default,
None, adds one when the axis has labelled artists and none already.- type legend:
bool, optional, keyword-only
- returns:
matplotlib.axes.Axes – The same axis, so the call can end a chain of statements.
- raises ValueError:
If
kindis not one ofKINDS.
Examples
>>> import matplotlib >>> matplotlib.use("Agg") >>> import matplotlib.pyplot as plt >>> import numpy as np >>> from comnumpy import style >>> snr = np.arange(0, 12, 2) >>> _, ax = plt.subplots() >>> _ = ax.semilogy(snr, 10.0 ** (-snr / 8), "o", label="QPSK") >>> _ = style.apply(ax, "error_rate") >>> ax.get_xlabel(), ax.get_ylabel() ('SNR [dB]', 'error rate')
A label the caller set is left alone:
>>> _, ax = plt.subplots() >>> _ = ax.semilogy(snr, 10.0 ** (-snr / 8)) >>> ax.set_ylabel("BER") Text(...) >>> _ = style.apply(ax, "error_rate") >>> ax.get_ylabel() 'BER'