Plots

A result’s figures. PlotConfig describes what is in a panel — its traces and its axis labels, with no styling — and the renderers here draw it. A fit’s own panels and a result decoded from the API therefore produce the same figure.

Reach for these directly only when building panels by hand; a result object plots itself with plot_fit_results(), which picks a renderer by the objective’s type.

Plotting needs the optional plot extra:

pip install ionworks-schema[plot]

Typed plot configs and the matplotlib renderers that draw them.

A PlotConfig declares what is in a panel (its traces and labels), not how it looks; style is decided here by trace label, so the same config renders identically from an in-process fit and from a result decoded over the API. render() dispatches on the objective’s type and falls back to a plain panel grid for an unknown type, so a new server objective cannot break plotting for an older client. Matplotlib is an optional dependency (the plot extra).

class ionworks_schema.plots.PlotConfig(*, x_label: str = '', y_label: str = '', x_range: tuple[float | None, float | None] | None=None, y_range: tuple[float | None, float | None] | None=None, traces: list[PlotTrace] = <factory>)

Bases: BaseModel

One panel: what to draw and how to label it, with no styling.

model_config = {'arbitrary_types_allowed': True}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

x_label: str
y_label: str
x_range: tuple[float | None, float | None] | None

Explicit (min, max) axis bounds; either side may be None to auto-scale.

y_range: tuple[float | None, float | None] | None
traces: list[PlotTrace]
classmethod from_wire(payload: dict) PlotConfig

Build a config from a stored plot payload.

The backend persists each plot in plotly’s vocabulary ({"type", "traces": [{"name", "x", "y"}], "layout": {"xaxis": ...}}); this maps that onto the fields above.

Parameters

payloaddict

One plot as returned by GET /datafits/{id}/plot_data.

Returns

PlotConfig

The equivalent config.

class ionworks_schema.plots.PlotTrace(*, label: str = '', x: Any = None, y: Any = None, color: str | None = None)

Bases: BaseModel

One labelled series in a panel.

model_config = {'arbitrary_types_allowed': True}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

label: str

Legend label. Its first word selects the style (“Data”, “Model”, “Fit”, “Error”).

x: Any

x values. Any array-like matplotlib accepts.

y: Any

y values, as for x.

color: str | None

Overrides the label-derived colour, to distinguish series sharing a role.

ionworks_schema.plots.error_label(variable: str) str

Axis label for a variable’s residual, carrying its unit when it has one.

ionworks_schema.plots.fit_panels(variables: list[str], x_key: str, data: dict, model: dict, *, x_label: str | None = None) list[PlotConfig]

Panels for a fit: measured against fitted per variable, then the residuals.

Residuals come last as a block, so laying the result out in len(variables) columns puts each residual under the curve it came from.

Parameters

variableslist of str

Keys to plot, one panel each. A "Name [unit]" key gives the residual panel its unit.

x_keystr

Key of the independent variable. Taken from model when it carries its own, else shared with data.

datadict

The measurement, keyed by variable.

modeldict

The fitted model’s output, keyed the same way.

x_labelstr, optional

Axis label for the independent variable. Defaults to x_key.

Returns

list of PlotConfig

One config per variable, then one residual config per variable.

ionworks_schema.plots.plot_eis(plots: list[PlotConfig | dict], **kwargs) tuple

Nyquist plot(s) for an EIS objective.

Impedance is plotted with an equal aspect ratio: a distorted Nyquist arc misrepresents the semicircle a reader is judging.

Parameters

plotslist of PlotConfig or dict

The objective’s panels.

Returns

tuple

(fig, axes).

ionworks_schema.plots.plot_panels(plots: list[PlotConfig | dict], *, equal_aspect: bool = False, fig_axes: tuple | None = None, n_cols: int | None = None, share_x: bool = False) tuple

Draw one panel per plot config, in a grid.

Parameters

plotslist of PlotConfig or dict

The panels, in the order they should appear. A dict is coerced — a stored plot payload via PlotConfig.from_wire(), otherwise as PlotConfig fields.

equal_aspectbool, optional

Force a 1:1 data aspect ratio on every panel. Defaults to False.

fig_axestuple, optional

An existing (fig, axes) to draw onto, so several datasets can be overlaid on shared panels. A new figure is created when omitted.

n_colsint, optional

Column count. Defaults to a roughly square grid. Panels fill row by row, so pass it when the order groups panels into columns.

share_xbool, optional

Share the x axis down each column and label only the bottom panel of each. Only meaningful with n_cols, which is what puts panels of the same quantity in one column. Defaults to False.

Returns

tuple

(fig, axes) where axes is a flat list, one entry per panel.

Raises

ValueError

If plots is empty.

ionworks_schema.plots.render(objective_type: str | None, plots: list[PlotConfig | dict], **kwargs) tuple

Draw an objective’s plots with the renderer for its type.

Parameters

objective_typestr or None

The objective’s type discriminator (e.g. "EIS"). An unknown or missing type falls back to a plain panel grid.

plotslist of PlotConfig or dict

The objective’s panels.

Returns

tuple

(fig, axes).

Raises

ValueError

If plots is empty.