Skip to content

Chart

The Chart class — declaration, encoding, theming, and rendering.

Ferrum — a statistical visualization library with a Rust core.

Chart

Bases: ConfigureMixin, StatisticalMarksMixin, DiagnosticMarksMixin, SpecBuildMixin, _RenderMixin

Top-level chart value class.

Every method returns a new Chart — the object is effectively immutable and safe to reuse across branches of a pipeline. The fluent API follows the pattern::

fm.Chart(df).mark_point().encode(x="sepal_length", y="sepal_width")

Parameters:

Name Type Description Default
data DataFrame - like or None

Input data. Accepts Polars DataFrame, pandas DataFrame, PyArrow Table / RecordBatch, dict-of-arrays, list-of-records, or a 2-D NumPy array. Passed through ferrum._coerce.to_arrow_table at render time. None is allowed when composing layered charts that share a parent's data.

None
width int or 'container'

Chart width in pixels, or "container" to fill the parent element. Default is 600.

None
height int or 'container'

Chart height in pixels. Default is 400.

None
title str

Title rendered above the plot area.

None
description str

Accessible description attached to the SVG root (<title> element).

None

Examples:

>>> import ferrum as fm
>>> import polars as pl
>>> df = pl.DataFrame({"x": [1, 2, 3], "y": [4, 5, 6]})
>>> chart = fm.Chart(df).mark_point().encode(x="x", y="y")
>>> svg = chart.to_svg()

layer_names property

layer_names: list[str]

Named sub-layers after composite-mark desugar resolution.

Returns [] for single-mark charts with no layers. Accessing this property forces resolution of any pending _PendingMark.

to_svg

to_svg(*, raster: bool | None = None) -> str

Return the chart rendered as an SVG string.

This returns the SVG markup; it does not display the chart. Use :meth:show to display inline or in a browser, or :meth:save to write to disk.

Parameters:

Name Type Description Default
raster bool or None

Override the auto-raster policy for this render only. False forces per-element SVG regardless of mark count. True forces raster aggregation. None uses the chart's RenderConfig policy.

None

Returns:

Type Description
str

SVG markup for the chart.

Examples:

>>> import ferrum as fm
>>> import polars as pl
>>> df = pl.DataFrame({"x": [1, 2, 3], "y": [4, 5, 6]})
>>> svg = fm.Chart(df).mark_point().encode(x="x", y="y").to_svg()
>>> svg.startswith("<svg")
True

to_png

to_png(*, raster: bool | None = None, scale: float = 2.0) -> bytes

Return the chart rendered as PNG bytes.

This returns the PNG-encoded image data; it does not display the chart. Use :meth:show to display, or :meth:save to write to disk.

Parameters:

Name Type Description Default
raster bool or None

Override the auto-raster policy for this render only. False forces per-element rendering. True forces raster. None uses the chart's RenderConfig policy.

None
scale float

Pixel-density multiplier applied to the chart's intrinsic dimensions. 2.0 (the default) produces a retina-quality image at twice the logical pixel count. 1.0 renders at 1:1 resolution.

2.0

Returns:

Type Description
bytes

PNG-encoded image data.

Examples:

>>> import ferrum as fm
>>> import polars as pl
>>> df = pl.DataFrame({"x": [1, 2, 3], "y": [4, 5, 6]})
>>> png = fm.Chart(df).mark_point().encode(x="x", y="y").to_png()
>>> png[:4] == b'\x89PNG'
True

to_html

to_html(*, embed_wasm: bool = True, toolbar: bool = True, raster: bool | None = None, csp_nonce: str | None = None) -> str

Return the chart as a self-contained interactive HTML document.

This returns the HTML markup; it does not display the chart or write it to disk. The returned string is byte-identical to what save(path) writes for an .html destination — it embeds the WASM-backed interactive renderer rather than a static SVG snapshot. Because it bundles that renderer, the document is substantially larger than a static export; for a lightweight static image use :meth:to_svg / :meth:to_png.

Parameters:

Name Type Description Default
embed_wasm bool

When True, the WASM binary is base64-inlined for single-file distribution. When False, the document references an adjacent ferrum_wasm_bg.wasm sidecar that must be served alongside it.

True
toolbar bool

When False, the interactive toolbar (zoom / pan controls, export button) is hidden in the rendered HTML.

True
raster bool or None

Override the auto-raster policy for this render only. False forces per-element rendering. True forces raster. None uses the chart's RenderConfig policy.

None
csp_nonce str

When provided, both the <style> and <script type="module"> tags receive a nonce="..." attribute so they pass strict Content-Security-Policy headers.

None

Returns:

Type Description
str

A complete, self-contained interactive HTML document.

Examples:

>>> import ferrum as fm
>>> import polars as pl
>>> df = pl.DataFrame({"x": [1, 2, 3], "y": [4, 5, 6]})
>>> html = fm.Chart(df).mark_point().encode(x="x", y="y").to_html()
>>> html.lstrip().startswith("<!")
True

show_svg

show_svg(*, raster: bool | None = None) -> str

Render the chart to an SVG string.

.. deprecated:: 0.16.0 Use :meth:to_svg instead. show_svg will be removed in a future release. It now forwards to :meth:to_svg.

Parameters:

Name Type Description Default
raster bool or None

Override the auto-raster policy for this render only.

None

Returns:

Type Description
str

SVG markup for the chart.

show_png

show_png(*, raster: bool | None = None, scale: float = 2.0) -> bytes

Render the chart to PNG bytes.

.. deprecated:: 0.16.0 Use :meth:to_png instead. show_png will be removed in a future release. It now forwards to :meth:to_png.

Parameters:

Name Type Description Default
raster bool or None

Override the auto-raster policy for this render only.

None
scale float

Pixel-density multiplier applied to the chart's intrinsic dimensions.

2.0

Returns:

Type Description
bytes

PNG-encoded image data.

save

save(path, *, format=None, embed_wasm=True, raster: bool | None = None, scale: float = 2.0, toolbar: bool = True, csp_nonce: str | None = None) -> None

Save the chart to a file on disk.

Parameters:

Name Type Description Default
path str or Path

Destination file path. Extension determines the default format: .svg -> SVG, .png -> PNG, .html -> HTML, .json -> JSON, .pdf -> PDF.

required
format ('svg', 'png', 'html', 'json', 'pdf')

Explicit format override. None (default) infers from path.

"svg"
embed_wasm bool

For "html" format only. When True (default), the WASM binary is base64-inlined for single-file distribution.

True
raster bool or None

Override the auto-raster policy for this save only. False forces per-element output. True forces raster. None uses the chart's RenderConfig policy.

None
scale float

Pixel-density multiplier for PNG and PDF output. Has no effect on SVG, HTML, or JSON exports.

2.0
toolbar bool

For "html" format only. When False, the interactive toolbar is hidden in the rendered HTML.

True
csp_nonce str

For "html" format only. When provided, both the <style> and <script type="module"> tags receive a nonce="..." attribute so they pass strict Content-Security-Policy headers.

None

Examples:

>>> import ferrum as fm
>>> import polars as pl
>>> df = pl.DataFrame({"x": [1, 2, 3], "y": [4, 5, 6]})
>>> fm.Chart(df).mark_point().encode(x="x", y="y").save("/tmp/chart.svg")

show

show(*, raster: bool | None = None) -> None

Display the chart inline or in a browser.

Parameters:

Name Type Description Default
raster bool or None

Override the auto-raster policy for this render only. False forces per-element SVG regardless of mark count. True forces raster aggregation. None uses the chart's RenderConfig policy.

None

Examples:

>>> import ferrum as fm
>>> import polars as pl
>>> df = pl.DataFrame({"x": [1, 2], "y": [3, 4]})
>>> fm.Chart(df).mark_point().encode(x="x", y="y").show()

mark_rank1d

mark_rank1d(*, orient: str = 'horizontal', color_field: str | None = None, position=None, **mark_kwargs) -> 'Chart'

Render a univariate feature-ranking bar chart.

Ranks features by a univariate score (e.g. mutual information, ANOVA F-statistic) and displays them as a bar chart sorted by rank. Data must carry the schema emitted by ModelSource.rank1d(): feature, score, rank.

Parameters:

Name Type Description Default
orient ('horizontal', 'vertical')

Bar orientation. "horizontal" places features on the y axis with score on x; "vertical" places features on x.

"horizontal"
color_field str or None

Column name driving per-feature colour.

None
position Position

Position adjustment.

None
**mark_kwargs

Mark-style overrides for the bar layer.

{}

Returns:

Type Description
Chart

New Chart configured for rank-1D rendering.

Examples:

>>> import ferrum as fm
>>> src = fm.ModelSource(model, X_test, y_test)
>>> fm.Chart(src.rank1d()).mark_rank1d()
Chart(mark='bar', encoding=[])

mark_rank2d

mark_rank2d(*, annot: bool = True, color_field: str = 'correlation', text_field: str = 'correlation_fmt', cmap: str | None = None, position=None, **mark_kwargs) -> 'Chart'

Render a pairwise feature-ranking correlation heatmap.

Displays pairwise feature correlation scores as a colour-coded matrix. When annot=True a text overlay renders each cell's value to 2 dp. Data must carry the schema emitted by ModelSource.rank2d(): feature_x, feature_y, correlation. The chart builder appends a correlation_fmt (Utf8) column when annot=True.

Parameters:

Name Type Description Default
annot bool

Whether to overlay per-cell correlation value text. Default is True.

True
color_field str

Column driving the heatmap colour scale. Default is "correlation".

'correlation'
text_field str

Column read by the text layer. Default is "correlation_fmt".

'correlation_fmt'
cmap str or None

Diverging colormap name for correlation cells. None (default) defers to the theme's diverging scheme.

None
position Position

Position adjustment.

None
**mark_kwargs

Mark-style overrides for the rect layer.

{}

Returns:

Type Description
Chart

New layered Chart configured for rank-2D rendering.

Examples:

>>> import ferrum as fm
>>> src = fm.ModelSource(model, X_test, y_test)
>>> fm.Chart(src.rank2d()).mark_rank2d(annot=True)
Chart(mark='rect', encoding=[])

mark_parallel_coordinates

mark_parallel_coordinates(*, alpha: float = 0.5, color_field: str | None = None, position=None, **mark_kwargs) -> 'Chart'

Render a parallel coordinates plot.

Draws one polyline per sample across normalised feature axes. Data must carry the long-form schema produced by _parallel_coords_chart_from_dataframe: feature (Utf8), value (Float64), sample_id (Utf8), and (optionally) a hue column passed via color_field. The line layer uses mark_style.detail = "sample_id" so each sample renders as its own polyline.

Parameters:

Name Type Description Default
alpha float

Line opacity. Default is 0.5.

0.5
color_field str or None

Column name driving per-sample (or per-class) line colour.

None
position Position

Position adjustment.

None
**mark_kwargs

Mark-style overrides for the line layer.

{}

Returns:

Type Description
Chart

New Chart configured for parallel-coordinates rendering.

Examples:

>>> import ferrum as fm
>>> import polars as pl
>>> df = pl.DataFrame({"feature": ["a","a","b","b"],
...                    "value": [0.5, 0.3, 0.8, 0.2],
...                    "sample_id": ["s0", "s1", "s0", "s1"]})
>>> fm.Chart(df).mark_parallel_coordinates(color_field="sample_id")
Chart(mark='line', encoding=[])

mark_silhouette

mark_silhouette(*, zero_line: bool = True, color_field: str | None = 'cluster', position=None, **mark_kwargs) -> 'Chart'

Render a Rousseeuw silhouette plot.

Displays one horizontal bar per sample whose width encodes its silhouette coefficient, coloured by cluster assignment. Samples within each cluster are stacked vertically in descending coefficient order. Data must carry the schema emitted by ModelSource.silhouette(): sample_id, y_position, cluster, silhouette_value.

When zero_line=True a sentinel _ref_zero column is injected so the downstream mark_rule renders a single vertical rule at x=0.

The method pre-computes _silhouette_x_lo, _silhouette_x_hi, _silhouette_y_lo, and _silhouette_y_hi columns from the raw data so the renderer can draw rect marks directly.

Parameters:

Name Type Description Default
zero_line bool

Whether to draw a vertical reference rule at silhouette = 0. Default is True.

True
color_field str or None

Column name driving per-cluster colour. Default is "cluster".

'cluster'
position Position

Position adjustment.

None
**mark_kwargs

Mark-style overrides for the rect layer.

{}

Returns:

Type Description
Chart

New layered Chart configured for silhouette rendering.

Examples:

>>> import ferrum as fm
>>> src = fm.ModelSource(kmeans, X)
>>> fm.Chart(src.silhouette()).mark_silhouette()
Chart(mark='rect', encoding=[])

mark_pca_scree

mark_pca_scree(*, cumulative_line: bool = True, threshold_line: float | None = None, position=None, **mark_kwargs) -> 'Chart'

Render a PCA scree plot.

Displays explained variance ratio per component as bars and optionally overlays the cumulative variance ratio as a line. Data must carry the schema emitted by ModelSource.pca_variance(): component, explained_variance_ratio, cumulative_variance_ratio.

When threshold_line is non-None a sentinel _threshold_line column is injected so the downstream mark_rule draws a single horizontal reference line at the threshold value.

Parameters:

Name Type Description Default
cumulative_line bool

Whether to overlay a cumulative explained variance line. Default is True.

True
threshold_line float or None

Y-position of an optional horizontal threshold reference line (e.g. 0.95 for 95% explained variance). None (default) omits the line.

None
position Position

Position adjustment.

None
**mark_kwargs

Mark-style overrides for the bar layer.

{}

Returns:

Type Description
Chart

New layered Chart configured for PCA scree rendering.

Examples:

>>> import ferrum as fm
>>> src = fm.ModelSource(pca_model, X)
>>> fm.Chart(src.pca_variance()).mark_pca_scree(threshold_line=0.95)
Chart(mark='rect', encoding=[])

mark_intercluster_distance

mark_intercluster_distance(*, label_clusters: bool = True, color_field: str | None = 'cluster', position=None, **mark_kwargs) -> 'Chart'

Render a 2-D intercluster distance (MDS) plot.

Embeds cluster centres into 2-D using MDS and visualises each centre as a point whose area encodes cluster size. With label_clusters=True a mark_text overlay labels each point by its cluster id. Data must carry the schema emitted by ModelSource.intercluster_distance(): cluster, x, y, size.

Parameters:

Name Type Description Default
label_clusters bool

Whether to overlay cluster-id text labels. Default is True.

True
color_field str or None

Column name driving per-cluster colour. Default is "cluster".

'cluster'
position Position

Position adjustment.

None
**mark_kwargs

Mark-style overrides for the point layer.

{}

Returns:

Type Description
Chart

New layered Chart configured for intercluster-distance rendering.

Examples:

>>> import ferrum as fm
>>> src = fm.ModelSource(kmeans, X)
>>> fm.Chart(src.intercluster_distance()).mark_intercluster_distance()
Chart(mark='point', encoding=[])

mark_decision_boundary

mark_decision_boundary(*, proba: bool = False, color_field: str = 'z', position=None, **mark_kwargs) -> 'Chart'

Render a decision-boundary heatmap.

Colours a pixel grid by the model's predicted class (proba=False) or class probability (proba=True) at each grid point. Data must carry pre-computed cell bound columns x, x2, y, y2 and a prediction column z. The chart builder helper _decision_boundary_chart_from_source produces these columns from a ModelSource.

Parameters:

Name Type Description Default
proba bool

Whether to colour by predicted probability rather than class index. Default is False.

False
color_field str

Column name for the colour encoding. Default is "z".

'z'
position Position

Position adjustment.

None
**mark_kwargs

Mark-style overrides for the rect layer.

{}

Returns:

Type Description
Chart

New Chart configured for decision-boundary rendering.

Examples:

>>> import ferrum as fm
>>> src = fm.ModelSource(clf, X_test, y_test)
>>> fm.Chart(src.decision_boundary()).mark_decision_boundary(proba=True)
Chart(mark='rect', encoding=[])

mark_learning_curve

mark_learning_curve(*, ci_style: str = 'band', color_field: str | None = 'split', position=None, **mark_kwargs) -> 'Chart'

Render a learning curve (train size vs. CV score).

Plots training set size on x against CV score on y, with separate lines for training and validation splits. Data must carry the schema emitted by ModelSource.learning_curve(), pre-deduped per (train_size, split) by the chart builder.

Parameters:

Name Type Description Default
ci_style ('band', 'bars', 'none')

How to display cross-validation variance. "band" draws a shaded ribbon; "bars" draws error bars; "none" omits CI.

"band"
color_field str or None

Column name to drive per-split line colour. Default is "split".

'split'
position Position

Position adjustment.

None
**mark_kwargs

Mark-style overrides for the line layer.

{}

Returns:

Type Description
Chart

New layered Chart configured for learning-curve rendering.

Examples:

>>> import ferrum as fm
>>> src = fm.ModelSource(model, X_train, y_train)
>>> fm.Chart(src.learning_curve()).mark_learning_curve(ci_style="band")
Chart(mark='point', encoding=[])

mark_validation_curve

mark_validation_curve(*, log_scale: bool = False, ci_style: str = 'band', color_field: str | None = 'split', param_label: str | None = None, position=None, **mark_kwargs) -> 'Chart'

Render a validation curve (hyperparameter vs. CV score).

Plots a swept hyperparameter value on x against CV score on y, with separate lines for training and validation splits. Data must carry the schema emitted by ModelSource.validation_curve(), pre-deduped per (param_value, split) by the chart builder.

Parameters:

Name Type Description Default
log_scale bool

Whether to use a log scale on the x axis. Useful for parameters like regularisation strength that span orders of magnitude. Default is False.

False
ci_style ('band', 'bars', 'none')

How to display cross-validation variance.

"band"
color_field str or None

Column name to drive per-split line colour. Default is "split".

'split'
param_label str or None

Human-readable x-axis title for the hyperparameter being swept. The chart builder forwards the user's param argument here.

None
position Position

Position adjustment.

None
**mark_kwargs

Mark-style overrides for the line layer.

{}

Returns:

Type Description
Chart

New layered Chart configured for validation-curve rendering.

Examples:

>>> import ferrum as fm
>>> src = fm.ModelSource(model, X_train, y_train)
>>> fm.Chart(src.validation_curve(param="C")).mark_validation_curve(
...     log_scale=True, param_label="C"
... )
Chart(mark='point', encoding=[])

mark_cv_scores

mark_cv_scores(*, kind: str = 'box', split: str = 'both', color_field: str | None = None, position=None, **mark_kwargs) -> 'Chart'

Render a per-fold cross-validation score summary.

Shows the distribution of CV scores across folds as a box plot, strip plot, or bar chart. Data must carry the schema emitted by ModelSource.cv_scores(). The chart builder pre-aggregates per split when kind="bar" and passes raw per-fold rows for "box" or "strip".

Parameters:

Name Type Description Default
kind ('box', 'strip', 'bar')

Summary plot type.

"box"
split ('train', 'test', 'both')

Which CV split(s) to display.

"train"
color_field str or None

Column to drive per-group colour (and, for kind="box", the transform groupby). None (default) keeps the single-model behaviour: box groups by split alone; strip colours by split and jitters within its band. Passing a distinct column (e.g. "model", the GH #42 compare= dodge path) groups box stats by (split, color_field) and, for kind="strip", drops the default jitter so a chart-level position=Dodge(...) can offset points instead (position adjustments are not composable).

None
position Position

Position adjustment.

None
**mark_kwargs

Mark-style overrides forwarded to constituent layers.

{}

Returns:

Type Description
Chart

New layered Chart configured for CV-score rendering.

Examples:

>>> import ferrum as fm
>>> src = fm.ModelSource(model, X_train, y_train)
>>> fm.Chart(src.cv_scores()).mark_cv_scores(kind="strip", split="test")
Chart(mark='point', encoding=[])

mark_alpha_selection

mark_alpha_selection(*, log_scale: bool = True, highlight_best: bool = True, ci_style: str = 'band', position=None, **mark_kwargs) -> 'Chart'

Render a regularisation-strength (alpha) selection curve.

Sweeps the regularisation parameter alpha and plots CV score as a function of alpha, with variance bands. When highlight_best=True a vertical rule is drawn at the alpha that maximises mean_score. Data must carry the schema emitted by ModelSource.alpha_selection(): alpha, mean_score, score_lo, score_hi, split.

Parameters:

Name Type Description Default
log_scale bool

Whether to use a log scale on the x axis. Default is True (regularisation parameters typically span orders of magnitude).

True
highlight_best bool

Whether to draw a vertical reference rule at the optimal alpha. Default is True.

True
ci_style ('band', 'bars', 'none')

How to display CV variance.

"band"
position Position

Position adjustment.

None
**mark_kwargs

Mark-style overrides forwarded to constituent layers.

{}

Returns:

Type Description
Chart

New layered Chart configured for alpha-selection rendering.

Examples:

>>> import ferrum as fm
>>> src = fm.ModelSource(lasso, X_train, y_train)
>>> fm.Chart(src.alpha_selection()).mark_alpha_selection(log_scale=True)
Chart(mark='point', encoding=[])

mark_importance

mark_importance(*, orient: str = 'horizontal', error_bars: bool = True, top_k: int | None = None, color_field: str | None = None, position=None, **mark_kwargs) -> 'Chart'

Render a feature-importance bar chart.

Renders one bar per feature, sorted descending by importance. When error_bars=True and the data carries imp_lower/imp_upper columns a second errorbar layer is added. Data must carry the schema emitted by ModelSource.importances(): feature, importance, std. The chart builder computes the bound columns and truncates to top_k rows before calling this method.

Parameters:

Name Type Description Default
orient ('horizontal', 'vertical')

Bar orientation. "horizontal" places features on the y axis with importance on x (default); "vertical" swaps axes.

"horizontal"
error_bars bool

Whether to draw error bars from imp_lower/imp_upper. Default is True.

True
top_k int or None

Limit results to the top-k features by importance. Truncation is applied by the figure-level chart builder (importance_chart); when mark_importance is called directly this parameter is forwarded to the desugar function but the desugar layer treats it as informational -- actual filtering must be done on the DataFrame before passing it to Chart.

None
color_field str or None

Column name to drive per-feature colour.

None
position Position

Position adjustment.

None
**mark_kwargs

Mark-style overrides for the bar layer.

{}

Returns:

Type Description
Chart

New layered Chart configured for feature-importance rendering.

Examples:

>>> import ferrum as fm
>>> src = fm.ModelSource(model, X_test, y_test)
>>> fm.Chart(src.importances()).mark_importance(top_k=10)
Chart(mark='point', encoding=[])

mark_shap_beeswarm

mark_shap_beeswarm(*, max_display: int = 20, color_bar: bool = True, order: str = 'abs_mean', zero_line: bool = True, position=None, **mark_kwargs) -> 'Chart'

Render a SHAP beeswarm summary plot.

Visualises the distribution of SHAP values across samples for each feature as a swarm of points, coloured by the feature's original value. Data must carry the long-form schema from ModelSource.shap_values() pre-filtered to the top max_display features by the chart builder.

When zero_line=True (default) a sentinel _ref_zero column is injected and the downstream desugar appends a dashed mark_rule layer at x=0.

Parameters:

Name Type Description Default
max_display int

Maximum number of top features to show. Default is 20.

20
color_bar bool

Whether to render a colour bar for the feature-value scale. Default is True.

True
order ('abs_mean', 'mean', 'none')

Feature ordering: by mean absolute SHAP ("abs_mean"), signed mean SHAP ("mean"), or original order ("none").

"abs_mean"
zero_line bool

Whether to overlay a dashed vertical reference rule at shap_value = 0. Default is True (Schwabish SB-followup 2026-05-12).

True
position Position

Position adjustment.

None
**mark_kwargs

Mark-style overrides for the point layer.

{}

Returns:

Type Description
Chart

New layered Chart configured for SHAP beeswarm rendering.

Examples:

>>> import ferrum as fm
>>> src = fm.ModelSource(model, X_test, y_test)
>>> fm.Chart(src.shap_values()).mark_shap_beeswarm(max_display=15)
Chart(mark='point', encoding=[])

mark_shap_bar

mark_shap_bar(*, max_display: int | None = 20, orient: str = 'horizontal', color_field: str | None = None, position=None, **mark_kwargs) -> 'Chart'

Render a SHAP aggregated-bar feature importance chart.

Shows mean absolute SHAP values per feature as a horizontal bar chart. Data must carry the long-form schema from ModelSource.shap_values() pre-filtered to the top max_display features by the chart builder.

Parameters:

Name Type Description Default
max_display int

Maximum number of top features to show. Default is 20.

20
orient ('horizontal', 'vertical')

Bar orientation. "horizontal" (default) places the value on x and feature on the ordinal y axis, matching the single-model layout. "vertical" swaps the axes (feature on ordinal x, value on y) -- used internally by the compare= dodge-by-model builder, which requires an ordinal-x band axis and re-applies CoordFlip to restore the horizontal visual.

"horizontal"
color_field str or None

Column name driving per-bar colour (e.g. "model" under compare=).

None
position Position

Position adjustment.

None
**mark_kwargs

Mark-style overrides for the bar layer.

{}

Returns:

Type Description
Chart

New Chart configured for SHAP bar rendering.

Examples:

>>> import ferrum as fm
>>> src = fm.ModelSource(model, X_test, y_test)
>>> fm.Chart(src.shap_values()).mark_shap_bar(max_display=10)
Chart(mark='point', encoding=[])

mark_shap_waterfall

mark_shap_waterfall(*, sample_idx: int = -1, max_display: int = 20, position=None, **mark_kwargs) -> 'Chart'

Render a SHAP waterfall chart for one sample.

Shows how each feature pushes the model output from the base value toward the final prediction for a single observation. Data must carry the long-form schema from ModelSource.shap_values() for the chosen sample_idx.

Parameters:

Name Type Description Default
sample_idx int

Row index of the sample to explain. Must be provided explicitly; the default -1 is a guard sentinel that raises ValueError immediately so callers get a clear error at call time rather than at render time.

-1
max_display int

Maximum number of features to show (smallest-magnitude features are collapsed into an "other" row). Default is 20.

20
position Position

Position adjustment.

None
**mark_kwargs

Mark-style overrides for the bar layer.

{}

Returns:

Type Description
Chart

New Chart configured for SHAP waterfall rendering.

Raises:

Type Description
ValueError

If sample_idx is not provided (left at its default of -1).

Examples:

>>> import ferrum as fm
>>> src = fm.ModelSource(model, X_test, y_test)
>>> fm.Chart(src.shap_values()).mark_shap_waterfall(sample_idx=0)
Chart(mark='point', encoding=[])

mark_pdp

mark_pdp(*, kind: str = 'average', ice_alpha: float = 0.2, center: bool = False, color_field: str | None = 'feature', position=None, **mark_kwargs) -> 'Chart'

Render partial-dependence plots (PDP / ICE).

Visualises how the model's output varies as a function of one feature while marginalising over all others. Data must carry the long-form schema from ModelSource.partial_dependence(): feature, feature_value, pd_value. The chart builder pre-sorts ascending by feature_value.

Parameters:

Name Type Description Default
kind ('average', 'individual', 'both')

What to render. "average" draws the mean PD line; "individual" draws ICE lines (one per sample); "both" overlays average on top of ICE lines.

"average"
ice_alpha float

Opacity of individual ICE lines when kind is "individual" or "both". Default is 0.2.

0.2
center bool

Whether to centre ICE lines at their first value (centred ICE). Default is False.

False
color_field str or None

Column name driving per-feature colour. Default is "feature".

'feature'
position Position

Position adjustment.

None
**mark_kwargs

Mark-style overrides for the line layer.

{}

Returns:

Type Description
Chart

New layered Chart configured for PDP / ICE rendering.

Examples:

>>> import ferrum as fm
>>> src = fm.ModelSource(model, X_test, y_test)
>>> fm.Chart(src.partial_dependence()).mark_pdp(kind="both", center=True)
Chart(mark='point', encoding=[])

mark_roc

mark_roc(*, average: str | None = None, reference_line: bool = True, annotate_auc: bool = False, color_field: str | None = 'class', position=None, **mark_kwargs) -> 'Chart'

Render a Receiver Operating Characteristic (ROC) curve.

Plots false-positive rate (fpr) on x against true-positive rate (tpr) on y as a line per class. Data must carry the schema emitted by ModelSource.roc_curve(): fpr, tpr, threshold, class, auc. When reference_line=True the data is pre-sorted ascending by fpr before rendering.

Parameters:

Name Type Description Default
average str or None

When the data contains a macro/micro average row with class=average, pass "macro" or "micro" to keep only that average line. None (default) renders all classes.

None
reference_line bool

Whether to overlay a diagonal chance-level reference line (TPR=FPR). Default is True.

True
annotate_auc bool

Whether to annotate each curve with its AUC value. Default is False: a raw mark stays un-annotated. (The roc_chart figure function defaults to True and owns the overlay via the shared _metric_labels helper; the divergent defaults are intentional.)

False
color_field str or None

Column name to drive per-class colour. Default is "class".

'class'
position Position

Position adjustment.

None
**mark_kwargs

Mark-style overrides for the line layer.

{}

Returns:

Type Description
Chart

New layered Chart configured for ROC rendering.

Examples:

>>> import ferrum as fm
>>> src = fm.ModelSource(clf, X_test, y_test)
>>> fm.Chart(src.roc_curve()).mark_roc(annotate_auc=True)
Chart(mark='point', encoding=[])

mark_pr

mark_pr(*, average: str | None = None, annotate_ap: bool = False, iso_lines: bool = False, color_field: str | None = 'class', position=None, **mark_kwargs) -> 'Chart'

Render a Precision-Recall (PR) curve.

Plots recall on x against precision on y as a line per class. Data must carry the schema emitted by ModelSource.pr_curve(): precision, recall, threshold, class, ap.

Parameters:

Name Type Description Default
average str or None

Filter to a specific average type row (e.g. "macro"). None (default) renders all classes.

None
annotate_ap bool

Whether to annotate each curve with its average-precision (AP) value. Default is False: a raw mark stays un-annotated. (The pr_chart figure function defaults to True and owns the overlay via the shared _metric_labels helper; the divergent defaults are intentional.)

False
iso_lines bool

Whether to draw iso-F1 reference lines in the background. Default is False.

False
color_field str or None

Column name to drive per-class colour. Default is "class".

'class'
position Position

Position adjustment.

None
**mark_kwargs

Mark-style overrides for the line layer.

{}

Returns:

Type Description
Chart

New layered Chart configured for PR-curve rendering.

Examples:

>>> import ferrum as fm
>>> src = fm.ModelSource(clf, X_test, y_test)
>>> fm.Chart(src.pr_curve()).mark_pr(annotate_ap=True)
Chart(mark='point', encoding=[])

mark_calibration

mark_calibration(*, n_bins: int = 10, strategy: str = 'uniform', reference_line: bool = True, color_field: str | None = None, position=None, **mark_kwargs) -> 'Chart'

Render a calibration (reliability) curve.

Plots mean predicted probability on x against fraction of positive outcomes (empirical probability) on y. A perfectly calibrated model lies on the diagonal. Data must carry the schema emitted by ModelSource.calibration_curve(): mean_predicted, fraction_positive, count.

When reference_line=True the data is pre-sorted ascending by mean_predicted before rendering.

Parameters:

Name Type Description Default
n_bins int

Number of calibration bins. Default is 10.

10
strategy ('uniform', 'quantile')

Binning strategy. "uniform" uses equally-spaced bins; "quantile" uses equal-frequency bins.

"uniform"
reference_line bool

Whether to overlay a perfect-calibration diagonal reference line. Default is True.

True
color_field str or None

Column name to drive per-group colour.

None
position Position

Position adjustment.

None
**mark_kwargs

Mark-style overrides for the line layer.

{}

Returns:

Type Description
Chart

New layered Chart configured for calibration rendering.

Examples:

>>> import ferrum as fm
>>> src = fm.ModelSource(clf, X_test, y_test)
>>> fm.Chart(src.calibration_curve()).mark_calibration(n_bins=15)
Chart(mark='point', encoding=[])

mark_gain

mark_gain(*, reference_line: bool = True, color_field: str | None = 'class', position=None, **mark_kwargs) -> 'Chart'

Render a cumulative gain chart.

Plots percent of population contacted on x against the cumulative gain (fraction of positive cases captured) on y. Data must carry the schema emitted by ModelSource.cumulative_gain(): percent_population, gain, class. The no-skill diagonal baseline is encoded as rows with class='baseline'.

Parameters:

Name Type Description Default
reference_line bool

Whether to draw the no-skill baseline diagonal. Default is True.

True
color_field str or None

Column name to drive per-class colour. Default is "class".

'class'
position Position

Position adjustment.

None
**mark_kwargs

Mark-style overrides for the line layer.

{}

Returns:

Type Description
Chart

New layered Chart configured for cumulative-gain rendering.

Examples:

>>> import ferrum as fm
>>> src = fm.ModelSource(clf, X_test, y_test)
>>> fm.Chart(src.cumulative_gain()).mark_gain()
Chart(mark='point', encoding=[])

mark_lift

mark_lift(*, reference_line: bool = True, color_field: str | None = 'class', position=None, **mark_kwargs) -> 'Chart'

Render a lift curve chart.

Plots percent of population targeted on x against lift (ratio of positive-case density to baseline) on y. Data must carry the schema emitted by ModelSource.lift_curve(): percent_population, lift, class. The no-skill lift=1 baseline is encoded as rows with class='baseline'.

Parameters:

Name Type Description Default
reference_line bool

Whether to draw the lift=1 baseline rule. Default is True.

True
color_field str or None

Column name to drive per-class colour. Default is "class".

'class'
position Position

Position adjustment.

None
**mark_kwargs

Mark-style overrides for the line layer.

{}

Returns:

Type Description
Chart

New layered Chart configured for lift-curve rendering.

Examples:

>>> import ferrum as fm
>>> src = fm.ModelSource(clf, X_test, y_test)
>>> fm.Chart(src.lift_curve()).mark_lift()
Chart(mark='point', encoding=[])

mark_discrimination_threshold

mark_discrimination_threshold(*, metrics: tuple[str, ...] = ('precision', 'recall', 'f1', 'queue_rate'), n_thresholds: int = 50, threshold_line: bool = False, optimum_label: bool = True, position=None, **mark_kwargs) -> 'Chart'

Render a discrimination-threshold sweep plot.

Sweeps the decision threshold from 0 to 1 and plots multiple metrics (precision, recall, F1, queue rate) as lines against the threshold value. Data must be in long form with columns threshold, metric, value -- the figure builder handles unpivoting from ModelSource.discrimination_threshold() output.

Parameters:

Name Type Description Default
metrics tuple of str

Metric names to include. Default is ("precision", "recall", "f1", "queue_rate").

('precision', 'recall', 'f1', 'queue_rate')
n_thresholds int

Number of evenly-spaced threshold steps to evaluate. Default is 50.

50
threshold_line bool

Whether to draw a vertical rule at the optimal threshold. Default is False.

False
optimum_label bool

Whether to overlay a text annotation at the F1-optimum point showing "max F1 = {f1:.3f} @ t={threshold:.2f}". Default True (Schwabish C7 audit-rework, 2026-05-12). The mark's data_transform injects _optimum_x / _optimum_y / _optimum_text sentinel columns from the long-form data; the desugar emits a mark_text layer.

True
position Position

Position adjustment.

None
**mark_kwargs

Mark-style overrides for the line layer.

{}

Returns:

Type Description
Chart

New layered Chart configured for discrimination-threshold rendering.

Examples:

>>> import ferrum as fm
>>> src = fm.ModelSource(clf, X_test, y_test)
>>> fm.Chart(src.discrimination_threshold()).mark_discrimination_threshold()
Chart(mark='point', encoding=[])

mark_confusion

mark_confusion(*, normalize: str | None = None, annotate: bool = True, color_field: str = 'value', cmap: str | None = None, position=None, **mark_kwargs) -> 'Chart'

Render a confusion matrix as an annotated heatmap.

Renders an ordinal heatmap with actual class on one axis and predicted class on the other. Data must carry the long-form schema emitted by ModelSource.confusion_matrix(): actual, predicted, value, value_fmt. When annotate=True, a second mark_text layer reads value_fmt for per-cell text labels.

Parameters:

Name Type Description Default
normalize ('true', 'pred', 'all')

Normalise cell counts. None (default) shows raw counts.

"true"
annotate bool

Whether to overlay per-cell count / percentage text. Default is True.

True
color_field str

Column name driving the heatmap colour scale. Default is "value".

'value'
cmap str or None

Sequential colormap name for the heat cells. None (default) defers to the theme's sequential scheme.

None
position Position

Position adjustment.

None
**mark_kwargs

Mark-style overrides for the rect layer.

{}

Returns:

Type Description
Chart

New layered Chart configured for confusion-matrix rendering.

Examples:

>>> import ferrum as fm
>>> src = fm.ModelSource(clf, X_test, y_test)
>>> fm.Chart(src.confusion_matrix()).mark_confusion(normalize="true")
Chart(mark='point', encoding=[])

mark_class_prediction_error

mark_class_prediction_error(*, normalize: bool = False, color_field: str = 'predicted', show_counts: bool = True, position=None, **mark_kwargs) -> 'Chart'

Render a class prediction error bar chart.

Renders one stacked bar per actual class (x-axis), with segments coloured by predicted class. This orientation surfaces which classes are confused with which -- for each actual class you can see how the model's predictions distribute across the predicted classes. Data must carry long-form columns (actual, predicted, value) -- same shape as ModelSource.confusion_matrix(normalize=None).

Parameters:

Name Type Description Default
normalize bool

Whether to normalise each bar to 100%. Default is False.

False
color_field str

Column driving the segment colour. Default is "predicted".

'predicted'
show_counts bool

Whether to overlay per-segment count text at the segment centre. Default is True (Schwabish SB-followup 2026-05-12). Empty segments are skipped.

True
position Position

Position adjustment.

None
**mark_kwargs

Mark-style overrides for the bar layer.

{}

Returns:

Type Description
Chart

New layered Chart configured for class-prediction-error rendering.

Examples:

>>> import ferrum as fm
>>> src = fm.ModelSource(clf, X_test, y_test)
>>> fm.Chart(src.confusion_matrix()).mark_class_prediction_error(normalize=True)
Chart(mark='point', encoding=[])

mark_residuals

mark_residuals(*, kind: str = 'studentized', reference_line: bool = True, cook_threshold: float | str | None = None, color_field: str | None = None, position=None, **mark_kwargs) -> 'Chart'

Render a residuals diagnostic plot.

Plots fitted values (y_pred) on x against residuals (raw or studentized) on y. Data must carry the schema emitted by ModelSource.predictions(): y_true, y_pred, residual, studentized_residual, and cooks_distance.

When reference_line=True a sentinel _ref_zero column is injected so the downstream mark_rule draws a single horizontal line at y=0.

When cook_threshold is set, high-leverage points (Cook's D above the threshold) are highlighted as a second mark_point layer drawn in red with a black outline.

Parameters:

Name Type Description Default
kind ('studentized', 'raw')

Residual type to plot on the y axis. "studentized" uses studentized_residual; "raw" uses residual.

"studentized"
reference_line bool

Whether to draw a horizontal reference line at y=0. Default is True.

True
cook_threshold float, "auto", or None

Cook's Distance threshold for outlier highlighting. "auto" uses the conventional 4 / n rule. None (default) disables outlier highlighting.

None
color_field str or None

Column name to drive per-group colour on the scatter layer.

None
position Position

Position adjustment.

None
**mark_kwargs

Mark-style overrides for the scatter layer.

{}

Returns:

Type Description
Chart

New layered Chart configured for residuals rendering.

Examples:

>>> import ferrum as fm
>>> src = fm.ModelSource(model, X_test, y_test)
>>> fm.Chart(src.predictions()).mark_residuals(cook_threshold="auto")
Chart(mark='point', encoding=[])

mark_prediction_error

mark_prediction_error(*, reference_line: bool = True, ci: float | None = None, reference_band: bool = False, color_field: str | None = None, position=None, **mark_kwargs) -> 'Chart'

Render an actual-vs-predicted plot.

Plots y_true on x against y_pred on y as scatter points. When reference_line=True the data is pre-sorted ascending by y_true so the downstream mark_line renders a monotonic y=x diagonal. Data must carry y_true and y_pred columns (schema from ModelSource.predictions()).

Parameters:

Name Type Description Default
reference_line bool

Whether to overlay a y=x identity reference line. Default is True.

True
ci float or None

Confidence level for a prediction-interval band (e.g. 0.95). None (default) omits the band.

None
reference_band bool

Whether to draw a shaded reference band around the identity line. Default is False.

False
color_field str or None

Column name to drive per-group colour.

None
position Position

Position adjustment.

None
**mark_kwargs

Mark-style overrides for the scatter layer.

{}

Returns:

Type Description
Chart

New layered Chart configured for prediction-error rendering.

Examples:

>>> import ferrum as fm
>>> src = fm.ModelSource(model, X_test, y_test)
>>> fm.Chart(src.predictions()).mark_prediction_error(ci=0.95)
Chart(mark='point', encoding=[])

mark_density

mark_density(*, position=None, **kwargs) -> 'Chart'

Render a kernel-density estimate (KDE) curve or filled contour.

When only x is encoded, draws a 1-D KDE area curve. When both x and y are encoded, renders a bivariate filled-contour density (routes through desugar_contour(fill=True)). Can be called before or after .encode().

Parameters:

Name Type Description Default
bandwidth float or 'scott' or 'silverman'

KDE bandwidth. "scott" and "silverman" use the corresponding rule-of-thumb estimates. Default is "scott".

required
kernel str

Kernel type: "gaussian", "tophat", "epanechnikov", "exponential", "linear", "cosine". Default is "gaussian".

required
extent list of float or None

[min, max] evaluation range. Defaults to data extent.

required
cumulative bool

Produce a CDF instead of a PDF. Default is False.

required
n int

Number of evaluation points. Default is 200.

required
multiple str

How to handle multiple densities when a color encoding is present: "layer" (default), "stack", "fill".

required
orient ('vertical', 'horizontal')

Canonical orientation alias for orientation. "horizontal" swaps the value and density axes. Takes precedence over orientation when both are given.

"vertical"
orientation ('vertical', 'horizontal')

Legacy spelling. orient is preferred.

"vertical"
position Position

Position adjustment.

None
**mark_kwargs

Constant mark-style overrides (opacity, fill, stroke, stroke_width, stroke_dash, size; aliases colorfill, alphaopacity) forwarded to the rendered area/line layer.

required

Returns:

Type Description
Chart

New Chart configured for density rendering.

Examples:

>>> import ferrum as fm
>>> import polars as pl
>>> df = pl.DataFrame({"val": [1.0, 2.1, 1.8, 3.0, 2.5]})
>>> fm.Chart(df).mark_density().encode(x="val")
Chart(mark='area', encoding=['x'])

mark_histogram

mark_histogram(*, position=None, **kwargs) -> 'Chart'

Render data as a histogram.

Bins the x-encoded column and encodes bin extents as x/x2 with counts (or densities) on y. Can be called before or after .encode(x=...).

Parameters:

Name Type Description Default
bin_count int

Target number of bins. Ignored when bin_width is set. Default is chosen automatically from Sturges' rule.

required
bin_width float

Exact bin width in data units. Overrides bin_count.

required
density bool

Normalise counts to a probability density. Default is False.

required
right bool

Whether bins are closed on the right. Default is False. right=True is not currently supported and raises ValueError; bins are always left-closed, right-open [lo, hi).

required
cumulative bool

Render a cumulative histogram. Default is False.

required
multiple str

How to handle grouped histograms when a color encoding is present: "layer" (default), "stack", "dodge".

required
orient ('vertical', 'horizontal')

Canonical orientation alias for orientation. "horizontal" swaps the bin-edge and count axes. Takes precedence over orientation when both are given.

"vertical"
orientation ('vertical', 'horizontal')

Legacy spelling. orient is preferred.

"vertical"
position Position

Position adjustment.

None
**mark_kwargs

Constant mark-style overrides (opacity, fill, stroke, stroke_width, stroke_dash, size; aliases colorfill, alphaopacity) forwarded to the rendered bar layer.

required

Returns:

Type Description
Chart

New Chart configured for histogram rendering.

Examples:

>>> import ferrum as fm
>>> import polars as pl
>>> df = pl.DataFrame({"val": [1.0, 1.2, 2.3, 3.1, 2.8, 1.5]})
>>> fm.Chart(df).mark_histogram(bin_count=5).encode(x="val")
Chart(mark='bar', encoding=['x', 'x2', 'y'])

mark_smooth

mark_smooth(*, position=None, **kwargs) -> 'Chart'

Render a smoothed regression line with optional confidence interval band.

Fits a smooth curve through (x, y) data using the method specified by method. When ci is set, emits a layered ribbon (CI band) + line chart. Can be called before or after .encode(x=..., y=...).

Parameters:

Name Type Description Default
method str

Smoothing method. Default is "loess".

  • "lm" or "linear" -- linear regression (OLS, degree-1 polynomial)
  • "loess" -- local regression (LOWESS)
  • "quadratic" -- polynomial regression, degree 2
  • "cubic" -- polynomial regression, degree 3
  • "log" -- linear fit on log-transformed x
  • "sqrt" -- linear fit on sqrt-transformed x
required
degree int

Polynomial degree for "linear"/"quadratic"/"cubic".

required
bandwidth float

LOESS bandwidth fraction in (0, 1]. Default is 0.75.

required
n int

Number of evaluation points along the x range. Default is 200.

required
ci float or None

Confidence level for the interval band, e.g. 0.95. When set, produces a layered ribbon + line chart. Default is None.

required
groupby str

Group-key column (Utf8). When set, the smooth is computed independently per group and the group column is preserved in the output so downstream color= encoding maps to it.

required
position Position

Position adjustment.

None
**mark_kwargs

Constant mark-style overrides (opacity, fill, stroke, stroke_width, stroke_dash, size; aliases colorfill, alphaopacity) forwarded to all emitted layers (the regression line, plus the CI ribbon when ci is set).

required

Returns:

Type Description
Chart

New Chart configured for smooth rendering.

Examples:

>>> import ferrum as fm
>>> import polars as pl
>>> df = pl.DataFrame({"x": [1.0, 2.0, 3.0, 4.0], "y": [1.1, 1.9, 3.1, 4.0]})
>>> fm.Chart(df).mark_smooth(method="linear", ci=0.95).encode(x="x", y="y")
Chart(mark='line', encoding=['x', 'y'])

mark_boxplot

mark_boxplot(*, whisker_mult: float | str = _MISSING, size=None, width=None, outliers=True, color_field=None, horizontal=False, orient=None, position=None, **mark_kwargs) -> 'Chart'

Render a Tukey boxplot via composite mark desugaring.

Desugars to a multi-layer chart: box (IQR rect), upper and lower whisker rules, median rule, and (optionally) outlier points. Requires a categorical x encoding and a continuous y (or the reverse when horizontal=True or orient="horizontal").

Parameters:

Name Type Description Default
whisker_mult float or 'min-max'

Whisker reach as a multiple of IQR, or "min-max" to extend whiskers to the data minimum/maximum. Default is 1.5.

.. deprecated:: The old spelling extent= is accepted as an alias for one release. Use whisker_mult= instead. extent is reserved for data-domain [min, max] bounds.

_MISSING
size float or None

Box band-width as a fraction of the category band (default 0.6). Alias: width.

None
width float or None

Alias for size. Controls box band-width as a fraction of the category band. When both size and width are provided, size takes precedence.

None
outliers bool

Whether to draw outlier points beyond the whiskers. Default is True.

True
color_field str or None

Column name to drive per-group fill colour on the box layer.

None
horizontal bool

Swap x and y axes so boxes run horizontally. Default is False. Legacy alias; prefer orient="horizontal".

False
orient ('vertical', 'horizontal')

Canonical orientation control. "horizontal" is equivalent to horizontal=True. When both are given, orient wins if it is not None.

"vertical"
position Position

Position adjustment -- e.g. fm.Dodge() for side-by-side boxes.

None
**mark_kwargs

Additional mark-style overrides forwarded to each constituent layer.

{}

Returns:

Type Description
Chart

New layered Chart representing the boxplot.

Examples:

>>> import ferrum as fm
>>> import polars as pl
>>> df = pl.DataFrame({"species": ["a"]*5 + ["b"]*5, "val": [1,2,3,2,1,4,5,4,5,6]})
>>> fm.Chart(df).mark_boxplot().encode(x="species", y="val")
Chart(mark='point', encoding=[])

mark_boxen

mark_boxen(*, k_depth: str = 'tukey', k_proportion: float = 0.007, outlier_threshold: float = 1.5, palette=None, horizontal: bool = False, orient=None, color_field=None, position=None, **mark_kwargs) -> 'Chart'

Render a letter-value (boxen) plot via composite mark desugaring.

Produces nested rectangular bands for each letter-value depth, a median rule, and an outlier-point layer via the LetterValue transform. Requires a categorical x encoding and a continuous y (or the reverse when horizontal=True or orient="horizontal").

Parameters:

Name Type Description Default
k_depth ('proportion', 'trustworthy', 'full')

Rule for choosing the number of letter-value levels.

"proportion"
k_proportion float

Proportion parameter used when k_depth="proportion". Default is 0.007.

0.007
outlier_threshold float

IQR multiple beyond which points are considered outliers. Default is 1.5.

1.5
palette list of str or None

Colour palette applied to successive depth bands. None uses the active theme's categorical palette.

None
horizontal bool

Swap axes so bands run horizontally. Default is False. Legacy alias; prefer orient="horizontal".

False
orient ('vertical', 'horizontal')

Canonical orientation control. "horizontal" is equivalent to horizontal=True. When both are given, orient wins if it is not None.

"vertical"
color_field str or None

Column name to drive per-group colour.

None
position Position

Position adjustment.

None
**mark_kwargs

Additional mark-style overrides forwarded to constituent layers.

{}

Returns:

Type Description
Chart

New layered Chart representing the boxen plot.

Examples:

>>> import ferrum as fm
>>> import polars as pl
>>> df = pl.DataFrame({"group": ["a"]*20 + ["b"]*20,
...                    "val": list(range(20)) + list(range(10, 30))})
>>> fm.Chart(df).mark_boxen().encode(x="group", y="val")
Chart(mark='point', encoding=[])

mark_errorbar

mark_errorbar(*, method=_MISSING, ticks=True, position=None, **mark_kwargs) -> 'Chart'

Render error bars via the ErrorExtent transform.

Computes extent values (CI, SD, SEM, or IQR) per group defined by the x encoding, then draws a vertical rule spanning the extent with optional tick caps.

Parameters:

Name Type Description Default
method ('ci', 'stderr', 'stdev', 'iqr')

Aggregation method: confidence interval ("ci"), standard error ("stderr"), standard deviation ("stdev"), or interquartile range ("iqr"). Forwarded verbatim as ErrorExtent.method (wire field unchanged).

.. deprecated:: The old spelling extent= is accepted as an alias for one release. Use method= instead. extent is reserved for data-domain [min, max] bounds.

"ci"
ticks bool

Whether to draw horizontal tick caps at the extent endpoints. Default is True.

True
position Position

Position adjustment.

None
**mark_kwargs

Mark-style overrides forwarded to constituent rule/tick layers.

{}

Returns:

Type Description
Chart

New layered Chart representing the error bars.

Examples:

>>> import ferrum as fm
>>> import polars as pl
>>> df = pl.DataFrame({"group": ["a"]*10 + ["b"]*10,
...                    "val": list(range(10)) + list(range(5, 15))})
>>> fm.Chart(df).mark_errorbar(method="stdev").encode(x="group", y="val")
Chart(mark='point', encoding=[])

mark_errorband

mark_errorband(*, method=_MISSING, borders=False, position=None, **mark_kwargs) -> 'Chart'

Render an error band (ribbon) via the ErrorExtent transform.

Similar to mark_errorbar but renders the extent as a filled ribbon rather than whisker rules. Optionally draws border lines at the upper and lower extent edges.

Parameters:

Name Type Description Default
method ('ci', 'stderr', 'stdev', 'iqr')

Aggregation method: confidence interval ("ci"), standard error ("stderr"), standard deviation ("stdev"), or interquartile range ("iqr"). Forwarded verbatim as ErrorExtent.method (wire field unchanged).

.. deprecated:: The old spelling extent= is accepted as an alias for one release. Use method= instead. extent is reserved for data-domain [min, max] bounds.

"ci"
borders bool

Whether to draw line borders at the band edges. Default is False.

False
position Position

Position adjustment.

None
**mark_kwargs

Mark-style overrides (e.g. opacity) forwarded to the ribbon layer.

{}

Returns:

Type Description
Chart

New layered Chart representing the error band.

Examples:

>>> import ferrum as fm
>>> import polars as pl
>>> df = pl.DataFrame({"x": list(range(10)), "y": [float(i) for i in range(10)]})
>>> fm.Chart(df).mark_errorband(method="ci", borders=True).encode(x="x", y="y")
Chart(mark='point', encoding=[])

mark_ribbon

mark_ribbon(*, opacity=0.3, interpolate='linear', position=None, **mark_kwargs) -> 'Chart'

Render a ribbon (filled area between y and y2 along x).

Requires both y and y2 encoding channels. Typically used to visualise confidence intervals alongside a mark_line in the same layered chart.

Parameters:

Name Type Description Default
opacity float

Fill opacity of the ribbon. Default is 0.3.

0.3
interpolate str

Boundary interpolation: "linear", "monotone", "step", "basis", "cardinal". Default is "linear".

'linear'
position Position

Position adjustment.

None
**mark_kwargs

Additional mark-style overrides (e.g. fill, stroke).

{}

Returns:

Type Description
Chart

New Chart configured for ribbon rendering.

Examples:

>>> import ferrum as fm
>>> import polars as pl
>>> df = pl.DataFrame({"x": [1, 2, 3], "y_lo": [0.5, 1.5, 2.5], "y_hi": [1.5, 2.5, 3.5]})
>>> fm.Chart(df).mark_ribbon().encode(x="x", y="y_lo", y2="y_hi")
Chart(mark='ribbon', encoding=['x', 'y', 'y2'])

mark_contour

mark_contour(*, bandwidth='scott', thresholds=6, smooth=True, fill=False, scheme=None, cmap=None, groupby=None, position=None, **mark_kwargs) -> 'Chart'

Render a bivariate contour plot via Kde2D + Contour transforms.

Estimates a 2-D kernel density and draws iso-contour lines (or filled contour regions when fill=True). Requires both x and y encodings.

Parameters:

Name Type Description Default
bandwidth float or 'scott' or 'silverman'

Bandwidth for the 2-D KDE. Default is "scott".

'scott'
thresholds int or list of float

Number of evenly-spaced contour levels, or an explicit list of density thresholds. Default is 6.

6
smooth bool

Whether to smooth contour paths via Gaussian filtering before contouring. Default is True.

True
fill bool

Render filled contour regions instead of contour lines. Default is False. When groupby is set, this parameter is ignored and isoline (segment) mode is always used.

False
scheme str or None

Colour map name applied to contour levels. None (default) defers to the theme's sequential scheme. Ignored when groupby is set.

None
cmap str or None

Back-compat alias for scheme. Pass at most one of the two.

None
groupby str or None

Group column (Utf8). When set, one 2-D KDE surface is computed per group and contour lines for each group are colored by the group field. Use .encode(color=<groupby>) to match legend colors to contours. Grouped contours use isoline (segment) mode to avoid cross-group polygon merging issues.

None
position Position

Position adjustment.

None
**mark_kwargs

Mark-style overrides forwarded to the polygon/path layers.

{}

Returns:

Type Description
Chart

New layered Chart configured for contour rendering.

Examples:

>>> import ferrum as fm
>>> import polars as pl
>>> df = pl.DataFrame({"x": [1.0, 2.0, 3.0, 2.0, 1.5], "y": [4.0, 5.0, 4.5, 3.0, 4.0]})
>>> fm.Chart(df).mark_contour(thresholds=4, fill=True).encode(x="x", y="y")
Chart(mark='polygon', encoding=['x', 'y'])

mark_violin

mark_violin(*, bandwidth='scott', inner='box', shared_extent=False, orient=None, horizontal=False, position=None, **mark_kwargs) -> 'Chart'

Render violin plots via the Violin transform.

Estimates a mirrored KDE per group and overlays an optional inner summary (box, quartile lines, or individual points). Requires a categorical x and continuous y encoding (or swapped when orient="horizontal" or horizontal=True).

Parameters:

Name Type Description Default
bandwidth float or 'scott' or 'silverman'

KDE bandwidth. Default is "scott".

'scott'
inner ('box', 'quartile', 'point', 'none')

Inner mark drawn on top of each violin: "box" -- IQR box + median rule, "quartile" -- three horizontal quartile rules, "point" -- individual data points (strip), "none" -- no inner mark.

"box"
shared_extent bool

When True, all groups share the same KDE evaluation range (cross-group global min/max), making the value axis directly comparable across groups. When False (default), each group evaluates its KDE on its own per-group data range.

False
orient ('vertical', 'horizontal')

Canonical orientation control. "horizontal" swaps the axes so the categorical grouping is on y and the value distribution is on x. Equivalent to horizontal=True. When both are given, orient wins.

"vertical"
horizontal bool

Legacy alias for orient="horizontal". Kept for backward compatibility.

False
position Position

Position adjustment.

None
**mark_kwargs

Mark-style overrides forwarded to the violin polygon layer.

{}

Returns:

Type Description
Chart

New layered Chart configured for violin rendering.

Examples:

>>> import ferrum as fm
>>> import polars as pl
>>> df = pl.DataFrame({"group": ["a"]*10 + ["b"]*10,
...                    "val": list(range(10)) + list(range(5, 15))})
>>> fm.Chart(df).mark_violin(inner="quartile").encode(x="group", y="val")
Chart(mark='polygon', encoding=['x', 'y'])

mark_qq

mark_qq(*, distribution='normal', dequantize=False, line=True, position=None, **mark_kwargs) -> 'Chart'

Render a quantile-quantile plot.

Computes theoretical vs. sample quantiles via the QQ transform. Reads the sample column from the x encoding; y is ignored.

Parameters:

Name Type Description Default
distribution ('normal', 'uniform', 'exponential', 'lognormal')

Theoretical distribution to compare the sample against.

"normal"
dequantize bool

Whether to apply rank-based dequantization before comparison. Default is False.

False
line bool

Whether to overlay a 45-degree reference line. Default is True.

True
position Position

Position adjustment.

None
**mark_kwargs

Mark-style overrides for the scatter layer.

{}

Returns:

Type Description
Chart

New Chart configured for QQ rendering.

Examples:

>>> import ferrum as fm
>>> import polars as pl
>>> df = pl.DataFrame({"val": [1.2, 0.8, 1.5, -0.5, 0.3, 2.1, -1.0, 0.6]})
>>> fm.Chart(df).mark_qq(distribution="normal").encode(x="val")
Chart(mark='point', encoding=['x'])

mark_raster

mark_raster(*, aggregate='count', field=None, scheme=None, cmap=None, resolution='screen', blend='alpha', min_count=None, log_scale=False, position=None, **mark_kwargs) -> 'Chart'

Render a 2-D raster (pixel heatmap) via the Raster transform.

Bins data into a pixel grid and colours each pixel by an aggregate statistic. Most useful for very large datasets where a scatter plot would overplot. Requires x and y encodings.

Parameters:

Name Type Description Default
aggregate str

Aggregate function applied to each pixel bin: "count" (default), "sum", "mean", "min", "max". When aggregate is not "count", field must be provided.

'count'
field str or None

Column name to aggregate. Required unless aggregate="count".

None
scheme str or None

Colour map name. None (default) defers to the theme's sequential scheme.

None
cmap str or None

Back-compat alias for scheme. Pass at most one of the two.

None
resolution 'screen' or int

Pixel grid resolution. "screen" (default) matches the rendered chart dimensions; pass an integer to set an explicit grid width.

'screen'
blend str

Alpha-compositing blend mode. Default is "alpha".

'alpha'
min_count int or None

Minimum count threshold; pixels below this are rendered transparent. None (default) shows all pixels.

None
log_scale bool

Apply a log transform to pixel values before colour mapping. Default is False.

False
position Position

Position adjustment.

None
**mark_kwargs

Mark-style overrides forwarded to the image layer.

{}

Returns:

Type Description
Chart

New Chart configured for raster rendering.

Examples:

>>> import ferrum as fm
>>> import polars as pl
>>> df = pl.DataFrame({"x": [1.0, 2.0, 3.0, 2.5], "y": [4.0, 5.0, 4.5, 4.0]})
>>> fm.Chart(df).mark_raster(cmap="plasma").encode(x="x", y="y")
Chart(mark='image', encoding=['x', 'y'])

mark_hex

mark_hex(*, bin_size=None, aggregate='count', field=None, scheme=None, cmap=None, stroke=None, stroke_width=0, position=None, **mark_kwargs) -> 'Chart'

Render a hexagonal bin plot via the Hex transform.

Bins data into a regular hexagonal grid and colours each cell by an aggregate statistic. Requires x and y encodings.

Parameters:

Name Type Description Default
bin_size float or None

Hexagon radius in data units. None (default) chooses a size automatically from the data range and chart dimensions.

None
aggregate str

Aggregate function: "count" (default), "sum", "mean", "min", "max".

'count'
field str or None

Column to aggregate. Required unless aggregate="count".

None
scheme str or None

Colour map name. None (default) defers to the theme's sequential scheme.

None
cmap str or None

Back-compat alias for scheme. Pass at most one of the two.

None
stroke str or None

Hex border colour. None (default) means no border.

None
stroke_width float

Hex border width in pixels. Default is 0.

0
position Position

Position adjustment.

None
**mark_kwargs

Constant mark-style overrides forwarded to the polygon layer. Note: stroke and stroke_width are method parameters (cell borders); scheme (alias cmap) is a transform parameter (fill colormap). Other style kwargs like opacity, fill, size override the polygon defaults.

{}

Returns:

Type Description
Chart

New Chart configured for hexagonal binning.

Examples:

>>> import ferrum as fm
>>> import polars as pl
>>> df = pl.DataFrame({"x": [1.0, 2.0, 1.5, 3.0, 2.5], "y": [4.0, 5.0, 4.5, 3.0, 4.0]})
>>> fm.Chart(df).mark_hex(bin_size=0.5).encode(x="x", y="y")
Chart(mark='polygon', encoding=['x', 'y'])

mark_swarm

mark_swarm(*, size=4, orient=None, horizontal=None, spacing=1.0, side='both', dodge=None, position=None, **mark_kwargs) -> 'Chart'

Render a beeswarm (strip swarm) plot via the Swarm transform.

Computes non-overlapping point positions along the categorical axis using a deterministic placement algorithm seeded for reproducibility. Requires a continuous y (or x) and an optional categorical grouping axis.

Parameters:

Name Type Description Default
size float

Point diameter in pixels. Default is 4.

4
orient ('vertical', 'horizontal')

Canonical orientation control. "vertical" (default) spreads points along x; "horizontal" spreads along y. When both orient and horizontal are given, orient wins.

"vertical"
horizontal bool or None

Legacy alias for orient. True is equivalent to orient="horizontal". Ignored when orient is also given; prefer orient in new code.

None
spacing float

Minimum spacing between point centres as a fraction of size. Default is 1.0.

1.0
side ('both', 'left', 'right')

Side of the axis on which points can be placed.

"both"
dodge str or None

Column name to use as a secondary grouping variable for dodging. None (default) means no dodging.

None
position Position

Position adjustment.

None
**mark_kwargs

Mark-style overrides forwarded to the point layer.

{}

Returns:

Type Description
Chart

New Chart configured for beeswarm rendering.

Examples:

>>> import ferrum as fm
>>> import polars as pl
>>> df = pl.DataFrame({"group": ["a"]*8 + ["b"]*8, "val": list(range(16))})
>>> fm.Chart(df).mark_swarm(size=6).encode(x="group", y="val")
Chart(mark='point', encoding=['x', 'y'])

mark_function

mark_function(fn, *, domain=None, n=200, clip=True, position=None, **mark_kwargs) -> 'Chart'

Render a mathematical function as a line.

Evaluates fn(xs) on n evenly-spaced x values in the specified domain and renders the result as a line. The input data on the chart is replaced with the synthetic dataset; use + composition to overlay a function on a scatter chart.

Parameters:

Name Type Description Default
fn callable

A function accepting a 1-D NumPy array of x values and returning a 1-D array of y values.

required
domain list of float or None

[x_min, x_max] evaluation range. None (default) infers the range from the parent chart's x column if available, otherwise raises ValueError.

None
n int

Number of evaluation points. Default is 200.

200
clip bool

Whether to clip rendered line to the plot viewport. Default is True.

True
position Position

Position adjustment.

None
**mark_kwargs

Mark-style overrides forwarded to the line layer (e.g. stroke, stroke_width).

{}

Returns:

Type Description
Chart

New Chart whose data is the synthetic (x, y) table.

Raises:

Type Description
ValueError

When domain is not provided and no parent x data can be inferred.

Examples:

>>> import ferrum as fm
>>> import numpy as np
>>> import polars as pl
>>> fm.Chart(None).mark_function(np.sin, domain=[0, 6.28], n=100)
Chart(mark='line', encoding=['x', 'y'])

configure_axis

configure_axis(*, x: bool = True, y: bool = True, label_angle: 'float | None' = None, label_font_size: 'float | None' = None, label_color: 'str | None' = None, label_format: 'str | None' = None, label_format_raw: 'str | None' = None, label_overlap: 'str | None' = None, tick_count: 'int | None' = None, tick_size: 'float | None' = None, tick_values: 'list | None' = None, title_font_size: 'float | None' = None, title_color: 'str | None' = None, title_padding: 'float | None' = None, label_padding: 'float | None' = None, domain: 'bool | None' = None, domain_color: 'str | None' = None, domain_width: 'float | None' = None, grid: 'bool | None' = None, grid_color: 'str | None' = None, grid_dash: 'list[float] | None' = None, grid_width: 'float | None' = None, grid_opacity: 'float | None' = None, domain_min: 'float | None' = None, domain_max: 'float | None' = None, nice: 'bool | None' = None, zero: 'bool | None' = None, translate: 'float | None' = None, min_band: 'float | None' = None, max_band: 'float | None' = None, tick_extra: 'bool | None' = None, tick_min_step: 'float | None' = None, title_orient: 'str | None' = None, zindex: 'int | None' = None, min_extent: object = _MISSING, max_extent: object = _MISSING)

Apply axis configuration.

Parameters:

Name Type Description Default
x bool

Deprecated and has no effect. Use Chart.axis(x=False) / Chart.axis(y=False) to show or hide an axis.

True
y bool

Deprecated and has no effect. Use Chart.axis(x=False) / Chart.axis(y=False) to show or hide an axis.

True
label_angle float

Tick label rotation in degrees.

None
label_font_size float

Tick label font size in pixels.

None
label_color str

Tick label color.

None
label_format str

Named format preset (e.g. "currency", "percent").

None
label_format_raw str

Raw d3-format string (e.g. ".2f", "~s"); overrides label_format when both are given.

None
label_overlap str

Overlap-handling strategy for crowded tick labels (e.g. "parity", "greedy").

None
tick_count int

Target number of ticks on the axis.

None
tick_size float

Tick mark length in pixels.

None
tick_values list

Explicit tick positions, overriding automatic tick selection.

None
title_font_size float

Axis title font size in pixels.

None
title_color str

Axis title color.

None
title_padding float

Gap between the axis title and its labels in pixels.

None
label_padding float

Gap between tick labels and the axis line in pixels.

None
domain bool

Whether to draw the axis domain (baseline) line.

None
domain_color str

Domain line color.

None
domain_width float

Domain line width in pixels.

None
grid bool

Whether to draw grid lines for this axis.

None
grid_color str

Grid line color.

None
grid_dash list[float]

Grid line dash pattern (on/off pixel lengths).

None
grid_width float

Grid line width in pixels.

None
grid_opacity float

Grid line opacity (0--1).

None
domain_min float

Explicit scale domain bounds.

None
domain_max float

Explicit scale domain bounds.

None
nice bool

Extend the domain to nice round numbers.

None
zero bool

Include zero in the scale domain.

None
translate float

Pixel translation of the axis group perpendicular to its line.

None
min_band float

Lower / upper bounds for the reserved axis margin band, in pixels.

.. deprecated:: 0.17.0 min_extent= and max_extent= are accepted as aliases but are deprecated; use min_band= / max_band= instead.

None
max_band float

Lower / upper bounds for the reserved axis margin band, in pixels.

.. deprecated:: 0.17.0 min_extent= and max_extent= are accepted as aliases but are deprecated; use min_band= / max_band= instead.

None
tick_extra bool

Append an extra tick at each domain boundary.

None
tick_min_step float

Minimum step between ticks in data space.

None
title_orient str

Side/orientation of the axis title.

None
zindex int

Coarse draw order of the axis relative to marks.

None

Returns:

Type Description
Self
Notes

orient (the axis side) is intentionally absent here: configure_axis applies to both the x and y axes, so a single side value can be valid for at most one of them. Set it per-axis instead, via configure(axis_x=AxisConfig(orient="top")) / configure(axis_y=AxisConfig(orient="right")) or per-channel fm.X("f", axis=fm.Axis(orient="top")).

configure_legend

configure_legend(*, orient: 'str | None' = None, direction: 'str | None' = None, columns: 'int | None' = None, title_font_size: 'float | None' = None, label_font_size: 'float | None' = None, label_color: 'str | None' = None, label_limit: 'float | None' = None, symbol_size: 'float | None' = None, symbol_stroke_width: 'float | None' = None, symbol_type: 'str | None' = None, gradient_length: 'float | None' = None, gradient_thickness: 'float | None' = None, title_padding: 'float | None' = None, row_padding: 'float | None' = None, column_padding: 'float | None' = None, clip_height: 'float | None' = None, tick_min_step: 'float | None' = None, offset: 'float | None' = None, padding: 'float | None' = None, zindex: 'int | None' = None)

Apply legend configuration.

Parameters:

Name Type Description Default
orient str

Legend position: "right", "left", "top", "bottom", "none".

None
direction str

Layout direction: "vertical" or "horizontal".

None
columns int

Number of columns for multi-column layout.

None
title_font_size float

Legend title font size in pixels.

None
label_font_size float

Legend entry label font size in pixels.

None
label_color str

Legend label color.

None
label_limit float

Maximum legend-label width in pixels; wider labels are truncated with an ellipsis.

None
symbol_size float

Legend symbol size in pixels.

None
symbol_stroke_width float

Stroke width of legend symbol swatches in pixels.

None
symbol_type str

Legend symbol shape (e.g. "circle", "square").

None
gradient_length float

Length of the continuous-legend gradient bar in pixels.

None
gradient_thickness float

Thickness of the continuous-legend gradient bar in pixels.

None
title_padding float

Padding between the legend title and its entries in pixels.

None
row_padding float

Vertical entry spacing in pixels (vertical-direction legends).

None
column_padding float

Horizontal entry spacing in pixels (horizontal-direction legends).

None
clip_height float

Cap on the legend group height in pixels; overflow is hard-clipped.

None
tick_min_step float

Minimum step between colorbar ticks in data units.

None
offset float

Legend offset from the plot edge in pixels.

None
padding float

Padding inside the legend box in pixels.

None
zindex int

Coarse draw order of the legend relative to marks.

None

Returns:

Type Description
Self

configure_title

configure_title(*, font_size: 'float | None' = None, font_weight: 'str | None' = None, anchor: 'str | None' = None, color: 'str | None' = None, offset: 'float | None' = None, subtitle_font_size: 'float | None' = None, subtitle_color: 'str | None' = None)

Apply title configuration.

Parameters:

Name Type Description Default
font_size float

Title font size in pixels.

None
font_weight str

Title font weight (e.g. "normal", "bold").

None
anchor str

Title alignment: "start", "middle", or "end".

None
color str

Title text color.

None
offset float

Title offset from the plot in pixels.

None
subtitle_font_size float

Subtitle font size in pixels.

None
subtitle_color str

Subtitle text color.

None

Returns:

Type Description
Self

configure_grid

configure_grid(*, x: 'bool | None' = None, y: 'bool | None' = None, color: 'str | None' = None, width: 'float | None' = None, dash: 'list[float] | None' = None, opacity: 'float | None' = None, band_colors: 'list[str] | None' = None)

Apply grid configuration.

Parameters:

Name Type Description Default
x bool

Enable/disable grid on each axis.

None
y bool

Enable/disable grid on each axis.

None
color str

Grid line color.

None
width float

Grid line width in pixels.

None
dash list[float]

Grid line dash pattern (on/off pixel lengths).

None
opacity float

Grid line opacity (0--1).

None
band_colors list[str]

Alternating band fill colors (None to disable).

None

Returns:

Type Description
Self

configure_padding

configure_padding(*, top: 'float | None' = None, right: 'float | None' = None, bottom: 'float | None' = None, left: 'float | None' = None, auto: bool = True)

Apply padding configuration.

Parameters:

Name Type Description Default
top float

Minimum padding in pixels per side.

None
right float

Minimum padding in pixels per side.

None
bottom float

Minimum padding in pixels per side.

None
left float

Minimum padding in pixels per side.

None
auto bool

Auto-expand margins to fit labels.

True

Returns:

Type Description
Self

configure_color

configure_color(*, scheme: 'str | None' = None, sequential_scheme: 'str | None' = None, diverging_scheme: 'str | None' = None, domain: 'list | None' = None, range: 'list[str] | None' = None)

Apply color scale configuration.

Parameters:

Name Type Description Default
scheme str

Categorical color scheme name.

None
sequential_scheme str

Sequential color scheme name.

None
diverging_scheme str

Diverging color scheme name.

None
domain list

Explicit color-scale domain values.

None
range list[str]

Explicit color range, overriding the scheme.

None

Returns:

Type Description
Self

configure

configure(*, axis: 'AxisConfig | None' = None, axis_x: 'AxisConfig | None' = None, axis_y: 'AxisConfig | None' = None, axis_y2: 'AxisConfig | None' = None, legend: 'LegendConfig | None' = None, title: 'TitleConfig | None' = None, grid: 'GridConfig | None' = None, padding: 'PaddingConfig | None' = None, color: 'ColorConfig | None' = None)

Append a :class:~ferrum.configure.Configure layer.

Accepts typed config objects for each domain. All parameters are keyword-only and default to None (no change for that domain).

Parameters:

Name Type Description Default
axis AxisConfig

Applies to all axes.

None
axis_x AxisConfig

Applies only to the x axis.

None
axis_y AxisConfig

Applies only to the y axis.

None
axis_y2 AxisConfig

Applies only to the secondary y axis.

None
legend LegendConfig

Legend appearance.

None
title TitleConfig

Chart title appearance.

None
grid GridConfig

Grid line appearance.

None
padding PaddingConfig

Plot-area padding.

None
color ColorConfig

Default color scale settings.

None

Returns:

Type Description
Self

New instance with the configure layer appended.

Examples:

>>> from ferrum.configure import AxisConfig, LegendConfig
>>> chart.configure(
...     axis=AxisConfig(label_angle=-45),
...     legend=LegendConfig(orient="bottom"),
... )

mark_point

mark_point(**kwargs) -> 'Chart'

Render data as points (scatter plot).

Parameters:

Name Type Description Default
size float

Point area in square pixels. Default is 36.

required
fill str

Fill colour override (CSS colour string or hex). Normally driven by the color encoding.

required
stroke str

Stroke colour for the point outline.

required
opacity float

Overall opacity in [0, 1].

required
filled bool

Whether points are filled. Default is True.

required
shape str

Point shape: "circle", "square", "cross", "diamond", "triangle-up", "triangle-down", "|" / "vline", "-" / "hline".

required
stroke_width float

Stroke width in pixels.

required
position Position

Position adjustment — fm.Jitter(), fm.Dodge(), etc.

required

Returns:

Type Description
Chart

New Chart with mark set to "point".

Examples:

>>> import ferrum as fm
>>> import polars as pl
>>> df = pl.DataFrame({"x": [1, 2, 3], "y": [4, 5, 6]})
>>> fm.Chart(df).mark_point(size=60, opacity=0.7).encode(x="x", y="y")
Chart(mark='point', encoding=['x', 'y'])

mark_line

mark_line(**kwargs) -> 'Chart'

Render data as a connected line.

Parameters:

Name Type Description Default
stroke str

Stroke colour override.

required
stroke_width float

Line width in pixels. Default is 2.

required
opacity float

Overall opacity in [0, 1].

required
interpolate str

Line interpolation: "linear", "monotone", "step", "step-before", "step-after", "basis", "cardinal".

required
stroke_cap str

Line cap: "butt", "round", "square".

required
stroke_join str

Line join: "miter", "round", "bevel".

required
position Position

Position adjustment.

required
point bool

When True, overlay a mark_point layer on top of the line. Mirrors the Altair mark_line(point=True) shorthand.

required

Returns:

Type Description
Chart

New Chart with mark set to "line". When point=True the result is a multi-layer chart (line + points).

Examples:

>>> import ferrum as fm
>>> import polars as pl
>>> df = pl.DataFrame({"x": [1, 2, 3], "y": [4, 5, 6]})
>>> fm.Chart(df).mark_line(stroke_width=3, interpolate="monotone").encode(x="x", y="y")
Chart(mark='line', encoding=['x', 'y'])

mark_circle

mark_circle(**kwargs) -> 'Chart'

Render data as filled circles — shorthand for mark_point(shape="circle").

Mirrors the Altair mark_circle() convenience method. All keyword arguments are forwarded to :meth:mark_point, including aliases such as color and alpha.

Parameters:

Name Type Description Default
**kwargs

Any keyword accepted by :meth:mark_point (size, fill, opacity, color, alpha, etc.).

{}

Returns:

Type Description
Chart

New Chart with mark set to "point" and shape="circle".

Examples:

>>> import ferrum as fm
>>> import polars as pl
>>> df = pl.DataFrame({"x": [1, 2], "y": [3, 4]})
>>> fm.Chart(df).mark_circle(size=80).encode(x="x", y="y")
Chart(mark='point', encoding=['x', 'y'])

mark_square

mark_square(**kwargs) -> 'Chart'

Render data as filled squares — shorthand for mark_point(shape="square").

Mirrors the Altair mark_square() convenience method. All keyword arguments are forwarded to :meth:mark_point, including aliases such as color and alpha.

Parameters:

Name Type Description Default
**kwargs

Any keyword accepted by :meth:mark_point (size, fill, opacity, color, alpha, etc.).

{}

Returns:

Type Description
Chart

New Chart with mark set to "point" and shape="square".

Examples:

>>> import ferrum as fm
>>> import polars as pl
>>> df = pl.DataFrame({"x": [1, 2], "y": [3, 4]})
>>> fm.Chart(df).mark_square(size=80).encode(x="x", y="y")
Chart(mark='point', encoding=['x', 'y'])

mark_bar

mark_bar(**kwargs) -> 'Chart'

Render data as bars.

Parameters:

Name Type Description Default
fill str

Bar fill colour override.

required
stroke str

Bar stroke colour.

required
stroke_width float

Bar stroke width in pixels.

required
opacity float

Overall opacity in [0, 1].

required
corner_radius float

Rounded corner radius in pixels.

required
orient str

"vertical" (default) or "horizontal".

required
position Position

Position adjustment — fm.Stack(), fm.Dodge(), etc.

required

Returns:

Type Description
Chart

New Chart with mark set to "bar".

Examples:

>>> import ferrum as fm
>>> import polars as pl
>>> df = pl.DataFrame({"cat": ["a", "b", "c"], "val": [10, 20, 15]})
>>> fm.Chart(df).mark_bar(corner_radius=4).encode(x="cat", y="val")
Chart(mark='bar', encoding=['x', 'y'])

mark_area

mark_area(**kwargs) -> 'Chart'

Render data as a filled area between the line and a baseline.

Parameters:

Name Type Description Default
fill str

Fill colour override.

required
stroke str

Border stroke colour.

required
stroke_width float

Border stroke width in pixels.

required
opacity float

Overall opacity in [0, 1].

required
interpolate str

Area boundary interpolation: "linear", "monotone", "step", "basis", "cardinal".

required
line bool

Whether to draw the top boundary as a line. Default is False.

required
position Position

Position adjustment — e.g. fm.Stack().

required

Returns:

Type Description
Chart

New Chart with mark set to "area".

Examples:

>>> import ferrum as fm
>>> import polars as pl
>>> df = pl.DataFrame({"x": [1, 2, 3], "y": [4, 5, 6]})
>>> fm.Chart(df).mark_area(opacity=0.5, line=True).encode(x="x", y="y")
Chart(mark='area', encoding=['x', 'y'])

mark_rule

mark_rule(**kwargs) -> 'Chart'

Render a horizontal or vertical reference rule spanning the plot area.

A rule spans the full width (when y is encoded) or full height (when x is encoded). Encoding both x/x2 or y/y2 draws finite line segments instead.

Parameters:

Name Type Description Default
stroke str

Rule colour override.

required
stroke_width float

Rule width in pixels. Default is 1.

required
stroke_dash str or list

Dash pattern, e.g. "4,2".

required
opacity float

Overall opacity in [0, 1].

required
position Position

Position adjustment.

required

Returns:

Type Description
Chart

New Chart with mark set to "rule".

Examples:

>>> import ferrum as fm
>>> import polars as pl
>>> df = pl.DataFrame({"y": [0.0]})
>>> fm.Chart(df).mark_rule(stroke="red", stroke_width=2).encode(y="y")
Chart(mark='rule', encoding=['y'])

mark_text

mark_text(**kwargs) -> 'Chart'

Render data values as text labels.

Places a free-positioned text glyph at each (x, y) data coordinate. No collision avoidance is applied and no leader line is drawn; the glyph sits exactly at the encoded position plus any dx/dy pixel offset. Use this mark when you control placement explicitly (e.g. inline bar labels, callout annotations at known coordinates).

See also :meth:mark_label for a point-anchored annotation with automatic collision avoidance and optional leader-line support.

Requires a text encoding channel pointing at the column to display.

Parameters:

Name Type Description Default
fill str

Text colour override.

required
font_size float

Font size in points. Default is 11.

required
font_weight str or int

CSS font-weight, e.g. "bold", 400, 700.

required
align str

Horizontal alignment: "left", "center", "right".

required
baseline str

Vertical alignment: "top", "middle", "bottom", "alphabetic".

required
dx float

Horizontal pixel offset from the anchor point.

required
dy float

Vertical pixel offset from the anchor point.

required
angle float

Rotation in degrees.

required
limit float

Maximum rendered width in pixels; clips overflow.

required
position Position

Position adjustment.

required

Returns:

Type Description
Chart

New Chart with mark set to "text".

Examples:

>>> import ferrum as fm
>>> import polars as pl
>>> df = pl.DataFrame({"x": [1, 2], "y": [3, 4], "label": ["A", "B"]})
>>> fm.Chart(df).mark_text(dy=-8).encode(x="x", y="y", text="label")
Chart(mark='text', encoding=['x', 'y', 'text'])

mark_tick

mark_tick(**kwargs) -> 'Chart'

Render data as short tick marks (rug / strip plot).

Parameters:

Name Type Description Default
stroke str

Tick colour override.

required
stroke_width float

Tick stroke width in pixels.

required
opacity float

Overall opacity in [0, 1].

required
band_size float

Tick length as a fraction of band width (0–1, default 0.3).

required
orient str

"vertical" (default ticks perpendicular to x) or "horizontal".

required
position Position

Position adjustment.

required

Returns:

Type Description
Chart

New Chart with mark set to "tick".

Examples:

>>> import ferrum as fm
>>> import polars as pl
>>> df = pl.DataFrame({"x": [1.1, 2.3, 3.5, 2.2, 1.8]})
>>> fm.Chart(df).mark_tick().encode(x="x")
Chart(mark='tick', encoding=['x'])

mark_rect

mark_rect(**kwargs) -> 'Chart'

Render data as rectangles (heatmap cells, Gantt bars).

Requires x/x2 or y/y2 encoding pairs (or ordinal x/y for a heatmap cell grid).

Parameters:

Name Type Description Default
fill str

Rectangle fill colour override.

required
stroke str

Rectangle border stroke colour.

required
stroke_width float

Border stroke width in pixels.

required
opacity float

Overall opacity in [0, 1].

required
corner_radius float

Rounded corner radius in pixels.

required
position Position

Position adjustment.

required

Returns:

Type Description
Chart

New Chart with mark set to "rect".

Examples:

>>> import ferrum as fm
>>> import polars as pl
>>> df = pl.DataFrame({"row": ["A", "B"], "col": ["X", "Y"], "val": [1.0, 0.5]})
>>> fm.Chart(df).mark_rect().encode(x="col", y="row", color="val")
Chart(mark='rect', encoding=['x', 'y', 'color'])

mark_segment

mark_segment(*, position=None, **kwargs) -> 'Chart'

Render data as line segments from (x, y) to (x2, y2).

Distinct from mark_rule (axis-aligned only); segments may take any direction. Requires x, y, x2, y2 on the encoding.

Parameters:

Name Type Description Default
stroke str

Segment stroke colour override.

required
stroke_width float

Segment stroke width in pixels.

required
stroke_dash list of float

Dash pattern (alternating on/off pixel lengths).

required
opacity float

Stroke opacity in [0, 1].

required
position Position

Position adjustment.

None
**kwargs

Additional mark-style overrides forwarded to the segment layer.

{}

Returns:

Type Description
Chart

New Chart configured for segment rendering.

Examples:

>>> import ferrum as fm
>>> import polars as pl
>>> df = pl.DataFrame({"x": [0, 1], "y": [0, 1], "x2": [1, 2], "y2": [1, 0]})
>>> fm.Chart(df).mark_segment().encode(x="x", y="y", x2="x2", y2="y2")
Chart(mark='segment', encoding=['x', 'y', 'x2', 'y2'])

mark_arc

mark_arc(**kwargs) -> 'Chart'

Render data as arcs (pie or donut slices).

Requires Chart.coord(fm.CoordPolar(theta="x")) to be set. The theta-mapped encoding channel (x by default) determines each slice's angular sweep proportional to its value.

Parameters:

Name Type Description Default
**kwargs

Mark style overrides: color, opacity, stroke_width, etc.

{}

Examples:

>>> fm.Chart(df).mark_arc().encode(x="value", color="category").coord(
...     fm.CoordPolar(theta="x")
... )

mark_image

mark_image(**kwargs) -> 'Chart'

Render data as raster images.

Each row in the dataset becomes one image tile. Supply a base64-encoded PNG/JPEG via the url encoding channel. Requires Cartesian coordinates; returns an empty scene for Polar or Geo coord systems.

Parameters:

Name Type Description Default
**kwargs

Mark style overrides: width, height, opacity, etc.

{}

Examples:

>>> fm.Chart(df).mark_image().encode(x="x", y="y", url="data_url")

mark_geoshape

mark_geoshape(**kwargs) -> 'Chart'

Render geographic shapes from a GeoJSON FeatureCollection.

Pass a GeoJSON FeatureCollection dict to Chart(data) — ferrum auto-detects the format and splits properties into encoding channels and geometry into a __geometry__ column. Set the projection via Chart.coord(fm.CoordGeo(projection="mercator")).

Parameters:

Name Type Description Default
**kwargs

Mark style overrides: color, opacity, stroke_width, etc.

{}

Examples:

>>> fm.Chart(geojson_data).mark_geoshape().coord(
...     fm.CoordGeo(projection="equal_earth")
... )

mark_label

mark_label(**kwargs) -> 'Chart'

Render point-anchored text annotations near data points.

Each label is anchored to its (x, y) data point and positioned by a greedy collision-avoidance algorithm (not placed at an arbitrary coordinate like :meth:mark_text). An optional leader line (leader_line=True) draws a thin connecting line from the data point to the placed label, useful when the label lands far from its source point. Use this mark when you want the renderer to find non-overlapping placements automatically.

See also :meth:mark_text for a free-positioned text glyph that places the label at the exact encoded coordinate without collision avoidance or a leader line.

Each row in the dataset becomes one text label. By default the renderer uses a greedy collision-avoidance algorithm: for each label in row order it tries a ranked list of candidate offsets (above, below, right, left, diagonals) and picks the first placement whose estimated bounding box overlaps no previously-placed label. When every candidate overlaps something, the least-bad placement is chosen.

When both dx and dy are supplied explicitly, collision avoidance is bypassed and those fixed offsets are applied to every label (manual positioning path).

Parameters:

Name Type Description Default
dx float

Fixed horizontal offset in pixels. Must be combined with dy to bypass collision avoidance.

required
dy float

Fixed vertical offset in pixels. Must be combined with dx to bypass collision avoidance. Default when auto-placing is to prefer dy = -8 (above the point).

required
font_size float

Label font size in points (default 11).

required
leader_line bool

When True, a thin line is drawn from each data point to its placed label position. Useful when labels are placed far from their source points. Default False.

required
**kwargs

Additional mark style overrides (fill, opacity, font_weight, etc.).

{}

Examples:

>>> fm.Chart(df).mark_label().encode(x="x:Q", y="y:Q", text="label")
>>> fm.Chart(df).mark_label(dx=5, dy=-12).encode(x="x:Q", y="y:Q", text="label")
>>> fm.Chart(df).mark_label(leader_line=True).encode(x="x:Q", y="y:Q", text="label")

encode

encode(**channels: Any) -> 'Chart'

Set or update encoding channels on this chart.

Each keyword argument maps a channel name to a field shorthand string (e.g. "species:N") or an explicit channel object (e.g. fm.X("sepal_length", type="Q")).

Parameters:

Name Type Description Default
x str or X

Field mapped to the x position. Shorthand format: "field" (type inferred), "field:Q" (quantitative), "field:N" (nominal), "field:O" (ordinal), "field:T" (temporal), or "agg(field):Q" (aggregation).

required
y str or Y

Field mapped to the y position.

required
x2 str or X2

Secondary x position (band / segment end).

required
y2 str or Y2

Secondary y position.

required
color str or Color

Field or value driving mark colour.

required
fill str or Fill

Field or value driving mark fill colour.

required
stroke str or Stroke

Field or value driving mark stroke colour.

required
size str or Size

Field or value driving mark size.

required
shape str or Shape

Field or value driving mark shape.

required
opacity str or Opacity

Field or value driving mark opacity.

required
text str or Text

Field rendered as text labels (used with mark_text).

required
detail str or Detail

Additional grouping field that does not map to any visual property.

required
tooltip str or Tooltip

Field shown on hover.

required
**channels Any

Any other valid channel names (x_error, y_error, theta, radius, etc.).

{}

Returns:

Type Description
Chart

New Chart with updated encoding channels.

Raises:

Type Description
ValueError

If an unknown channel name is passed.

TypeError

If a value is not a string, channel instance, or Repeat placeholder.

Examples:

>>> import ferrum as fm
>>> import polars as pl
>>> df = pl.DataFrame({"x": [1, 2, 3], "y": [4, 5, 6], "c": ["a", "b", "a"]})
>>> fm.Chart(df).mark_point().encode(x="x:Q", y="y:Q", color="c:N")
Chart(mark='point', encoding=['x', 'y', 'color'])

layer

layer(*layers) -> 'Chart'

Add one or more layer objects to this chart.

Accepts both public Layer instances (user-facing API) and internal _Layer instances (used by ferrum internals).

When a Layer(data=df, ...) has its own data attribute, that data is merged with the chart's existing data via diagonal concatenation (same strategy as the + operator). Each layer's encoding references only its own columns; null-padded rows in the merged batch are invisible to mark renderers that skip null values.

Parameters:

Name Type Description Default
*layers Layer or _Layer

Layer objects to append. Public Layer instances may carry an independent data= DataFrame.

()

Returns:

Type Description
Chart

This chart with the new layers appended.

transform

transform(*transforms) -> 'Chart'

Append one or more data transforms to the chart's pipeline.

Transforms are executed in order by the Rust engine before rendering. Multiple calls to transform() accumulate — each appends to the existing pipeline.

Parameters:

Name Type Description Default
*transforms

One or more transform objects (e.g. fm.Filter(...), fm.Aggregate(...), fm.Sort(...), fm.Window(...)). Accepts any object that serialises to a valid TransformSpec JSON shape.

()

Returns:

Type Description
Chart

New Chart with the additional transforms appended.

Examples:

>>> import ferrum as fm
>>> import polars as pl
>>> df = pl.DataFrame({"x": [1, 2, 3], "y": [4, 5, 6]})
>>> fm.Chart(df).mark_point().encode(x="x", y="y").transform(
...     fm.Filter("datum.x > 1")
... )
Chart(mark='point', encoding=['x', 'y'])

facet

facet(field: Optional[str] = None, *, row: Optional[str] = None, col: Optional[str] = None, ncols: Optional[int] = None, nrows: Optional[int] = None) -> 'Chart'

Facet this chart into small multiples by a field.

Two modes are supported:

  • Wrap — a single field is wrapped across columns (rows auto). Pass field= or equivalently col= alone.
  • Grid — two fields define row × column layout. Pass both row= and col=.

Parameters:

Name Type Description Default
field str

Column name used for wrap-mode faceting. Mutually exclusive with using both row and col together.

None
row str

Column name for the row dimension (grid mode). When used alone, behaves as wrap mode on the row axis.

None
col str

Column name for the column dimension (wrap or grid mode).

None
ncols int or None

Maximum number of columns in wrap mode. None lets the renderer choose.

None
nrows int or None

Maximum number of rows. None lets the renderer choose.

None

Returns:

Type Description
Chart

New Chart with faceting configured.

Raises:

Type Description
ValueError

If neither field, row, nor col is provided.

Examples:

>>> import ferrum as fm
>>> import polars as pl
>>> df = pl.DataFrame({"x": [1,2,3]*3, "y": [4,5,6]*3,
...                    "g": ["a","a","b","b","c","c","a","b","c"]})
>>> fm.Chart(df).mark_point().encode(x="x", y="y").facet(col="g", ncols=2)
Chart(mark='point', encoding=['x', 'y'])

share_scale

share_scale(*, x: Optional[str] = None, y: Optional[str] = None) -> 'Chart'

Set per-channel facet scale resolution for this faceted chart.

Each panel can either lock to the union domain across all partitions ("shared", the default) or compute its own domain from its partition's data ("independent").

Parameters:

Name Type Description Default
x str or None

Scale resolution for the x channel. "shared" or "independent". None leaves the current setting unchanged.

None
y str or None

Scale resolution for the y channel. "shared" or "independent". None leaves the current setting unchanged.

None

Returns:

Type Description
Chart

New Chart with the scale resolution updated.

Raises:

Type Description
ValueError

If called before facet(), or if a value is not "shared" or "independent".

Examples:

>>> import ferrum as fm
>>> import polars as pl
>>> df = pl.DataFrame({"g": ["a","a","b","b"], "x": [1,2,1,2],
...                    "y": [1.0,2.0,100.0,101.0]})
>>> (fm.Chart(df).mark_point().encode(x="x:Q", y="y:Q")
...  .facet(col="g").share_scale(y="independent"))
Chart(mark='point', encoding=['x', 'y'])

theme

theme(theme: Any) -> 'Chart'

Attach a Theme to this chart, overriding the process-level default.

Per-chart theme always wins over ferrum.set_default_theme(). Theme objects are immutable value classes — modifying the original Theme after calling .theme() has no effect on the chart.

Parameters:

Name Type Description Default
theme Theme

A ferrum.Theme instance (e.g. fm.themes.dark(), fm.Theme(background="white", font="serif")).

required

Returns:

Type Description
Chart

New Chart with the specified theme attached.

Examples:

>>> import ferrum as fm
>>> import polars as pl
>>> df = pl.DataFrame({"x": [1, 2, 3], "y": [4, 5, 6]})
>>> dark = fm.themes.dark()
>>> fm.Chart(df).mark_point().encode(x="x", y="y").theme(dark)
Chart(mark='point', encoding=['x', 'y'])

axis

axis(*, x: Optional[bool] = None, y: Optional[bool] = None, show: Optional[bool] = None) -> 'Chart'

Suppress (or restore) the chart's x/y axis decorations.

Spec-level axis suppression — when x=False (or y=False), the corresponding axis line, ticks, tick labels, and axis title are omitted at layout time. The plot area's pixel rect is unchanged (gutters reserved for axis decorations are preserved), so this method is intended for sub-charts whose axes are shared with a neighbouring chart in a compound view: clustermap dendrograms, JointChart marginals, RepeatChart off-diagonal panels.

Parameters:

Name Type Description Default
x bool

False hides the x axis; True shows it; None leaves the current setting (default visible).

None
y bool

False hides the y axis; True shows it; None leaves the current setting (default visible).

None
show bool

Shorthand for axis(x=show, y=show). Mutually exclusive with per-axis x/y arguments.

None

Returns:

Type Description
Chart

New Chart with the requested axis-visibility settings.

Raises:

Type Description
ValueError

If show is combined with x or y.

Examples:

Hide both axes (e.g. for a dendrogram panel):

>>> chart.axis(show=False)

Hide just the x axis (top marginal of a JointChart):

>>> chart.axis(x=False)

override

override(**kwargs: Any) -> 'Chart'

Store low-level spec-path overrides to be applied at render time.

Overrides are merged into :attr:_overrides with later calls winning on key conflicts. The override() call never mutates the receiver.

Parameters:

Name Type Description Default
**kwargs Any

Arbitrary spec-path key/value pairs forwarded verbatim to the renderer (e.g. x_axis_label_angle=-45).

{}

Returns:

Type Description
Chart

New Chart with the overrides merged.

Examples:

>>> chart.override(x_axis_label_angle=-45, width=600)

coord

coord(coord: Any) -> 'Chart'

Set the coordinate system for this chart.

Currently only CoordFlip is supported (swaps x and y axes).

Parameters:

Name Type Description Default
coord CoordFlip

A coordinate-system object. Pass fm.CoordFlip() to swap the horizontal and vertical axes.

required

Returns:

Type Description
Chart

New Chart with the coordinate system set.

Raises:

Type Description
TypeError

If coord is not a supported coordinate-system type.

Examples:

>>> import ferrum as fm
>>> import polars as pl
>>> df = pl.DataFrame({"cat": ["a", "b", "c"], "val": [10, 20, 15]})
>>> fm.Chart(df).mark_bar().encode(x="cat", y="val").coord(fm.CoordFlip())
Chart(mark='bar', encoding=['x', 'y'])

xlim

xlim(lo: float, hi: float) -> 'Chart'

Set the x-axis domain to [lo, hi] (plotnine-style).

Equivalent to .coord(fm.CoordCartesian(xlim=(lo, hi))). When a CoordCartesian is already set on this chart its ylim (and other parameters) are preserved; only xlim is updated.

Parameters:

Name Type Description Default
lo float

Lower bound of the x-axis domain.

required
hi float

Upper bound of the x-axis domain.

required

Returns:

Type Description
Chart

New Chart with the x-axis domain constrained.

Examples:

>>> import ferrum as fm
>>> import polars as pl
>>> df = pl.DataFrame({"x": [1.0, 2.0, 3.0], "y": [4.0, 5.0, 6.0]})
>>> fm.Chart(df).mark_point().encode(x="x", y="y").xlim(0, 10)
Chart(mark='point', encoding=['x', 'y'])

ylim

ylim(lo: float, hi: float) -> 'Chart'

Set the y-axis domain to [lo, hi] (plotnine-style).

Equivalent to .coord(fm.CoordCartesian(ylim=(lo, hi))). When a CoordCartesian is already set on this chart its xlim (and other parameters) are preserved; only ylim is updated.

Parameters:

Name Type Description Default
lo float

Lower bound of the y-axis domain.

required
hi float

Upper bound of the y-axis domain.

required

Returns:

Type Description
Chart

New Chart with the y-axis domain constrained.

Examples:

>>> import ferrum as fm
>>> import polars as pl
>>> df = pl.DataFrame({"x": [1.0, 2.0, 3.0], "y": [4.0, 5.0, 6.0]})
>>> fm.Chart(df).mark_point().encode(x="x", y="y").ylim(0, 20)
Chart(mark='point', encoding=['x', 'y'])

properties

properties(*, width=None, height=None, title=None, subtitle=None, caption=None, description=None, render_config=None) -> 'Chart'

Set chart-level display properties.

Only the keyword arguments that are explicitly provided are updated; unset properties inherit from the existing chart.

Parameters:

Name Type Description Default
width int or 'container' or None

Chart width in pixels, or "container" to fill the parent.

None
height int or 'container' or None

Chart height in pixels.

None
title str or None

Chart title rendered above the plot area.

None
subtitle str or None

Chart subtitle rendered below the title. On a faceted chart this renders inside the facet grid via the Title spec. On a plain single-panel chart it behaves identically to .labs(subtitle=...).

None
caption str or None

Figure-level caption rendered below the chart. Applied as a post-render chrome band so that it appears beneath the plot area regardless of chart type.

None
description str or None

Accessible description attached to the SVG root.

None
render_config RenderConfig or None

Rendering policy configuration. Controls auto-raster threshold and behavior. For one-off overrides prefer the raster= keyword on .show() / .save() / .to_svg() instead.

None

Returns:

Type Description
Chart

New Chart with the specified properties updated.

Examples:

>>> import ferrum as fm
>>> import polars as pl
>>> df = pl.DataFrame({"x": [1, 2], "y": [3, 4]})
>>> fm.Chart(df).mark_point().encode(x="x", y="y").properties(
...     width=400, height=300, title="My Chart"
... )
Chart(mark='point', encoding=['x', 'y'])

labs

labs(**kwargs) -> 'Chart'

Set human-readable labels for axes and title (plotnine-style).

A convenience wrapper around properties() and per-channel title kwargs. Only the keys you provide are updated; everything else is inherited from the existing chart.

Parameters:

Name Type Description Default
title str

Chart title — delegates to .properties(title=...).

required
subtitle str

Chart subtitle — delegates to .properties(subtitle=...).

required
x str

Horizontal-axis title. Wraps the existing x encoding channel in a new X(field, title=x, **original_kwargs) value, or creates X(None, title=x) if no x encoding is present.

required
y str

Vertical-axis title. Analogous to x above for the y channel.

required

Returns:

Type Description
Chart

New Chart with the specified labels applied.

Raises:

Type Description
ValueError

If any key in kwargs is not one of title, subtitle, x, or y.

Examples:

>>> import ferrum as fm
>>> import polars as pl
>>> df = pl.DataFrame({"x": [1, 2], "y": [3, 4]})
>>> fm.Chart(df).mark_point().encode(x="x", y="y").labs(
...     title="My Chart", x="Horizontal", y="Vertical"
... )
Chart(mark='point', encoding=['x', 'y'])

to_spec

to_spec(*, _override_payload=None)

Build the Rust ChartSpec for this chart.

Resolves any pending statistical-mark desugar, converts Python encoding channel objects to EncodingSpec instances, and constructs the ChartSpec PyO3 object that the Rust renderer consumes.

When the chart carries Chart.override kwargs, the spec-targeted pieces of the override payload (encoding scales, mark style, coord) are applied last so override wins the cascade (spec §7). _render_inputs builds the payload once per render and threads it via _override_payload; a direct .to_spec() call builds it on demand from self._overrides so the standalone spec also reflects overrides. The chart-config, property, and deprecation pieces are applied by the render path, not here.

Returns:

Type Description
ChartSpec

The fully-resolved ferrum._core.ChartSpec for this chart.

Examples:

>>> import ferrum as fm
>>> import polars as pl
>>> df = pl.DataFrame({"x": [1, 2], "y": [3, 4]})
>>> spec = fm.Chart(df).mark_point().encode(x="x", y="y").to_spec()
>>> spec.mark
'point'

to_json

to_json(*, indent=None) -> str

Serialise the chart specification to a JSON string.

.. note:: Unlike :meth:to_svg, :meth:to_png, and :meth:to_html — which return rendered output — to_json returns the chart specification (the declaration you built), not the rendered scene graph. save(path) with a .json extension writes the rendered scene graph instead, which is a different artifact. For the specification as a Python value, see :meth:to_dict.

Calls to_spec() to build the ChartSpec and then serialises it via the Rust serde_json encoder. When indent is given the compact JSON is reformatted via json.loads / json.dumps on the Python side (the Rust encoder always produces compact output).

Parameters:

Name Type Description Default
indent int or None

Number of spaces to use for pretty-printing. None (default) returns compact single-line JSON.

None

Returns:

Type Description
str

JSON representation of the chart specification.

Examples:

>>> import ferrum as fm
>>> import polars as pl
>>> df = pl.DataFrame({"x": [1], "y": [2]})
>>> spec_json = fm.Chart(df).mark_point().encode(x="x", y="y").to_json()
>>> '"mark"' in spec_json
True

to_dict

to_dict() -> dict

Serialise the chart specification to a plain Python dict (Altair-style).

Equivalent to json.loads(self.to_json()). Useful for introspection, testing, and interoperability with tools that consume chart-spec dicts.

Returns:

Type Description
dict

The chart specification as a nested Python dictionary.

Examples:

>>> import ferrum as fm
>>> import polars as pl
>>> df = pl.DataFrame({"x": [1], "y": [2]})
>>> d = fm.Chart(df).mark_point().encode(x="x", y="y").to_dict()
>>> d["mark"]
'point'

add_selection

add_selection(*selections) -> 'Chart'

Attach interactive selection(s) to this chart.

Per ferrum-spec.md §3.10 (L736), the SVG/PNG renderer silently ignores selections — they are intended for the WASM renderer (Phase 11). This method accepts any number of selection objects and returns a new Chart unchanged so that user code building selection-aware charts remains forward-compatible without raising under SVG/PNG rendering.

Parameters:

Name Type Description Default
*selections

Any number of selection objects (currently ignored).

()

Returns:

Type Description
Chart

New Chart (clone), with the selections recorded but not rendered.

Examples:

>>> import ferrum as fm
>>> import polars as pl
>>> df = pl.DataFrame({"x": [1, 2], "y": [3, 4]})
>>> chart = fm.Chart(df).mark_point().encode(x="x", y="y").add_selection()

add_params

add_params(*params) -> 'Chart'

Attach reactive variable parameter(s) to this chart.

Records one or more :class:~ferrum.parameter.Parameter objects (built via fm.param()) so they are emitted into the spec's params section. Parameters drive reactive scale domains (scale={"domain": param}) and crossfilters (transform_filter(param)) in the WASM runtime; at static render time their initial value is used.

Selections referenced as scale domains or registered via add_selection are auto-promoted into the params section at serialization, so they do not need to be passed here. Duplicate names are de-duplicated (first-seen wins) when the spec is built.

Parameters:

Name Type Description Default
*params Parameter

Any number of parameter objects (typically fm.param(...)).

()

Returns:

Type Description
Chart

New Chart (clone) with the parameters recorded.

Examples:

>>> import ferrum as fm
>>> import polars as pl
>>> df = pl.DataFrame({"x": [1, 2], "y": [3, 4]})
>>> k = fm.param("k", value=3)
>>> chart = fm.Chart(df).mark_point().encode(x="x", y="y").add_params(k)

interactive

interactive(*, toolbar: bool = True) -> 'InteractiveChart'

Return an interactive rendering of this chart.

Wraps the chart in an InteractiveChart widget backed by the WASM renderer, enabling selections, pan/zoom, and conditional encodings in Jupyter and HTML exports.

Parameters:

Name Type Description Default
toolbar bool

Whether to show the interactive toolbar (zoom/pan controls, export button). Set to False to render without the toolbar.

True

Returns:

Type Description
InteractiveChart

An interactive widget/container backed by the WASM renderer.

Examples:

>>> import ferrum as fm
>>> import polars as pl
>>> df = pl.DataFrame({"x": [1, 2], "y": [3, 4]})
>>> chart = fm.Chart(df).mark_point().encode(x="x", y="y").interactive()

conditional

conditional(spec: Any) -> 'Chart'

Apply a conditional encoding to this chart.

Convenience sugar: chart.conditional(sel.when(Color("x")).otherwise(value("#ccc"))) is equivalent to::

chart.add_selection(sel).encode(color=sel.when(Color("x")).otherwise(value("#ccc")))

Parameters:

Name Type Description Default
spec ConditionalSpec

A ConditionalSpec produced by sel.when(...).otherwise(...).

required

Returns:

Type Description
Chart

New Chart with the conditional recorded.

Examples:

>>> import ferrum as fm
>>> import polars as pl
>>> from ferrum.selection import selection_point, value
>>> df = pl.DataFrame({"x": [1, 2], "y": [3, 4], "z": ["a", "b"]})
>>> sel = selection_point(fields=["z"])
>>> chart = (
...     fm.Chart(df)
...     .mark_point()
...     .encode(x="x", y="y")
...     .conditional(sel.when(fm.Color("z")).otherwise(value("#ccc")))
... )