Skip to content

ferrum.composition

Compound view classes for combining multiple charts into a single output.

Multi-chart composition primitives (HConcat, VConcat, Joint, Repeat, ClusterMap).

HConcatChart

Bases: _CompositeBase

Horizontal concatenation of two or more charts.

Each sub-chart retains its own scales, axes, and legend. Construct via the | operator on Chart instances or directly with a list.

Parameters:

Name Type Description Default
charts list of Chart

Sub-charts to concatenate left-to-right.

required
spacing float

Horizontal pixel gap between adjacent charts.

10.0

Examples:

>>> import ferrum as fm
>>> combined = fm.Chart(df).encode(x="hp", y="mpg").mark_point() | fm.Chart(df).encode(x="hp").mark_histogram()
>>> combined.save("side_by_side.svg")

show_svg

show_svg() -> str

Render the horizontally concatenated charts to an SVG string.

Returns:

Type Description
str

SVG markup with sub-charts placed left-to-right.

show

show() -> None

Print the SVG markup to stdout.

show_png

show_png() -> bytes

Render to PNG bytes (2x retina by default).

Rasterises the SVG produced by show_svg() through the Rust resvg pipeline -- the same rasteriser Chart.show_png() uses, with the same 2x default scale.

Returns:

Type Description
bytes

PNG image as raw bytes suitable for IPython.display.Image or writing directly to disk.

save

save(path: str, *, format=None, **kwargs) -> None

Save the composition to a file.

Parameters:

Name Type Description Default
path str

Destination file path. The extension determines the format when format is omitted.

required
format str

"svg" or "png". Other formats raise NotImplementedError.

None

Raises:

Type Description
NotImplementedError

If format is not "svg" or "png".

share_scale

share_scale(**channels)

Share scales across this composition's member charts.

Computes the union domain for each channel marked "shared" and re-emits every member chart with an explicit scale= dict on that channel, so the participating axes lock to the same ticks. Channels marked "independent" (the default for any channel not listed) keep their per-chart domains.

Parameters:

Name Type Description Default
**channels str

Channel name → "shared" | "independent". Common channels: x, y, color, size.

{}

Returns:

Type Description
_ChartLike

A new composition of the same type with the shared scales injected. No-op (returns self) when no channel is "shared" or none of the requested channels are bound on any member chart.

Raises:

Type Description
ValueError

If any value is not "shared" or "independent".

Examples:

>>> import ferrum as fm
>>> combined = (chart_a | chart_b).share_scale(x="shared")
>>> grid = fm.JointChart(center, top=hist_x, right=hist_y).share_scale(y="shared")

theme

theme(t)

Apply a theme to every sub-chart and return a new composition.

Parameters:

Name Type Description Default
t Theme

Theme value to apply.

required

Returns:

Type Description
_ChartLike

A new instance of the same composition class with t applied to each sub-chart.

properties

properties(**kwargs)

Forward properties(**kwargs) to every sub-chart.

Parameters:

Name Type Description Default
**kwargs

Keyword arguments accepted by Chart.properties (e.g. width, height, title, background).

{}

Returns:

Type Description
_ChartLike

A new instance of the same composition class with updated sub-chart properties.

VConcatChart

Bases: _CompositeBase

Vertical concatenation of two or more charts.

Each sub-chart retains its own scales, axes, and legend. Construct via the & operator on Chart instances or directly with a list.

Parameters:

Name Type Description Default
charts list of Chart

Sub-charts to stack top-to-bottom.

required
spacing float

Vertical pixel gap between adjacent charts.

10.0

Examples:

>>> import ferrum as fm
>>> stacked = fm.Chart(df).encode(x="hp", y="mpg").mark_point() & fm.Chart(df).encode(x="hp").mark_histogram()
>>> stacked.save("stacked.svg")

show_svg

show_svg() -> str

Render the vertically concatenated charts to an SVG string.

Returns:

Type Description
str

SVG markup with sub-charts stacked top-to-bottom.

show

show() -> None

Print the SVG markup to stdout.

show_png

show_png() -> bytes

Render to PNG bytes (2x retina by default).

Rasterises the SVG produced by show_svg() through the Rust resvg pipeline -- the same rasteriser Chart.show_png() uses, with the same 2x default scale.

Returns:

Type Description
bytes

PNG image as raw bytes suitable for IPython.display.Image or writing directly to disk.

save

save(path: str, *, format=None, **kwargs) -> None

Save the composition to a file.

Parameters:

Name Type Description Default
path str

Destination file path. The extension determines the format when format is omitted.

required
format str

"svg" or "png". Other formats raise NotImplementedError.

None

Raises:

Type Description
NotImplementedError

If format is not "svg" or "png".

share_scale

share_scale(**channels)

Share scales across this composition's member charts.

Computes the union domain for each channel marked "shared" and re-emits every member chart with an explicit scale= dict on that channel, so the participating axes lock to the same ticks. Channels marked "independent" (the default for any channel not listed) keep their per-chart domains.

Parameters:

Name Type Description Default
**channels str

Channel name → "shared" | "independent". Common channels: x, y, color, size.

{}

Returns:

Type Description
_ChartLike

A new composition of the same type with the shared scales injected. No-op (returns self) when no channel is "shared" or none of the requested channels are bound on any member chart.

Raises:

Type Description
ValueError

If any value is not "shared" or "independent".

Examples:

>>> import ferrum as fm
>>> combined = (chart_a | chart_b).share_scale(x="shared")
>>> grid = fm.JointChart(center, top=hist_x, right=hist_y).share_scale(y="shared")

theme

theme(t)

Apply a theme to every sub-chart and return a new composition.

Parameters:

Name Type Description Default
t Theme

Theme value to apply.

required

Returns:

Type Description
_ChartLike

A new instance of the same composition class with t applied to each sub-chart.

properties

properties(**kwargs)

Forward properties(**kwargs) to every sub-chart.

Parameters:

Name Type Description Default
**kwargs

Keyword arguments accepted by Chart.properties (e.g. width, height, title, background).

{}

Returns:

Type Description
_ChartLike

A new instance of the same composition class with updated sub-chart properties.

JointChart

Bases: _ChartLike

Joint distribution view: center chart plus optional top and right marginals.

Lays out a 2 × 2 grid: center chart occupies the bottom-left cell, top marginal goes top-left, right marginal goes bottom-right, and the top-right corner is empty. The x-axis is shared between the center and top charts; the y-axis is shared between the center and right charts.

The cell size ratio between the center and each marginal is controlled by ratio. A ratio of 5 gives the center 5/(5+1) of each dimension and each marginal 1/(5+1).

Most users obtain a JointChart from ferrum.jointplot rather than constructing one directly.

Parameters:

Name Type Description Default
center Chart

Primary scatter / distribution chart occupying the main panel.

required
top Chart

Marginal chart drawn above the center (e.g. a histogram of the x variable).

None
right Chart

Marginal chart drawn to the right of the center (e.g. a histogram of the y variable).

None
ratio int

Size ratio of the center panel to each marginal panel. Must be > 0.

5
spacing float

Pixel gap between adjacent cells.

10.0

Raises:

Type Description
ValueError

If ratio is not > 0.

Examples:

>>> import ferrum as fm
>>> joint = fm.jointplot(df, x="hp", y="mpg")
>>> joint.save("joint.svg")

charts property

charts: list

List of Chart : All non-None sub-charts (center, top, right).

spec property

spec: dict

Dict : Serializable layout spec consumed by the SVG compositor.

properties

properties(**kwargs)

Forward properties(**kwargs) to the center chart.

The marginals (top, right) are kept unchanged because their width / height is derived from the center plus ratio at render time.

Parameters:

Name Type Description Default
**kwargs

Keyword arguments accepted by Chart.properties (e.g. width, height, title).

{}

Returns:

Type Description
JointChart

A new instance with updated center-chart properties.

show_svg

show_svg() -> str

Render the joint chart to an SVG string.

Returns:

Type Description
str

SVG markup with the 2 × 2 grid layout.

show

show() -> None

Print the SVG markup to stdout.

show_png

show_png() -> bytes

Render to PNG bytes (2x retina by default).

Rasterises the SVG produced by show_svg() through the Rust resvg pipeline -- the same rasteriser Chart.show_png() uses, with the same 2x default scale.

Returns:

Type Description
bytes

PNG image as raw bytes suitable for IPython.display.Image or writing directly to disk.

save

save(path: str, *, format=None, **kwargs) -> None

Save the composition to a file.

Parameters:

Name Type Description Default
path str

Destination file path. The extension determines the format when format is omitted.

required
format str

"svg" or "png". Other formats raise NotImplementedError.

None

Raises:

Type Description
NotImplementedError

If format is not "svg" or "png".

share_scale

share_scale(**channels)

Share scales across this composition's member charts.

Computes the union domain for each channel marked "shared" and re-emits every member chart with an explicit scale= dict on that channel, so the participating axes lock to the same ticks. Channels marked "independent" (the default for any channel not listed) keep their per-chart domains.

Parameters:

Name Type Description Default
**channels str

Channel name → "shared" | "independent". Common channels: x, y, color, size.

{}

Returns:

Type Description
_ChartLike

A new composition of the same type with the shared scales injected. No-op (returns self) when no channel is "shared" or none of the requested channels are bound on any member chart.

Raises:

Type Description
ValueError

If any value is not "shared" or "independent".

Examples:

>>> import ferrum as fm
>>> combined = (chart_a | chart_b).share_scale(x="shared")
>>> grid = fm.JointChart(center, top=hist_x, right=hist_y).share_scale(y="shared")

theme

theme(t)

Apply a theme to every sub-chart and return a new composition.

Parameters:

Name Type Description Default
t Theme

Theme value to apply.

required

Returns:

Type Description
_ChartLike

A new instance of the same composition class with t applied to each sub-chart.

RepeatChart

Bases: _ChartLike

Repeat a template chart over a grid of row / column field combinations.

Use Repeat.column, Repeat.row, or Repeat.layer typed sentinels in the template's .encode(...) call to mark which encoding channel receives the per-cell field substitution. RepeatChart.expand() materializes the grid into fully-resolved (row_field, col_field, Chart) tuples.

diagonal= provides an alternate template for cells where row_field == col_field (symmetric n × n repeat). corner=True filters the expanded grid to the lower triangle including the diagonal.

Most users obtain a RepeatChart through Chart.repeat() or ferrum.pairplot.

Parameters:

Name Type Description Default
template Chart

Template chart whose Repeat.* placeholders are substituted per cell.

required
row list of str

Field names assigned to the row axis.

None
column list of str

Field names assigned to the column axis.

None
layer list of str

Field names assigned to the layer axis (for non-grid repeat layouts).

None
diagonal Chart

Alternate template used when row_field == col_field. Requires both row and column to be set.

None
corner bool

When True, only the lower-triangle cells (ri >= ci) are rendered, giving a half-matrix layout.

False
spacing float

Pixel gap between adjacent cells.

10.0
columns int

Maximum number of columns for a wrapped 1-D repeat layout (no-op for 2-D row/column repeat).

None
resolve dict

Per-channel scale-sharing overrides — e.g. resolve={"x": "shared", "y": "independent"}. "shared" computes the union domain across all cells (and across every layer of layered cells) and injects an explicit scale on every participating chart so the axis ticks match. "independent" (the default for unlisted channels) keeps per-cell domains.

None

Raises:

Type Description
ValueError

If diagonal is set but row or column is not.

Examples:

>>> import ferrum as fm
>>> base = fm.Chart(df).encode(x=fm.Repeat.column, y=fm.Repeat.row).mark_point()
>>> grid = fm.RepeatChart(base, row=["mpg", "hp"], column=["mpg", "hp"])
>>> grid.save("pair_grid.svg")

charts property

charts: list

List of Chart : Template plus diagonal (when set), in init order.

spec property

spec: dict

Dict : Serializable layout spec consumed by the SVG compositor.

expand

expand() -> list

Materialize the template into fully-resolved chart cells.

Cell iteration shape:

  • 2-D grid (both row and column set): len(row) × len(column) cells, optionally filtered by corner; diagonal substitutes the template on row_field == col_field cells.
  • 1-D wrap (only one of row or column set): the populated field list, paired with None on the missing axis. Geometry is applied by :meth:show_svg driven by columns.
  • Layer-only (layer= set, row and column both None): a single cell containing all layers.

When layer= is set, each cell becomes a layered Chart with one layer per element in self.layer (substituted into every Repeat.layer placeholder). Diagonal cells skip layering — the diagonal template already defines that cell.

Returns:

Type Description
list of tuple

Each element is (row_field, col_field, Chart) with all Repeat.* placeholders replaced. For 1-D and layer-only layouts the unused axis is None.

Raises:

Type Description
ValueError

If diagonal is set but row != column (asymmetric repeat), or if the template references a Repeat.* placeholder for an axis that was not populated.

share_scale

share_scale(**channels)

Share scales across this repeat's cells by merging into resolve=.

Equivalent to constructing the chart with resolve={...} set — both paths run through :meth:_apply_resolve at expand() time, so the union-domain computation sees every cell (including each layer of layered cells) exactly once. Passing the same channel twice with different modes takes the call's value.

Parameters:

Name Type Description Default
**channels str

Channel name → "shared" | "independent".

{}

Returns:

Type Description
RepeatChart

A new RepeatChart with the merged resolve= config.

show_svg

show_svg() -> str

Render the repeated grid to an SVG string.

Returns:

Type Description
str

SVG markup containing all materialized cell charts in a grid.

Notes

2-D grids (both row and column set) lay out as len(row) × len(column). 1-D layouts (only one axis set) wrap by columns — column-only spreads left-to-right and wraps downward; row-only spreads top-to-bottom in a single column unless columns opens additional columns. When columns is unset the 1-D layout is a single row (column-only) or column (row-only).

show

show() -> None

Print the SVG markup to stdout.

show_png

show_png() -> bytes

Render to PNG bytes (2x retina by default).

Rasterises the SVG produced by show_svg() through the Rust resvg pipeline -- the same rasteriser Chart.show_png() uses, with the same 2x default scale.

Returns:

Type Description
bytes

PNG image as raw bytes suitable for IPython.display.Image or writing directly to disk.

save

save(path: str, *, format=None, **kwargs) -> None

Save the composition to a file.

Parameters:

Name Type Description Default
path str

Destination file path. The extension determines the format when format is omitted.

required
format str

"svg" or "png". Other formats raise NotImplementedError.

None

Raises:

Type Description
NotImplementedError

If format is not "svg" or "png".

theme

theme(t)

Apply a theme to every sub-chart and return a new composition.

Parameters:

Name Type Description Default
t Theme

Theme value to apply.

required

Returns:

Type Description
_ChartLike

A new instance of the same composition class with t applied to each sub-chart.

properties

properties(**kwargs)

Forward properties(**kwargs) to every sub-chart.

Parameters:

Name Type Description Default
**kwargs

Keyword arguments accepted by Chart.properties (e.g. width, height, title, background).

{}

Returns:

Type Description
_ChartLike

A new instance of the same composition class with updated sub-chart properties.

ClusterMapChart

Bases: _ChartLike

Clustered heatmap with optional row and column dendrograms.

Lays out a 2 × 2 grid: the heatmap occupies the bottom-right cell, the column dendrogram goes top-right, the row dendrogram (rotated 90°) goes bottom-left, and the top-left corner is empty. Dendrogram value axes are hidden; categorical axes align with the heatmap row/column labels.

Cell size is split by dendrogram_ratio: dendrograms receive that fraction of the total width/height, the heatmap receives the remainder.

Most users obtain a ClusterMapChart from ferrum.clustermap rather than constructing one directly.

Parameters:

Name Type Description Default
heatmap Chart

The central heatmap chart.

required
row_dendrogram Chart

Dendrogram chart for the row axis. Displayed to the left of the heatmap, rotated 90°.

None
col_dendrogram Chart

Dendrogram chart for the column axis. Displayed above the heatmap.

None
dendrogram_ratio float

Fraction of the total width/height allocated to each dendrogram panel. Must be in the open interval (0, 1).

0.2
spacing float

Pixel gap between adjacent cells.

10.0

Raises:

Type Description
ValueError

If dendrogram_ratio is not in the open interval (0, 1).

Examples:

>>> import ferrum as fm
>>> cm = fm.clustermap(df, method="ward", cmap="rdbu")
>>> cm.save("clustermap.svg")

charts property

charts: list

List of Chart : All non-None sub-charts in __init__ order (heatmap, row_dendrogram, col_dendrogram).

spec property

spec: dict

Dict : Serializable layout spec consumed by the SVG compositor.

properties

properties(**kwargs)

Forward properties(**kwargs) to the heatmap chart.

The dendrogram panels are kept unchanged because their width / height is derived from the heatmap plus dendrogram_ratio at render time.

Parameters:

Name Type Description Default
**kwargs

Keyword arguments accepted by Chart.properties (e.g. width, height, title).

{}

Returns:

Type Description
ClusterMapChart

A new instance with updated heatmap-chart properties.

show_svg

show_svg() -> str

Render the cluster map to an SVG string.

Returns:

Type Description
str

SVG markup with the 2 × 2 grid layout.

show

show() -> None

Print the SVG markup to stdout.

show_png

show_png() -> bytes

Render to PNG bytes (2x retina by default).

Rasterises the SVG produced by show_svg() through the Rust resvg pipeline -- the same rasteriser Chart.show_png() uses, with the same 2x default scale.

Returns:

Type Description
bytes

PNG image as raw bytes suitable for IPython.display.Image or writing directly to disk.

save

save(path: str, *, format=None, **kwargs) -> None

Save the composition to a file.

Parameters:

Name Type Description Default
path str

Destination file path. The extension determines the format when format is omitted.

required
format str

"svg" or "png". Other formats raise NotImplementedError.

None

Raises:

Type Description
NotImplementedError

If format is not "svg" or "png".

share_scale

share_scale(**channels)

Share scales across this composition's member charts.

Computes the union domain for each channel marked "shared" and re-emits every member chart with an explicit scale= dict on that channel, so the participating axes lock to the same ticks. Channels marked "independent" (the default for any channel not listed) keep their per-chart domains.

Parameters:

Name Type Description Default
**channels str

Channel name → "shared" | "independent". Common channels: x, y, color, size.

{}

Returns:

Type Description
_ChartLike

A new composition of the same type with the shared scales injected. No-op (returns self) when no channel is "shared" or none of the requested channels are bound on any member chart.

Raises:

Type Description
ValueError

If any value is not "shared" or "independent".

Examples:

>>> import ferrum as fm
>>> combined = (chart_a | chart_b).share_scale(x="shared")
>>> grid = fm.JointChart(center, top=hist_x, right=hist_y).share_scale(y="shared")

theme

theme(t)

Apply a theme to every sub-chart and return a new composition.

Parameters:

Name Type Description Default
t Theme

Theme value to apply.

required

Returns:

Type Description
_ChartLike

A new instance of the same composition class with t applied to each sub-chart.