Skip to content

Axis

Axis value class for axis configuration.

Ferrum — a statistical visualization library with a Rust core.

Axis dataclass

Per-channel axis configuration.

Parameters:

Name Type Description Default
title str

Axis title text. Pass title=None to suppress the axis title (the field name will not be shown). Omitting title entirely keeps the field-name default.

_UNSET
orient str

Axis orientation ("top", "bottom", "left", "right").

None
ticks bool

Show tick marks. Omitting ticks (or passing ticks=None, treated identically — the same "unset" spelling every other optional field here accepts) keeps the renderer's own default (shown); passing any other value explicitly — even True — always reaches the wire, so an explicit value beats a conflicting chart-level configure_axis(ticks=...) (per-channel wins).

_UNSET
tick_count int

Suggested number of ticks.

None
tick_extra bool

Include extra tick at domain boundary. Same omit-vs-explicit contract as ticks.

_UNSET
tick_min_step float

Minimum step between ticks.

None
grid bool

Show grid lines. Same omit-vs-explicit contract as ticks.

_UNSET
grid_dash list[float]

Grid line dash pattern.

None
grid_width float

Grid line width.

None
grid_color str

Grid line color.

None
grid_opacity float

Grid line opacity.

None
labels bool

Show tick labels. Same omit-vs-explicit contract as ticks.

_UNSET
label_angle float

Tick label rotation angle.

None
label_flush bool

Flush the first and last tick labels against the axis ends so they do not overhang the plot area. Omitting label_flush keeps the renderer's own default (False, no flush); passing it explicitly — even as False — always reaches the wire (same omit-vs-explicit contract as ticks).

_UNSET
label_overlap str

Label overlap strategy: "greedy" (the graduated collision cascade), "parity" (stride-2 decimation), "rotate" (force the rotate stage), or "true"/"false" (show every label / the "greedy" alias). An unrecognized token raises ValueError at construction. Omitting label_overlap keeps the renderer's own default ("greedy"); passing it explicitly — even as "greedy" — always reaches the wire (same omit-vs-explicit contract as ticks).

_UNSET
label_format str

d3-format string for labels.

None
label_format_type str

Format type ("number", "time").

None
label_font_size float

Label font size.

None
label_color str

Label color.

None
domain bool

Show axis domain line. Same omit-vs-explicit contract as ticks.

_UNSET
domain_width float

Domain line width.

None
domain_color str

Domain line color.

None
offset float

Axis offset from plot area.

None
translate float

Pixel translation.

None
min_band float

Lower bound for the reserved axis margin band, in pixels.

None
max_band float

Upper bound for the reserved axis margin band, in pixels.

.. deprecated:: 0.17.0 min_extent and max_extent are accepted as aliases for min_band and max_band respectively, but are deprecated and will be removed in a future release.

None
title_orient str

Title orientation.

None
title_font_size float

Title font size.

None
title_color str

Title color.

None
title_padding float

Title padding from axis.

None
values list

Explicit tick values.

None
zindex int

Z-index for layering.

None
label_map dict[str, str]

Mapping from original tick-label text to display text. Applied in the Python layer at render time by renaming the corresponding column values in the DataFrame before Rust computes the scale domain. Keys not present in the data are silently ignored.

Example — rename categorical axis labels::

fm.Axis(label_map={"a": "Group A", "b": "Group B"})
None

Examples:

>>> import ferrum as fm
>>> ax = fm.Axis(title="Speed (km/h)", label_angle=-45)
>>> ax.title
'Speed (km/h)'
>>> ax.to_dict()
{'title': 'Speed (km/h)', 'label_angle': -45}

to_dict

to_dict() -> dict[str, Any]

Serialize to dict for the renderer, omitting only unset/None/Python-only fields.

ticks/tick_extra/grid/labels/label_flush/ label_overlap/domain follow the two-way omit-vs-explicit contract :func:ferrum._title_sentinel.is_unspecified implements (distinct from title's three-way contract below): "not specified" is either omitting the kwarg (_UNSET, the field default) or passing the field =None explicitly — the same "unset" spelling every other optional field on this class already accepts — and either spelling drops the key so the renderer's own default applies. Any OTHER explicitly passed value — including one that happens to equal what the renderer would have picked anyway — always reaches the wire (NF-B3). Skipping an explicit-equals-default value here previously made it indistinguishable from "not specified", which silently lost the per-channel-wins cascade for that field (e.g. an explicit Axis(label_overlap="greedy") could be overridden by a conflicting configure_axis(label_overlap=...) even though the per-channel value should always win).

label_format preset names are resolved to their d3-format/strftime strings via :func:ferrum.format_presets.resolve_format_field before serialization (NF-B1); an unrecognized name passes through as an honest raw spec. The resolved format_type fills label_format_type only when the caller did not set it explicitly.