Theme and Primitives#
Theme, Palettes, and Figure Sizing#
coco_pipe.viz.theme is the single source of truth for visual styling across
both backends. Matplotlib rcParams and the Plotly coco template are derived
from the same palettes and font choices, so changing the theme in one place
updates static and interactive plots consistently.
—
1. Theme Modes#
Three rcParam presets target the most common output contexts:
Mode |
Use case |
|---|---|
|
Print figures, tight font sizes (11 pt body, 12 pt titles). |
|
Jupyter / on-screen review at default zoom (13/14 pt). |
|
Conference posters and slide decks (16/18 pt). |
All three share the same colorblind-safe palette and remove top/right spines.
from coco_pipe.viz.theme import coco_theme, set_coco_theme
# Scoped: safe in tests and notebooks (always restores prior rcParams).
with coco_theme("paper", colorblind=True):
fig, ax = plt.subplots()
ax.plot(x, y)
# Global: applies for the rest of the process.
set_coco_theme("notebook")
Prefer the context manager in notebooks and tests; reach for
set_coco_theme only at script entry points.
—
2. Palettes#
Four palette constants are exported from coco_pipe.viz.theme and reused
by every domain plot:
Constant |
Use |
|---|---|
|
Non-negative continuous values (importance, counts, density). |
|
Signed values centered on zero (signed importance, contrasts, residuals). |
|
Up to ~10 categorical labels. |
|
Okabe–Ito-style 8-color cycle, the default when |
( |
|
The Plotly colorway and color scales are seeded from the same constants in
coco_pipe.viz.interactive._utils, so interactive figures stay aligned
with the matplotlib output.
—
3. Figure Sizing for Papers#
figure_size returns inches sized for one-column or two-column manuscripts.
Width defaults match common journal templates (3.5 in single, 7.0 in double);
pass width_pt to override using a journal-specific value.
from coco_pipe.viz.theme import coco_theme, figure_size
with coco_theme("paper"):
fig, ax = plt.subplots(figsize=figure_size(columns=1, aspect_ratio=0.7))
fig2, ax2 = plt.subplots(figsize=figure_size(columns=2, aspect_ratio=0.5))
# Override with a journal-specific column width (in points)
fig3, ax3 = plt.subplots(figsize=figure_size(columns=1, width_pt=246))
—
4. Saving Figures#
save_figure standardizes DPI, background color, and bounding-box mode so
exports look the same regardless of which plot was used.
from coco_pipe.viz.theme import save_figure
save_figure(fig, "fig1.pdf") # 300 dpi, white background, tight bbox
save_figure(fig, "fig1.png", dpi=600) # higher resolution for raster output
For interactive Plotly figures, use fig.write_html(...) /
fig.write_image(...) directly — the coco template is already applied.
—
5. End-to-End Paper Figure Recipe#
import matplotlib.pyplot as plt
from coco_pipe.viz import plot_decoding_scores, plot_confusion_matrix
from coco_pipe.viz.theme import coco_theme, figure_size, save_figure
with coco_theme("paper", colorblind=True):
fig, axes = plt.subplots(
1, 2, figsize=figure_size(columns=2, aspect_ratio=0.45),
constrained_layout=True,
)
plot_decoding_scores(result, metric="accuracy", ax=axes[0])
plot_confusion_matrix(result, model="logistic_regression", ax=axes[1])
save_figure(fig, "figures/fig1.pdf")
—
6. Compatibility Notes#
coco_themeonly mutates Matplotlib rcParams; it does not touch the Plotly template (which is registered eagerly at import time).Setting
colorblind=Trueswaps the matplotlibaxes.prop_cycleto the Okabe–Ito colors but leaves continuous colormaps alone — those remain perceptually uniform (viridis/RdBu_r).The
cocoPlotly template is namedCOCO_TEMPLATEand can be applied manually withfig.update_layout(template="coco")if you build a Plotly figure outside the wrappers.
Plotting Primitives (Base)#
The coco_pipe.viz.base module exposes 12 generic plotting primitives.
Every domain plot in viz.decoding and viz.dim_reduction ultimately calls
one of them. They are also available directly for custom figures that don’t
fit one of the higher-level templates.
All primitives share a consistent contract:
Accept
ax(existing axes) orfigsize(new axes).Return
(matplotlib.figure.Figure, matplotlib.axes.Axes).Apply titles/labels/legends through
coco_pipe.viz._utils.finalize_axes().Use the theme palettes for default colors.
—
1. Catalog#
Primitive |
Use |
|---|---|
|
Ranked bars with optional error bars, sorting, |
|
2D line with optional error band or bars. |
|
Scatter of point estimates with x/y error bars and optional reference lines. |
|
Grouped box or violin with overlaid jittered points. |
|
2D scatter with categorical or continuous color encoding, optional error bars and reference lines. |
|
3D scatter with categorical or continuous color encoding. |
|
2D matrix heatmap with diverging-around-center support, optional cell annotations, colorbar. |
|
2D hexagonal density binning. |
|
Stream plot from a gridded |
|
Sensor-level topographic map (MNE-backed). |
Each primitive accepts a permissive input type (Series, mapping, sequence, DataFrame, ndarray as appropriate) and coerces internally so callers don’t have to pre-normalize.
—
2. Bars: plot_bar#
Ranked horizontal or vertical bars with optional error magnitudes and a colormap applied across values.
from coco_pipe.viz import plot_bar
fig, ax = plot_bar(
{"accuracy": 0.71, "balanced_accuracy": 0.66, "roc_auc": 0.78},
errors={"accuracy": 0.02, "balanced_accuracy": 0.03, "roc_auc": 0.015},
sort=True,
top_n=10,
orientation="horizontal",
cmap="viridis",
ylabel="Score",
title="Cross-validated scores",
)
Used internally by plot_decoding_scores(kind="bar"),
plot_feature_importance, plot_eigenvalues, and more.
—
3. Lines: plot_line#
A single 2D line with an optional uncertainty band (error_style="band") or
error bars (error_style="bar").
from coco_pipe.viz import plot_line
fig, ax = plot_line(
times, scores,
yerr=score_std,
error_style="band",
label="LogisticRegression",
legend=True,
xlabel="Time (s)", ylabel="Accuracy",
)
Backbone of every temporal-curve plot.
—
4. Grouped Distributions: plot_distribution_groups#
Box or violin plots across groups with optional jittered individual points overlaid. Non-finite values are dropped automatically.
from coco_pipe.viz import plot_distribution_groups
fig, ax = plot_distribution_groups(
[fold_scores_lr, fold_scores_rf, fold_scores_svm],
labels=["LR", "RF", "SVM"],
kind="violin",
showmeans=True,
ylabel="Accuracy",
)
—
5. Scatters: plot_scatter2d / plot_scatter3d#
Categorical (labels) or continuous (c) color encoding — passing
labels disables the continuous branch. Both 2D and 3D variants accept the
same color/legend options. 2D additionally supports x/y error bars and dashed
reference lines.
from coco_pipe.viz import plot_scatter2d, plot_scatter3d
# Categorical
fig, ax = plot_scatter2d(
emb[:, 0], emb[:, 1],
labels=class_ids, alpha=0.7,
legend_title="Class",
)
# Continuous
fig, ax = plot_scatter2d(
emb[:, 0], emb[:, 1],
c=time_index, cmap="viridis", colorbar=True,
reference_x=0.0, reference_y=0.0,
)
# 3D
fig, ax = plot_scatter3d(
emb[:, 0], emb[:, 1], emb[:, 2],
labels=class_ids,
)
—
6. Heatmaps: plot_heatmap#
Numeric 2D matrices with diverging-around-center support (set center to a
numeric reference and the colormap is centered with TwoSlopeNorm). Use
annotate=True for cell annotations.
from coco_pipe.viz import plot_heatmap
fig, ax = plot_heatmap(
confusion_df,
cmap="viridis",
annotate=True,
annotation_format=".2f",
colorbar_label="Count",
title="Confusion matrix",
)
Backbone of confusion matrices, generalization matrices, and the co-ranking matrix.
—
7. Density: plot_hexbin#
Hexagonal density binning for 2D scatter clouds too dense for individual points.
—
8. Vector Fields: plot_streamfield#
Stream-line rendering of a gridded (U, V) vector field. Underlying scatter
points (e.g., raw embedding samples) can be overlaid via points. Colors
encode local flow speed.
—
9. Topographic Maps: plot_topomap#
Sensor-level topographic visualization backed by mne.viz.plot_topomap.
Sensor positions can come from any of three sources:
info: an MNEmne.Infoobject (preferred when available).coords: an(N, 2+)array,{name: (x, y)}mapping, or DataFrame withx/ycolumns and aFeatureNameorSensorcolumn.The function infers names from
values(Series/mapping) orindex.
from coco_pipe.viz import plot_topomap
fig, ax = plot_topomap(
importance_series, # {sensor_name: value}
info=raw.info, # MNE Info
symmetric=True,
cbar_label="Importance",
)
When symmetric=True (the default) the color scale is anchored at zero with
the diverging palette; otherwise the sequential palette is used.
—
10. Composing Primitives#
Domain plots are deliberately thin. To build a custom figure that mixes plots, share an axes between primitives:
import matplotlib.pyplot as plt
from coco_pipe.viz import plot_line, plot_distribution_groups
from coco_pipe.viz.theme import coco_theme, figure_size
with coco_theme("paper"):
fig, axes = plt.subplots(
1, 2, figsize=figure_size(columns=2, aspect_ratio=0.4),
constrained_layout=True,
)
plot_line(times, mean_score, yerr=score_std, ax=axes[0],
xlabel="Time (s)", ylabel="Accuracy")
plot_distribution_groups(
[fold_lr, fold_rf], labels=["LR", "RF"], ax=axes[1], ylabel="Accuracy"
)