Skip to content

API Reference (Plot)

sciwork.plot.Plot(figsize=(9, 6))

Bases: Decor, Drawing, Layout, Ticks

Featureful Matplotlib figure manager with SciWork integrations.

Source code in src/sciwork/plot/base.py
52
53
54
55
56
def __init__(self, figsize: Tuple[float, float] = (9, 6)) -> None:
	self.figsize = figsize
	self.fig, self.ax = plt.subplots(figsize=figsize)
	self._limits = _DataLimits.empty()
	LOG.debug("Initialized Plot with figsize=%s", self.figsize)

__slots__ = () class-attribute instance-attribute

Base

sciwork.plot.base.BasePlot(figsize=(9, 6))

Provide figure lifecycle management and shared helpers.

Source code in src/sciwork/plot/base.py
52
53
54
55
56
def __init__(self, figsize: Tuple[float, float] = (9, 6)) -> None:
	self.figsize = figsize
	self.fig, self.ax = plt.subplots(figsize=figsize)
	self._limits = _DataLimits.empty()
	LOG.debug("Initialized Plot with figsize=%s", self.figsize)

_limits = _DataLimits.empty() instance-attribute

figsize = figsize instance-attribute

_axes_or_default(ax)

Return ax when provided or fall back to the default axes.

Source code in src/sciwork/plot/base.py
59
60
61
62
63
64
65
def _axes_or_default(self, ax: Optional["Axes"]) -> "Axes":
	"""Return ``ax`` when provided or fall back to the default axes."""
	if ax is not None:
		return ax
	if self.ax is None:
		raise RuntimeError("Default axes missing; create a subplot first.")
	return self.ax

_get_axis_limits(axis)

Return cached (min, max) values for axis.

Source code in src/sciwork/plot/base.py
79
80
81
82
def _get_axis_limits(self, axis: Axis) -> Tuple[Optional[float], Optional[float]]:
	"""Return cached ``(min, max)`` values for ``axis``."""
	stored = getattr(self._limits, axis)
	return stored[0], stored[1]

_iter_axes(selector) staticmethod

Yield axis names that match selector.

Source code in src/sciwork/plot/base.py
84
85
86
87
88
89
90
91
@staticmethod
def _iter_axes(selector: AxisSelector) -> Union[Sequence[Literal["x", "y", "both"]], Sequence[Literal["x", "y", "z", "all"]]]:
	"""Yield axis names that match ``selector``."""
	if selector == "both":
		return "x", "y"
	if selector == "all":
		return "x", "y", "z"
	return (selector,)

_update_limits(x, y=None, z=None)

Store min/max boundaries for any axis that receives data.

Source code in src/sciwork/plot/base.py
67
68
69
70
71
72
73
74
75
76
77
def _update_limits(
		self,
		x: Optional[Sequence[float]],
		y: Optional[Sequence[float]] = None,
		z: Optional[Sequence[float]] = None
) -> None:
	"""Store min/max boundaries for any axis that receives data."""
	for axis_name, values in (("x", x), ("y", y), ("z", z)):
		if values is None:
			continue
		self._limits.update(axis=axis_name, values=values)

add_inset(main_ax, *, left, bottom, width, height) staticmethod

Create inset axes anchored to main_ax.

Parameters:

Name Type Description Default
main_ax 'Axes'

The parent axes that will host the inset axes.

required
left float

Relative coordinate in a figure fraction.

required
bottom float

Relative coordinate in a figure fraction.

required
width float

Relative coordinate in a figure fraction.

required
height float

Relative coordinate in a figure fraction.

required

Returns:

Type Description
'Axes'

Newly created inset axes.

Raises:

Type Description
ValueError

If any dimension is negative or exceeds the figure bounds.

Source code in src/sciwork/plot/base.py
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
@staticmethod
def add_inset(
		main_ax: "Axes",
		*,
		left: float,
		bottom: float,
		width: float,
		height: float
) -> "Axes":
	"""
	Create inset axes anchored to ``main_ax``.

	:param main_ax: The parent axes that will host the inset axes.
	:param left: Relative coordinate in a figure fraction.
	:param bottom: Relative coordinate in a figure fraction.
	:param width: Relative coordinate in a figure fraction.
	:param height: Relative coordinate in a figure fraction.
	:return: Newly created inset axes.
	:raises ValueError: If any dimension is negative or exceeds the figure bounds.
	"""
	if min(left, bottom, width, height) < 0:
		raise ValueError("Inset coordinates must be non-negative.")
	if left + width > 1 or bottom + height > 1:
		raise ValueError("Inset extends beyond the parent axes area.")

	return main_ax.inset_axes((left, bottom, width, height))

create_grid_layout(nrows, ncols)

Create a grid of subplots sized to the instance default.

Parameters:

Name Type Description Default
nrows int

Number of rows in the grid.

required
ncols int

Number of columns in the grid.

required

Returns:

Type Description
Tuple['Figure', Sequence[Sequence['Axes']]]

The generated Matplotlib figure and an array-like structure of axes objects for further customization.

Raises:

Type Description
ValueError

If nrows or ncols is less than 1.

Source code in src/sciwork/plot/base.py
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
def create_grid_layout(self, nrows: int, ncols: int) -> Tuple["Figure", Sequence[Sequence["Axes"]]]:
	"""
	Create a grid of subplots sized to the instance default.

	:param nrows: Number of rows in the grid.
	:param ncols: Number of columns in the grid.
	:return: The generated Matplotlib figure and an array-like structure of
		axes objects for further customization.
	:raises ValueError: If ``nrows`` or ``ncols`` is less than ``1``.
	"""
	if nrows < 1 or ncols < 1:
		raise ValueError("Grid dimensions must be positive integers.")

	fig, axes = plt.subplots(nrows, ncols, figsize=self.figsize)
	return fig, axes

save_plot(filename, *, dpi=300, fig_format='.png')

Persist the current figure to disk and return the solved path.

Parameters:

Name Type Description Default
filename str

Base filename or path where the figure should be stored. The file extension is inferred from fig_format when missing.

required
dpi int

Rendering resolution in dots per inch.

300
fig_format str

Output format passed to :meth:matplotlib.figure.Figure.savefig.

'.png'

Returns:

Type Description
str

The filename with the ensured extension.

Raises:

Type Description
ValueError

If dpi is not positive or fig_format is empty.

Source code in src/sciwork/plot/base.py
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
def save_plot(self, filename: str, *, dpi: int = 300, fig_format: str = ".png") -> str:
	"""
	Persist the current figure to disk and return the solved path.

	:param filename: Base filename or path where the figure should be stored. The file
		extension is inferred from ``fig_format`` when missing.
	:param dpi: Rendering resolution in dots per inch.
	:param fig_format: Output format passed to :meth:`matplotlib.figure.Figure.savefig`.
	:return: The filename with the ensured extension.
	:raises ValueError: If ``dpi`` is not positive or ``fig_format`` is empty.
	"""
	if dpi <= 0:
		raise ValueError("dpi must be a positive integer.")
	if not fig_format:
		raise ValueError("fig_format must be a non-empty string.")

	if not filename.endswith(f".{fig_format}"):
		filename += f"{filename}.{fig_format}"
	self.fig.savefig(filename, dpi=dpi, format=fig_format, bbox_inches='tight')
	LOG.info("Saved figure with plot to %s", filename)
	return filename

show_plot() staticmethod

Display the figure using tight layout adjustments.

The method applies :func:matplotlib.pyplot.tight_layout before calling :func:matplotlib.pyplot.show to reduce superfluous margins.

Source code in src/sciwork/plot/base.py
137
138
139
140
141
142
143
144
145
146
@staticmethod
def show_plot() -> None:
	"""
	Display the figure using tight layout adjustments.

	The method applies :func:`matplotlib.pyplot.tight_layout` before
	calling :func:`matplotlib.pyplot.show` to reduce superfluous margins.
	"""
	plt.tight_layout()
	plt.show()

Drawing

sciwork.plot.drawing.Drawing(figsize=(9, 6))

Bases: BasePlot

Collection of drawing primitives used by :class:~sciwork.plot.Plot.

Source code in src/sciwork/plot/base.py
52
53
54
55
56
def __init__(self, figsize: Tuple[float, float] = (9, 6)) -> None:
	self.figsize = figsize
	self.fig, self.ax = plt.subplots(figsize=figsize)
	self._limits = _DataLimits.empty()
	LOG.debug("Initialized Plot with figsize=%s", self.figsize)

draw_horizontal_line(y, *, color='black', linewidth=2.0, linestyle='-', label=None, alpha=1.0, ax=None)

Add a horizontal line across the axes.

Parameters:

Name Type Description Default
y float

Y coordinate where the line should be drawn.

required
color str

Color styling parameter.

'black'
linewidth float

Line width styling parameter.

2.0
linestyle str

Line style styling parameter.

'-'
label Optional[str]

Optional line label.

None
alpha float

Opacity of the line.

1.0
ax Optional['Axes']

Axes to draw on. Defaults to the primary axes.

None

Returns:

Type Description
'Axes'

The axes that contain the new line.

Source code in src/sciwork/plot/drawing.py
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
def draw_horizontal_line(
		self,
		y: float,
		*,
		color: str = "black",
		linewidth: float = 2.0,
		linestyle: str = "-",
		label: Optional[str] = None,
		alpha: float = 1.0,
		ax: Optional["Axes"] = None
) -> "Axes":
	"""
	Add a horizontal line across the axes.

	:param y: Y coordinate where the line should be drawn.
	:param color: Color styling parameter.
	:param linewidth: Line width styling parameter.
	:param linestyle: Line style styling parameter.
	:param label: Optional line label.
	:param alpha: Opacity of the line.
	:param ax: Axes to draw on.
		Defaults to the primary axes.
	:return: The axes that contain the new line.
	"""

	axes = self._axes_or_default(ax)
	axes.axhline(y=y, color=color, linewidth=linewidth, linestyle=linestyle, label=label, alpha=alpha)
	return axes

draw_vertical_line(x, *, color='black', linewidth=2.0, linestyle='-', label=None, alpha=1.0, ax=None)

Add a vertical line across the axes.

Parameters:

Name Type Description Default
x float

X coordinate for the line.

required
color str

Color styling parameter.

'black'
linewidth float

Line width styling parameter.

2.0
linestyle str

Line style styling parameter.

'-'
label Optional[str]

Optional line label.

None
alpha float

Opacity of the line.

1.0
ax Optional['Axes']

Axes to draw on. Defaults to the primary axes.

None

Returns:

Type Description
'Axes'

The axes that contain the new line.

Source code in src/sciwork/plot/drawing.py
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
def draw_vertical_line(
		self,
		x: float,
		*,
		color: str = "black",
		linewidth: float = 2.0,
		linestyle: str = "-",
		label: Optional[str] = None,
		alpha: float = 1.0,
		ax: Optional["Axes"] = None
) -> "Axes":
	"""
	Add a vertical line across the axes.

	:param x: X coordinate for the line.
	:param color: Color styling parameter.
	:param linewidth: Line width styling parameter.
	:param linestyle: Line style styling parameter.
	:param label: Optional line label.
	:param alpha: Opacity of the line.
	:param ax: Axes to draw on.
		Defaults to the primary axes.
	:return: The axes that contain the new line.
	"""

	axes = self._axes_or_default(ax)
	axes.axvline(x=x, color=color, linewidth=linewidth, linestyle=linestyle, label=label, alpha=alpha)
	return axes

plot_1d(data, *, ax=None)

Plot a simple 1D series against its index.

Parameters:

Name Type Description Default
data Sequence[float]

Iterable of numeric values.

required
ax Optional['Axes']

Axes to draw on. Defaults to the primary axes.

None

Returns:

Type Description
'Axes'

The axes that contain the line plot.

Source code in src/sciwork/plot/drawing.py
120
121
122
123
124
125
126
127
128
129
130
131
132
133
def plot_1d(self, data: Sequence[float], *, ax: Optional["Axes"] = None) -> "Axes":
	"""
	Plot a simple 1D series against its index.

	:param data: Iterable of numeric values.
	:param ax: Axes to draw on.
		Defaults to the primary axes.
	:return: The axes that contain the line plot.
	"""

	axes = self._axes_or_default(ax)
	axes.plot(data)
	self._update_limits(range(len(data)), data)
	return axes

plot_2d(x, y, *, plot_type='line', ax=None, color=None, alpha=1.0, label=None, linewidth=2.0, linestyle='-', markersize=20.0, markertype='o', ma_window=5, ma_iterations=1, bar_width=0.8, edgecolor=None, zorder=None)

Render diverse 2D visualizations (line, scatter, moving average, histogram, bar).

Parameters:

Name Type Description Default
x Sequence[float]

X-coordinates of the observations.

required
y Sequence[float]

Y-coordinates of the observations. Must be provided for all built-in plot types.

required
plot_type PlotKind

One of "line", "scatter", "moving_average", "histogram", or "bar".

'line'
ax Optional['Axes']

Axes to draw on. Defaults to the primary axes.

None
color Optional[str]

Color of the data visualization.

None
alpha float

Opacity of the data visualization.

1.0
label Optional[str]

Label for the legend.

None
linewidth float

Line width of the data visualization. Applies to "line" and "moving_average" plot types.

2.0
linestyle str

Line style of the data visualization. Applies to "line" and "moving_average" plot types.

'-'
markersize float

Size of the markers in "scatter" plots.

20.0
markertype str

Type of the markers in "scatter" plots.

'o'
ma_window int

Size of the moving window used in the "moving_average" convolution.

5
ma_iterations int

Iteration count for the "moving_average" convolution.

1
bar_width float

Width of the bars in "bar" and "histogram" plots.

0.8
edgecolor Optional[str]

Edge color of the bars in "bar" and "histogram" plots.

None
zorder Optional[int]

Z-order of the visualization (rendering order).

None

Returns:

Type Description
'Axes'

The axes that contain the visualization.

Raises:

Type Description
ValueError

If required data is missing, or plot_type is unsupported.

Source code in src/sciwork/plot/drawing.py
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
def plot_2d(
		self,
		x: Sequence[float],
		y: Sequence[float],
		*,
		plot_type: PlotKind = "line",
		ax: Optional["Axes"] = None,
		color: Optional[str] = None,
		alpha: float = 1.0,
		label: Optional[str] = None,
		linewidth: float = 2.0,
		linestyle: str = "-",
		markersize: float = 20.0,
		markertype: str = "o",
		ma_window: int = 5,
		ma_iterations: int = 1,
		bar_width: float = 0.8,
		edgecolor: Optional[str] = None,
		zorder: Optional[int] = None
) -> "Axes":
	"""
	Render diverse 2D visualizations (line, scatter, moving average, histogram, bar).

	:param x: X-coordinates of the observations.
	:param y: Y-coordinates of the observations.
		Must be provided for all built-in plot types.
	:param plot_type: One of ``"line"``, ``"scatter"``, ``"moving_average"``, ``"histogram"``, or ``"bar"``.
	:param ax: Axes to draw on.
		Defaults to the primary axes.
	:param color: Color of the data visualization.
	:param alpha: Opacity of the data visualization.
	:param label: Label for the legend.
	:param linewidth: Line width of the data visualization.
		Applies to ``"line"`` and ``"moving_average"`` plot types.
	:param linestyle: Line style of the data visualization.
		Applies to ``"line"`` and ``"moving_average"`` plot types.
	:param markersize: Size of the markers in ``"scatter"`` plots.
	:param markertype: Type of the markers in ``"scatter"`` plots.
	:param ma_window: Size of the moving window used in the ``"moving_average"`` convolution.
	:param ma_iterations: Iteration count for the ``"moving_average"`` convolution.
	:param bar_width: Width of the bars in ``"bar"`` and ``"histogram"`` plots.
	:param edgecolor: Edge color of the bars in ``"bar"`` and ``"histogram"`` plots.
	:param zorder: Z-order of the visualization (rendering order).
	:return: The axes that contain the visualization.
	:raises ValueError: If required data is missing, or ``plot_type`` is unsupported.
	"""

	axes = self._axes_or_default(ax)
	params: Dict[str, Union[float, str]] = {'alpha': alpha, 'zorder': zorder}
	if color is not None:
		params['color'] = color
	if label is not None:
		params['label'] = label

	if plot_type in {"scatter", "line", "moving_average", "histogram", "bar"} and y is None:
		raise ValueError(f"Plot type {plot_type} requires y data.")

	if plot_type == "scatter":
		params.update({"s": markersize, "marker": markertype})
		axes.scatter(x, y, **params)

	elif plot_type == "line":
		params.update({"linewidth": linewidth, "linestyle": linestyle})
		axes.plot(x, y, **params)

	elif plot_type == "moving_average":
		params.update({"linewidth": linewidth, "linestyle": linestyle})
		smoothed = MathStat(y).moving_average(window_size=ma_window, iterations=ma_iterations)
		axes.plot(x, smoothed, **params)

	elif plot_type in {"histogram", "bar"}:
		params.update({"edgecolor": edgecolor})
		axes.bar(x, y, width=bar_width, align='center', **params)
	else:
		raise ValueError(f"Unsupported plot type: {plot_type}.")

	self._update_limits(x, y if y is not None else x)
	axes.relim()
	axes.autoscale_view()
	return axes

plot_3d(x, y, z, *, ax=None)

Create a 3D scatter plot (creates 3D axes if necessary).

Parameters:

Name Type Description Default
x Sequence[float]

X-coordinates of the observations.

required
y Sequence[float]

Y-coordinates of the observations.

required
z Sequence[float]

Z-coordinates of the observations.

required
ax Optional['Axes']

Existing 3D axes. When None, a new subplot is created.

None

Returns:

Type Description
'Axes'

The 3D axes containing the scatter plot.

Raises:

Type Description
ValueError

If the coordinate sequences differ in length.

Source code in src/sciwork/plot/drawing.py
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
def plot_3d(
		self,
		x: Sequence[float],
		y: Sequence[float],
		z: Sequence[float],
		*,
		ax: Optional["Axes"] = None
) -> "Axes":
	"""
	Create a 3D scatter plot (creates 3D axes if necessary).

	:param x: X-coordinates of the observations.
	:param y: Y-coordinates of the observations.
	:param z: Z-coordinates of the observations.
	:param ax: Existing 3D axes.
		When ``None``, a new subplot is created.
	:return: The 3D axes containing the scatter plot.
	:raises ValueError: If the coordinate sequences differ in length.
	"""
	if not (len(x) == len(y) == len(z)):
		raise ValueError(f"x, y, and z must share identical lengths: x={len(x)}, y={len(y)}, z={len(z)}")

	axes = ax
	if axes is None:
		axes = self.fig.add_subplot(111, projection="3d")
	axes.scatter(x, y, z)
	self._update_limits(x, y, z)
	return axes

plot_std_deviation(x, y, yerr, *, color='gray', alpha=0.6, linewidth=2.0, ax=None)

Plot error bars representing a standard deviation envelope.

Parameters:

Name Type Description Default
x Sequence[float]

X coordinates for the error bars.

required
y Sequence[float]

Y coordinates for the error bars.

required
yerr Sequence[float]

Symmetric deviations for each point; forwarded to :func:matplotlib.axes.Axes.errorbar.

required
color str

Base color of the error bars.

'gray'
alpha float

Opacity of the error bars.

0.6
linewidth float

Thickness of the error lines.

2.0
ax Optional['Axes']

Axes to draw on. Defaults to the primary axes.

None

Returns:

Type Description
'Axes'

The axes that contain the error bars.

Raises:

Type Description
ValueError

If the input sequences differ in length.

Source code in src/sciwork/plot/drawing.py
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
def plot_std_deviation(
		self,
		x: Sequence[float],
		y: Sequence[float],
		yerr: Sequence[float],
		*,
		color: str = "gray",
		alpha: float = 0.6,
		linewidth: float = 2.0,
		ax: Optional["Axes"] = None
) -> "Axes":
	"""
	Plot error bars representing a standard deviation envelope.

	:param x: X coordinates for the error bars.
	:param y: Y coordinates for the error bars.
	:param yerr: Symmetric deviations for each point; forwarded to
		:func:`matplotlib.axes.Axes.errorbar`.
	:param color: Base color of the error bars.
	:param alpha: Opacity of the error bars.
	:param linewidth: Thickness of the error lines.
	:param ax: Axes to draw on. Defaults to the primary axes.
	:return: The axes that contain the error bars.
	:raises ValueError: If the input sequences differ in length.
	"""
	if not (len(x) == len(y) == len(yerr)):
		raise ValueError(f"x, y, and yerr must share identical lengths: "
		                 f"x={len(x)}, y={len(y)}, yerr={len(yerr)}")

	axes = self._axes_or_default(ax)
	axes.errorbar(
		x,
		y,
		yerr=yerr,
		fmt="",
		color=color,
		alpha=alpha,
		ecolor=color,
		capsize=4,
		linewidth=0,
		elinewidth=linewidth
	)
	self._update_limits(x, y)
	return axes

Layout

sciwork.plot.layout.Layout(figsize=(9, 6))

Bases: BasePlot

Methods adjusting axis labels, limits, and spine positions.

Source code in src/sciwork/plot/base.py
52
53
54
55
56
def __init__(self, figsize: Tuple[float, float] = (9, 6)) -> None:
	self.figsize = figsize
	self.fig, self.ax = plt.subplots(figsize=figsize)
	self._limits = _DataLimits.empty()
	LOG.debug("Initialized Plot with figsize=%s", self.figsize)

_set_spine_position(axes, spine, position) staticmethod

Position a spine against a data coordinate without type warnings.

Source code in src/sciwork/plot/layout.py
20
21
22
23
24
25
@staticmethod
def _set_spine_position(axes: "Axes", spine: str, position: float) -> None:
	"""Position a spine against a data coordinate without type warnings."""
	spine_obj = axes.spines[spine]
	set_position = getattr(spine_obj, "set_position")
	set_position(("data", position))

set_axes_limits(*, ax=None, xmin=None, xmax=None, ymin=None, ymax=None, zmin=None, zmax=None)

Set numeric boundaries for each axis.

Parameters:

Name Type Description Default
ax Optional['Axes']

Axes to update; defaults to the primary axes.

None
xmin Optional[Union[float, str]]

X-axis minimum.

None
xmax Optional[Union[float, str]]

X-axis maximum.

None
ymin Optional[Union[float, str]]

Y-axis minimum.

None
ymax Optional[Union[float, str]]

Y-axis maximum.

None
zmin Optional[Union[float, str]]

Z-axis minimum.

None
zmax Optional[Union[float, str]]

Z-axis maximum.

None

Returns:

Type Description
'Axes'

The axes with updated limits.

Raises:

Type Description
ValueError

When "data" is specified but no limits are available.

AttributeError

If z-axis limits are requested on a 2D axes.

Source code in src/sciwork/plot/layout.py
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
def set_axes_limits(
		self,
		*,
		ax: Optional["Axes"] = None,
		xmin: Optional[Union[float, str]] = None,
		xmax: Optional[Union[float, str]] = None,
		ymin: Optional[Union[float, str]] = None,
		ymax: Optional[Union[float, str]] = None,
		zmin: Optional[Union[float, str]] = None,
		zmax: Optional[Union[float, str]] = None
) -> "Axes":
	"""
	Set numeric boundaries for each axis.

	:param ax: Axes to update; defaults to the primary axes.
	:param xmin: X-axis minimum.
	:param xmax: X-axis maximum.
	:param ymin: Y-axis minimum.
	:param ymax: Y-axis maximum.
	:param zmin: Z-axis minimum.
	:param zmax: Z-axis maximum.
	:return: The axes with updated limits.
	:raises ValueError: When ``"data"`` is specified but no limits are available.
	:raises AttributeError: If z-axis limits are requested on a 2D axes.
	"""

	axes = self._axes_or_default(ax)

	def resolve(
			axis: Axis,
			value: Optional[Union[float, str]],
			extreme: Literal["min", "max"],
			current: Tuple[float, float]
	) -> float:
		if value == "data":
			limits = self._get_axis_limits(axis)
			selected = limits[0] if extreme == "min" else limits[1]
			if selected is None:
				raise ValueError(f"No stored data limits for axis {axis!r}.")
			return selected
		return current[0 if extreme == "min" else 1] if value is None else float(value)

	axes.set_xlim(
		left=resolve("x", xmin, "min", axes.get_xlim()),
		right=resolve("x", xmax, "max", axes.get_xlim())
	)
	axes.set_ylim(
		bottom=resolve("y", ymin, "min", axes.get_ylim()),
		top=resolve("y", ymax, "max", axes.get_ylim())
	)
	if hasattr(axes, "set_zlim"):
		axes3d = cast("Axes3D", axes)
		axes3d.set_zlim(
			bottom=resolve("z", zmin, "min", axes3d.get_zlim()),
			top=resolve("z", zmax, "max", axes3d.get_zlim())
		)
	return axes

set_axes_linewidth(linewidth=1.0, *, ax=None)

Update the thickness of the axes' spines.

Parameters:

Name Type Description Default
linewidth float

Width applied to the axes' spines.

1.0
ax Optional['Axes']

Target axes to modify, defaults to the primary axes.

None

Returns:

Type Description
'Axes'

The axes after linewidth updates.

Source code in src/sciwork/plot/layout.py
106
107
108
109
110
111
112
113
114
115
116
117
118
def set_axes_linewidth(self, linewidth: float = 1.0, *, ax: Optional["Axes"] = None) -> "Axes":
	"""
	Update the thickness of the axes' spines.

	:param linewidth: Width applied to the axes' spines.
	:param ax: Target axes to modify, defaults to the primary axes.
	:return: The axes after linewidth updates.
	"""

	axes = self._axes_or_default(ax)
	for spine in axes.spines.values():
		spine.set_linewidth(linewidth)
	return axes

set_axis_label_size(size=12.0, *, axis='both', ax=None)

Change the font size for one or more axis labels.

Parameters:

Name Type Description Default
size float

Font size to the selected labels.

12.0
axis AxisSelector

Selector describing which axes should change ("x", "y", "z", "both", or "all").

'both'
ax Optional['Axes']

Axes to modify; defaults to the instance axes.

None

Returns:

Type Description
'Axes'

The axes with resized labels.

Source code in src/sciwork/plot/layout.py
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
def set_axis_label_size(
		self,
		size: float = 12.0,
		*,
		axis: AxisSelector = "both",
		ax: Optional["Axes"] = None
) -> "Axes":
	"""
	Change the font size for one or more axis labels.

	:param size: Font size to the selected labels.
	:param axis: Selector describing which axes should change ("x", "y", "z",
		"both", or "all").
	:param ax: Axes to modify; defaults to the instance axes.
	:return: The axes with resized labels.
	"""

	axes = self._axes_or_default(ax)
	for target in self._iter_axes(axis):
		label = getattr(axes, f"{target}axis").get_label()
		label.set_size(size)
	return axes

set_axis_position(*, axis='y', position=0.0, ax=None)

Reposition a spine to a data coordinate on the opposing axis.

Parameters:

Name Type Description Default
axis Literal['x', 'y']

Which axis to reposition ("x" or "y").

'y'
position float

The coordinate on the opposite axis where the spine should cross.

0.0
ax Optional['Axes']

Axes to update. Defaults to the plot's primary axes.

None

Returns:

Type Description
'Axes'

The axes with updated spine placement.

Raises:

Type Description
ValueError

If axis is not "x" or "y".

Source code in src/sciwork/plot/layout.py
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
def set_axis_position(
		self,
		*,
		axis: Literal["x", "y"] = "y",
		position: float = 0.0,
		ax: Optional["Axes"] = None
) -> "Axes":
	"""
	Reposition a spine to a data coordinate on the opposing axis.

	:param axis: Which axis to reposition ("x" or "y").
	:param position: The coordinate on the opposite axis where the spine should cross.
	:param ax: Axes to update.
		Defaults to the plot's primary axes.
	:return: The axes with updated spine placement.
	:raises ValueError: If ``axis`` is not "x" or "y".
	"""

	axes = self._axes_or_default(ax)
	if axis == "x":
		self._set_spine_position(axes, "bottom", position)
		axes.spines['top'].set_visible(False)
		axes.spines['right'].set_visible(False)
	elif axis == "y":
		self._set_spine_position(axes, "left", position)
		axes.spines['right'].set_visible(False)
		axes.spines['top'].set_visible(False)
	else:
		raise ValueError(f"axis must be 'x' or 'y'; got '{axis}'.")
	self.fig.canvas.draw_idle()
	return axes

set_plot_labels(*, ax=None, title=None, xlabel=None, ylabel=None, zlabel=None, xshift=0.0, yshift=0.0, zshift=0.0, xt=0.0, yt=0.0)

Assign axis labels to each axis and optionally shift their positions.

Parameters:

Name Type Description Default
ax Optional['Axes']

Axes instance to modify. When None the default plot axes are used.

None
title Optional[str]

The plot title.

None
xlabel Optional[str]

X-label of the plot.

None
ylabel Optional[str]

Y-label of the plot.

None
zlabel Optional[str]

Z-label of the plot.

None
xshift float

Normalized horizontal shift of X-label.

0.0
yshift float

Normalized vertical shift of Y-label.

0.0
zshift float

Normalized shift along the Z-axis.

0.0
xt float

Additional vertical shift for X-label.

0.0
yt float

Additional horizontal shift for Y-label.

0.0

Returns:

Type Description
'Axes'

The axes that received the updates.

Raises:

Type Description
AttributeError

If zlabel is provided for 2D axes without a z-axis.

Source code in src/sciwork/plot/layout.py
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
def set_plot_labels(
		self,
		*,
		ax: Optional["Axes"] = None,
		title: Optional[str] = None,
		xlabel: Optional[str] = None,
		ylabel: Optional[str] = None,
		zlabel: Optional[str] = None,
		xshift: float = 0.0,
		yshift: float = 0.0,
		zshift: float = 0.0,
		xt: float = 0.0,
		yt: float = 0.0
) -> "Axes":
	"""
	Assign axis labels to each axis and optionally shift their positions.

	:param ax: Axes instance to modify.
		When ``None`` the default plot axes are used.
	:param title: The plot title.
	:param xlabel: X-label of the plot.
	:param ylabel: Y-label of the plot.
	:param zlabel: Z-label of the plot.
	:param xshift: Normalized horizontal shift of X-label.
	:param yshift: Normalized vertical shift of Y-label.
	:param zshift: Normalized shift along the Z-axis.
	:param xt: Additional vertical shift for X-label.
	:param yt: Additional horizontal shift for Y-label.
	:return: The axes that received the updates.
	:raises AttributeError: If ``zlabel`` is provided for 2D axes without a z-axis.
	"""

	axes = self._axes_or_default(ax)

	if title:
		axes.set_title(title)
	if xlabel:
		axes.set_xlabel(xlabel)
		transform = mpl.transforms.Scaledtranslation(xshift, yt, self.fig.dpi_scale_trans)
		axes.xaxis.get_label().set_transform(axes.xaxis.get_label().get_transform() + transform)
	if ylabel:
		axes.set_ylabel(ylabel)
		transform = mpl.transforms.Scaledtranslation(xt, yshift, self.fig.dpi_scale_trans)
		axes.yaxis.get_label().set_transform(axes.yaxis.get_label().get_transform() + transform)
	if zlabel:
		if not hasattr(axes, "zaxis"):
			raise AttributeError("zlabel requires a 3D axes.")
		axes3d = cast("Axes3D", axes)
		axes3d.set_zlabel(zlabel)
		transform = mpl.transforms.Scaledtranslation(0, zshift, self.fig.dpi_scale_trans)
		axes3d.zaxis.get_label().set_transform(axes3d.zaxis.get_label().get_transform() + transform)

	self.fig.canvas.draw_idle()
	return axes

set_title_size(size=14.0, *, ax=None)

Resize the title font.

Parameters:

Name Type Description Default
size float

Target font size in points.

14.0
ax Optional['Axes']

Axes containing the title. Default to the primary axes.

None

Returns:

Type Description
'Axes'

The axes with updated title size.

Source code in src/sciwork/plot/layout.py
178
179
180
181
182
183
184
185
186
187
188
189
190
def set_title_size(self, size: float = 14.0, *, ax: Optional["Axes"] = None) -> "Axes":
	"""
	Resize the title font.

	:param size: Target font size in points.
	:param ax: Axes containing the title.
		Default to the primary axes.
	:return: The axes with updated title size.
	"""

	axes = self._axes_or_default(ax)
	axes.title.set_fontsize(size)
	return axes

toggle_dark_mode(dark_mode=True, *, ax=None)

Switch between light and dark color schemes.

Parameters:

Name Type Description Default
dark_mode bool

When `True`` enable a dark background with light foreground colors; otherwise revert to light mode.

True
ax Optional['Axes']

Axes to update; defaults to the primary axes.

None

Returns:

Type Description
'Axes'

The axes after color adjustments.

Source code in src/sciwork/plot/layout.py
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
def toggle_dark_mode(self, dark_mode: bool = True, *, ax: Optional["Axes"] = None) -> "Axes":
	"""
	Switch between light and dark color schemes.

	:param dark_mode: When `True`` enable a dark background with light foreground
		colors; otherwise revert to light mode.
	:param ax: Axes to update; defaults to the primary axes.
	:return: The axes after color adjustments.
	"""

	axes = self._axes_or_default(ax)
	background_color, element_color = ("black", "white") if dark_mode else ("white", "black")
	axes.set_facecolor(background_color)
	axes.figure.set_facecolor(background_color)
	axes.tick_params(colors=element_color, which='both')
	for spine in axes.spines.values():
		spine.set_edgecolor(element_color)
	axes.xaxis.label.set_color(element_color)
	axes.yaxis.label.set_color(element_color)
	if hasattr(axes, "zaxis"):
		cast("Axes3D", axes).zaxis.label.set_color(element_color)
	axes.title.set_color(element_color)
	return axes

Decor

sciwork.plot.decor.Decor(figsize=(9, 6))

Bases: BasePlot

Helpers for grid lines, legends, and textual annotations.

Source code in src/sciwork/plot/base.py
52
53
54
55
56
def __init__(self, figsize: Tuple[float, float] = (9, 6)) -> None:
	self.figsize = figsize
	self.fig, self.ax = plt.subplots(figsize=figsize)
	self._limits = _DataLimits.empty()
	LOG.debug("Initialized Plot with figsize=%s", self.figsize)

custom_text(text, *, position='upper right', fontcolor='black', fontsize=10.0, style=None, ha='center', va='center', ax=None)

Insert arbitrary text in axes-relative coordinates.

Parameters:

Name Type Description Default
text str

String rendered inside the axes.

required
position Union[str, Tuple[float, float]]

Named location or explicit (x,y) pair in axes coordinates.

'upper right'
fontcolor str

Color of the text.

'black'
fontsize float

Text size in points.

10.0
style Optional[str]

Case-insensitive keywords such as "bold" or "italic" to adjust style.

None
ha str

Horizontal alignment keyword passed to Matplotlib.

'center'
va str

Vertical alignment keyword passed to Matplotlib.

'center'
ax Optional['Axes']

Axes receiving the text. Defaults to the primary axes.

None

Returns:

Type Description
'Axes'

The axes containing the annotation.

Source code in src/sciwork/plot/decor.py
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
def custom_text(
		self,
		text: str,
		*,
		position: Union[str, Tuple[float, float]] = "upper right",
		fontcolor: str = "black",
		fontsize: float = 10.0,
		style: Optional[str] = None,
		ha: str = "center",
		va: str = "center",
		ax: Optional["Axes"] = None,
) -> "Axes":
	"""
	Insert arbitrary text in axes-relative coordinates.

	:param text: String rendered inside the axes.
	:param position: Named location or explicit ``(x,y)`` pair in axes coordinates.
	:param fontcolor: Color of the text.
	:param fontsize: Text size in points.
	:param style: Case-insensitive keywords such as ``"bold"`` or ``"italic"`` to
		adjust style.
	:param ha: Horizontal alignment keyword passed to Matplotlib.
	:param va: Vertical alignment keyword passed to Matplotlib.
	:param ax: Axes receiving the text.
		Defaults to the primary axes.
	:return: The axes containing the annotation.
	"""

	axes = self._axes_or_default(ax)
	fontdict = {'fontsize': fontsize, 'color': fontcolor}
	if style:
		lowered = style.lower()
		if "bold" in lowered:
			fontdict['weight'] = "bold"
		if "italic" in lowered:
			fontdict['style'] = "italic"
	if isinstance(position, tuple):
		x, y = position
	else:
		mapping = {
			"upper right": (0.9, 0.9),
			"upper left": (0.1, 0.9),
			"lower left": (0.1, 0.1),
			"lower right": (0.9, 0.1),
			"center": (0.5, 0.5),
			"center left": (0.1, 0.5),
			"center right": (0.9, 0.5),
			"lower center": (0.5, 0.1),
			"upper center": (0.5, 0.9),
		}
		x, y = mapping.get(position, (0.5, 0.5))
	axes.text(x, y, text, transform=axes.transAxes, fontdict=fontdict, ha=ha, va=va)
	return axes

set_grid(*, color='grey', alpha=0.5, which='both', linewidth=1.0, linestyle='--', axis='both', ax=None)

Enable grid lines with custom styling.

Parameters:

Name Type Description Default
color str

Grid line color.

'grey'
alpha float

Opacity applied to the grid lines.

0.5
which TickType

Whether to align grid lines with major ticks, minor ticks, or both.

'both'
linewidth float

Line width for the grid.

1.0
linestyle str

Matplotlib line style string such as "--" or ":".

'--'
axis str

Select "x", "y", or "both" axes for the grid.

'both'
ax Optional['Axes']

Axes to update; defaults to the primary axes.

None

Returns:

Type Description
'Axes'

The axes with the applied grid styling.

Raises:

Type Description
ValueError

If axis is not one of "x", "y", or "both".

Source code in src/sciwork/plot/decor.py
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
def set_grid(
		self,
		*,
		color: str = "grey",
		alpha: float = 0.5,
		which: TickType = "both",
		linewidth: float = 1.0,
		linestyle: str = "--",
		axis: str = "both",
		ax: Optional["Axes"] = None,
) -> "Axes":
	"""
	Enable grid lines with custom styling.

	:param color: Grid line color.
	:param alpha: Opacity applied to the grid lines.
	:param which: Whether to align grid lines with major ticks, minor ticks, or both.
	:param linewidth: Line width for the grid.
	:param linestyle: Matplotlib line style string such as ``"--"`` or ``":"``.
	:param axis: Select ``"x"``, ``"y"``, or ``"both"`` axes for the grid.
	:param ax: Axes to update; defaults to the primary axes.
	:return: The axes with the applied grid styling.
	:raises ValueError: If ``axis`` is not one of ``"x"``, ``"y"``, or ``"both"``.
	"""

	if axis not in {"x", "y", "both"}:
		raise ValueError(f"axis must be 'x', 'y', or 'both'; got '{axis}'.")

	axes = self._axes_or_default(ax)
	axes.grid(True, which=which, axis=axis, color=color, alpha=alpha, linestyle=linestyle, linewidth=linewidth)
	return axes

set_legend(*, position='best', alpha=1.0, fontsize=10.0, fontcolor='black', order=None, exclude_labels=None, ax=None)

Display a legend with additional formatting controls.

Parameters:

Name Type Description Default
position Union[str, Tuple[float, float]]

Legend location key or explicit axes-relative coordinates.

'best'
alpha float

Transparency of the legend background.

1.0
fontsize float

Size of the legend text.

10.0
fontcolor str

Color that is applied to each label.

'black'
order Optional[Sequence[int]]

Optional reordering indices for legend entries.

None
exclude_labels Optional[Sequence[str]]

Iterable of labels to omit from the legend.

None
ax Optional['Axes']

Axes to query for handles. Defaults to the primary axes.

None

Returns:

Type Description
Optional['Axes']

The axes when a legend is created, otherwise None if no handles are available or all entries were filtered out.

Source code in src/sciwork/plot/decor.py
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
def set_legend(
		self,
		*,
		position: Union[str, Tuple[float, float]] = "best",
		alpha: float = 1.0,
		fontsize: float = 10.0,
		fontcolor: str = "black",
		order: Optional[Sequence[int]] = None,
		exclude_labels: Optional[Sequence[str]] = None,
		ax: Optional["Axes"] = None,
) -> Optional["Axes"]:
	"""
	Display a legend with additional formatting controls.

	:param position: Legend location key or explicit axes-relative coordinates.
	:param alpha: Transparency of the legend background.
	:param fontsize: Size of the legend text.
	:param fontcolor: Color that is applied to each label.
	:param order: Optional reordering indices for legend entries.
	:param exclude_labels: Iterable of labels to omit from the legend.
	:param ax: Axes to query for handles.
		Defaults to the primary axes.
	:return: The axes when a legend is created, otherwise ``None`` if no
		handles are available or all entries were filtered out.
	"""

	axes = self._axes_or_default(ax)
	handles, labels = axes.get_legend_handles_labels()

	if order is not None:
		handles = [handles[idx] for idx in order if idx < len(handles)]
		labels = [labels[idx] for idx in order if idx < len(labels)]
	if exclude_labels:
		filtered = [(h, l) for h, l in zip(handles, labels) if l not in exclude_labels]
		if not filtered:
			LOG.warning("Legend request ignored: no labeled artists present.")
			return None
	if not handles:
		LOG.warning("Legend request ignored: no labeled artists present.")
		return None
	legend = axes.legend(handles, labels, loc=position, framealpha=alpha, fontsize=fontsize)
	for text in legend.get_texts():
		text.set_color(fontcolor)
	return axes

Ticks

sciwork.plot.ticks.Ticks(figsize=(9, 6))

Bases: BasePlot

Operations for tick appearance and axis scaling.

Source code in src/sciwork/plot/base.py
52
53
54
55
56
def __init__(self, figsize: Tuple[float, float] = (9, 6)) -> None:
	self.figsize = figsize
	self.fig, self.ax = plt.subplots(figsize=figsize)
	self._limits = _DataLimits.empty()
	LOG.debug("Initialized Plot with figsize=%s", self.figsize)

reverse_axis(*, reverse_x=False, reverse_y=False, reverse_z=False, ax=None)

Invert axis directions.

Parameters:

Name Type Description Default
reverse_x bool

Flag to reverse the X axis.

False
reverse_y bool

Flag to reverse the Y axis.

False
reverse_z bool

Flag to reverse the Z axis.

False
ax Optional['Axes']

Axes to modify; defaults to the instance axes.

None

Returns:

Type Description
'Axes'

The axes with updated orientation.

Source code in src/sciwork/plot/ticks.py
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
def reverse_axis(
		self,
		*,
		reverse_x: bool = False,
		reverse_y: bool = False,
		reverse_z: bool = False,
		ax: Optional["Axes"] = None
) -> "Axes":
	"""
	Invert axis directions.

	:param reverse_x: Flag to reverse the X axis.
	:param reverse_y: Flag to reverse the Y axis.
	:param reverse_z: Flag to reverse the Z axis.
	:param ax: Axes to modify; defaults to the instance axes.
	:return: The axes with updated orientation.
	"""

	axes = self._axes_or_default(ax)
	if reverse_x:
		current = axes.get_xlim()
		axes.set_xlim(left=current[1], right=current[0])
	if reverse_y:
		current = axes.get_ylim()
		axes.set_ylim(bottom=current[1], top=current[0])
	if reverse_z and hasattr(axes, "set_zlim"):
		axes3d = cast("Axes3D", axes)
		current = axes3d.get_zlim()
		axes3d.set_zlim(bottom=current[1], top=current[0])
	return axes

scale_axis_labels(scale_factor=None, *, method='simple', axis='x', is_log_scale=False, ax=None)

Scale tick labels either by multiplication or orders of magnitude.

Parameters:

Name Type Description Default
scale_factor Optional[float]

Scaling factor. For method="order", it represents the exponent.

None
method Literal['simple', 'order']

Choose "simple" for direct multiplication or "order" to shift orders of magnitude.

'simple'
axis Axis

Axis whose labels should be modified.

'x'
is_log_scale bool

Set to True when the axis uses logarithmic scaling to produce exponent-formatted labels.

False
ax Optional['Axes']

Axes to modify; defaults to the instance axes.

None

Returns:

Type Description
'Axes'

The axes with scaled labels.

Raises:

Type Description
ValueError

If method is invalid or the multiplier is not positive for logarithmic axes.

Source code in src/sciwork/plot/ticks.py
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
def scale_axis_labels(
		self,
		scale_factor: Optional[float] = None,
		*,
		method: Literal["simple", "order"] = "simple",
		axis: Axis = "x",
		is_log_scale: bool = False,
		ax: Optional["Axes"] = None
) -> "Axes":
	"""
	Scale tick labels either by multiplication or orders of magnitude.

	:param scale_factor: Scaling factor.
		For ``method="order"``, it represents the exponent.
	:param method: Choose ``"simple"`` for direct multiplication or ``"order"`` to
		shift orders of magnitude.
	:param axis: Axis whose labels should be modified.
	:param is_log_scale: Set to ``True`` when the axis uses logarithmic scaling to produce
		exponent-formatted labels.
	:param ax: Axes to modify; defaults to the instance axes.
	:return: The axes with scaled labels.
	:raises ValueError: If ``method`` is invalid or the multiplier is not positive for
		logarithmic axes.
	"""

	axes = self._axes_or_default(ax)
	if scale_factor is None:
		scale_factor = 0.0 if method == "order" else 1.0
	if method not in {"simple", "order"}:
		raise ValueError(f"method must be 'simple' or 'order'; got '{method}'.")

	multiplier = (10 ** scale_factor) if method == "order" else scale_factor

	if is_log_scale and multiplier <= 0:
		raise ValueError("Logarithmic scaling requires a positive multiplier.")

	def formatter(value: float, _pos: int) -> str:
		if is_log_scale:
			if value <= 0:
				return "0"
			exponent = np.log10(value) + np.log10(multiplier)
			if float(exponent).is_integer():
				return rf"$10^{{{int(round(exponent))}}}$"
			return rf"$10^{{{exponent:.2f}}}$"
		return f"{value * multiplier:g}"

	getattr(axes, f"{axis}axis").set_major_formatter(mpl.ticker.FuncFormatter(formatter))
	self.fig.canvas.draw_idle()
	return axes

set_custom_tick_labels(tick_labels, *, axis='x', ax=None)

Assign textual labels to currently visible ticks.

Parameters:

Name Type Description Default
tick_labels Sequence[str]

Strings representing the replacement tick labels.

required
axis Axis

Axis whose ticks should change.

'x'
ax Optional['Axes']

Axes to modify; defaults to the instance axes.

None

Returns:

Type Description
'Axes'

The axes with updated labels.

Raises:

Type Description
ValueError

If the number of labels does not match the visible tick count.

Source code in src/sciwork/plot/ticks.py
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
def set_custom_tick_labels(
		self,
		tick_labels: Sequence[str],
		*,
		axis: Axis = "x",
		ax: Optional["Axes"] = None
) -> "Axes":
	"""
	Assign textual labels to currently visible ticks.

	:param tick_labels: Strings representing the replacement tick labels.
	:param axis: Axis whose ticks should change.
	:param ax: Axes to modify; defaults to the instance axes.
	:return: The axes with updated labels.
	:raises ValueError: If the number of labels does not match the visible tick count.
	"""

	axes = self._axes_or_default(ax)
	ticks = getattr(axes, f"get_{axis}ticks")()
	limits = getattr(axes, f"get_{axis}lim")()
	visible_ticks = [tick for tick in ticks if limits[0] <= tick <= limits[1]]
	if len(tick_labels) != len(visible_ticks):
		raise ValueError(
			f"Number of tick labels ({len(tick_labels)}) does not match visible ticks ({len(visible_ticks)})."
		)
	getattr(axes, f"set_{axis}tick")(visible_ticks)
	getattr(axes, f"{axis}axis").set_ticklabels(tick_labels)
	self.fig.canvas.draw_idle()
	return axes

set_custom_ticks(tick_values, *, axis='x', ax=None)

Apply explicit tick positions for the given axis.

Parameters:

Name Type Description Default
tick_values Sequence[float]

Iterable of numeric positions for ticks.

required
axis Axis

Axis that receives the ticks ("x", "y", or "z").

'x'
ax Optional['Axes']

Axes to modify; defaults to the instance axes.

None

Returns:

Type Description
'Axes'

The axes with the custom tick positions.

Source code in src/sciwork/plot/ticks.py
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
def set_custom_ticks(
		self,
		tick_values: Sequence[float],
		*,
		axis: Axis = "x",
		ax: Optional["Axes"] = None
) -> "Axes":
	"""
	Apply explicit tick positions for the given axis.

	:param tick_values: Iterable of numeric positions for ticks.
	:param axis: Axis that receives the ticks (``"x"``, ``"y"``, or ``"z"``).
	:param ax: Axes to modify; defaults to the instance axes.
	:return: The axes with the custom tick positions.
	"""

	axes = self._axes_or_default(ax)
	getattr(axes, f"set_{axis}ticks")(tick_values)
	formatter = (
		mpl.ticker.LogFormatter()
		if getattr(axes, f"get_{axis}scale")() == "log"
		else mpl.ticker.ScalarFormatter()
	)
	getattr(axes, f"{axis}axis").set_major_formatter(formatter)
	return axes

set_log_scale(*, log_x=False, log_y=False, log_z=False, ax=None)

Switch axes to a logarithmic scale if requested.

Parameters:

Name Type Description Default
log_x bool

If True, X axis is set to logarithmic.

False
log_y bool

If True, Y axis is set to logarithmic.

False
log_z bool

If True, Z axis is set to logarithmic.

False
ax Optional['Axes']

Axes to modify; defaults to the instance axes.

None

Returns:

Type Description
'Axes'

The axes with updated scale configuration.

Source code in src/sciwork/plot/ticks.py
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
def set_log_scale(
		self,
		*,
		log_x: bool = False,
		log_y: bool = False,
		log_z: bool = False,
		ax: Optional["Axes"] = None
) -> "Axes":
	"""
	Switch axes to a logarithmic scale if requested.

	:param log_x: If ``True``, X axis is set to logarithmic.
	:param log_y: If ``True``, Y axis is set to logarithmic.
	:param log_z: If ``True``, Z axis is set to logarithmic.
	:param ax: Axes to modify; defaults to the instance axes.
	:return: The axes with updated scale configuration.
	"""

	axes = self._axes_or_default(ax)
	if log_x:
		axes.set_xscale("log")
	if log_y:
		axes.set_yscale("log")
	if log_z and hasattr(axes, "set_zscale"):
		cast("Axes3D", axes).set_zscale("log")
	return axes

set_minor_ticks(num_minor_ticks=1, *, axis='both', ax=None)

Configure additional minor ticks for linear or logarithmic axes.

Parameters:

Name Type Description Default
num_minor_ticks int

Number of subdivisions between major ticks (>=1).

1
axis AxisSelector

Selector that describes which axes to adjust.

'both'
ax Optional['Axes']

Axes to modify; defaults to the instance axes.

None

Returns:

Type Description
'Axes'

The axes with new minor locators.

Raises:

Type Description
ValueError

If num_minor_ticks is less than 1.

Source code in src/sciwork/plot/ticks.py
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
def set_minor_ticks(
		self,
		num_minor_ticks: int = 1,
		*,
		axis: AxisSelector = "both",
		ax: Optional["Axes"] = None
) -> "Axes":
	"""
	Configure additional minor ticks for linear or logarithmic axes.

	:param num_minor_ticks: Number of subdivisions between major ticks (``>=1``).
	:param axis: Selector that describes which axes to adjust.
	:param ax: Axes to modify; defaults to the instance axes.
	:return: The axes with new minor locators.
	:raises ValueError: If ``num_minor_ticks`` is less than ``1``.
	"""

	if num_minor_ticks < 1:
		raise ValueError(f"num_minor_ticks must be >= 1; got {num_minor_ticks}.")

	axes = self._axes_or_default(ax)
	for target in self._iter_axes(axis):
		axis_obj = getattr(axes, f"{target}axis")
		if axis_obj.get_scale() == "log":
			subs = np.linspace(1, 10, num_minor_ticks + 1, endpoint=True)[1:]
			locator = mpl.ticker.LogLocator(base=10, subs=subs)
		else:
			locator = mpl.ticker.AutoMinorLocator(num_minor_ticks + 1)
		axis_obj.set_minor_locator(locator)
	return axes

set_tick_invisible(*, axis='both', ax=None)

Hide ticks and tick labels on the requested axes.

Parameters:

Name Type Description Default
axis AxisSelector

Selector describing which axes to hide.

'both'
ax Optional['Axes']

Axes to modify; defaults to the instance axes.

None

Returns:

Type Description
'Axes'

The axes with disabled ticks.

Source code in src/sciwork/plot/ticks.py
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
def set_tick_invisible(self, *, axis: AxisSelector = "both", ax: Optional["Axes"] = None) -> "Axes":
	"""
	Hide ticks and tick labels on the requested axes.

	:param axis: Selector describing which axes to hide.
	:param ax: Axes to modify;
		defaults to the instance axes.
	:return: The axes with disabled ticks.
	"""

	axes = self._axes_or_default(ax)
	for target in self._iter_axes(axis):
		params = {"axis": target, "which": "both", "length": 0}
		if target == "x":
			params.update({"labelbottom": False, "labeltop": False})
		elif target == "y":
			params.update({"labelleft": False, "labelright": False})
		else:
			params.update({"labelbottom": False})
		axes.tick_params(**params)
	return axes

set_tick_label_size(size=10.0, *, axis='both', ax=None)

Resize tick label fonts, including offset text.

Parameters:

Name Type Description Default
size float

Target font size in points.

10.0
axis AxisSelector

Selector that describes which axes to update.

'both'
ax Optional['Axes']

Axes to modify; defaults to the instance axes.

None

Returns:

Type Description
'Axes'

The axes with resized tick labels.

Source code in src/sciwork/plot/ticks.py
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
def set_tick_label_size(
		self,
		size: float = 10.0,
		*,
		axis: AxisSelector = "both",
		ax: Optional["Axes"] = None
) -> "Axes":
	"""
	Resize tick label fonts, including offset text.

	:param size: Target font size in points.
	:param axis: Selector that describes which axes to update.
	:param ax: Axes to modify; defaults to the instance axes.
	:return: The axes with resized tick labels.
	"""

	axes = self._axes_or_default(ax)
	for target in self._iter_axes(axis):
		axis_obj = getattr(axes, f"{target}axis")
		for label in axis_obj.get_ticklabels(which="both"):
			label.set_fontsize(size)
		axis_obj.get_offset_text().set_fontsize(size)
		if axis_obj.get_scale() == "log":
			axis_obj.set_major_formatter(mpl.ticker.LogFormatterMathtext())
	self.fig.canvas.draw_idle()
	return axes

set_tick_length(length=4.0, *, tick_type='both', axis='both', ax=None)

Update tick lengths for major and/or minor ticks.

Parameters:

Name Type Description Default
length float

Length in points assigned to the selected tick types.

4.0
tick_type TickType

Choose "major", "minor", or "both" ticks to update.

'both'
axis AxisSelector

Selector describing the axes that should change.

'both'
ax Optional['Axes']

Axes to modify; defaults to the instance axes.

None

Returns:

Type Description
'Axes'

The axes after tick length updates.

Source code in src/sciwork/plot/ticks.py
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
def set_tick_length(
		self,
		length: float = 4.0,
		*,
		tick_type: TickType = "both",
		axis: AxisSelector = "both",
		ax: Optional["Axes"] = None
) -> "Axes":
	"""
	Update tick lengths for major and/or minor ticks.

	:param length: Length in points assigned to the selected tick types.
	:param tick_type: Choose ``"major"``, ``"minor"``, or ``"both"`` ticks to update.
	:param axis: Selector describing the axes that should change.
	:param ax: Axes to modify;
		defaults to the instance axes.
	:return: The axes after tick length updates.
	"""

	axes = self._axes_or_default(ax)
	which = ["major", "minor"] if tick_type == "both" else [tick_type]
	for target in self._iter_axes(axis):
		for entry in which:
			axes.tick_params(axis=target, which=entry, length=length)
	return axes

set_ticks_linewidth(linewidth=1.0, *, axis='both', ax=None)

Adjust tick line width on selected axes.

Parameters:

Name Type Description Default
linewidth float

Width applied to the ticks.

1.0
axis AxisSelector

Selector describing which axes to update ("x", "y", "z", "both", or "all").

'both'
ax Optional['Axes']

Axes to modify; defaults to the instance axes.

None

Returns:

Type Description
'Axes'

The axes with updated tick widths.

Source code in src/sciwork/plot/ticks.py
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
def set_ticks_linewidth(
		self,
		linewidth: float = 1.0,
		*,
		axis: AxisSelector = "both",
		ax: Optional["Axes"] = None
) -> "Axes":
	"""
	Adjust tick line width on selected axes.

	:param linewidth: Width applied to the ticks.
	:param axis: Selector describing which axes to update ("x", "y", "z",
		"both", or "all").
	:param ax: Axes to modify;
		defaults to the instance axes.
	:return: The axes with updated tick widths.
	"""

	axes = self._axes_or_default(ax)
	for target in self._iter_axes(axis):
		axes.tick_params(axis=target, which="both", width=linewidth)
	return axes