API reference#

The top-level API contains narrow semantic rendering, date-axis semantics, publication-finishing values, figure export, numeric labels, palettes, and opt-in themes. Internal modules are not compatibility guarantees.

Facet planning and rendering#

ggstyle.facets(data, *, row=None, col=None, wrap=None, scales='fixed', row_order=None, col_order=None, include_unobserved=False, missing='drop', max_panels=64, theme=None, figsize=None, subplot_kw=None)[source]#

Create callback-ready wrap or grid facets on native Matplotlib axes.

Parameters:
datadataframe-like

Pandas, Polars, or Arrow dataframe; equal-length column mapping; or dataframe supporting positional iloc selection. The input is never mutated.

row, colstr or None, optional

Columns assigned to grid rows and columns. At least one is required and they must be distinct. A wrap layout requires col and no row.

wrapint or None, optional

Positive maximum number of columns for a one-variable col wrap. None creates a row, column, or two-variable grid.

scales{“fixed”, “free_x”, “free_y”, “free”}, default “fixed”

Native Matplotlib axis-sharing policy. Shared collapsed-date registry training is deferred to the dedicated date-integration workstream.

row_order, col_ordersequence or None, optional

Explicit facet-level orders. Observed values outside them are rejected.

include_unobservedbool, default False

Retain explicit or categorical levels absent from the observed data.

missing{“drop”, “keep”, “raise”}, default “drop”

Drop, retain as an NA panel, or reject missing facet values.

max_panelsint, default 64

Positive panel-count safety limit checked before figure creation.

themestr, ThemeSpec, or None, optional

Scoped ggstyle theme used only while creating the figure. None preserves the caller’s current Matplotlib configuration.

figsizesequence of two real numbers or None, optional

Figure width and height in inches. Both values must be finite and positive.

subplot_kwmapping or None, optional

Keyword arguments forwarded to each native Matplotlib subplot.

Returns:
FacetGrid

Callback-ready grid exposing its native figure, row-major axes, and immutable partition plan.

Notes

Each active panel receives a native axes title containing its facet values in row-then-column order. Unused wrap cells are removed from the figure. Use grid.map(lambda panel, ax: ...) to add one or more plotting layers.

Examples

>>> import matplotlib.pyplot as plt
>>> import ggstyle as gs
>>> grid = gs.facets(
...     {"group": ["A", "A", "B"], "x": [1, 2, 1], "y": [2, 3, 4]},
...     col="group",
...     wrap=2,
... )
>>> _ = grid.map(lambda panel, ax: ax.plot(panel["x"], panel["y"]))
>>> len(grid.axes)
2
>>> plt.close(grid.figure)
>>> grid = gs.facets(
...     {"region": ["N", "S"], "metric": ["A", "B"]},
...     row="region",
...     col="metric",
... )
>>> grid.plan.shape
(2, 2)
>>> plt.close(grid.figure)
class ggstyle.FacetGrid(figure, axes, plan, panel_data, theme_name)[source]#

Own native Matplotlib axes for callback-rendered wrap or grid facets.

Instances are created by facets(). The source data is partitioned into defensive panel snapshots before any figure is created. Each map() call gives its callback a fresh panel copy and the corresponding ordinary Matplotlib axes.

Parameters:
figurematplotlib.figure.Figure

Figure containing the facet axes.

axestuple of matplotlib.axes.Axes

Active panel axes in row-major plan order; unused rectangular cells are absent.

planFacetPlan

Immutable partition and layout plan used to create the grid.

panel_datatuple of object

Internal defensive dataframe subsets aligned with plan.panels.

theme_namestr or None

Applied ggstyle theme name, or None when current Matplotlib settings were used.

as_dict()[source]#

Return bounded strict-JSON inspection data for this grid.

Returns:
dict of str to object

Fresh containers describing the native grid, completed mapping passes, applied theme, diagnostics, and its immutable facet plan. Live figures, axes, callbacks, callback results, and source data are excluded.

property axes#

Return active native Matplotlib axes in row-major panel order.

property date_handles#

Return date handles aligned with axes, including empty slots.

dates(*, mode='collapse', limits='union')[source]#

Configure date coordinates according to this grid’s fixed/free x policy.

Parameters:
mode{“show”, “collapse”}, default “collapse”

Date coordinate mode applied to every date-bearing panel.

limits{“union”, “intersection”}, default “union”

Shared visible-range policy for fixed x scales. Each free x panel applies the policy to its own observations independently.

Returns:
FacetGrid

This grid, enabling fluent date configuration and further mapping passes.

Raises:
ValueError

If options are invalid or no panel contains date observations.

DateDiscoveryError

If panel artists do not expose safe date observation provenance.

Notes

fixed and free_y layouts use one shared revisioned observation registry. free_x and free layouts retain independent per-panel registries. Empty fixed-x panels have no handle but inherit the shared native x transform and limits. Later successful map() passes refresh the configured registry policy.

describe()[source]#

Return the facet grid as deterministic formatted strict JSON.

Returns:
str

Strict JSON containing the same values as as_dict().

property diagnostics#

Return deterministic planning diagnostics for the rendered grid.

property figure#

Return the native Matplotlib figure containing every panel.

map(callback)[source]#

Invoke a plotting callback once for every panel and return this grid.

Parameters:
callbackcallable

Called as callback(panel_data, ax) in row-major order. panel_data is a fresh defensive subset with the same dataframe type for pandas and Polars. Its return value is intentionally ignored; callbacks draw on ax.

Returns:
FacetGrid

This grid, enabling repeated mapping passes for multiple layers.

Raises:
TypeError

If callback is not callable.

FacetCallbackError

If a panel callback fails. The original exception is chained and the error identifies the panel and number of completed calls.

Notes

Arbitrary callback mutations cannot be rolled back safely. When a callback fails, panels completed earlier in that pass remain changed and map_count is not incremented. Defensive copies follow each dataframe library’s copy semantics; nested mutable Python objects stored inside cells may still share references.

property map_count#

Return the number of complete callback mapping passes.

property plan#

Return the immutable partition and layout plan used by this grid.

exception ggstyle.FacetCallbackError(panel, completed_panels)[source]#

Report a callback failure with the responsible facet panel.

Parameters:
panelFacetPanel

Panel whose callback invocation failed.

completed_panelsint

Number of panel callbacks completed during the current mapping pass.

Notes

The original exception remains available as __cause__. Callback code can make arbitrary changes to native Matplotlib axes, so changes made before the failure are left visible rather than incompletely guessed at and rolled back.

ggstyle.facet_plan(data, *, row=None, col=None, wrap=None, scales='fixed', row_order=None, col_order=None, include_unobserved=False, missing='drop', max_panels=64)[source]#

Plan deterministic dataframe partitions and a facet layout without rendering.

Parameters:
datadataframe-like

Column-bearing dataframe-like or mapping-like data. Input is never mutated or retained by the returned plan.

row, colstr or None, optional

Columns assigned to grid rows and columns. At least one is required and they must be distinct.

wrapint or None, optional

Maximum number of columns for a one-variable col wrap. It cannot be combined with row.

scales{“fixed”, “free_x”, “free_y”, “free”}, default “fixed”

Coordinate-sharing policy recorded for later rendering.

row_order, col_ordersequence or None, optional

Explicit facet-level order. Observed values outside it are rejected.

include_unobservedbool, default False

Retain explicit or categorical levels absent from the observed data.

missing{“drop”, “keep”, “raise”}, default “drop”

Drop rows with any missing facet value, retain a final missing level, or reject the input.

max_panelsint, default 64

Positive safety limit checked before panel descriptions are allocated.

Returns:
FacetPlan

Immutable row-major partitions, layout shape, policy, and bounded inspection.

Notes

Grid plans use the Cartesian product of resolved row and column levels, retaining empty combinations. Wrap plans contain one panel per resolved column level. This function creates no Matplotlib figure, axes, artists, callbacks, or global state.

class ggstyle.FacetPlan(layout, row, col, wrap, scales, include_unobserved, missing, max_panels, nrows, ncols, panels, row_levels, col_levels, input_rows, dropped_rows, diagnostics=())[source]#

Describe a validated facet partition and layout without creating a figure.

Parameters:
layout{“wrap”, “grid”}

Resolved layout strategy.

row, colstr or None

Source columns assigned to layout rows and columns.

wrapint or None

Maximum wrap columns for a one-variable wrap layout.

scales{“fixed”, “free_x”, “free_y”, “free”}

Planned coordinate-sharing policy for later rendering.

include_unobservedbool

Whether explicit or categorical levels absent from the data receive panels.

missing{“drop”, “keep”, “raise”}

Facet-variable missing-value policy.

max_panelsint

Validated panel-count safety limit.

nrows, ncolsint

Resolved rectangular layout dimensions.

panelstuple of FacetPanel

Row-major immutable panel descriptions.

row_levels, col_levelstuple of object

Resolved facet levels. Missing levels appear as None.

input_rowsint

Number of rows in the supplied dataframe-like input.

dropped_rowsint

Number excluded by the missing-value policy.

diagnosticstuple of str

Deterministic non-fatal planning diagnostics.

as_dict()[source]#

Return deterministic strict-JSON facet inspection data.

Returns:
dict of str to object

Fresh bounded containers describing policy, levels, shape, panels, and row accounting without retaining or serializing source data.

describe()[source]#

Return the facet plan as deterministic formatted strict JSON.

Returns:
str

Strict JSON containing the same values as as_dict().

property shape#

Return the resolved (rows, columns) layout shape.

class ggstyle.FacetPanel(index, row, column, values, indices)[source]#

Describe one planned facet panel without retaining source data.

Parameters:
indexint

Zero-based row-major position in the plan’s panel sequence.

rowint

Zero-based layout row.

columnint

Zero-based layout column.

valuesmapping of str to object

Facet-variable values selecting this panel. A missing facet level is None.

indicestuple of int

Zero-based source-row positions assigned to the panel.

as_dict()[source]#

Return bounded JSON-compatible panel inspection data.

Returns:
dict of str to object

Panel position, facet values, row count, and empty status. Source-row positions are intentionally excluded from the bounded representation.

property empty#

Return whether no source rows belong to this panel.

Semantic rendering#

class ggstyle.RenderedResult(*args, **kwargs)[source]#

Common inspection boundary for a committed semantic render.

Concrete line, point, ribbon, and guide results retain their native artist attributes. This protocol exposes the stable subset that monitoring, notebooks, and tests can consume without depending on those geometry-specific attributes.

as_dict()[source]#

Return a bounded, deterministic, JSON-compatible summary.

describe()[source]#

Return the result summary as deterministic strict JSON.

ggstyle.line(data, *, x, y, ax, color=None, group=None, linestyle=None, color_scale=None, linestyle_scale=None, style=None, sort='input', group_missing='drop')[source]#

Draw deterministic grouped lines from named tidy-data columns.

Parameters:
datadataframe-like

Column-bearing dataframe-like or mapping-like data. Input data is never mutated.

x, ystr

Required coordinate column names. Strings are names only; expressions are never evaluated.

axmatplotlib.axes.Axes

Existing caller-owned target axes.

colorstr or None, optional

Column mapped to color. Numeric values use a continuous scale; categorical, boolean, and other values use a discrete scale.

groupstr or None, optional

Column that partitions rows into separate lines without assigning an aesthetic. Discrete color and linestyle mappings also imply grouping.

linestylestr or None, optional

Column mapped to a discrete line style.

color_scaleDiscreteScale, ContinuousScale, or None, optional

Explicit color policy. Omit to infer continuous numeric color and discrete categorical color.

linestyle_scaleDiscreteScale or None, optional

Explicit discrete line-style policy.

stylemapping or None, optional

Fixed Line2D properties. A mapped color or linestyle cannot also appear here, including through Matplotlib’s c and ls aliases.

sort{“input”, “x”}, default “input”

Preserve input order within each line or stably sort by x. Duplicate x values retain their relative input order; no aggregation is performed.

group_missing{“drop”, “keep”, “raise”}, default “drop”

Policy for rows whose explicit group value is missing.

Returns:
LineResult

The original axes, ordinary line artists, trained scales, diagnostics, and committed layer identifier.

Raises:
TypeError

If inputs, columns, grouping values, or fixed style are invalid.

ValueError

If columns conflict, scale training fails, or a continuous color varies within one resolved line.

Notes

The operation resolves and validates every group before drawing, then commits semantic state and artists transactionally. Adding a layer may retrain a shared continuous scale and update earlier managed lines on the same axes. Existing ggstyle date handles are refreshed after drawing, including collapsed axes.

This helper does not aggregate, smooth, interpolate, construct guides, or create axes. Use style={"color": ...} for a fixed color and color="column" for a semantic mapping.

class ggstyle.LineResult(axes, artists, scales, diagnostics, layer_id)[source]#

Return native artists and trained mappings created by line().

Parameters:
axesmatplotlib.axes.Axes

The exact caller-owned axes passed to line().

artiststuple of matplotlib.lines.Line2D

Ordinary Matplotlib line artists, one per resolved group.

scalesmapping of str to AestheticScale

Trained scales used by this layer, keyed by "color" or "linestyle". The mapping is read-only.

diagnosticstuple of str

Non-fatal accessibility or dropped-row diagnostics.

layer_idstr

Stable identifier for this committed semantic layer.

as_dict()[source]#

Return a bounded, deterministic, JSON-compatible summary.

Returns:
dict of str to object

Fresh containers describing the layer, native artist counts, trained scales, and diagnostics. Live Matplotlib objects are excluded.

describe()[source]#

Return the result summary as deterministic strict JSON.

Returns:
str

Strict JSON containing the same values as as_dict().

ggstyle.points(data, *, x, y, ax, color=None, group=None, color_scale=None, style=None, missing='drop', group_missing='drop')[source]#

Draw mapped points from named tidy-data columns on an existing axes.

Parameters:
datadataframe-like

Column-bearing dataframe-like or mapping-like data. Input is never mutated.

x, ystr

Required coordinate column names.

axmatplotlib.axes.Axes

Existing caller-owned target axes.

colorstr or None, optional

Column mapped to point face color.

groupstr or None, optional

Column partitioning points into separate native collections.

color_scaleDiscreteScale, ContinuousScale, or None, optional

Explicit color policy. Omit for dtype-based inference.

stylemapping or None, optional

Fixed scatter style. marker and scalar size/s are supported with ordinary collection properties such as alpha, edgecolor, and linewidth.

missing{“drop”, “raise”}, default “drop”

Policy for rows with missing x or y coordinates.

group_missing{“drop”, “keep”, “raise”}, default “drop”

Policy for rows with a missing explicit group value.

Returns:
PointResult

Original axes, ordinary PathCollection artists, trained scales, diagnostics, and the committed layer identifier.

Notes

Discrete color implies separate collections by level. Continuous color maps each retained point independently. No aggregation, jitter, or statistical transform is performed. Existing semantic artists and date handles update transactionally.

class ggstyle.PointResult(axes, artists, scales, diagnostics, layer_id)[source]#

Return native point collections and mappings created by points().

Parameters:
axesmatplotlib.axes.Axes

The exact caller-owned axes passed to points().

artiststuple of matplotlib.collections.PathCollection

Ordinary Matplotlib scatter collections, one per resolved group.

scalesmapping of str to AestheticScale

Read-only trained scales used by this layer.

diagnosticstuple of str

Non-fatal accessibility or dropped-row diagnostics.

layer_idstr

Stable identifier for this committed semantic layer.

as_dict()[source]#

Return a bounded, deterministic, JSON-compatible summary.

Returns:
dict of str to object

Fresh containers describing the layer, native artist counts, trained scales, and diagnostics. Live Matplotlib objects are excluded.

describe()[source]#

Return the result summary as deterministic strict JSON.

Returns:
str

Strict JSON containing the same values as as_dict().

ggstyle.ribbon(data, *, x, lower, upper, ax, color=None, group=None, color_scale=None, style=None, alpha=0.2, label=None, sort='input', missing='break', group_missing='drop', validate_order=False)[source]#

Draw caller-supplied lower/upper bounds as native Matplotlib ribbons.

Parameters:
datadataframe-like

Column-bearing dataframe-like or mapping-like data. Input is never mutated.

x, lower, upperstr

Required coordinate and bound column names.

axmatplotlib.axes.Axes

Existing caller-owned target axes.

colorstr or None, optional

Column mapped to ribbon face color.

groupstr or None, optional

Column partitioning rows into separate ribbons.

color_scaleDiscreteScale, ContinuousScale, or None, optional

Explicit color policy. Omit for dtype-based inference.

stylemapping or None, optional

Fixed PolyCollection properties excluding mapped color, alpha, and label.

alphafloat, default 0.2

Fixed ribbon opacity between zero and one.

labelstr or None, optional

Verbatim Matplotlib label applied to every resolved ribbon.

sort{“input”, “x”}, default “input”

Preserve input order within each ribbon or stably sort by x.

missing{“break”, “drop”, “raise”}, default “break”

Break ribbons at missing coordinates, connect across them, or reject them.

group_missing{“drop”, “keep”, “raise”}, default “drop”

Policy for rows with a missing explicit group value.

validate_orderbool, default False

Reject rows whose lower bound exceeds their upper bound when true.

Returns:
RibbonResult

Original axes, ordinary PolyCollection artists, trained scales, diagnostics, and the committed layer identifier.

Notes

The helper performs no statistical inference. Missing coordinates break a ribbon by default, while missing="drop" explicitly connects across gaps. Crossed bounds are accepted unless validate_order=True. A caller label is preserved verbatim and never synthesized from mappings.

class ggstyle.RibbonResult(axes, artists, scales, diagnostics, layer_id)[source]#

Return native ribbon collections and mappings created by ribbon().

Parameters:
axesmatplotlib.axes.Axes

The exact caller-owned axes passed to ribbon().

artiststuple of matplotlib.collections.PolyCollection

Ordinary Matplotlib ribbon collections, one per resolved segment.

scalesmapping of str to AestheticScale

Read-only trained scales used by this layer.

diagnosticstuple of str

Non-fatal accessibility or dropped-row diagnostics.

layer_idstr

Stable identifier for this committed semantic layer.

as_dict()[source]#

Return a bounded, deterministic, JSON-compatible summary.

Returns:
dict of str to object

Fresh containers describing the layer, native artist counts, trained scales, and diagnostics. Live Matplotlib objects are excluded.

describe()[source]#

Return the result summary as deterministic strict JSON.

Returns:
str

Strict JSON containing the same values as as_dict().

ggstyle.guides(ax, *, enabled=True)[source]#

Build native legends and colorbars from an axes’ trained mappings.

Parameters:
axmatplotlib.axes.Axes

Existing caller-owned axes whose complete semantic registry supplies the guides.

enabledbool, default True

Build or refresh managed guides. False removes managed guides and disables their automatic refresh without touching caller-owned guides.

Returns:
GuideResult

The original axes, native managed legends and colorbars, and diagnostics.

Notes

Guide entries, titles, ordering, and colors/styles are derived from the complete semantic registry. Compatible color and linestyle mappings for the same variable are merged. Distinct variables or titles remain distinct guides. Caller-owned native legends and colorbars are preserved.

Once called, the managed guides refresh automatically when later line(), points(), or ribbon() calls retrain the axes. Pass enabled=False to remove managed guides and disable that refresh behavior.

class ggstyle.GuideResult(axes, legends, colorbars, diagnostics)[source]#

Return native guides managed by guides().

Parameters:
axesmatplotlib.axes.Axes

The exact caller-owned semantic axes.

legendstuple of matplotlib.legend.Legend

One native legend for each distinct compatible discrete guide.

colorbarstuple of matplotlib.colorbar.Colorbar

One native colorbar for each continuous color scale.

diagnosticstuple of str

Deterministic merge and coexistence diagnostics.

as_dict()[source]#

Return a bounded, deterministic, JSON-compatible summary.

Returns:
dict of str to object

Fresh containers describing native guide counts, titles, and diagnostics. Live Matplotlib objects are excluded.

describe()[source]#

Return the result summary as deterministic strict JSON.

Returns:
str

Strict JSON containing the same values as as_dict().

class ggstyle.AestheticScale(*args, **kwargs)[source]#

Public inspection boundary for a trained semantic scale.

as_dict()[source]#

Return the trained scale as deterministic JSON-compatible data.

describe()[source]#

Return a deterministic strict-JSON description of the scale.

class ggstyle.DiscreteScale(values=None, order=None, include_unobserved=False, missing='map', missing_value=None, name=None)[source]#

Configure a reusable discrete color or linestyle mapping.

Parameters:
valuestuple of str or None, optional

Ordered output values. Use #RRGGBB colors for color_scale= or solid, dashed, dashdot, and dotted for linestyle_scale=. None uses ggstyle’s accessible defaults.

ordertuple of object or None, optional

Explicit category order. Observations outside it are errors.

include_unobservedbool, default False

Retain explicit or pandas categorical levels absent from the current data.

missing{“map”, “drop”, “raise”}, default “map”

Missing-value policy.

missing_valuestr or None, optional

Output used when missing="map". The aesthetic default is used when omitted.

namestr or None, optional

Guide title. The mapped source-column name is used when omitted.

Notes

The policy is axes-independent and immutable. Context-specific validation, such as hexadecimal colors versus named line styles, occurs when the policy is applied to a mapped aesthetic.

class ggstyle.ContinuousScale(palette=<factory>, limits=None, missing='map', infinite='raise', name=None)[source]#

Configure a reusable continuous color mapping.

Parameters:
palettePalette, optional

Sequential or diverging palette policy.

limitstuple of float or None, optional

Explicit lower and upper data-domain limits. Automatic training uses the finite union of all participating layers.

missing{“map”, “drop”, “raise”}, default “map”

Missing-value policy.

infinite{“clip”, “color”, “drop”, “raise”}, default “raise”

Policy for positive and negative infinity.

namestr or None, optional

Guide title. The mapped source-column name is used when omitted.

Plot finishing#

ggstyle.finish(ax, *, title=None, subtitle=None, caption=None, theme=None, direct_labels=None, x=None, y=None, dry_run=False)[source]#

Apply coherent labels to an existing Matplotlib axes transactionally.

Parameters:
axmatplotlib.axes.Axes

Existing axes to finish. The axes and its data artists are not wrapped.

titlestr or None, optional

Plot title. None leaves every existing title unchanged.

subtitlestr, False, or None, optional

Layout-managed subtitle. None leaves an existing ggstyle subtitle unchanged and False removes it.

captionstr, False, or None, optional

Layout-managed caption. None leaves an existing ggstyle caption unchanged and False removes it.

themestr, ThemeSpec, or None, optional

Complete theme for the existing axes. Only safely retroactive properties are applied; the plan reports preserved creation-, data-, and output-time settings.

direct_labelsEndLabelSpec, False, or None, optional

Managed labels for visible line endpoints. None leaves existing endpoint labels unchanged and False removes them.

xAxisSpec or None, optional

X-axis title and numeric label policy.

yAxisSpec or None, optional

Y-axis title and numeric label policy.

dry_runbool, default False

Return the validated plan without changing Matplotlib state when true.

Returns:
FinishResult or FinishPlan

Native axes and artists after commit, or an immutable plan for a dry run.

Raises:
TypeError

If an argument has the wrong type.

Notes

A subtitle or caption participates in the active figure layout. If no layout engine is configured, ggstyle enables constrained layout for that figure. Existing layout engines are preserved. Validation and dry runs never draw the canvas or mutate the axes, artists, figure, or global rcParams.

Examples

>>> import matplotlib.pyplot as plt
>>> fig, ax = plt.subplots()
>>> result = finish(
...     ax,
...     title="Revenue",
...     subtitle="Trailing twelve months",
...     caption="Source: annual report",
...     x=axis(title="Date"),
... )
>>> result.axes is ax
True
>>> plt.close(fig)
ggstyle.axis(*, title=None, labels=None)[source]#

Create an immutable axis-finishing specification.

Parameters:
titlestr or None, optional

Axis title. None leaves the existing title unchanged.

labelsNumericLabeller or None, optional

Numeric label policy. Use label_percent(), label_currency(), label_number(), or label_si() to construct one.

Returns:
AxisSpec

Reusable, axes-independent specification.

Examples

>>> specification = axis(title="Share", labels=label_percent(decimals=1))
>>> specification.title
'Share'
class ggstyle.AxisSpec(title=None, labels=None)[source]#

Describe the labels applied to one existing Matplotlib axis.

Parameters:
titlestr or None, optional

Axis title. None leaves the existing title unchanged; an empty string clears it.

labelsNumericLabeller or None, optional

Numeric label policy installed through an ordinary Matplotlib FuncFormatter. None leaves the existing formatter unchanged.

Notes

The model is immutable and does not retain an Axes. Use axis() for construction and pass the result to finish().

class ggstyle.FinishPlan(title, subtitle, caption, theme, direct_labels, direct_label_action, x, y, managed_changes, layout_action, diagnostics=())[source]#

Describe a validated finishing operation without retaining live artists.

Parameters:
titlestr or None

Requested plot title; None means unchanged.

subtitlestr, False, or None

Requested managed subtitle operation.

captionstr, False, or None

Requested managed caption operation.

themeThemeSpec or None

Resolved theme requested for the existing axes.

direct_labelsEndLabelSpec, False, or None

Requested endpoint-label operation.

direct_label_action{“unchanged”, “remove”, “labels”, “legend”}

Resolved endpoint-label strategy.

xAxisSpec or None

Requested x-axis changes.

yAxisSpec or None

Requested y-axis changes.

managed_changestuple of str

Ordered descriptions of requested mutations.

layout_action{“unchanged”, “enable-constrained”}

Figure layout action required for outer managed text.

diagnosticstuple of str

Non-fatal limitations discovered while planning.

as_dict()[source]#

Return the complete finishing plan as JSON-compatible plain values.

The result contains no Matplotlib artists or Python callables. It is suitable for logging, snapshot tests, and strict json.dumps() serialization.

Returns:
dict of str to object

Fresh nested values suitable for strict JSON serialization.

describe()[source]#

Return the complete finishing plan as deterministic formatted JSON.

Returns:
str

Strict JSON containing the same values as as_dict().

class ggstyle.FinishResult(axes, artists, plan)[source]#

Return native Matplotlib objects and the plan applied by finish().

Parameters:
axesmatplotlib.axes.Axes

The exact axes passed to finish().

artiststuple of matplotlib.artist.Artist

Native non-data artists affected by the request and attached managed text.

planFinishPlan

Immutable plan used for the successful mutation.

property diagnostics#

Return non-fatal diagnostics recorded during planning.

ggstyle.end_labels(*, collision='avoid', fallback='legend')[source]#

Create an immutable line endpoint-label specification.

Parameters:
collision{“avoid”, “none”}, default “avoid”

Vertical collision policy.

fallback{“legend”, “raise”}, default “legend”

Policy for unsupported artists, invisible endpoints, or insufficient space.

Returns:
EndLabelSpec

Reusable policy that retains no Matplotlib artists.

Examples

>>> specification = end_labels(collision="avoid", fallback="legend")
>>> specification.collision
'avoid'
class ggstyle.EndLabelSpec(collision='avoid', fallback='legend')[source]#

Describe collision and fallback policy for line endpoint labels.

Parameters:
collision{“avoid”, “none”}, default “avoid”

Resolve vertical overlap in display space, or retain exact endpoint positions.

fallback{“legend”, “raise”}, default “legend”

Use an ordinary Matplotlib legend when every participating artist cannot be labelled safely, or raise before mutating the axes.

Notes

The specification is immutable and retains no Matplotlib artists. Pass it to ggstyle.finish() through direct_labels=.

Figure export#

ggstyle.save(figure, filename, *, width, height, units='in', dpi=300, format=None, transparent=False, bbox='tight', metadata=None, overwrite=False)[source]#

Save an explicit Matplotlib figure with reproducible, safe defaults.

Parameters:
figurematplotlib.figure.Figure

Figure to export. A current figure is never inferred.

filenamestr or path-like

Exact destination. Parent directories are not created automatically.

widthfloat

Positive output-canvas width in units.

heightfloat

Positive output-canvas height in units.

units{“in”, “cm”, “mm”, “px”}, default “in”

Unit for width and height. Pixel dimensions use dpi for conversion.

dpifloat, default 300

Positive rendering resolution. This also defines the physical size of pixel dimensions for vector output.

formatstr or None, optional

Matplotlib output format. None infers it from the filename extension. An explicit format must agree with any extension.

transparentbool, default False

Whether figure and axes patches are transparent in the saved artifact.

bbox{“tight”, “standard”}, default “tight”

"tight" crops to decorated content with deterministic 0.1-inch padding; "standard" preserves the complete requested canvas.

metadatamapping or None, optional

Format-specific string metadata passed to Matplotlib. None values suppress supported backend defaults. SVG and PDF timestamps are suppressed by default.

overwritebool, default False

Replace an existing file only when explicitly true.

Returns:
pathlib.Path

The destination path after a successful atomic publication.

Raises:
TypeError

If an argument has the wrong type.

ValueError

If dimensions, format, units, bounding policy, or metadata are invalid.

FileExistsError

If the destination exists and overwrite is false.

FileNotFoundError

If the destination parent does not exist.

Notes

Rendering occurs in a temporary file in the destination directory. A failed render leaves an existing destination intact and never publishes a partial new artifact. The original figure size and global rcParams are restored before publication. SVG IDs use a stable salt and SVG/PDF timestamps are omitted for repeatable output.

Examples

>>> import matplotlib.pyplot as plt
>>> fig, ax = plt.subplots()
>>> _ = ax.plot([0, 1], [0, 1])
>>> path = save(fig, "report.png", width=7, height=4, overwrite=True)
>>> path.name
'report.png'
>>> path.unlink()
>>> plt.close(fig)

Date axes#

ggstyle.dates(ax=None, data=None, *, mode=None, missing='raise')[source]#

Return the date-axis handle for a matplotlib axes.

Works on any Axes, including plots this package never made:

fig, ax = plt.subplots()
ax.plot(df["date"], df["close"])       # plain matplotlib
gs.dates(ax).ticks("quarterly")        # adopted
Parameters:
axmatplotlib.axes.Axes, optional

Target Axes. Defaults to the current one.

dataarray-like, optional

Optional dates to register as observations, in addition to whatever is already plotted. Needed only when collapsing an axis whose dates are not recoverable from its artists.

mode{“show”, “collapse”}, optional

"show" or "collapse". Omit to leave an existing handle alone.

missing{“raise”, “drop”}, default “raise”

Policy for missing values in explicitly supplied data.

Returns:
DateAxis

Cached handle bound to ax.

Raises:
TypeError

If the target does not appear to use a date x-axis.

ValueError

If mode is invalid.

Notes

Repeated calls for the same axes return the same object and refresh its observation registry. This discovers supported artists added, changed, or removed since the previous call.

class ggstyle.DateAxis(ax, data=None, *, mode='show', missing='raise')[source]#

Manage a date-aware x-axis bound to a matplotlib axes.

Obtain instances with dates() instead of constructing them directly. The accessor caches one handle per axes, so repeated calls return the same object.

Parameters:
axmatplotlib.axes.Axes

Axes whose x-axis will be managed.

dataarray-like, optional

Additional observed dates. Values must already have a datetime dtype or be unambiguously date-like Python objects.

mode{“show”, “collapse”}, default “show”

Initial coordinate mode. "show" preserves calendar gaps; "collapse" uses observation-ordinal positions.

missing{“raise”, “drop”}, default “raise”

Policy for missing values in explicitly supplied data.

Attributes:
axmatplotlib.axes.Axes

Bound matplotlib axes.

See also

dates

Create or retrieve a date-axis handle.

ggstyle.theme

Apply a scoped matplotlib theme.

Notes

The handle updates tick locators when x-axis limits change. Importing ggstyle never creates a handle or changes matplotlib global state.

Examples

>>> import matplotlib.pyplot as plt
>>> import pandas as pd
>>> fig, ax = plt.subplots()
>>> _ = ax.plot(pd.date_range("2024-01-01", periods=10), range(10))
>>> handle = dates(ax).ticks("daily").fmt("day")
property annotation_artists#

Return the currently attached artists created by annotation helpers.

caption(*, add=False, **kwargs)[source]#

Format a concise description of axis semantics.

Parameters:
addbool, default False

Add the caption below the axes when true.

**kwargs

Additional keyword arguments passed to matplotlib.axes.Axes.text() when add is true.

Returns:
str

Generated caption text.

Notes

Repeated calls with add=True replace the previously managed caption.

clear_annotations()[source]#

Remove all ggstyle-managed date annotations from this axes.

Returns:
DateAxis

This handle, for method chaining.

collapse()[source]#

Switch to observation-ordinal coordinates.

Returns:
DateAxis

This handle, for method chaining.

Raises:
RuntimeError

If no observations are registered.

Notes

The registered x-scale changes display coordinates without rewriting artist geometry. Native matplotlib lines, collections, and data-space annotations therefore retain their calendar date coordinates.

date_at(position)[source]#

Return the date corresponding to a native matplotlib data coordinate.

Parameters:
positionfloat

Matplotlib date number, such as an x coordinate obtained from transData.inverted().

Returns:
pandas.Timestamp

Timezone-naive timestamp at position.

dispose()[source]#

Disconnect callbacks and release registry and managed-artist references.

Existing Matplotlib artists remain on the axes; ggstyle simply stops managing them. Calling this method repeatedly is safe.

property disposed#

Return whether this handle has released its axes lifecycle state.

expand()[source]#

Switch to calendar coordinates and restore gaps.

Returns:
DateAxis

This handle, for method chaining.

fmt(spec=None, *, major=None, minor=<object object>)[source]#

Configure tick labels without moving ticks.

Parameters:
specstr or callable, optional

Preset name, strftime pattern, or callable accepting one pandas.Timestamp.

majorstr or callable, optional

Keyword form of spec.

minorstr, callable, or False, optional

Minor tick label format. Omit to leave the current setting unchanged; use False to disable minor labels.

Returns:
DateAxis

This handle, for method chaining.

Raises:
TypeError

If both spec and major are supplied.

ValueError

If a named format is unknown.

grid(spec=None, **kwargs)[source]#

Configure gridlines independently of ticks.

Parameters:
specstr, Cadence, or False, optional

Grid cadence. Use False to remove managed gridlines.

**kwargs

Additional keyword arguments passed to matplotlib.axes.Axes.axvline().

Returns:
DateAxis

This handle, for method chaining.

Examples

.grid(False) removes them; .grid("yearly") draws them once a year regardless of how often ticks appear.

loc(date, *, snap=False, strict=False)[source]#

Return the native matplotlib data coordinate corresponding to a date.

Parameters:
datedate-like

Anything to_timestamp() accepts, including partial strings.

snapbool, default False

Round to the nearest observed date rather than interpolating.

strictbool, default False

Raise if date is not itself an observation.

Returns:
float

Matplotlib date number accepted by native data-space artists and limits.

Raises:
KeyError

If strict is true and date was not observed.

RuntimeError

If strict lookup is requested but no observations are registered.

Notes

The returned coordinate is independent of display mode. In collapsed mode, the registered x-scale maps it to an observation position during rendering. Native datetime-like inputs also work directly with matplotlib; loc() remains useful for parsing, snapping, and strict observation lookup.

property mode#

Return the active coordinate mode.

property observations#

Return sorted, unique dates backing the collapsed axis.

pad(left=None, right=None)[source]#

Extend the visible range without changing artist data.

Parameters:
leftstr or pandas offset, optional

Amount added before the current left limit.

rightstr or pandas offset, optional

Amount added after the current right limit.

Returns:
DateAxis

This handle, for method chaining.

refresh()[source]#

Rescan live data artists and publish one shared registry revision.

Synchronized handles refresh as a group. Existing date-number limits are preserved even when new observations change collapsed display positions.

Returns:
DateAxis

This handle, for method chaining.

Raises:
DateDiscoveryError

If a candidate artist uses an unsupported coordinate transform.

RuntimeError

If this handle has been disposed.

property revision#

Return the committed observation-registry revision.

rotate(degrees=45, *, ha=None)[source]#

Rotate major tick labels.

Parameters:
degreesfloat, default 45

Rotation in degrees.

ha{“left”, “center”, “right”}, optional

Horizontal alignment. Defaults to "right" for nonzero rotation and "center" otherwise.

Returns:
DateAxis

This handle, for method chaining.

Notes

Rotation is usually a symptom of bad tick selection; try .ticks(n=...) or a coarser cadence first.

span(start, end, label=None, **kwargs)[source]#

Draw a shaded region in date coordinates.

Parameters:
startdate-like

Start of the region.

enddate-like

End of the region.

labelstr, optional

Text drawn near the top of the axes.

**kwargs

Additional keyword arguments passed to matplotlib.axes.Axes.axvspan().

Returns:
DateAxis

This handle, for method chaining.

spans(frame, start='start', end='end', label=None, **kwargs)[source]#

Draw multiple shaded regions from an event table.

Parameters:
framepandas.DataFrame

Event table containing start and end columns.

startstr, default “start”

Name of the start-date column.

endstr, default “end”

Name of the end-date column.

labelstr, optional

Name of a column containing annotation text.

**kwargs

Additional keyword arguments forwarded to span().

Returns:
DateAxis

This handle, for method chaining.

summary()[source]#

Return structured information about the date axis.

Returns:
AxisSummary

Immutable snapshot of observations and active configuration.

See also

caption

Format the summary for display on a figure.

ticks(spec=None, *, every=None, n=None, at=None, major=None, minor=None)[source]#

Configure tick positions without changing label formatting.

Parameters:
specstr or Cadence, optional

Named cadence such as "monthly" or an offset alias.

everystr or pandas offset, optional

Explicit interval such as "3M".

nint, optional

Approximate desired number of major ticks.

atiterable of date-like, optional

Explicit major tick dates.

majorstr or Cadence, optional

Keyword form of spec.

minorstr, Cadence, or False, optional

Minor tick cadence. Use False to disable minor ticks.

Returns:
DateAxis

This handle, for method chaining.

Raises:
TypeError

If conflicting major tick specifications are supplied.

ValueError

If n is not a positive integer or the cadence is invalid.

Examples

.ticks("quarterly"), .ticks(every="3M"), .ticks(n=6), .ticks(at=["2020-01-01", "2021-07-01"]), .ticks(major="yearly", minor="monthly"), .ticks("month-end").

tz(zone)[source]#

Set the display timezone used for labels.

Parameters:
zonestr or None

IANA timezone name. Use None to display naive UTC values.

Returns:
DateAxis

This handle, for method chaining.

Notes

This operation changes labels only; it never changes artist data.

vline(date, label=None, **kwargs)[source]#

Draw a vertical line in date coordinates.

Parameters:
datedate-like

Date at which to draw the line.

labelstr, optional

Text drawn near the top of the axes.

**kwargs

Additional keyword arguments passed to matplotlib.axes.Axes.axvline().

Returns:
DateAxis

This handle, for method chaining.

zoom(start=None, end=None, *, last=None, ytd=False)[source]#

Set the visible date range.

Parameters:
startdate-like, optional

Left bound. Partial strings expand to the start of their period.

enddate-like, optional

Right bound. Partial strings expand to the end of their period.

laststr or pandas offset, optional

Trailing window measured from the final observation.

ytdbool, default False

Display the year containing the final observation through that observation.

Returns:
DateAxis

This handle, for method chaining.

Raises:
RuntimeError

If last or ytd is requested without observations.

Notes

"2020" means the whole year and "2020-03" the whole month, so .zoom("2020", "2022") covers three complete years.

class ggstyle.AxisSummary(mode, observations, start, end, inferred_frequency, major_cadence, minor_cadence, timezone, missing_values)[source]#

Describe the data and configuration behind a date axis.

Parameters:
mode{“show”, “collapse”}

Active coordinate mode.

observationsint

Number of unique, non-missing observed dates.

startpandas.Timestamp or None

First observed date.

endpandas.Timestamp or None

Final observed date.

inferred_frequencystr or None

Pandas frequency alias, or a median-spacing description for irregular data.

major_cadencestr

Resolved major tick cadence or "explicit".

minor_cadencestr or None

Resolved minor tick cadence.

timezonestr or None

Label display timezone.

missing_valuesint

Number of explicitly supplied missing dates that were dropped.

Notes

Summaries contain plain values and can be logged, tested, or serialized without inspecting matplotlib artists.

as_dict()[source]#

Return a JSON-compatible description of the resolved date-axis state.

Timestamp values use ISO 8601 text. The returned dictionary retains no Matplotlib artists and may be passed directly to json.dumps().

Returns:
dict of str to object

Fresh nested values suitable for strict JSON serialization.

describe()[source]#

Return the resolved date-axis state as deterministic formatted JSON.

Returns:
str

Strict JSON containing the same values as as_dict().

exception ggstyle.DateDiscoveryError[source]#

Raised when an artist’s date coordinates cannot be discovered safely.

class ggstyle.Cadence(unit, interval=1, anchor='start')[source]#

Describe a recurring tick cadence.

A cadence controls tick placement only. Label text is configured separately by ggstyle.DateAxis.fmt().

Parameters:
unit{“minute”, “hour”, “day”, “week”, “month”, “quarter”, “year”}

One of minute, hour, day, week, month, quarter, year.

intervalint, default 1

Every n-th unit.

anchor{“start”, “end”}, default “start”

"start" or "end" of each period. Month-start vs. month-end is the difference between labels that line up with observations and labels that float between them.

Raises:
ValueError

If the unit, interval, or anchor is invalid.

See also

ggstyle.DateAxis.ticks

Apply a cadence to an axis.

Examples

>>> Cadence("month", interval=3)
Cadence(unit='month', interval=3, anchor='start')
property approx_seconds#

Return the approximate cadence duration in seconds.

property freq#

Return the pandas offset alias used to generate ticks.

property period_alias#

Return the pandas period alias used to group observations.

ggstyle.sync_dates(axes, *, mode=None, limits='union')[source]#

Synchronize date semantics across a collection of axes.

Parameters:
axesiterable of matplotlib.axes.Axes

Axes to adopt and synchronize.

mode{“show”, “collapse”}, optional

Coordinate mode applied to every axes. If omitted, existing modes must agree.

limits{“union”, “intersection”}, default “union”

Whether limits cover every observation or only the overlapping range.

Returns:
list of DateAxis

Handles in the same order as axes.

Raises:
ValueError

If no axes are supplied, modes disagree, limits are invalid, or ranges do not overlap.

Notes

All handles join one live, revisioned observation registry. Refreshing any member rescans every live member and applies the resulting union transactionally.

Numeric labels#

class ggstyle.NumericLabeller[source]#

Convert one numeric value to display text.

Notes

Labellers operate on one value at a time so they compose with Matplotlib’s formatter protocol and remain useful outside an axis. Factory results are immutable; callers may also supply any compatible callable to ggstyle.as_formatter().

ggstyle.label_percent(*, scale=1.0, decimals=0, grouping=False, suffix='%', negative='minus', nan='NaN', infinity='∞')[source]#

Create a locale-independent percentage labeller.

Parameters:
scalefloat, default 1.0

Input value corresponding to 100 percent. Use 100 for inputs already expressed as percentages.

decimalsint, default 0

Fixed number of digits after the decimal point.

groupingbool, default False

Whether to group thousands with commas.

suffixstr, default “%”

Text appended to each finite value.

negative{“minus”, “parentheses”}, default “minus”

Presentation for negative finite values and negative infinity.

nanstr, default “NaN”

Complete label used for not-a-number values.

infinitystr, default “∞”

Unsigned complete label used for infinite values.

Returns:
NumericLabeller

Immutable callable accepting one numeric value.

Raises:
TypeError

If an option has the wrong type.

ValueError

If scale, decimals, or negative is invalid.

Examples

>>> percent = label_percent(decimals=1)
>>> percent(0.125)
'12.5%'
ggstyle.label_currency(symbol='$', *, scale=1.0, decimals=2, grouping=True, suffix='', negative='minus', nan='NaN', infinity='∞')[source]#

Create a locale-independent currency labeller.

Parameters:
symbolstr, default “$”

Currency symbol or code placed before finite values.

scalefloat, default 1.0

Positive divisor applied before formatting. For example, 1_000_000 formats source units as millions.

decimalsint, default 2

Fixed number of digits after the decimal point.

groupingbool, default True

Whether to group thousands with commas.

suffixstr, optional

Text appended to each finite value, such as "M".

negative{“minus”, “parentheses”}, default “minus”

Presentation for negative finite values and negative infinity.

nanstr, default “NaN”

Complete label used for not-a-number values.

infinitystr, default “∞”

Unsigned complete label used for infinite values.

Returns:
NumericLabeller

Immutable callable accepting one numeric value.

Raises:
TypeError

If an option has the wrong type.

ValueError

If scale, decimals, or negative is invalid.

Examples

>>> currency = label_currency("$", scale=1_000_000, decimals=1, suffix="M")
>>> currency(2_500_000)
'$2.5M'
ggstyle.label_number(*, scale=1.0, decimals=0, grouping=True, prefix='', suffix='', negative='minus', nan='NaN', infinity='∞')[source]#

Create a locale-independent decimal number labeller.

Parameters:
scalefloat, default 1.0

Positive divisor applied before formatting.

decimalsint, default 0

Fixed number of digits after the decimal point.

groupingbool, default True

Whether to group thousands with commas.

prefixstr, optional

Text placed before each finite value.

suffixstr, optional

Text appended to each finite value.

negative{“minus”, “parentheses”}, default “minus”

Presentation for negative finite values and negative infinity.

nanstr, default “NaN”

Complete label used for not-a-number values.

infinitystr, default “∞”

Unsigned complete label used for infinite values.

Returns:
NumericLabeller

Immutable callable accepting one numeric value.

Raises:
TypeError

If an option has the wrong type.

ValueError

If scale, decimals, or negative is invalid.

Examples

>>> number = label_number(decimals=1)
>>> number(12345.6)
'12,345.6'
ggstyle.label_si(*, unit='', decimals=1, separator=' ', negative='minus', nan='NaN', infinity='∞')[source]#

Create a labeller using powers-of-1000 SI prefixes.

Parameters:
unitstr, optional

Unit appended after the SI prefix.

decimalsint, default 1

Fixed number of digits after the decimal point.

separatorstr, default “ “

Text between the number and the combined SI prefix and unit.

negative{“minus”, “parentheses”}, default “minus”

Presentation for negative finite values and negative infinity.

nanstr, default “NaN”

Complete label used for not-a-number values.

infinitystr, default “∞”

Unsigned complete label used for infinite values.

Returns:
NumericLabeller

Immutable callable accepting one numeric value.

Raises:
TypeError

If an option has the wrong type.

ValueError

If decimals or negative is invalid.

Notes

Prefixes cover powers from quecto (q, 10^-30) through quetta (Q, 10^30). Values beyond that range use the nearest available prefix. Rounding uses Python’s locale-independent fixed-point formatting.

Examples

>>> storage = label_si(unit="B")
>>> storage(1_500_000)
'1.5 MB'
ggstyle.as_formatter(labeller)[source]#

Adapt a one-value numeric labeller to Matplotlib.

Parameters:
labellercallable

Callable accepting one numeric value and returning display text.

Returns:
matplotlib.ticker.FuncFormatter

Formatter that ignores Matplotlib’s optional tick-position argument.

Raises:
TypeError

If labeller is not callable.

Notes

Creating an adapter does not install it on an axis or mutate Matplotlib configuration. Pass the result to Axis.set_major_formatter explicitly.

Examples

>>> from ggstyle import as_formatter, label_percent
>>> formatter = as_formatter(label_percent(decimals=1))
>>> formatter(0.125)
'12.5%'

Palettes#

class ggstyle.Palette(name, kind, colors, positions, missing_color, out_of_bounds, under_color, over_color, midpoint)[source]#

Describe an immutable collection of related colours.

Parameters:
namestr

Canonical palette name.

kind{“qualitative”, “sequential”, “diverging”}

Semantic palette kind.

colorstuple of str

Stable #RRGGBB colours. Qualitative order is meaningful.

positionstuple of float

Normalized positions for continuous and diverging colours; empty for a qualitative palette.

missing_colorstr

Colour returned for a missing normalized value.

out_of_bounds{“clip”, “color”, “raise”}

Policy for normalized values outside zero through one.

under_colorstr or None

Colour below zero when out_of_bounds="color".

over_colorstr or None

Colour above one when out_of_bounds="color".

midpointfloat or None

Normalized neutral position for a diverging palette.

Notes

Use palette() instead of constructing this model directly. The model remains public so policy is inspectable and reusable without Matplotlib.

at(position, /)[source]#

Return the colour at one normalized numeric position.

Parameters:
positionfloat or None

Value from zero through one. None and NaN use missing_color.

Returns:
str

Uppercase #RRGGBB colour.

Raises:
TypeError

If this is a qualitative palette or position is not numeric.

ValueError

If an out-of-bounds value is rejected by the configured policy.

Notes

This method maps an already-normalized value. Training a data domain and assigning category colours belong to semantic scales, not palettes.

sample(n)[source]#

Return n deterministic colours from the palette.

Parameters:
nint

Positive number of colours. Qualitative palettes cannot exceed their declared cardinality. Diverging samples require an odd value of at least three so the neutral midpoint remains present.

Returns:
tuple of str

Immutable sequence of uppercase #RRGGBB colours.

Raises:
TypeError

If n is not an integer.

ValueError

If n is outside the palette’s supported cardinality.

ggstyle.palette(name='qualitative', n=None, *, missing_color='#B3B3B3', out_of_bounds='clip', under_color=None, over_color=None, midpoint=None)[source]#

Create an immutable qualitative, sequential, or diverging palette.

Parameters:
namestr, default “qualitative”

Canonical name or "okabe-ito", "viridis", or "blue-orange" alias.

nint or None, optional

Number of colours to materialize. None retains the reviewed anchor set. Qualitative palettes support at most eight colours; diverging palettes require an odd value of at least three.

missing_colorstr, default “#B3B3B3”

#RRGGBB colour for missing normalized values.

out_of_bounds{“clip”, “color”, “raise”}, default “clip”

Policy for normalized values outside zero through one.

under_colorstr or None, optional

Colour below zero when out_of_bounds="color".

over_colorstr or None, optional

Colour above one when out_of_bounds="color".

midpointfloat or None, optional

Neutral normalized position for a diverging palette. The default is 0.5. Other palette kinds reject this argument.

Returns:
Palette

Immutable palette with stable colour order and explicit policies.

Raises:
TypeError

If an option has the wrong type.

ValueError

If a name, colour, cardinality, midpoint, or policy is invalid.

Notes

The qualitative palette is the cycle used by ggstyle themes. Requesting more than eight colours fails instead of synthesizing hard-to-distinguish values. Continuous and diverging sampling interpolates in CIELAB space.

Examples

>>> palette("qualitative", n=3).colors
('#0072B2', '#D55E00', '#009E73')
>>> palette("sequential").at(0.5)
'#26908B'
ggstyle.available_palettes()[source]#

Return canonical palette names in semantic order.

Returns:
list of str

Qualitative, sequential, and diverging palette names.

Examples

>>> available_palettes()
['qualitative', 'sequential', 'diverging']

Themes#

class ggstyle.ThemeSpec(name='minimal', base_size=None, base_family=None, overrides=None)[source]#

Describe an immutable parameterized ggstyle theme.

Parameters:
namestr, default “minimal”

Canonical theme name or accepted alias.

base_sizefloat or None, optional

Base font size in points. Related theme text sizes scale proportionally. None preserves the packaged stylesheet values exactly.

base_familystr or None, optional

Font family used by the theme. None preserves the stylesheet family.

overridesmapping or None, optional

Explicit Matplotlib rcParam replacements. Values are validated immediately and defensively copied; explicit overrides win over base scaling.

Notes

A specification is pure policy and does not change rcParams. Pass it to theme_params(), theme, use_theme(), or ggstyle.finish.

ggstyle.theme_spec(name='minimal', *, base_size=None, base_family=None, overrides=None)[source]#

Create an immutable, validated theme specification.

Parameters:
namestr, default “minimal”

Canonical theme name or accepted alias.

base_sizefloat or None, optional

Base font size in points.

base_familystr or None, optional

Font family name.

overridesmapping or None, optional

Matplotlib rcParam values applied after base size and family resolution.

Returns:
ThemeSpec

Reusable theme policy that retains no Matplotlib artists.

Examples

>>> specification = theme_spec("minimal", base_size=11)
>>> specification.name
'minimal'
ggstyle.theme_params(specification='minimal')[source]#

Return a validated, read-only parameter mapping for one theme.

Parameters:
specificationstr or ThemeSpec, default “minimal”

Packaged theme name or parameterized theme specification.

Returns:
collections.abc.Mapping

Read-only resolved rcParam mapping suitable for matplotlib.rc_context or third-party integrations.

Raises:
TypeError

If specification is neither a string nor a ThemeSpec.

Notes

Calling this function does not mutate Matplotlib global configuration. Returned sequences are immutable defensive values.

Examples

>>> parameters = theme_params(theme_spec("minimal", base_size=11))
>>> parameters["font.size"]
11.0
ggstyle.use_theme(name='minimal')[source]#

Apply a theme to matplotlib process-wide.

This function delegates to matplotlib’s style system and intentionally changes global rcParams.

Parameters:
namestr or ThemeSpec, default “minimal”

Theme name, accepted alias, or parameterized specification.

See also

theme

Apply a theme temporarily.

theme_spec

Create a parameterized theme recipe.

stylesheet

Return a theme’s stylesheet path.

Notes

gs.use_theme() applies "minimal"; gs.use_theme("grey") applies the ggplot2-style grey panel. ggplot2 function spellings such as "theme_bw" are accepted as aliases, as is "gray" for "grey".

Examples

>>> use_theme("minimal")
class ggstyle.theme(name='minimal')[source]#

Temporarily apply a matplotlib theme.

Parameters:
namestr or ThemeSpec, default “minimal”

Theme name, accepted alias, or parameterized specification.

See also

use_theme

Apply a theme process-wide.

theme_spec

Create a parameterized theme recipe.

stylesheet

Return a theme’s stylesheet path.

Notes

Wraps matplotlib.pyplot.style.context, so every rcParam is restored on exit including ones the caller changed inside the block.

Examples

Use the context manager around figure creation:

with gs.theme("grey"):
    fig, ax = plt.subplots()
ggstyle.stylesheet(name='minimal')[source]#

Return the path to a packaged matplotlib stylesheet.

Accepted aliases are normalized to one of the names returned by available_themes().

Parameters:
namestr, default “minimal”

Theme name or accepted alias.

Returns:
pathlib.Path

Existing stylesheet path.

Raises:
ValueError

If name is unknown.

FileNotFoundError

If the installed package is missing the requested stylesheet.

See also

available_themes

Return canonical theme names.

theme_params

Resolve a parameterized theme without applying it.

use_theme

Apply a stylesheet process-wide.

Examples

Useful on its own: plt.style.use(gs.stylesheet()) works without importing anything else from this package.

ggstyle.available_themes()[source]#

Return available theme names in preference order.

Theme aliases are excluded. The first entry is the default used by use_theme() and theme.

Returns:
list of str

Canonical names with the default theme first.

See also

stylesheet

Return the stylesheet for a theme.

theme_spec

Create a parameterized theme recipe.

use_theme

Apply a theme process-wide.

Examples

>>> available_themes()
['minimal', 'grey', 'bw', 'linedraw', 'light', 'dark', 'classic', 'void', 'test']