From a611e0e34cdef34feb87c508cfbc51f6ed36b886 Mon Sep 17 00:00:00 2001 From: Max Date: Sat, 22 Aug 2026 12:24:47 +0200 Subject: [PATCH 1/5] More coverage of mpl --- src/maxplotlib/canvas/canvas.py | 247 ++++++++++++++++++++++++++ src/maxplotlib/subfigure/line_plot.py | 174 +++++++++++++++++- src/maxplotlib/tests/test_canvas.py | 156 ++++++++++++++++ 3 files changed, 575 insertions(+), 2 deletions(-) diff --git a/src/maxplotlib/canvas/canvas.py b/src/maxplotlib/canvas/canvas.py index 248f4b5..2540929 100644 --- a/src/maxplotlib/canvas/canvas.py +++ b/src/maxplotlib/canvas/canvas.py @@ -313,12 +313,20 @@ def __init__( self._supylabel_kwargs: dict = {} self._subplots_adjust_kwargs: dict = {} self._tight_layout_kwargs: dict | None = None + self._set_tight_layout = None + self._align_labels = False + self._align_titles = False + self._align_xlabels = False + self._align_ylabels = False + self._autofmt_xdate_kwargs: dict | None = None # Dictionary to store lines for each subplot # Key: (row, col), Value: list of lines with their data and kwargs self._subplots = {} self._twinx_subplots = {} + self._twiny_subplots = {} self._matplotlib_twin_axes = {} + self._matplotlib_twiny_axes = {} self._num_subplots = 0 self._subplot_matrix = [[None] * self.ncols for _ in range(self.nrows)] @@ -398,6 +406,9 @@ def layers(self): twin_subplot = self._twinx_subplots.get((row, col)) if twin_subplot is not None: layers.extend(twin_subplot.layers) + twin_subplot = self._twiny_subplots.get((row, col)) + if twin_subplot is not None: + layers.extend(twin_subplot.layers) return list(set(layers)) def generate_new_rowcol(self, row, col): @@ -877,6 +888,12 @@ def table( cellText=cellText, layer=layer, **kwargs ) + def add_table(self, cellText=None, layer=0, row=None, col=None, **kwargs): + """Matplotlib-style alias for ``table``.""" + self._get_or_create_subplot(row, col).add_table( + cellText=cellText, layer=layer, **kwargs + ) + def gantt( self, tasks, @@ -983,6 +1000,9 @@ def set_legend( """Show or hide the legend for a subplot (default top-left).""" self._get_or_create_subplot(row, col).set_legend(visible) + def legend(self, row=None, col=None, **kwargs): + self._get_or_create_subplot(row, col).set_legend(**kwargs) + def tick_params(self, row: int | None = None, col: int | None = None, **kwargs): """Configure major/minor tick appearance for a subplot.""" self._get_or_create_subplot(row, col).tick_params(**kwargs) @@ -1011,6 +1031,108 @@ def set_facecolor(self, color, row: int | None = None, col: int | None = None): """Set a subplot's background color.""" self._get_or_create_subplot(row, col).set_facecolor(color) + def set_fc(self, color, row=None, col=None): + self._get_or_create_subplot(row, col).set_fc(color) + + def set_adjustable(self, adjustable, row=None, col=None): + self._get_or_create_subplot(row, col).set_adjustable(adjustable) + + def set_anchor(self, anchor, row=None, col=None): + self._get_or_create_subplot(row, col).set_anchor(anchor) + + def set(self, row=None, col=None, **kwargs): + return self._get_or_create_subplot(row, col).set(**kwargs) + + def update(self, kwargs, row=None, col=None): + return self._get_or_create_subplot(row, col).update(kwargs) + + def xaxis_inverted(self, row=None, col=None): + return self._get_or_create_subplot(row, col).xaxis_inverted() + + def yaxis_inverted(self, row=None, col=None): + return self._get_or_create_subplot(row, col).yaxis_inverted() + + def set_frame_on(self, state=True, row=None, col=None): + self._get_or_create_subplot(row, col).set_frame_on(state) + + def set_visible(self, state=True, row=None, col=None): + self._get_or_create_subplot(row, col).set_visible(state) + + def set_alpha(self, alpha, row=None, col=None): + self._get_or_create_subplot(row, col).set_alpha(alpha) + + def set_zorder(self, zorder, row=None, col=None): + self._get_or_create_subplot(row, col).set_zorder(zorder) + + def set_rasterized(self, rasterized=True, row=None, col=None): + self._get_or_create_subplot(row, col).set_rasterized(rasterized) + + def set_autoscale_on(self, enable=True, row=None, col=None): + self._get_or_create_subplot(row, col).set_autoscale_on(enable) + + def set_autoscalex_on(self, enable=True, row=None, col=None): + self._get_or_create_subplot(row, col).set_autoscalex_on(enable) + + def set_autoscaley_on(self, enable=True, row=None, col=None): + self._get_or_create_subplot(row, col).set_autoscaley_on(enable) + + def set_xbound(self, lower=None, upper=None, row=None, col=None): + self._get_or_create_subplot(row, col).set_xbound(lower, upper) + + def set_ybound(self, lower=None, upper=None, row=None, col=None): + self._get_or_create_subplot(row, col).set_ybound(lower, upper) + + def set_xmargin(self, margin, row=None, col=None): + self._get_or_create_subplot(row, col).set_xmargin(margin) + + def set_ymargin(self, margin, row=None, col=None): + self._get_or_create_subplot(row, col).set_ymargin(margin) + + def get_adjustable(self, row=None, col=None): + return self._get_or_create_subplot(row, col).get_adjustable() + + def get_anchor(self, row=None, col=None): + return self._get_or_create_subplot(row, col).get_anchor() + + def get_alpha(self, row=None, col=None): + return self._get_or_create_subplot(row, col).get_alpha() + + def get_box_aspect(self, row=None, col=None): + return self._get_or_create_subplot(row, col).get_box_aspect() + + def get_facecolor(self, row=None, col=None): + return self._get_or_create_subplot(row, col).get_facecolor() + + def get_frame_on(self, row=None, col=None): + return self._get_or_create_subplot(row, col).get_frame_on() + + def get_legend(self, row=None, col=None): + return self._get_or_create_subplot(row, col).get_legend() + + def get_rasterization_zorder(self, row=None, col=None): + return self._get_or_create_subplot(row, col).get_rasterization_zorder() + + def get_rasterized(self, row=None, col=None): + return self._get_or_create_subplot(row, col).get_rasterized() + + def get_visible(self, row=None, col=None): + return self._get_or_create_subplot(row, col).get_visible() + + def get_zorder(self, row=None, col=None): + return self._get_or_create_subplot(row, col).get_zorder() + + def get_xbound(self, row=None, col=None): + return self._get_or_create_subplot(row, col).get_xbound() + + def get_ybound(self, row=None, col=None): + return self._get_or_create_subplot(row, col).get_ybound() + + def get_xmargin(self, row=None, col=None): + return self._get_or_create_subplot(row, col).get_xmargin() + + def get_ymargin(self, row=None, col=None): + return self._get_or_create_subplot(row, col).get_ymargin() + def margins(self, *args, row: int | None = None, col: int | None = None, **kwargs): """Set x/y data margins for a subplot.""" self._get_or_create_subplot(row, col).margins(*args, **kwargs) @@ -1244,6 +1366,12 @@ def imshow( """Add an image/matrix plot to a subplot.""" self._get_or_create_subplot(row, col).add_imshow(data, layer=layer, **kwargs) + def add_image( + self, data, layer=0, row: int | None = None, col: int | None = None, **kwargs + ): + """Matplotlib-style alias for ``imshow``.""" + self._get_or_create_subplot(row, col).add_image(data, layer=layer, **kwargs) + def add_patch( self, patch, @@ -1301,11 +1429,26 @@ def twinx(self, row: int | None = None, col: int | None = None) -> LinePlot: self._twinx_subplots[key] = LinePlot() return self._twinx_subplots[key] + def twiny(self, row: int | None = None, col: int | None = None) -> LinePlot: + """Create or return a secondary x-axis sharing a subplot's y-axis.""" + self._get_or_create_subplot(row, col) + if row is None: + row, col = 0, 0 + key = (row, col) + if key not in self._twiny_subplots: + self._twiny_subplots[key] = LinePlot() + return self._twiny_subplots[key] + @property def twinx_axes(self): """Return materialized Matplotlib secondary axes by ``(row, col)``.""" return dict(self._matplotlib_twin_axes) + @property + def twiny_axes(self): + """Return materialized Matplotlib secondary x-axes by ``(row, col)``.""" + return dict(self._matplotlib_twiny_axes) + def iter_subplots(self): """Yield (row, col, subplot) for every initialized subplot, row-major.""" for r in range(self.nrows): @@ -1343,6 +1486,91 @@ def tight_layout(self, **kwargs): """Apply Matplotlib's automatic tight layout after plotting.""" self._tight_layout_kwargs = dict(kwargs) + def set_tight_layout(self, tight=True, **kwargs): + self._set_tight_layout = (tight, dict(kwargs)) + if tight: + self._tight_layout_kwargs = dict(kwargs) + + def align_labels(self, **kwargs): + self._align_labels = True + + def align_titles(self, **kwargs): + self._align_titles = True + + def align_xlabels(self, **kwargs): + self._align_xlabels = True + + def align_ylabels(self, **kwargs): + self._align_ylabels = True + + def autofmt_xdate(self, **kwargs): + self._autofmt_xdate_kwargs = dict(kwargs) + + def get_axes(self): + """Return rendered Matplotlib axes, or the current subplot models.""" + if self._matplotlib_fig is not None: + return self._matplotlib_fig.get_axes() + return list(self._subplot_dict.values()) + + def get_suptitle(self): + return self._suptitle + + def get_supxlabel(self): + return self._supxlabel + + def get_supylabel(self): + return self._supylabel + + def set_size_inches(self, w, h=None, forward=True): + """Set the figure size in inches, matching Matplotlib.""" + if h is None: + try: + w, h = w + except (TypeError, ValueError) as exc: + raise ValueError("set_size_inches expects (width, height)") from exc + self._figsize = (float(w), float(h)) + self._width = None + if forward and self._matplotlib_fig is not None: + self._matplotlib_fig.set_size_inches(self._figsize, forward=True) + + def get_size_inches(self): + """Return the figure size as ``(width, height)`` in inches.""" + if self._matplotlib_fig is not None: + return self._matplotlib_fig.get_size_inches() + if self._figsize is not None: + return np.asarray(self._figsize, dtype=float) + return np.asarray((6.4, 4.8), dtype=float) + + def set_figwidth(self, w): + """Set the figure width in inches.""" + _, height = self.get_size_inches() + self.set_size_inches(w, height) + + def set_figheight(self, h): + """Set the figure height in inches.""" + width, _ = self.get_size_inches() + self.set_size_inches(width, h) + + def get_figwidth(self): + """Return the figure width in inches.""" + return float(self.get_size_inches()[0]) + + def get_figheight(self): + """Return the figure height in inches.""" + return float(self.get_size_inches()[1]) + + def set_dpi(self, dpi): + """Set the figure DPI used for rendering and export.""" + self._dpi = dpi + if self._matplotlib_fig is not None: + self._matplotlib_fig.set_dpi(dpi) + + def get_dpi(self): + """Return the configured or rendered figure DPI.""" + if self._matplotlib_fig is not None: + return self._matplotlib_fig.get_dpi() + return self._dpi + def add_tikzfigure( self, col=None, @@ -1782,6 +2010,16 @@ def plot_matplotlib( fig.subplots_adjust(**self._subplots_adjust_kwargs) if self._tight_layout_kwargs is not None: fig.tight_layout(**self._tight_layout_kwargs) + if self._align_labels: + fig.align_labels() + if self._align_titles: + fig.align_titles() + if self._align_xlabels: + fig.align_xlabels() + if self._align_ylabels: + fig.align_ylabels() + if self._autofmt_xdate_kwargs is not None: + fig.autofmt_xdate(**self._autofmt_xdate_kwargs) if verbose: print("Set suptitle.") @@ -1795,6 +2033,11 @@ def plot_matplotlib( twin_axis = axes[row][col].twinx() twin_subplot.plot_matplotlib(twin_axis, layers=layers) self._matplotlib_twin_axes[(row, col)] = twin_axis + self._matplotlib_twiny_axes = {} + for (row, col), twin_subplot in self._twiny_subplots.items(): + twin_axis = axes[row][col].twiny() + twin_subplot.plot_matplotlib(twin_axis, layers=layers) + self._matplotlib_twiny_axes[(row, col)] = twin_axis if matplotlib_customizations is not None: _apply_matplotlib_customizations(fig, axes, matplotlib_customizations) if matplotlib_postprocess is not None: @@ -2021,6 +2264,10 @@ def plot_plotly( "secondary_xaxis and secondary_yaxis are currently supported " "only by the matplotlib backend" ) + if self._twiny_subplots: + raise NotImplementedError( + "twiny is currently supported only by the matplotlib backend" + ) setup_tex_fonts( fontsize=self.fontsize, diff --git a/src/maxplotlib/subfigure/line_plot.py b/src/maxplotlib/subfigure/line_plot.py index 6e7c78a..fb43e5b 100644 --- a/src/maxplotlib/subfigure/line_plot.py +++ b/src/maxplotlib/subfigure/line_plot.py @@ -70,6 +70,7 @@ def __init__( self._caption = None self._grid = grid self._legend = legend + self._legend_kwargs: dict = {} self._xmin = xmin self._xmax = xmax self._ymin = ymin @@ -107,6 +108,18 @@ def __init__( self._box_aspect = None self._secondary_xaxis_settings: dict | None = None self._secondary_yaxis_settings: dict | None = None + self._frame_on = None + self._visible = None + self._alpha = None + self._zorder = None + self._rasterized = None + self._autoscale_on = None + self._autoscalex_on = None + self._autoscaley_on = None + self._xmargin = None + self._ymargin = None + self._adjustable = None + self._anchor = None # Custom tick positions and labels self._xticks: list | None = None @@ -557,6 +570,10 @@ def table(self, cellText=None, layer=0, **kwargs): layer, ) + def add_table(self, cellText=None, layer=0, **kwargs): + """Matplotlib-style alias for ``table``.""" + self.table(cellText=cellText, layer=layer, **kwargs) + def gantt(self, tasks, start_times, durations, layer=0, **kwargs): """ Add a Gantt chart to the subplot. @@ -672,9 +689,10 @@ def tick_params(self, **kwargs): """Configure tick appearance using Matplotlib-style keyword arguments.""" self._tick_params = dict(kwargs) - def set_legend(self, visible: bool = True): + def set_legend(self, visible: bool = True, **kwargs): """Show or hide the legend.""" self._legend = visible + self._legend_kwargs = dict(kwargs) def set_xscale(self, scale: str): """Set the x-axis scale type: 'linear', 'log', or 'symlog'.""" @@ -700,6 +718,87 @@ def set_facecolor(self, color): """Set the subplot background color.""" self._facecolor = color + def set_frame_on(self, state): + self._frame_on = state + + def set_visible(self, state): + self._visible = state + + def set_alpha(self, alpha): + self._alpha = alpha + + def set_zorder(self, zorder): + self._zorder = zorder + + def set_rasterized(self, rasterized): + self._rasterized = rasterized + + def set_autoscale_on(self, enable): + self._autoscale_on = enable + + def set_autoscalex_on(self, enable): + self._autoscalex_on = enable + + def set_autoscaley_on(self, enable): + self._autoscaley_on = enable + + def set_xbound(self, lower=None, upper=None): + self.set_xlim(lower, upper) + + def set_ybound(self, lower=None, upper=None): + self.set_ylim(lower, upper) + + def set_xmargin(self, margin): + self._xmargin = margin + + def set_ymargin(self, margin): + self._ymargin = margin + + def get_adjustable(self): + return self._adjustable + + def get_anchor(self): + return self._anchor + + def get_alpha(self): + return self._alpha + + def get_box_aspect(self): + return self._box_aspect + + def get_facecolor(self): + return self._facecolor + + def get_frame_on(self): + return self._frame_on + + def get_legend(self): + return self._legend + + def get_rasterization_zorder(self): + return self._rasterization_zorder + + def get_rasterized(self): + return self._rasterized + + def get_visible(self): + return self._visible + + def get_zorder(self): + return self._zorder + + def get_xbound(self): + return self._xmin, self._xmax + + def get_ybound(self): + return self._ymin, self._ymax + + def get_xmargin(self): + return self._xmargin + + def get_ymargin(self): + return self._ymargin + def margins(self, *args, **kwargs): """Set x/y data margins using Matplotlib-style arguments.""" self._margins = {"args": args, **kwargs} @@ -749,6 +848,49 @@ def set_aspect(self, aspect): """Set the axes aspect ratio: 'equal', 'auto', or a float.""" self._aspect = aspect + def set_adjustable(self, adjustable): + self._adjustable = adjustable + + def set_anchor(self, anchor): + self._anchor = anchor + + def set_fc(self, color): + self.set_facecolor(color) + + def set(self, **kwargs): + """Set common axes properties using Matplotlib-style names.""" + handlers = { + "title": self.set_title, + "xlabel": self.set_xlabel, + "ylabel": self.set_ylabel, + "xlim": lambda value: self.set_xlim(*value), + "ylim": lambda value: self.set_ylim(*value), + "xscale": self.set_xscale, + "yscale": self.set_yscale, + "facecolor": self.set_facecolor, + "fc": self.set_fc, + "aspect": self.set_aspect, + "adjustable": self.set_adjustable, + "anchor": self.set_anchor, + "visible": self.set_visible, + "alpha": self.set_alpha, + "zorder": self.set_zorder, + } + for name, value in kwargs.items(): + if name not in handlers: + raise AttributeError(f"Unknown LinePlot property: {name}") + handlers[name](value) + return kwargs + + def update(self, kwargs): + return self.set(**dict(kwargs)) + + def xaxis_inverted(self): + return self._invert_xaxis + + def yaxis_inverted(self): + return self._invert_yaxis + def axis(self, *args, **kwargs): """Set Matplotlib-style axis limits or modes.""" self._axis_settings = {"args": args, **kwargs} @@ -1025,6 +1167,10 @@ def add_imshow(self, data, layer=0, **kwargs): } self._add(ld, layer) + def add_image(self, data, layer=0, **kwargs): + """Matplotlib-style alias for ``imshow``.""" + self.add_imshow(data, layer=layer, **kwargs) + def add_patch(self, patch, layer=0, **kwargs): ld = { "patch": patch, @@ -1343,7 +1489,7 @@ def plot_matplotlib( if self._ylabel: ax.set_ylabel(self._ylabel, **self._ylabel_kwargs) if self._legend and len(self.line_data) > 0: - ax.legend() + ax.legend(**self._legend_kwargs) if self._grid: ax.grid() if self._axis_settings: @@ -1382,12 +1528,36 @@ def plot_matplotlib( ax.tick_params(**self._tick_params) if self._aspect is not None: ax.set_aspect(self._aspect) + if self._adjustable is not None: + ax.set_adjustable(self._adjustable) + if self._anchor is not None: + ax.set_anchor(self._anchor) if self._box_aspect is not None: ax.set_box_aspect(self._box_aspect) if self._axisbelow is not None: ax.set_axisbelow(self._axisbelow) if self._facecolor is not None: ax.set_facecolor(self._facecolor) + if self._frame_on is not None: + ax.set_frame_on(self._frame_on) + if self._visible is not None: + ax.set_visible(self._visible) + if self._alpha is not None: + ax.set_alpha(self._alpha) + if self._zorder is not None: + ax.set_zorder(self._zorder) + if self._rasterized is not None: + ax.set_rasterized(self._rasterized) + if self._autoscale_on is not None: + ax.set_autoscale_on(self._autoscale_on) + if self._autoscalex_on is not None: + ax.set_autoscalex_on(self._autoscalex_on) + if self._autoscaley_on is not None: + ax.set_autoscaley_on(self._autoscaley_on) + if self._xmargin is not None: + ax.set_xmargin(self._xmargin) + if self._ymargin is not None: + ax.set_ymargin(self._ymargin) if self._margins: margin_settings = dict(self._margins) margin_args = margin_settings.pop("args", ()) diff --git a/src/maxplotlib/tests/test_canvas.py b/src/maxplotlib/tests/test_canvas.py index 32d3f7d..9aa0bd6 100644 --- a/src/maxplotlib/tests/test_canvas.py +++ b/src/maxplotlib/tests/test_canvas.py @@ -726,6 +726,162 @@ def test_secondary_axes_are_supported_by_matplotlib(): plt.close(fig) +def test_twiny_is_supported_by_matplotlib(): + import matplotlib.pyplot as plt + + from maxplotlib import Canvas + + canvas, axis = Canvas.subplots() + secondary = canvas.twiny() + axis.plot([0, 1], [0, 1]) + secondary.plot([10, 20], [0, 1], color="red") + + fig, axes = canvas.plot(backend="matplotlib") + + assert canvas.twiny_axes[(0, 0)] is not axes[0, 0] + plt.close(fig) + + +def test_axis_state_setter_aliases_are_supported(): + import matplotlib.pyplot as plt + + from maxplotlib import Canvas + + canvas, axis = Canvas.subplots() + axis.plot([0, 1], [0, 1]) + axis.set_frame_on(False) + axis.set_visible(True) + axis.set_alpha(0.8) + axis.set_zorder(3) + axis.set_rasterized(True) + axis.set_autoscale_on(True) + axis.set_autoscalex_on(False) + axis.set_autoscaley_on(True) + axis.set_autoscale_on(False) + axis.set_xbound(-1, 2) + axis.set_ybound(-2, 3) + + fig, axes = canvas.plot(backend="matplotlib") + matplotlib_axis = axes[0, 0] + + assert matplotlib_axis.get_frame_on() is False + assert matplotlib_axis.get_visible() is True + assert matplotlib_axis.get_alpha() == 0.8 + assert matplotlib_axis.get_zorder() == 3 + assert matplotlib_axis.get_rasterized() is True + assert matplotlib_axis.get_xlim() == (-1, 2) + assert matplotlib_axis.get_ylim() == (-2, 3) + plt.close(fig) + + +def test_figure_size_and_dpi_setters_are_supported(): + import pytest + + from maxplotlib import Canvas + + canvas, _ = Canvas.subplots(figsize=(4, 3), dpi=120) + assert canvas.get_size_inches() == pytest.approx([4, 3]) + assert canvas.get_figwidth() == 4 + assert canvas.get_figheight() == 3 + assert canvas.get_dpi() == 120 + + canvas.set_figwidth(5) + canvas.set_figheight(2) + canvas.set_dpi(150) + + assert canvas.get_size_inches() == pytest.approx([5, 2]) + assert canvas.get_dpi() == 150 + + +def test_generic_axis_setters_and_metadata_getters_are_supported(): + import matplotlib.pyplot as plt + + from maxplotlib import Canvas + + canvas, axis = Canvas.subplots() + canvas.suptitle("Figure title") + canvas.supxlabel("Shared x") + canvas.supylabel("Shared y") + axis.plot([0, 1], [0, 1]) + axis.set(fc="lavender", adjustable="box", anchor="C") + axis.update({"aspect": "equal"}) + axis.invert_xaxis() + + fig, axes = canvas.plot(backend="matplotlib") + matplotlib_axis = axes[0, 0] + + assert canvas.get_suptitle() == "Figure title" + assert canvas.get_supxlabel() == "Shared x" + assert canvas.get_supylabel() == "Shared y" + assert len(canvas.get_axes()) == 1 + assert canvas.xaxis_inverted() is True + assert matplotlib_axis.get_adjustable() == "box" + assert matplotlib_axis.get_anchor() == "C" + plt.close(fig) + + +def test_figure_layout_helpers_and_aliases_are_supported(): + import matplotlib.pyplot as plt + + from maxplotlib import Canvas + + canvas, axis = Canvas.subplots() + axis.plot([0, 1], [0, 1], label="line") + axis.set_legend(loc="upper left") + axis.add_table(cellText=[["A"]]) + axis.add_image([[1, 2], [3, 4]]) + canvas.set_tight_layout(True) + canvas.align_labels() + canvas.align_titles() + canvas.align_xlabels() + canvas.align_ylabels() + canvas.autofmt_xdate(rotation=20) + + fig, axes = canvas.plot(backend="matplotlib") + + assert axes[0, 0].get_legend() is not None + assert len(axes[0, 0].tables) == 1 + assert len(axes[0, 0].images) == 1 + plt.close(fig) + + +def test_axis_getters_reflect_configured_state(): + from maxplotlib import Canvas + + canvas, axis = Canvas.subplots() + axis.set_adjustable("datalim") + axis.set_anchor("SW") + axis.set_alpha(0.5) + axis.set_box_aspect(1.2) + axis.set_facecolor("pink") + axis.set_frame_on(False) + axis.set_legend(True) + axis.set_rasterization_zorder(4) + axis.set_rasterized(True) + axis.set_visible(False) + axis.set_zorder(7) + axis.set_xbound(-1, 2) + axis.set_ybound(-2, 3) + axis.set_xmargin(0.1) + axis.set_ymargin(0.2) + + assert canvas.get_adjustable() == "datalim" + assert canvas.get_anchor() == "SW" + assert canvas.get_alpha() == 0.5 + assert canvas.get_box_aspect() == 1.2 + assert canvas.get_facecolor() == "pink" + assert canvas.get_frame_on() is False + assert canvas.get_legend() is True + assert canvas.get_rasterization_zorder() == 4 + assert canvas.get_rasterized() is True + assert canvas.get_visible() is False + assert canvas.get_zorder() == 7 + assert canvas.get_xbound() == (-1, 2) + assert canvas.get_ybound() == (-2, 3) + assert canvas.get_xmargin() == 0.1 + assert canvas.get_ymargin() == 0.2 + + def test_matplotlib_postprocess_can_customize_figure_and_axes(): import matplotlib.pyplot as plt from matplotlib.colors import to_rgba From bdc2194924c9475bab4c4b511c04ff5de4a9e590 Mon Sep 17 00:00:00 2001 From: Max Date: Sat, 22 Aug 2026 12:59:27 +0200 Subject: [PATCH 2/5] Rewrote notebooks using the canvas style --- src/maxplotlib/canvas/canvas.py | 14 ++ tutorials/tutorial_01.ipynb | 36 +-- tutorials/tutorial_03.ipynb | 142 ++++++------ tutorials/tutorial_04.ipynb | 80 +++---- tutorials/tutorial_05.ipynb | 84 +++---- tutorials/tutorial_06.ipynb | 54 ++--- tutorials/tutorial_07_tikz.ipynb | 22 +- tutorials/tutorial_08_plotly.ipynb | 30 +-- tutorials/tutorial_09_plotext.ipynb | 218 +++++++++--------- .../tutorial_10_matplotlib_nxm_spacing.ipynb | 16 +- .../tutorial_13_advanced_matplotlib.ipynb | 98 ++++---- ...tutorial_14_axis_and_layout_controls.ipynb | 52 ++--- 12 files changed, 430 insertions(+), 416 deletions(-) diff --git a/src/maxplotlib/canvas/canvas.py b/src/maxplotlib/canvas/canvas.py index 2540929..d755b4e 100644 --- a/src/maxplotlib/canvas/canvas.py +++ b/src/maxplotlib/canvas/canvas.py @@ -620,6 +620,10 @@ def set_box_aspect(self, aspect, row=None, col=None): """Set the physical height-to-width ratio of a subplot.""" self._get_or_create_subplot(row, col).set_box_aspect(aspect) + def set_aspect(self, aspect, row=None, col=None): + """Set the data aspect ratio of a subplot.""" + self._get_or_create_subplot(row, col).set_aspect(aspect) + def secondary_xaxis( self, location="top", functions=None, row=None, col=None, **kwargs ): @@ -894,6 +898,10 @@ def add_table(self, cellText=None, layer=0, row=None, col=None, **kwargs): cellText=cellText, layer=layer, **kwargs ) + def add_caption(self, caption): + """Set the figure caption.""" + self._caption = caption + def gantt( self, tasks, @@ -1396,6 +1404,12 @@ def colorbar( label=label, layer=layer, **kwargs ) + def add_colorbar( + self, label: str = "", layer=0, row=None, col=None, **kwargs + ): + """Alias for ``colorbar``.""" + self.colorbar(label=label, layer=layer, row=row, col=col, **kwargs) + # ------------------------------------------------------------------ # Multi-subplot helpers # ------------------------------------------------------------------ diff --git a/tutorials/tutorial_01.ipynb b/tutorials/tutorial_01.ipynb index 964b647..4336629 100644 --- a/tutorials/tutorial_01.ipynb +++ b/tutorials/tutorial_01.ipynb @@ -79,8 +79,8 @@ "x = np.linspace(0, 2 * np.pi, 200)\n", "y = np.sin(x)\n", "\n", - "canvas, ax = Canvas.subplots()\n", - "ax.plot(x, y)\n", + "canvas = Canvas()\n", + "canvas.add_line(x, y)\n", "canvas.show(backend=BACKEND)" ] }, @@ -99,11 +99,11 @@ "metadata": {}, "outputs": [], "source": [ - "canvas, ax = Canvas.subplots()\n", + "canvas = Canvas()\n", "\n", - "ax.plot(x, np.sin(x), label=\"sin(x)\", color=\"royalblue\", linestyle=\"solid\", linewidth=2)\n", - "ax.plot(x, np.cos(x), label=\"cos(x)\", color=\"tomato\", linestyle=\"dashed\", linewidth=2)\n", - "ax.plot(\n", + "canvas.add_line(x, np.sin(x), label=\"sin(x)\", color=\"royalblue\", linestyle=\"solid\", linewidth=2)\n", + "canvas.add_line(x, np.cos(x), label=\"cos(x)\", color=\"tomato\", linestyle=\"dashed\", linewidth=2)\n", + "canvas.add_line(\n", " x,\n", " np.sin(2 * x),\n", " label=\"sin(2x)\",\n", @@ -112,10 +112,10 @@ " linewidth=1.5,\n", ")\n", "\n", - "ax.set_xlabel(\"x\")\n", - "ax.set_ylabel(\"y\")\n", - "ax.set_title(\"Sine and Cosine\")\n", - "ax.set_legend(True)\n", + "canvas.set_xlabel(\"x\")\n", + "canvas.set_ylabel(\"y\")\n", + "canvas.set_title(\"Sine and Cosine\")\n", + "canvas.set_legend(True)\n", "\n", "canvas.show(backend=BACKEND)" ] @@ -179,8 +179,8 @@ " legend=True,\n", ")\n", "\n", - "ax.plot(x, np.sin(x), label=\"sin\", color=\"royalblue\")\n", - "ax.plot(x, x / (2 * np.pi), label=\"x/2π\", color=\"coral\", linestyle=\"dashed\")\n", + "canvas.add_line(x, np.sin(x), label=\"sin\", color=\"royalblue\")\n", + "canvas.add_line(x, x / (2 * np.pi), label=\"x/2π\", color=\"coral\", linestyle=\"dashed\")\n", "\n", "canvas.show(backend=BACKEND)" ] @@ -205,7 +205,7 @@ "source": [ "canvas = Canvas(ratio=0.5)\n", "ax = canvas.add_subplot(xlabel=\"x\", ylabel=\"sin(x)\", grid=True)\n", - "ax.plot(x, np.sin(x), color=\"steelblue\")\n", + "canvas.add_line(x, np.sin(x), color=\"steelblue\")\n", "\n", "canvas.savefig(\"tutorial_01_output.png\")\n", "print(\"Figure saved to tutorial_01_output.png\")" @@ -220,11 +220,11 @@ "\n", "| Task | Code |\n", "|---|---|\n", - "| Create canvas + subplot | `canvas, ax = Canvas.subplots()` |\n", - "| Add a line | `ax.plot(x, y, label=..., color=..., linestyle=...)` |\n", - "| Canvas shortcut | `canvas.add_line(x, y, ...)` |\n", - "| Labels / title | `ax.set_xlabel()`, `ax.set_ylabel()`, `ax.set_title()` |\n", - "| Legend / grid | `ax.set_legend(True)`, `ax.set_grid(True)` |\n", + "| Create a canvas | `canvas = Canvas()` |\n", + "| Add a line | `canvas.add_line(x, y, label=..., color=..., linestyle=...)` |\n", + "| Optional Matplotlib-style axes | `canvas, ax = Canvas.subplots()` |\n", + "| Labels / title | `canvas.set_xlabel()`, `canvas.set_ylabel()`, `canvas.set_title()` |\n", + "| Legend / grid | `canvas.set_legend(True)`, `canvas.set_grid(True)` |\n", "| Display | `canvas.show()` |\n", "| Save | `canvas.savefig('out.png')` |\n", "\n", diff --git a/tutorials/tutorial_03.ipynb b/tutorials/tutorial_03.ipynb index c3b8e12..cf5eac6 100644 --- a/tutorials/tutorial_03.ipynb +++ b/tutorials/tutorial_03.ipynb @@ -64,7 +64,7 @@ "id": "4", "metadata": {}, "source": [ - "## 1 Line plot — `ax.plot()`" + "## 1 Line plot — `canvas.add_line()`" ] }, { @@ -74,16 +74,16 @@ "metadata": {}, "outputs": [], "source": [ - "canvas, ax = Canvas.subplots()\n", + "canvas = Canvas()\n", "\n", - "ax.plot(x, np.sin(x), label=\"sin(x)\", color=\"royalblue\", linestyle=\"solid\", linewidth=2)\n", - "ax.plot(x, np.cos(x), label=\"cos(x)\", color=\"tomato\", linestyle=\"dashed\", linewidth=2)\n", + "canvas.add_line(x, np.sin(x), label=\"sin(x)\", color=\"royalblue\", linestyle=\"solid\", linewidth=2)\n", + "canvas.add_line(x, np.cos(x), label=\"cos(x)\", color=\"tomato\", linestyle=\"dashed\", linewidth=2)\n", "\n", - "ax.set_xlabel(\"x\")\n", - "ax.set_ylabel(\"y\")\n", - "ax.set_title(\"Line Plot\")\n", - "ax.set_legend(True)\n", - "ax.set_grid(True)\n", + "canvas.set_xlabel(\"x\")\n", + "canvas.set_ylabel(\"y\")\n", + "canvas.set_title(\"Line Plot\")\n", + "canvas.set_legend(True)\n", + "canvas.set_grid(True)\n", "canvas.show(backend=BACKEND)" ] }, @@ -109,12 +109,12 @@ "sy = rng.standard_normal(n)\n", "values = np.sqrt(sx**2 + sy**2) # colour by distance from origin\n", "\n", - "canvas, ax = Canvas.subplots()\n", - "ax.scatter(sx, sy, c=values, s=30, label=\"data points\")\n", - "ax.set_xlabel(\"x\")\n", - "ax.set_ylabel(\"y\")\n", - "ax.set_title(\"Scatter Plot — coloured by distance\")\n", - "ax.set_aspect(\"equal\")\n", + "canvas = Canvas()\n", + "canvas.scatter(sx, sy, c=values, s=30, label=\"data points\")\n", + "canvas.set_xlabel(\"x\")\n", + "canvas.set_ylabel(\"y\")\n", + "canvas.set_title(\"Scatter Plot — coloured by distance\")\n", + "canvas.set_aspect(\"equal\")\n", "canvas.show(backend=BACKEND)" ] }, @@ -136,12 +136,12 @@ "categories = [\"Jan\", \"Feb\", \"Mar\", \"Apr\", \"May\", \"Jun\"]\n", "values_bar = [12, 19, 15, 22, 30, 27]\n", "\n", - "canvas, ax = Canvas.subplots()\n", - "ax.bar(categories, values_bar, color=\"steelblue\", width=0.6, label=\"monthly sales\")\n", - "ax.set_xlabel(\"Month\")\n", - "ax.set_ylabel(\"Sales (units)\")\n", - "ax.set_title(\"Bar Chart\")\n", - "ax.set_legend(True)\n", + "canvas = Canvas()\n", + "canvas.bar(categories, values_bar, color=\"steelblue\", width=0.6, label=\"monthly sales\")\n", + "canvas.set_xlabel(\"Month\")\n", + "canvas.set_ylabel(\"Sales (units)\")\n", + "canvas.set_title(\"Bar Chart\")\n", + "canvas.set_legend(True)\n", "# canvas.show(backend=BACKEND) # TODO: Fix this error" ] }, @@ -167,13 +167,13 @@ "upper = mean + 0.3 * (1 - t / (4 * np.pi))\n", "lower = mean - 0.3 * (1 - t / (4 * np.pi))\n", "\n", - "canvas, ax = Canvas.subplots()\n", - "ax.plot(t, mean, color=\"royalblue\", label=\"mean\", linewidth=2)\n", - "ax.fill_between(t, lower, upper, alpha=0.25, color=\"royalblue\", label=\"±1 std\")\n", - "ax.set_xlabel(\"t\")\n", - "ax.set_ylabel(\"value\")\n", - "ax.set_title(\"Fill Between — Confidence Band\")\n", - "ax.set_legend(True)\n", + "canvas = Canvas()\n", + "canvas.add_line(t, mean, color=\"royalblue\", label=\"mean\", linewidth=2)\n", + "canvas.fill_between(t, lower, upper, alpha=0.25, color=\"royalblue\", label=\"±1 std\")\n", + "canvas.set_xlabel(\"t\")\n", + "canvas.set_ylabel(\"value\")\n", + "canvas.set_title(\"Fill Between — Confidence Band\")\n", + "canvas.set_legend(True)\n", "canvas.show(backend=BACKEND)" ] }, @@ -196,14 +196,14 @@ "ym = np.sin(xm) + rng.normal(0, 0.1, len(xm))\n", "yerr = 0.1 + 0.05 * rng.random(len(xm))\n", "\n", - "canvas, ax = Canvas.subplots()\n", - "ax.errorbar(xm, ym, yerr=yerr, fmt=\"o\", capsize=4, color=\"tomato\", label=\"measurements\")\n", - "ax.plot(x, np.sin(x), color=\"gray\", linestyle=\"dashed\", label=\"true sin(x)\")\n", - "ax.set_xlabel(\"x\")\n", - "ax.set_ylabel(\"y\")\n", - "ax.set_title(\"Error Bars\")\n", - "ax.set_legend(True)\n", - "ax.set_grid(True)\n", + "canvas = Canvas()\n", + "canvas.errorbar(xm, ym, yerr=yerr, fmt=\"o\", capsize=4, color=\"tomato\", label=\"measurements\")\n", + "canvas.add_line(x, np.sin(x), color=\"gray\", linestyle=\"dashed\", label=\"true sin(x)\")\n", + "canvas.set_xlabel(\"x\")\n", + "canvas.set_ylabel(\"y\")\n", + "canvas.set_title(\"Error Bars\")\n", + "canvas.set_legend(True)\n", + "canvas.set_grid(True)\n", "canvas.show(backend=BACKEND)" ] }, @@ -224,17 +224,17 @@ "metadata": {}, "outputs": [], "source": [ - "canvas, ax = Canvas.subplots()\n", - "ax.plot(x, np.sin(x), color=\"royalblue\", label=\"sin(x)\")\n", + "canvas = Canvas()\n", + "canvas.add_line(x, np.sin(x), color=\"royalblue\", label=\"sin(x)\")\n", "\n", - "ax.axhline(y=0, color=\"black\", linestyle=\"solid\", linewidth=0.8)\n", - "ax.axhline(y=0.5, color=\"green\", linestyle=\"dashed\", linewidth=1.2, label=\"y = 0.5\")\n", - "ax.axhline(y=-0.5, color=\"green\", linestyle=\"dashed\", linewidth=1.2, label=\"y = -0.5\")\n", - "ax.axvline(x=np.pi, color=\"red\", linestyle=\"dotted\", linewidth=1.5, label=\"x = π\")\n", + "canvas.axhline(y=0, color=\"black\", linestyle=\"solid\", linewidth=0.8)\n", + "canvas.axhline(y=0.5, color=\"green\", linestyle=\"dashed\", linewidth=1.2, label=\"y = 0.5\")\n", + "canvas.axhline(y=-0.5, color=\"green\", linestyle=\"dashed\", linewidth=1.2, label=\"y = -0.5\")\n", + "canvas.axvline(x=np.pi, color=\"red\", linestyle=\"dotted\", linewidth=1.5, label=\"x = π\")\n", "\n", - "ax.set_xlabel(\"x\")\n", - "ax.set_title(\"axhline / axvline\")\n", - "ax.set_legend(True)\n", + "canvas.set_xlabel(\"x\")\n", + "canvas.set_title(\"axhline / axvline\")\n", + "canvas.set_legend(True)\n", "canvas.show(backend=BACKEND)" ] }, @@ -255,11 +255,11 @@ "metadata": {}, "outputs": [], "source": [ - "canvas, ax = Canvas.subplots()\n", - "ax.plot(x, np.sin(x), color=\"lightgray\", linewidth=1)\n", + "canvas = Canvas()\n", + "canvas.add_line(x, np.sin(x), color=\"lightgray\", linewidth=1)\n", "\n", "# Horizontal segments spanning half the x-range\n", - "ax.hlines(\n", + "canvas.hlines(\n", " y=[0.5, -0.5],\n", " xmin=0,\n", " xmax=np.pi,\n", @@ -269,7 +269,7 @@ ")\n", "\n", "# Vertical segments at specific x positions\n", - "ax.vlines(\n", + "canvas.vlines(\n", " x=[np.pi / 2, 3 * np.pi / 2],\n", " ymin=-1,\n", " ymax=1,\n", @@ -278,9 +278,9 @@ " label=\"vlines at π/2, 3π/2\",\n", ")\n", "\n", - "ax.set_xlabel(\"x\")\n", - "ax.set_title(\"hlines / vlines\")\n", - "ax.set_legend(True)\n", + "canvas.set_xlabel(\"x\")\n", + "canvas.set_title(\"hlines / vlines\")\n", + "canvas.set_legend(True)\n", "canvas.show(backend=BACKEND)" ] }, @@ -311,20 +311,20 @@ "tidx = np.arange(0, len(t), 20)\n", "tx, ty = t[tidx], (signal + noise)[tidx]\n", "\n", - "canvas, ax = Canvas.subplots()\n", + "canvas = Canvas()\n", "\n", - "ax.fill_between(\n", + "canvas.fill_between(\n", " t, signal - band, signal + band, alpha=0.2, color=\"royalblue\", label=\"uncertainty\"\n", ")\n", - "ax.plot(t, signal, color=\"royalblue\", linewidth=2, label=\"model\")\n", - "ax.scatter(tx, ty, color=\"tomato\", s=25, marker=\"o\", label=\"measurements\")\n", - "ax.axhline(y=0, color=\"gray\", linestyle=\"dashed\", linewidth=0.8)\n", - "\n", - "ax.set_xlabel(\"time\")\n", - "ax.set_ylabel(\"amplitude\")\n", - "ax.set_title(\"Combined: line + fill_between + scatter\")\n", - "ax.set_legend(True)\n", - "ax.set_grid(True)\n", + "canvas.add_line(t, signal, color=\"royalblue\", linewidth=2, label=\"model\")\n", + "canvas.scatter(tx, ty, color=\"tomato\", s=25, marker=\"o\", label=\"measurements\")\n", + "canvas.axhline(y=0, color=\"gray\", linestyle=\"dashed\", linewidth=0.8)\n", + "\n", + "canvas.set_xlabel(\"time\")\n", + "canvas.set_ylabel(\"amplitude\")\n", + "canvas.set_title(\"Combined: line + fill_between + scatter\")\n", + "canvas.set_legend(True)\n", + "canvas.set_grid(True)\n", "canvas.show(backend=BACKEND)" ] }, @@ -343,11 +343,11 @@ "metadata": {}, "outputs": [], "source": [ - "canvas, ax = Canvas.subplots()\n", - "ax.plot(x, np.sin(x), color=\"royalblue\")\n", + "canvas = Canvas()\n", + "canvas.add_line(x, np.sin(x), color=\"royalblue\")\n", "\n", "# Arrow annotation pointing to the peak\n", - "ax.annotate(\n", + "canvas.annotate(\n", " \"peak\",\n", " xy=(np.pi / 2, 1.0),\n", " xytext=(np.pi / 2 + 0.8, 0.7),\n", @@ -355,11 +355,11 @@ ")\n", "\n", "# Free-floating text label\n", - "ax.text(3 * np.pi / 2, 0.15, \"zero\\ncrossing\", ha=\"center\", fontsize=9)\n", + "canvas.text(3 * np.pi / 2, 0.15, \"zero\\ncrossing\", ha=\"center\", fontsize=9)\n", "\n", - "ax.set_xlabel(\"x\")\n", - "ax.set_ylabel(\"sin(x)\")\n", - "ax.set_title(\"Annotate and Text\")\n", + "canvas.set_xlabel(\"x\")\n", + "canvas.set_ylabel(\"sin(x)\")\n", + "canvas.set_title(\"Annotate and Text\")\n", "canvas.show(backend=BACKEND)" ] }, @@ -372,7 +372,7 @@ "\n", "| Plot type | Method | Key kwargs |\n", "|---|---|---|\n", - "| Line | `ax.plot(x, y)` | `color`, `linestyle`, `linewidth`, `label` |\n", + "| Line | `canvas.add_line(x, y)` | `color`, `linestyle`, `linewidth`, `label` |\n", "| Scatter | `ax.scatter(x, y)` | `c`, `s`, `marker`, `label` |\n", "| Bar | `ax.bar(x, height)` | `color`, `width`, `label` |\n", "| Filled band | `ax.fill_between(x, y1, y2)` | `alpha`, `color`, `label` |\n", diff --git a/tutorials/tutorial_04.ipynb b/tutorials/tutorial_04.ipynb index e7f3808..52ccdbb 100644 --- a/tutorials/tutorial_04.ipynb +++ b/tutorials/tutorial_04.ipynb @@ -67,16 +67,16 @@ "source": [ "x = np.linspace(0, 2 * np.pi, 200)\n", "\n", - "canvas, ax = Canvas.subplots(width=\"10cm\", ratio=0.6)\n", + "canvas = Canvas(width=\"10cm\", ratio=0.6)\n", "\n", - "ax.plot(x, np.sin(x), color=\"steelblue\", label=\"named: steelblue\")\n", - "ax.plot(x, np.sin(x - 0.5), color=\"#e74c3c\", label=\"hex: #e74c3c\")\n", - "ax.plot(x, np.sin(x - 1.0), color=(0.2, 0.7, 0.3), label=\"RGB tuple\")\n", + "canvas.add_line(x, np.sin(x), color=\"steelblue\", label=\"named: steelblue\")\n", + "canvas.add_line(x, np.sin(x - 0.5), color=\"#e74c3c\", label=\"hex: #e74c3c\")\n", + "canvas.add_line(x, np.sin(x - 1.0), color=(0.2, 0.7, 0.3), label=\"RGB tuple\")\n", "\n", - "ax.set_xlabel(\"x\")\n", - "ax.set_ylabel(\"y\")\n", - "ax.set_title(\"Color options\")\n", - "ax.set_legend(True)\n", + "canvas.set_xlabel(\"x\")\n", + "canvas.set_ylabel(\"y\")\n", + "canvas.set_title(\"Color options\")\n", + "canvas.set_legend(True)\n", "canvas.show(backend=BACKEND)" ] }, @@ -100,10 +100,10 @@ "x = np.linspace(0, 4 * np.pi, 300)\n", "styles = [(\"solid\", \"-\"), (\"dashed\", \"--\"), (\"dotted\", \":\"), (\"dashdot\", \"-.\")]\n", "\n", - "canvas, ax = Canvas.subplots(width=\"10cm\", ratio=0.6)\n", + "canvas = Canvas(width=\"10cm\", ratio=0.6)\n", "\n", "for i, (name, ls) in enumerate(styles):\n", - " ax.plot(\n", + " canvas.add_line(\n", " x,\n", " np.sin(x) + i * 0.4,\n", " linestyle=ls,\n", @@ -112,9 +112,9 @@ " label=f\"{name!r} / {ls!r}\",\n", " )\n", "\n", - "ax.set_xlabel(\"x\")\n", - "ax.set_title(\"Linestyle comparison\")\n", - "ax.set_legend(True)\n", + "canvas.set_xlabel(\"x\")\n", + "canvas.set_title(\"Linestyle comparison\")\n", + "canvas.set_legend(True)\n", "canvas.show(backend=BACKEND)" ] }, @@ -138,10 +138,10 @@ "x = np.linspace(0, 2 * np.pi, 10)\n", "markers = [\"o\", \"s\", \"^\", \"D\", \"*\", \"x\", \"+\"]\n", "\n", - "canvas, ax = Canvas.subplots(width=\"10cm\", ratio=0.65)\n", + "canvas = Canvas(width=\"10cm\", ratio=0.65)\n", "\n", "for i, m in enumerate(markers):\n", - " ax.plot(\n", + " canvas.add_line(\n", " x,\n", " np.sin(x) + i * 0.5,\n", " marker=m,\n", @@ -150,9 +150,9 @@ " label=f\"marker={m!r}\",\n", " )\n", "\n", - "ax.set_xlabel(\"x\")\n", - "ax.set_title(\"Marker comparison\")\n", - "ax.set_legend(True)\n", + "canvas.set_xlabel(\"x\")\n", + "canvas.set_title(\"Marker comparison\")\n", + "canvas.set_legend(True)\n", "canvas.show(backend=BACKEND)" ] }, @@ -175,17 +175,17 @@ "source": [ "x = np.linspace(0, 2 * np.pi, 40)\n", "\n", - "canvas, ax = Canvas.subplots(width=\"10cm\", ratio=0.55)\n", + "canvas = Canvas(width=\"10cm\", ratio=0.55)\n", "\n", - "ax.plot(x, np.sin(x), linewidth=0.8, marker=\"o\", markersize=3, label=\"thin / small\")\n", - "ax.plot(x, np.sin(x) - 0.6, linewidth=2.5, marker=\"o\", markersize=7, label=\"medium\")\n", - "ax.plot(\n", + "canvas.add_line(x, np.sin(x), linewidth=0.8, marker=\"o\", markersize=3, label=\"thin / small\")\n", + "canvas.add_line(x, np.sin(x) - 0.6, linewidth=2.5, marker=\"o\", markersize=7, label=\"medium\")\n", + "canvas.add_line(\n", " x, np.sin(x) - 1.2, linewidth=4.5, marker=\"o\", markersize=12, label=\"thick / large\"\n", ")\n", "\n", - "ax.set_xlabel(\"x\")\n", - "ax.set_title(\"Linewidth and markersize\")\n", - "ax.set_legend(True)\n", + "canvas.set_xlabel(\"x\")\n", + "canvas.set_title(\"Linewidth and markersize\")\n", + "canvas.set_legend(True)\n", "canvas.show(backend=BACKEND)" ] }, @@ -208,15 +208,15 @@ "source": [ "x = np.linspace(0, 2 * np.pi, 200)\n", "\n", - "canvas, ax = Canvas.subplots(width=\"10cm\", ratio=0.55)\n", + "canvas = Canvas(width=\"10cm\", ratio=0.55)\n", "\n", - "ax.fill_between(x, np.sin(x), 0, alpha=0.7, color=\"steelblue\", label=\"alpha=0.7\")\n", - "ax.fill_between(x, np.sin(2 * x), 0, alpha=0.4, color=\"tomato\", label=\"alpha=0.4\")\n", - "ax.fill_between(x, np.sin(3 * x), 0, alpha=0.2, color=\"seagreen\", label=\"alpha=0.2\")\n", + "canvas.fill_between(x, np.sin(x), 0, alpha=0.7, color=\"steelblue\", label=\"alpha=0.7\")\n", + "canvas.fill_between(x, np.sin(2 * x), 0, alpha=0.4, color=\"tomato\", label=\"alpha=0.4\")\n", + "canvas.fill_between(x, np.sin(3 * x), 0, alpha=0.2, color=\"seagreen\", label=\"alpha=0.2\")\n", "\n", - "ax.set_xlabel(\"x\")\n", - "ax.set_title(\"Alpha transparency\")\n", - "ax.set_legend(True)\n", + "canvas.set_xlabel(\"x\")\n", + "canvas.set_title(\"Alpha transparency\")\n", + "canvas.set_legend(True)\n", "canvas.show(backend=BACKEND)" ] }, @@ -240,18 +240,18 @@ "x = np.linspace(0, 2 * np.pi, 80)\n", "noise = np.random.default_rng(0).normal(0, 0.05, len(x))\n", "\n", - "canvas, ax = Canvas.subplots(width=\"10cm\", ratio=0.6)\n", + "canvas = Canvas(width=\"10cm\", ratio=0.6)\n", "\n", "# Shaded uncertainty band\n", - "ax.fill_between(x, np.sin(x) - 0.15, np.sin(x) + 0.15, alpha=0.15, color=\"steelblue\")\n", + "canvas.fill_between(x, np.sin(x) - 0.15, np.sin(x) + 0.15, alpha=0.15, color=\"steelblue\")\n", "\n", "# Noisy data\n", - "ax.scatter(\n", + "canvas.scatter(\n", " x, np.sin(x) + noise, color=\"steelblue\", marker=\"o\", s=18, alpha=0.6, label=\"data\"\n", ")\n", "\n", "# Clean model\n", - "ax.plot(\n", + "canvas.add_line(\n", " x,\n", " np.sin(x),\n", " color=\"#e74c3c\",\n", @@ -261,10 +261,10 @@ " label=\"model\",\n", ")\n", "\n", - "ax.set_xlabel(\"x\")\n", - "ax.set_ylabel(\"y\")\n", - "ax.set_title(\"Publication-style plot\")\n", - "ax.set_legend(True)\n", + "canvas.set_xlabel(\"x\")\n", + "canvas.set_ylabel(\"y\")\n", + "canvas.set_title(\"Publication-style plot\")\n", + "canvas.set_legend(True)\n", "canvas.show(backend=BACKEND)" ] }, diff --git a/tutorials/tutorial_05.ipynb b/tutorials/tutorial_05.ipynb index 6c16f4e..0cf0467 100644 --- a/tutorials/tutorial_05.ipynb +++ b/tutorials/tutorial_05.ipynb @@ -67,12 +67,12 @@ "source": [ "x = np.linspace(0, 2 * np.pi, 200)\n", "\n", - "canvas, ax = Canvas.subplots(width=\"10cm\", ratio=0.55)\n", - "ax.plot(x, np.sin(x), color=\"steelblue\")\n", + "canvas = Canvas(width=\"10cm\", ratio=0.55)\n", + "canvas.add_line(x, np.sin(x), color=\"steelblue\")\n", "\n", - "ax.set_xlabel(r\"$x$ (radians)\")\n", - "ax.set_ylabel(r\"$\\sin(x)$\")\n", - "ax.set_title(r\"The sine function $f(x) = \\sin(x)$\")\n", + "canvas.set_xlabel(r\"$x$ (radians)\")\n", + "canvas.set_ylabel(r\"$\\sin(x)$\")\n", + "canvas.set_title(r\"The sine function $f(x) = \\sin(x)$\")\n", "canvas.show(backend=BACKEND)" ] }, @@ -93,16 +93,16 @@ "source": [ "x = np.linspace(0, 4 * np.pi, 300)\n", "\n", - "canvas, ax = Canvas.subplots(width=\"10cm\", ratio=0.5)\n", - "ax.plot(x, np.sin(x), color=\"tomato\")\n", + "canvas = Canvas(width=\"10cm\", ratio=0.5)\n", + "canvas.add_line(x, np.sin(x), color=\"tomato\")\n", "\n", "# Show only the first full period\n", - "ax.set_xlim(0, 2 * np.pi)\n", - "ax.set_ylim(-1.2, 1.2)\n", + "canvas.set_xlim(0, 2 * np.pi)\n", + "canvas.set_ylim(-1.2, 1.2)\n", "\n", - "ax.set_xlabel(\"x\")\n", - "ax.set_ylabel(r\"$\\sin(x)$\")\n", - "ax.set_title(\"Axis limits: first period only\")\n", + "canvas.set_xlabel(\"x\")\n", + "canvas.set_ylabel(r\"$\\sin(x)$\")\n", + "canvas.set_title(\"Axis limits: first period only\")\n", "canvas.show(backend=BACKEND)" ] }, @@ -139,12 +139,12 @@ "]\n", "temps = [3, 4, 7, 12, 17, 21, 23, 22, 18, 13, 7, 4]\n", "\n", - "canvas, ax = Canvas.subplots(width=\"12cm\", ratio=0.45)\n", - "ax.plot(range(12), temps, marker=\"o\", color=\"steelblue\", linewidth=2)\n", + "canvas = Canvas(width=\"12cm\", ratio=0.45)\n", + "canvas.add_line(range(12), temps, marker=\"o\", color=\"steelblue\", linewidth=2)\n", "\n", - "ax.set_xticks(list(range(12)), labels=months)\n", - "ax.set_ylabel(r\"Temperature ($^\\circ$C)\")\n", - "ax.set_title(\"Monthly average temperature\")\n", + "canvas.set_xticks(list(range(12)), labels=months)\n", + "canvas.set_ylabel(r\"Temperature ($^\\circ$C)\")\n", + "canvas.set_title(\"Monthly average temperature\")\n", "canvas.show(backend=BACKEND)" ] }, @@ -234,14 +234,14 @@ "source": [ "x = np.linspace(0, 2 * np.pi, 200)\n", "\n", - "canvas, ax = Canvas.subplots(width=\"10cm\", ratio=0.55)\n", - "ax.plot(x, np.sin(x), color=\"steelblue\", label=r\"$\\sin(x)$\")\n", - "ax.plot(x, np.cos(x), color=\"tomato\", label=r\"$\\cos(x)$\")\n", - "ax.plot(x, np.sin(2 * x), color=\"seagreen\", label=r\"$\\sin(2x)$\", linestyle=\"dashed\")\n", + "canvas = Canvas(width=\"10cm\", ratio=0.55)\n", + "canvas.add_line(x, np.sin(x), color=\"steelblue\", label=r\"$\\sin(x)$\")\n", + "canvas.add_line(x, np.cos(x), color=\"tomato\", label=r\"$\\cos(x)$\")\n", + "canvas.add_line(x, np.sin(2 * x), color=\"seagreen\", label=r\"$\\sin(2x)$\", linestyle=\"dashed\")\n", "\n", - "ax.set_xlabel(\"x\")\n", - "ax.set_legend(True)\n", - "ax.set_title(\"Legend demo\")\n", + "canvas.set_xlabel(\"x\")\n", + "canvas.set_legend(True)\n", + "canvas.set_title(\"Legend demo\")\n", "canvas.show(backend=BACKEND)" ] }, @@ -265,11 +265,11 @@ "x = np.linspace(0, 2 * np.pi, 200)\n", "y = np.sin(x)\n", "\n", - "canvas, ax = Canvas.subplots(width=\"10cm\", ratio=0.55)\n", - "ax.plot(x, y, color=\"steelblue\")\n", + "canvas = Canvas(width=\"10cm\", ratio=0.55)\n", + "canvas.add_line(x, y, color=\"steelblue\")\n", "\n", "# Annotate the maximum\n", - "ax.annotate(\n", + "canvas.annotate(\n", " r\"maximum $\\approx 1$\",\n", " xy=(np.pi / 2, 1.0),\n", " xytext=(np.pi / 2 + 1.0, 0.7),\n", @@ -278,9 +278,9 @@ " color=\"darkred\",\n", ")\n", "\n", - "ax.set_xlabel(\"x\")\n", - "ax.set_ylabel(r\"$\\sin(x)$\")\n", - "ax.set_title(\"annotate demo\")\n", + "canvas.set_xlabel(\"x\")\n", + "canvas.set_ylabel(r\"$\\sin(x)$\")\n", + "canvas.set_title(\"annotate demo\")\n", "canvas.show(backend=BACKEND)" ] }, @@ -303,16 +303,16 @@ "source": [ "x = np.linspace(-2, 2, 200)\n", "\n", - "canvas, ax = Canvas.subplots(width=\"10cm\", ratio=0.55)\n", - "ax.plot(x, x**2, color=\"darkorange\")\n", + "canvas = Canvas(width=\"10cm\", ratio=0.55)\n", + "canvas.add_line(x, x**2, color=\"darkorange\")\n", "\n", - "ax.text(\n", + "canvas.text(\n", " 0, 3.2, r\"$f(x) = x^2$\", ha=\"center\", va=\"bottom\", fontsize=12, color=\"darkorange\"\n", ")\n", "\n", - "ax.set_xlabel(\"x\")\n", - "ax.set_ylabel(r\"$f(x)$\")\n", - "ax.set_title(\"text demo\")\n", + "canvas.set_xlabel(\"x\")\n", + "canvas.set_ylabel(r\"$f(x)$\")\n", + "canvas.set_title(\"text demo\")\n", "canvas.show(backend=BACKEND)" ] }, @@ -335,12 +335,12 @@ "source": [ "theta = np.linspace(0, 2 * np.pi, 300)\n", "\n", - "canvas, ax = Canvas.subplots(width=\"7cm\", ratio=1.0)\n", - "ax.plot(np.cos(theta), np.sin(theta), color=\"steelblue\", linewidth=2)\n", - "ax.set_aspect(\"equal\")\n", - "ax.set_title(\"Circle with equal aspect ratio\")\n", - "ax.set_xlabel(\"x\")\n", - "ax.set_ylabel(\"y\")\n", + "canvas = Canvas(width=\"7cm\", ratio=1.0)\n", + "canvas.add_line(np.cos(theta), np.sin(theta), color=\"steelblue\", linewidth=2)\n", + "canvas.set_aspect(\"equal\")\n", + "canvas.set_title(\"Circle with equal aspect ratio\")\n", + "canvas.set_xlabel(\"x\")\n", + "canvas.set_ylabel(\"y\")\n", "canvas.show(backend=BACKEND)" ] }, diff --git a/tutorials/tutorial_06.ipynb b/tutorials/tutorial_06.ipynb index 6902623..c24c205 100644 --- a/tutorials/tutorial_06.ipynb +++ b/tutorials/tutorial_06.ipynb @@ -67,11 +67,11 @@ "source": [ "x = np.linspace(0, 2 * np.pi, 200)\n", "\n", - "canvas, ax = Canvas.subplots(width=\"10cm\", ratio=0.55)\n", + "canvas = Canvas(width=\"10cm\", ratio=0.55)\n", "\n", - "ax.plot(x, np.sin(x), color=\"steelblue\", label=r\"$\\sin(x)$\", layer=0)\n", - "ax.plot(x, np.cos(x), color=\"tomato\", label=r\"$\\cos(x)$\", layer=1)\n", - "ax.plot(\n", + "canvas.add_line(x, np.sin(x), color=\"steelblue\", label=r\"$\\sin(x)$\", layer=0)\n", + "canvas.add_line(x, np.cos(x), color=\"tomato\", label=r\"$\\cos(x)$\", layer=1)\n", + "canvas.add_line(\n", " x,\n", " np.sin(x) * np.cos(x),\n", " color=\"seagreen\",\n", @@ -80,9 +80,9 @@ " layer=2,\n", ")\n", "\n", - "ax.set_xlabel(\"x\")\n", - "ax.set_legend(True)\n", - "ax.set_title(\"Three curves on three layers\")\n", + "canvas.set_xlabel(\"x\")\n", + "canvas.set_legend(True)\n", + "canvas.set_title(\"Three curves on three layers\")\n", "canvas.show(backend=BACKEND) # renders all layers by default" ] }, @@ -105,11 +105,11 @@ "source": [ "x = np.linspace(0, 2 * np.pi, 200)\n", "\n", - "canvas, ax = Canvas.subplots(width=\"10cm\", ratio=0.55)\n", + "canvas = Canvas(width=\"10cm\", ratio=0.55)\n", "\n", - "ax.plot(x, np.sin(x), color=\"steelblue\", label=r\"$\\sin(x)$\", layer=0)\n", - "ax.plot(x, np.cos(x), color=\"tomato\", label=r\"$\\cos(x)$\", layer=1)\n", - "ax.plot(\n", + "canvas.add_line(x, np.sin(x), color=\"steelblue\", label=r\"$\\sin(x)$\", layer=0)\n", + "canvas.add_line(x, np.cos(x), color=\"tomato\", label=r\"$\\cos(x)$\", layer=1)\n", + "canvas.add_line(\n", " x,\n", " np.sin(x) * np.cos(x),\n", " color=\"seagreen\",\n", @@ -118,11 +118,11 @@ " layer=2,\n", ")\n", "\n", - "ax.set_xlabel(\"x\")\n", - "ax.set_legend(True)\n", + "canvas.set_xlabel(\"x\")\n", + "canvas.set_legend(True)\n", "\n", "print(\"--- Layer 0 only ---\")\n", - "ax.set_title(\"Layer 0 only\")\n", + "canvas.set_title(\"Layer 0 only\")\n", "\n", "canvas.show(backend=BACKEND, layers=[0])" ] @@ -135,7 +135,7 @@ "outputs": [], "source": [ "# Same canvas — now show layers 0 and 1 together\n", - "ax.set_title(\"Layers 0 and 1\")\n", + "canvas.set_title(\"Layers 0 and 1\")\n", "\n", "canvas.show(backend=BACKEND, layers=[0, 1])" ] @@ -148,7 +148,7 @@ "outputs": [], "source": [ "# All layers\n", - "ax.set_title(\"All layers\")\n", + "canvas.set_title(\"All layers\")\n", "\n", "canvas.show(backend=BACKEND, layers=[0, 1, 2])" ] @@ -202,18 +202,18 @@ "source": [ "x = np.linspace(0, 2 * np.pi, 300)\n", "\n", - "canvas, ax = Canvas.subplots(width=\"11cm\", ratio=0.6)\n", + "canvas = Canvas(width=\"11cm\", ratio=0.6)\n", "\n", "# Layer 0: raw data (noisy sine)\n", "rng = np.random.default_rng(42)\n", "y_data = np.sin(x) + rng.normal(0, 0.15, len(x))\n", - "ax.scatter(x, y_data, color=\"gray\", s=8, alpha=0.5, label=\"measured data\", layer=0)\n", + "canvas.scatter(x, y_data, color=\"gray\", s=8, alpha=0.5, label=\"measured data\", layer=0)\n", "\n", "# Layer 1: true function\n", - "ax.plot(x, np.sin(x), color=\"steelblue\", linewidth=2, label=r\"true: $\\sin(x)$\", layer=1)\n", + "canvas.add_line(x, np.sin(x), color=\"steelblue\", linewidth=2, label=r\"true: $\\sin(x)$\", layer=1)\n", "\n", "# Layer 2: envelope\n", - "ax.fill_between(\n", + "canvas.fill_between(\n", " x,\n", " np.sin(x) - 0.15,\n", " np.sin(x) + 0.15,\n", @@ -223,12 +223,12 @@ " layer=2,\n", ")\n", "\n", - "ax.set_xlabel(\"x\")\n", - "ax.set_ylabel(\"y\")\n", - "ax.set_legend(True)\n", + "canvas.set_xlabel(\"x\")\n", + "canvas.set_ylabel(\"y\")\n", + "canvas.set_legend(True)\n", "\n", "# Step 1: only the data cloud\n", - "ax.set_title(\"Step 1 – raw data\")\n", + "canvas.set_title(\"Step 1 – raw data\")\n", "canvas.show(backend=BACKEND, layers=[0])" ] }, @@ -240,7 +240,7 @@ "outputs": [], "source": [ "# Step 2: add the true curve\n", - "ax.set_title(\"Step 2 – add true function\")\n", + "canvas.set_title(\"Step 2 – add true function\")\n", "canvas.show(backend=BACKEND, layers=[0, 1])" ] }, @@ -252,7 +252,7 @@ "outputs": [], "source": [ "# Step 3: add the uncertainty envelope\n", - "ax.set_title(\"Step 3 – add uncertainty envelope\")\n", + "canvas.set_title(\"Step 3 – add uncertainty envelope\")\n", "canvas.show(backend=BACKEND, layers=[0, 1, 2])" ] }, @@ -265,7 +265,7 @@ "\n", "| Concept | How |\n", "|---|---|\n", - "| Assign to layer | `ax.plot(..., layer=1)` |\n", + "| Assign to layer | `canvas.add_line(..., layer=1)` |\n", "| Render subset | `canvas.show(layers=[0, 1])` |\n", "| Save all layers | `canvas.savefig('fig.pdf', layer_by_layer=True)` |\n", "| Default layer | `0` (omit `layer=` and it goes to layer 0) |\n", diff --git a/tutorials/tutorial_07_tikz.ipynb b/tutorials/tutorial_07_tikz.ipynb index 078e321..3a85ad8 100644 --- a/tutorials/tutorial_07_tikz.ipynb +++ b/tutorials/tutorial_07_tikz.ipynb @@ -67,12 +67,12 @@ "source": [ "x = np.linspace(0, 2 * np.pi, 60)\n", "\n", - "canvas, ax = Canvas.subplots(width=\"10cm\", ratio=0.6)\n", - "ax.plot(x, np.sin(x), label=\"sin\", color=\"steelblue\", line_width=1.5)\n", - "ax.plot(x, np.cos(x), label=\"cos\", color=\"tomato\", line_width=1.2)\n", - "ax.set_xlabel(\"x\")\n", - "ax.set_ylabel(\"y\")\n", - "ax.set_title(\"Trigonometric functions\")\n", + "canvas = Canvas(width=\"10cm\", ratio=0.6)\n", + "canvas.add_line(x, np.sin(x), label=\"sin\", color=\"steelblue\", line_width=1.5)\n", + "canvas.add_line(x, np.cos(x), label=\"cos\", color=\"tomato\", line_width=1.2)\n", + "canvas.set_xlabel(\"x\")\n", + "canvas.set_ylabel(\"y\")\n", + "canvas.set_title(\"Trigonometric functions\")\n", "\n", "# backend='tikzfigure' returns a TikzFigure object\n", "tikz = canvas.plot(backend=\"tikzfigure\")\n", @@ -287,12 +287,12 @@ "\n", "| Feature | Supported? |\n", "|---|---|\n", - "| Line plots (`ax.plot`) | ✅ |\n", + "| Line plots (`canvas.plot`) | ✅ |\n", "| Layer filtering | ✅ |\n", "| `line_width=` kwarg | ✅ |\n", "| Multiple subplots | ❌ (raises `NotImplementedError`) |\n", - "| `ax.scatter`, `ax.bar` | ❌ (silently ignored) |\n", - "| `ax.fill_between` | ❌ |\n", + "| `canvas.scatter`, `canvas.bar` | ❌ (silently ignored) |\n", + "| `canvas.fill_between` | ❌ |\n", "| Axis labels / titles | ❌ (TikZ has no axis frame by default) |\n", "\n", "For anything beyond line plots, use the `tikzfigure` API directly (Part 2 below)." @@ -716,8 +716,8 @@ "\n", "### Canvas → TikZ workflow\n", "```python\n", - "canvas, ax = Canvas.subplots(width='10cm', ratio=0.6)\n", - "ax.plot(x, y, color='steelblue', line_width=1.5)\n", + "canvas = Canvas(width='10cm', ratio=0.6)\n", + "canvas.add_line(x, y, color='steelblue', line_width=1.5)\n", "tikz = canvas.plot(backend='tikzfigure')\n", "print(tikz.generate_tikz()) # inspect LaTeX\n", "tikz.show() # render (needs pdflatex)\n", diff --git a/tutorials/tutorial_08_plotly.ipynb b/tutorials/tutorial_08_plotly.ipynb index 2ecf2ef..a065c19 100644 --- a/tutorials/tutorial_08_plotly.ipynb +++ b/tutorials/tutorial_08_plotly.ipynb @@ -106,7 +106,7 @@ "source": [ "## 2 · Multiple lines\n", "\n", - "Each `ax.plot()` call becomes a separate Plotly trace. Enable the legend with `ax.set_legend(True)` so trace labels appear." + "Each `canvas.add_line()` call becomes a separate Plotly trace. Enable the legend with `canvas.set_legend(True)` so trace labels appear." ] }, { @@ -146,7 +146,7 @@ "source": [ "## 3 · Scatter plot\n", "\n", - "`ax.scatter()` maps to a Plotly scatter trace with markers only." + "`canvas.scatter()` maps to a Plotly scatter trace with markers only." ] }, { @@ -190,7 +190,7 @@ "source": [ "## 4 · Bar chart\n", "\n", - "`ax.bar()` maps to a Plotly bar trace." + "`canvas.bar()` maps to a Plotly bar trace." ] }, { @@ -320,7 +320,7 @@ "source": [ "## 7 · Log scale\n", "\n", - "`ax.set_yscale('log')` is passed through to Plotly's axis type." + "`canvas.set_yscale('log')` is passed through to Plotly's axis type." ] }, { @@ -389,16 +389,16 @@ "\n", "| Feature | Supported | Notes |\n", "|---|---|---|\n", - "| `ax.plot()` — line trace | ✅ | `color`, `linestyle`, `linewidth`, `marker` all passed through |\n", - "| `ax.scatter()` — markers | ✅ | `color`, `marker`, `s`, `alpha` |\n", - "| `ax.bar()` — bar chart | ✅ | `color`, `alpha` |\n", - "| `ax.fill_between()` | ❌ | Not supported by this backend |\n", - "| `ax.errorbar()` | ❌ | Not supported by this backend |\n", - "| `ax.axhline/axvline` | ❌ | Not supported by this backend |\n", + "| `canvas.add_line()` — line trace | ✅ | `color`, `linestyle`, `linewidth`, `marker` all passed through |\n", + "| `canvas.scatter()` — markers | ✅ | `color`, `marker`, `s`, `alpha` |\n", + "| `canvas.bar()` — bar chart | ✅ | `color`, `alpha` |\n", + "| `canvas.fill_between()` | ❌ | Not supported by this backend |\n", + "| `canvas.errorbar()` | ❌ | Not supported by this backend |\n", + "| `canvas.axhline/axvline` | ❌ | Not supported by this backend |\n", "| Multi-subplot canvas | ✅ | `Canvas.subplots(ncols=...)` etc. |\n", "| `canvas.suptitle()` | ✅ | Maps to figure title |\n", - "| `ax.set_yscale('log')` | ✅ | |\n", - "| `ax.set_legend(True)` | ✅ | |\n", + "| `canvas.set_yscale('log')` | ✅ | |\n", + "| `canvas.set_legend(True)` | ✅ | |\n", "| `fig.show()` | ✅ | Interactive in Jupyter |\n", "| `fig.write_html(path)` | ✅ | Standalone interactive HTML |\n", "\n", @@ -408,9 +408,9 @@ "from maxplotlib import Canvas\n", "import numpy as np\n", "\n", - "canvas, ax = Canvas.subplots()\n", - "ax.plot(x, y, label='data')\n", - "ax.set_legend(True)\n", + "canvas = Canvas()\n", + "canvas.add_line(x, y, label='data')\n", + "canvas.set_legend(True)\n", "\n", "fig = canvas.plot(backend='plotly') # → plotly.graph_objects.Figure\n", "fig.show() # interactive in Jupyter\n", diff --git a/tutorials/tutorial_09_plotext.ipynb b/tutorials/tutorial_09_plotext.ipynb index e395ded..4b6276b 100644 --- a/tutorials/tutorial_09_plotext.ipynb +++ b/tutorials/tutorial_09_plotext.ipynb @@ -73,11 +73,11 @@ "source": [ "x = np.linspace(0, 2 * np.pi, 100)\n", "\n", - "canvas, ax = Canvas.subplots()\n", - "ax.plot(x, np.sin(x), color=\"cyan\", label=\"sin(x)\")\n", - "ax.set_title(\"Demo\")\n", - "ax.set_xlabel(\"x\")\n", - "ax.set_ylabel(\"y\")\n", + "canvas = Canvas()\n", + "canvas.add_line(x, np.sin(x), color=\"cyan\", label=\"sin(x)\")\n", + "canvas.set_title(\"Demo\")\n", + "canvas.set_xlabel(\"x\")\n", + "canvas.set_ylabel(\"y\")\n", "\n", "terminal_fig = canvas.plot(backend=\"plotext\")\n", "preview = terminal_fig.build(keep_colors=False)\n", @@ -106,15 +106,15 @@ "source": [ "x = np.linspace(0, 2 * np.pi, 120)\n", "\n", - "canvas, ax = Canvas.subplots()\n", - "ax.plot(x, np.sin(x), color=\"cyan\", label=\"sin(x)\")\n", - "ax.plot(x, np.cos(x), color=\"yellow\", label=\"cos(x)\", marker=\"dot\")\n", - "ax.plot(x, np.sin(2 * x), color=\"green\", label=\"sin(2x)\")\n", - "ax.set_title(\"Multiple terminal lines\")\n", - "ax.set_xlabel(\"x\")\n", - "ax.set_ylabel(\"value\")\n", - "ax.set_grid(True)\n", - "ax.set_legend(True)\n", + "canvas = Canvas()\n", + "canvas.add_line(x, np.sin(x), color=\"cyan\", label=\"sin(x)\")\n", + "canvas.add_line(x, np.cos(x), color=\"yellow\", label=\"cos(x)\", marker=\"dot\")\n", + "canvas.add_line(x, np.sin(2 * x), color=\"green\", label=\"sin(2x)\")\n", + "canvas.set_title(\"Multiple terminal lines\")\n", + "canvas.set_xlabel(\"x\")\n", + "canvas.set_ylabel(\"value\")\n", + "canvas.set_grid(True)\n", + "canvas.set_legend(True)\n", "\n", "print(canvas.plot(backend=\"plotext\").build(keep_colors=False))" ] @@ -141,13 +141,13 @@ "samples_x = np.linspace(0, 8, 15)\n", "samples_y = np.sin(samples_x) + rng.normal(0, 0.15, len(samples_x))\n", "\n", - "canvas, ax = Canvas.subplots()\n", - "ax.plot(x, np.sin(x), color=\"white\", label=\"sin(x)\")\n", - "ax.scatter(samples_x, samples_y, color=\"red\", marker=\"x\", label=\"samples\")\n", - "ax.set_title(\"Scatter + line\")\n", - "ax.set_xlabel(\"x\")\n", - "ax.set_ylabel(\"y\")\n", - "ax.set_legend(True)\n", + "canvas = Canvas()\n", + "canvas.add_line(x, np.sin(x), color=\"white\", label=\"sin(x)\")\n", + "canvas.scatter(samples_x, samples_y, color=\"red\", marker=\"x\", label=\"samples\")\n", + "canvas.set_title(\"Scatter + line\")\n", + "canvas.set_xlabel(\"x\")\n", + "canvas.set_ylabel(\"y\")\n", + "canvas.set_legend(True)\n", "\n", "print(canvas.plot(backend=\"plotext\").build(keep_colors=False))" ] @@ -172,13 +172,13 @@ "bins = np.arange(5)\n", "values = np.array([4.0, 6.5, 3.2, 7.4, 5.8])\n", "\n", - "canvas, ax = Canvas.subplots()\n", - "ax.bar(bins, values, color=\"green\", label=\"count\")\n", - "ax.scatter(bins, values, color=\"yellow\", label=\"sample mean\")\n", - "ax.set_title(\"Bar + scatter overlay\")\n", - "ax.set_xlabel(\"bin\")\n", - "ax.set_ylabel(\"value\")\n", - "ax.set_legend(True)\n", + "canvas = Canvas()\n", + "canvas.bar(bins, values, color=\"green\", label=\"count\")\n", + "canvas.scatter(bins, values, color=\"yellow\", label=\"sample mean\")\n", + "canvas.set_title(\"Bar + scatter overlay\")\n", + "canvas.set_xlabel(\"bin\")\n", + "canvas.set_ylabel(\"value\")\n", + "canvas.set_legend(True)\n", "\n", "print(canvas.plot(backend=\"plotext\").build(keep_colors=False))" ] @@ -205,18 +205,18 @@ "source": [ "x = np.linspace(0, 5, 100)\n", "\n", - "canvas, ax = Canvas.subplots()\n", - "ax.fill_between(\n", + "canvas = Canvas()\n", + "canvas.fill_between(\n", " x,\n", " np.exp(-0.5 * x) * np.sin(3 * x) + 1.0,\n", " 0.0,\n", " color=\"cyan\",\n", " label=\"signal envelope\",\n", ")\n", - "ax.set_title(\"fill_between() to a scalar baseline\")\n", - "ax.set_xlabel(\"x\")\n", - "ax.set_ylabel(\"amplitude\")\n", - "ax.set_legend(True)\n", + "canvas.set_title(\"fill_between() to a scalar baseline\")\n", + "canvas.set_xlabel(\"x\")\n", + "canvas.set_ylabel(\"amplitude\")\n", + "canvas.set_legend(True)\n", "\n", "print(canvas.plot(backend=\"plotext\").build(keep_colors=False))" ] @@ -232,12 +232,12 @@ "upper = np.sin(x) + 1.8\n", "lower = np.cos(x) + 0.8\n", "\n", - "canvas, ax = Canvas.subplots()\n", - "ax.fill_between(x, upper, lower, color=\"blue\", label=\"between curves\")\n", - "ax.plot(x, upper, color=\"white\", label=\"upper\")\n", - "ax.plot(x, lower, color=\"yellow\", label=\"lower\")\n", - "ax.set_title(\"fill_between() between two curves\")\n", - "ax.set_legend(True)\n", + "canvas = Canvas()\n", + "canvas.fill_between(x, upper, lower, color=\"blue\", label=\"between curves\")\n", + "canvas.add_line(x, upper, color=\"white\", label=\"upper\")\n", + "canvas.add_line(x, lower, color=\"yellow\", label=\"lower\")\n", + "canvas.set_title(\"fill_between() between two curves\")\n", + "canvas.set_legend(True)\n", "\n", "print(canvas.plot(backend=\"plotext\").build(keep_colors=False))" ] @@ -262,16 +262,16 @@ "x = np.linspace(1, 10, 9)\n", "y = np.sqrt(x)\n", "\n", - "canvas, ax = Canvas.subplots()\n", - "ax.errorbar(x, y, yerr=0.15, color=\"cyan\", label=\"sqrt(x)\")\n", - "ax.axhline(2.0, color=\"white\")\n", - "ax.axvline(4.0, color=\"yellow\")\n", - "ax.hlines([1.2, 2.7], xmin=[1, 5], xmax=[3, 9], color=\"green\")\n", - "ax.vlines([2.0, 8.0], ymin=[1.0, 2.0], ymax=[1.8, 3.0], color=\"red\")\n", - "ax.set_title(\"Error bars + reference lines\")\n", - "ax.set_xlabel(\"x\")\n", - "ax.set_ylabel(\"y\")\n", - "ax.set_legend(True)\n", + "canvas = Canvas()\n", + "canvas.errorbar(x, y, yerr=0.15, color=\"cyan\", label=\"sqrt(x)\")\n", + "canvas.axhline(2.0, color=\"white\")\n", + "canvas.axvline(4.0, color=\"yellow\")\n", + "canvas.hlines([1.2, 2.7], xmin=[1, 5], xmax=[3, 9], color=\"green\")\n", + "canvas.vlines([2.0, 8.0], ymin=[1.0, 2.0], ymax=[1.8, 3.0], color=\"red\")\n", + "canvas.set_title(\"Error bars + reference lines\")\n", + "canvas.set_xlabel(\"x\")\n", + "canvas.set_ylabel(\"y\")\n", + "canvas.set_legend(True)\n", "\n", "print(canvas.plot(backend=\"plotext\").build(keep_colors=False))" ] @@ -298,17 +298,17 @@ "peak_x = x[np.argmax(y)]\n", "peak_y = y.max()\n", "\n", - "canvas, ax = Canvas.subplots()\n", - "ax.plot(x, y, color=\"cyan\")\n", - "ax.text(0.8, -0.8, \"terminal note\", color=\"yellow\")\n", - "ax.annotate(\n", + "canvas = Canvas()\n", + "canvas.add_line(x, y, color=\"cyan\")\n", + "canvas.text(0.8, -0.8, \"terminal note\", color=\"yellow\")\n", + "canvas.annotate(\n", " \"peak\",\n", " xy=(peak_x, peak_y),\n", " xytext=(4.4, 0.4),\n", " color=\"white\",\n", " arrowprops={\"color\": \"green\"},\n", ")\n", - "ax.set_title(\"Text and annotations\")\n", + "canvas.set_title(\"Text and annotations\")\n", "\n", "print(canvas.plot(backend=\"plotext\").build(keep_colors=False))" ] @@ -332,19 +332,19 @@ "source": [ "x = np.linspace(1, 20, 120)\n", "\n", - "canvas, ax = Canvas.subplots()\n", - "ax.plot(x, x**0.5, color=\"cyan\", label=\"sqrt(x)\")\n", - "ax.plot(x, np.log(x + 1), color=\"yellow\", label=\"log(x + 1)\")\n", - "ax.set_title(\"Axis controls\")\n", - "ax.set_xlabel(\"x\")\n", - "ax.set_ylabel(\"value\")\n", - "ax.set_xlim(1, 20)\n", - "ax.set_ylim(0, 5)\n", - "ax.set_xticks([1, 2, 5, 10, 20], [\"1\", \"2\", \"5\", \"10\", \"20\"])\n", - "ax.set_yticks([0, 1, 2, 3, 4, 5])\n", - "ax.set_xscale(\"log\")\n", - "ax.set_grid(True)\n", - "ax.set_legend(True)\n", + "canvas = Canvas()\n", + "canvas.add_line(x, x**0.5, color=\"cyan\", label=\"sqrt(x)\")\n", + "canvas.add_line(x, np.log(x + 1), color=\"yellow\", label=\"log(x + 1)\")\n", + "canvas.set_title(\"Axis controls\")\n", + "canvas.set_xlabel(\"x\")\n", + "canvas.set_ylabel(\"value\")\n", + "canvas.set_xlim(1, 20)\n", + "canvas.set_ylim(0, 5)\n", + "canvas.set_xticks([1, 2, 5, 10, 20], [\"1\", \"2\", \"5\", \"10\", \"20\"])\n", + "canvas.set_yticks([0, 1, 2, 3, 4, 5])\n", + "canvas.set_xscale(\"log\")\n", + "canvas.set_grid(True)\n", + "canvas.set_legend(True)\n", "\n", "print(canvas.plot(backend=\"plotext\").build(keep_colors=False))" ] @@ -368,12 +368,12 @@ "source": [ "x = np.linspace(0, 2 * np.pi, 100)\n", "\n", - "canvas, ax = Canvas.subplots()\n", - "ax.plot(x, np.sin(x), color=\"cyan\", label=\"layer 0\", layer=0)\n", - "ax.plot(x, np.cos(x), color=\"yellow\", label=\"layer 1\", layer=1)\n", - "ax.fill_between(x, np.sin(x) + 1.5, 0.0, color=\"green\", label=\"layer 2\", layer=2)\n", - "ax.set_title(\"Layers 0 and 1 only\")\n", - "ax.set_legend(True)" + "canvas = Canvas()\n", + "canvas.add_line(x, np.sin(x), color=\"cyan\", label=\"layer 0\", layer=0)\n", + "canvas.add_line(x, np.cos(x), color=\"yellow\", label=\"layer 1\", layer=1)\n", + "canvas.fill_between(x, np.sin(x) + 1.5, 0.0, color=\"green\", label=\"layer 2\", layer=2)\n", + "canvas.set_title(\"Layers 0 and 1 only\")\n", + "canvas.set_legend(True)" ] }, { @@ -467,11 +467,11 @@ "source": [ "data = np.arange(1, 26).reshape(5, 5)\n", "\n", - "canvas, ax = Canvas.subplots()\n", - "ax.add_imshow(data)\n", - "ax.set_title(\"Matrix-style imshow\")\n", - "ax.set_xlabel(\"column\")\n", - "ax.set_ylabel(\"row\")\n", + "canvas = Canvas()\n", + "canvas.imshow(data)\n", + "canvas.set_title(\"Matrix-style imshow\")\n", + "canvas.set_xlabel(\"column\")\n", + "canvas.set_ylabel(\"row\")\n", "\n", "print(canvas.plot(backend=\"plotext\").build(keep_colors=False))" ] @@ -501,16 +501,16 @@ "metadata": {}, "outputs": [], "source": [ - "canvas, ax = Canvas.subplots()\n", - "ax.add_patch(\n", + "canvas = Canvas()\n", + "canvas.add_patch(\n", " mpatches.Rectangle(\n", " (0.2, 0.2), 1.3, 0.7, fill=False, edgecolor=\"yellow\", label=\"window\"\n", " )\n", ")\n", - "ax.add_patch(\n", + "canvas.add_patch(\n", " mpatches.Circle((2.2, 1.6), 0.45, fill=False, edgecolor=\"cyan\", label=\"sensor\")\n", ")\n", - "ax.add_patch(\n", + "canvas.add_patch(\n", " mpatches.Polygon(\n", " [[3.0, 0.5], [3.8, 1.2], [3.4, 2.0]],\n", " fill=True,\n", @@ -518,15 +518,15 @@ " label=\"region\",\n", " )\n", ")\n", - "ax.add_patch(\n", + "canvas.add_patch(\n", " mpatches.Ellipse(\n", " (2.8, 1.0), 0.8, 0.5, fill=False, edgecolor=\"white\", label=\"ellipse\"\n", " )\n", ")\n", - "ax.set_xlim(0, 4.5)\n", - "ax.set_ylim(0, 2.5)\n", - "ax.set_title(\"Supported patch types\")\n", - "ax.set_legend(True)\n", + "canvas.set_xlim(0, 4.5)\n", + "canvas.set_ylim(0, 2.5)\n", + "canvas.set_title(\"Supported patch types\")\n", + "canvas.set_legend(True)\n", "\n", "print(canvas.plot(backend=\"plotext\").build(keep_colors=False))" ] @@ -578,14 +578,14 @@ "source": [ "x = np.linspace(-20, 20, 161)\n", "\n", - "canvas, ax = Canvas.subplots()\n", - "ax.plot(x, x**3, color=\"cyan\", label=\"x^3\")\n", - "ax.set_title(\"Symlog example\")\n", - "ax.add_caption(\"caption text\")\n", - "ax.set_xscale(\"symlog\")\n", - "ax.set_yscale(\"symlog\")\n", - "ax.set_aspect(\"equal\")\n", - "ax.set_legend(True)\n", + "canvas = Canvas()\n", + "canvas.add_line(x, x**3, color=\"cyan\", label=\"x^3\")\n", + "canvas.set_title(\"Symlog example\")\n", + "canvas.add_caption(\"caption text\")\n", + "canvas.set_xscale(\"symlog\")\n", + "canvas.set_yscale(\"symlog\")\n", + "canvas.set_aspect(\"equal\")\n", + "canvas.set_legend(True)\n", "\n", "print(canvas.plot(backend=\"plotext\").build(keep_colors=False))" ] @@ -599,10 +599,10 @@ "source": [ "heat = np.arange(1, 26).reshape(5, 5)\n", "\n", - "canvas, ax = Canvas.subplots()\n", - "ax.add_imshow(heat)\n", - "ax.add_colorbar(label=\"intensity\")\n", - "ax.set_title(\"Matrix + colorbar note\")\n", + "canvas = Canvas()\n", + "canvas.imshow(heat)\n", + "canvas.add_colorbar(label=\"intensity\")\n", + "canvas.set_title(\"Matrix + colorbar note\")\n", "\n", "print(canvas.plot(backend=\"plotext\").build(keep_colors=False))" ] @@ -648,9 +648,9 @@ "source": [ "x = np.linspace(0, 2 * np.pi, 60)\n", "\n", - "canvas, ax = Canvas.subplots()\n", - "ax.plot(x, np.sin(x), color=\"cyan\", label=\"sin(x)\")\n", - "ax.set_title(\"Saved terminal figure\")\n", + "canvas = Canvas()\n", + "canvas.add_line(x, np.sin(x), color=\"cyan\", label=\"sin(x)\")\n", + "canvas.set_title(\"Saved terminal figure\")\n", "terminal_fig = canvas.plot(backend=\"plotext\")\n", "\n", "output_path = Path(\"plotext_output.txt\")\n", @@ -684,12 +684,12 @@ "x = np.linspace(0, 2 * np.pi, 120)\n", "\n", "for phase in np.linspace(0, 2 * np.pi, 24):\n", - " canvas, ax = Canvas.subplots()\n", - " ax.plot(x, np.sin(x + phase), color=\"cyan\", label=\"sin(x + phase)\")\n", - " ax.plot(x, np.cos(x + phase), color=\"yellow\", label=\"cos(x + phase)\")\n", - " ax.set_ylim(-1.2, 1.2)\n", - " ax.set_title(f\"Animated phase = {phase:.2f}\")\n", - " ax.set_legend(True)\n", + " canvas = Canvas()\n", + " canvas.add_line(x, np.sin(x + phase), color=\"cyan\", label=\"sin(x + phase)\")\n", + " canvas.add_line(x, np.cos(x + phase), color=\"yellow\", label=\"cos(x + phase)\")\n", + " canvas.set_ylim(-1.2, 1.2)\n", + " canvas.set_title(f\"Animated phase = {phase:.2f}\")\n", + " canvas.set_legend(True)\n", "\n", " clear_output(wait=True)\n", " print(canvas.plot(backend=\"plotext\").build(keep_colors=False))\n", diff --git a/tutorials/tutorial_10_matplotlib_nxm_spacing.ipynb b/tutorials/tutorial_10_matplotlib_nxm_spacing.ipynb index b5bebab..e1bded3 100644 --- a/tutorials/tutorial_10_matplotlib_nxm_spacing.ipynb +++ b/tutorials/tutorial_10_matplotlib_nxm_spacing.ipynb @@ -70,8 +70,8 @@ ")\n", "for i, row in enumerate(tight_axes):\n", " for j, ax in enumerate(row):\n", - " ax.plot(x, np.sin((i + 1) * (j + 1) * x), label=f\"sin({(i + 1) * (j + 1)}x)\")\n", - " ax.set_title(f\"line {i},{j}\")\n", + " canvas.add_line(x, np.sin((i + 1) * (j + 1) * x), label=f\"sin({(i + 1) * (j + 1)}x)\")\n", + " canvas.set_title(f\"line {i},{j}\")\n", "\n", "tight_fig, tight_m_axes = tight_canvas.plot(backend=\"matplotlib\")\n", "tight_fig.suptitle(\"Line plots - tight spacing\")\n", @@ -88,8 +88,8 @@ ")\n", "for i, row in enumerate(loose_axes):\n", " for j, ax in enumerate(row):\n", - " ax.plot(x, np.sin((i + 1) * (j + 1) * x), label=f\"sin({(i + 1) * (j + 1)}x)\")\n", - " ax.set_title(f\"line {i},{j}\")\n", + " canvas.add_line(x, np.sin((i + 1) * (j + 1) * x), label=f\"sin({(i + 1) * (j + 1)}x)\")\n", + " canvas.set_title(f\"line {i},{j}\")\n", "\n", "loose_fig, loose_m_axes = loose_canvas.plot(backend=\"matplotlib\")\n", "loose_fig.suptitle(\"Line plots - loose spacing\")\n", @@ -128,8 +128,8 @@ "idx = 0\n", "for row in tight_axes:\n", " for ax in row:\n", - " ax.add_imshow(base + idx, cmap=\"viridis\")\n", - " ax.set_title(f\"heatmap {idx}\")\n", + " canvas.imshow(base + idx, cmap=\"viridis\")\n", + " canvas.set_title(f\"heatmap {idx}\")\n", " idx += 1\n", "\n", "tight_fig, tight_m_axes = tight_canvas.plot(backend=\"matplotlib\")\n", @@ -148,8 +148,8 @@ "idx = 0\n", "for row in loose_axes:\n", " for ax in row:\n", - " ax.add_imshow(base + idx, cmap=\"viridis\")\n", - " ax.set_title(f\"heatmap {idx}\")\n", + " canvas.imshow(base + idx, cmap=\"viridis\")\n", + " canvas.set_title(f\"heatmap {idx}\")\n", " idx += 1\n", "\n", "loose_fig, loose_m_axes = loose_canvas.plot(backend=\"matplotlib\")\n", diff --git a/tutorials/tutorial_13_advanced_matplotlib.ipynb b/tutorials/tutorial_13_advanced_matplotlib.ipynb index 580a319..2ce019e 100644 --- a/tutorials/tutorial_13_advanced_matplotlib.ipynb +++ b/tutorials/tutorial_13_advanced_matplotlib.ipynb @@ -42,11 +42,11 @@ "metadata": {}, "outputs": [], "source": [ - "canvas, ax = Canvas.subplots(width=\"12cm\", ratio=0.65)\n", - "ax.barh([0, 1, 2], [2, 4, 3], color=\"steelblue\", alpha=0.8)\n", - "ax.set_yticks([0, 1, 2], labels=[\"A\", \"B\", \"C\"])\n", - "ax.set_xlabel(\"Amount\")\n", - "ax.set_title(\"Horizontal bars\")\n", + "canvas = Canvas(width=\"12cm\", ratio=0.65)\n", + "canvas.barh([0, 1, 2], [2, 4, 3], color=\"steelblue\", alpha=0.8)\n", + "canvas.set_yticks([0, 1, 2], labels=[\"A\", \"B\", \"C\"])\n", + "canvas.set_xlabel(\"Amount\")\n", + "canvas.set_title(\"Horizontal bars\")\n", "canvas.show()" ] }, @@ -58,11 +58,11 @@ "outputs": [], "source": [ "samples = np.random.default_rng(4).normal(size=1000)\n", - "canvas, ax = Canvas.subplots()\n", - "ax.hist(samples, bins=30, color=\"slateblue\", alpha=0.75)\n", - "ax.set_xlabel(\"Value\")\n", - "ax.set_ylabel(\"Count\")\n", - "ax.set_title(\"Distribution\")\n", + "canvas = Canvas()\n", + "canvas.hist(samples, bins=30, color=\"slateblue\", alpha=0.75)\n", + "canvas.set_xlabel(\"Value\")\n", + "canvas.set_ylabel(\"Count\")\n", + "canvas.set_title(\"Distribution\")\n", "canvas.show()" ] }, @@ -81,11 +81,11 @@ "metadata": {}, "outputs": [], "source": [ - "canvas, ax = Canvas.subplots()\n", - "ax.step([0, 1, 2, 3], [1, 3, 2, 4], where=\"mid\", label=\"step\")\n", - "ax.stairs([1, 2, 1], edges=[0, 1, 2, 3], color=\"purple\", label=\"stairs\")\n", - "ax.set_title(\"Discrete data\")\n", - "ax.set_legend(True)\n", + "canvas = Canvas()\n", + "canvas.step([0, 1, 2, 3], [1, 3, 2, 4], where=\"mid\", label=\"step\")\n", + "canvas.stairs([1, 2, 1], edges=[0, 1, 2, 3], color=\"purple\", label=\"stairs\")\n", + "canvas.set_title(\"Discrete data\")\n", + "canvas.set_legend(True)\n", "canvas.show()" ] }, @@ -96,9 +96,9 @@ "metadata": {}, "outputs": [], "source": [ - "canvas, ax = Canvas.subplots()\n", - "ax.broken_barh([(0, 1), (1.5, 0.75), (2.75, 1.0)], (0, 0.6), color=\"orange\")\n", - "ax.set_xlabel(\"Intervals\")\n", + "canvas = Canvas()\n", + "canvas.broken_barh([(0, 1), (1.5, 0.75), (2.75, 1.0)], (0, 0.6), color=\"orange\")\n", + "canvas.set_xlabel(\"Intervals\")\n", "canvas.show()" ] }, @@ -109,9 +109,9 @@ "metadata": {}, "outputs": [], "source": [ - "canvas, ax = Canvas.subplots()\n", - "ax.pie([30, 45, 25], labels=[\"A\", \"B\", \"C\"], autopct=\"%1.0f%%\")\n", - "ax.set_title(\"Shares\")\n", + "canvas = Canvas()\n", + "canvas.pie([30, 45, 25], labels=[\"A\", \"B\", \"C\"], autopct=\"%1.0f%%\")\n", + "canvas.set_title(\"Shares\")\n", "canvas.show()" ] }, @@ -130,13 +130,13 @@ "metadata": {}, "outputs": [], "source": [ - "canvas, ax = Canvas.subplots()\n", - "ax.plot(x, np.sin(x), color=\"black\")\n", - "ax.fill_betweenx([-1, 0, 1], 0.5, [1.0, 1.5, 2.0], alpha=0.2)\n", - "ax.axvspan(1.0, 2.0, color=\"orange\", alpha=0.2)\n", - "ax.axhspan(-0.25, 0.25, color=\"steelblue\", alpha=0.15)\n", - "ax.arrow(2.0, np.sin(2.0), 0.5, 0.3, length_includes_head=True)\n", - "ax.axline((0, 0), slope=0.2, linestyle=\"--\", color=\"crimson\")\n", + "canvas = Canvas()\n", + "canvas.add_line(x, np.sin(x), color=\"black\")\n", + "canvas.fill_betweenx([-1, 0, 1], 0.5, [1.0, 1.5, 2.0], alpha=0.2)\n", + "canvas.axvspan(1.0, 2.0, color=\"orange\", alpha=0.2)\n", + "canvas.axhspan(-0.25, 0.25, color=\"steelblue\", alpha=0.15)\n", + "canvas.arrow(2.0, np.sin(2.0), 0.5, 0.3, length_includes_head=True)\n", + "canvas.axline((0, 0), slope=0.2, linestyle=\"--\", color=\"crimson\")\n", "canvas.show()" ] }, @@ -191,11 +191,11 @@ "xx, yy = np.meshgrid(x, y)\n", "z = xx**2 + yy**2\n", "\n", - "canvas, ax = Canvas.subplots()\n", - "ax.contour(x, y, z, colors=\"black\")\n", - "ax.contourf(x, y, z, alpha=0.5)\n", - "ax.pcolormesh(x, y, z, alpha=0.25)\n", - "ax.set_title(\"Scalar field\")\n", + "canvas = Canvas()\n", + "canvas.contour(x, y, z, colors=\"black\")\n", + "canvas.contourf(x, y, z, alpha=0.5)\n", + "canvas.pcolormesh(x, y, z, alpha=0.25)\n", + "canvas.set_title(\"Scalar field\")\n", "canvas.show()" ] }, @@ -214,9 +214,9 @@ "metadata": {}, "outputs": [], "source": [ - "canvas, ax = Canvas.subplots()\n", - "ax.hexbin(xx.ravel(), yy.ravel(), gridsize=12)\n", - "ax.matshow(z)\n", + "canvas = Canvas()\n", + "canvas.hexbin(xx.ravel(), yy.ravel(), gridsize=12)\n", + "canvas.matshow(z)\n", "canvas.show()" ] }, @@ -240,11 +240,11 @@ "triangles = [[0, 1, 2], [1, 3, 2]]\n", "values = points_x + points_y\n", "\n", - "canvas, ax = Canvas.subplots()\n", - "ax.quiver(points_x, points_y, np.ones(4), np.ones(4))\n", - "ax.triplot(points_x, points_y, triangles=triangles)\n", - "ax.tripcolor(points_x, points_y, values, triangles=triangles, alpha=0.3)\n", - "ax.tricontour(points_x, points_y, values, triangles=triangles)\n", + "canvas = Canvas()\n", + "canvas.quiver(points_x, points_y, np.ones(4), np.ones(4))\n", + "canvas.triplot(points_x, points_y, triangles=triangles)\n", + "canvas.tripcolor(points_x, points_y, values, triangles=triangles, alpha=0.3)\n", + "canvas.tricontour(points_x, points_y, values, triangles=triangles)\n", "canvas.show()" ] }, @@ -263,10 +263,10 @@ "metadata": {}, "outputs": [], "source": [ - "canvas, ax = Canvas.subplots()\n", - "ax.stem([0, 1, 2], [1, 3, 2])\n", - "ax.stackplot([0, 1, 2], [1, 2, 1], [2, 1, 2], alpha=0.4)\n", - "ax.set_title(\"Discrete and stacked data\")\n", + "canvas = Canvas()\n", + "canvas.stem([0, 1, 2], [1, 3, 2])\n", + "canvas.stackplot([0, 1, 2], [1, 2, 1], [2, 1, 2], alpha=0.4)\n", + "canvas.set_title(\"Discrete and stacked data\")\n", "canvas.show()" ] }, @@ -277,10 +277,10 @@ "metadata": {}, "outputs": [], "source": [ - "canvas, ax = Canvas.subplots()\n", - "ax.boxplot([[1, 2, 3], [2, 4, 5]])\n", - "ax.violinplot([[1, 2, 3], [2, 4, 5]])\n", - "ax.eventplot([[0.2, 0.5], [1.0, 1.5]])\n", + "canvas = Canvas()\n", + "canvas.boxplot([[1, 2, 3], [2, 4, 5]])\n", + "canvas.violinplot([[1, 2, 3], [2, 4, 5]])\n", + "canvas.eventplot([[0.2, 0.5], [1.0, 1.5]])\n", "canvas.show()" ] } diff --git a/tutorials/tutorial_14_axis_and_layout_controls.ipynb b/tutorials/tutorial_14_axis_and_layout_controls.ipynb index ac43ba3..855631c 100644 --- a/tutorials/tutorial_14_axis_and_layout_controls.ipynb +++ b/tutorials/tutorial_14_axis_and_layout_controls.ipynb @@ -40,9 +40,9 @@ "metadata": {}, "outputs": [], "source": [ - "canvas, ax = Canvas.subplots()\n", - "ax.fill([0, 1, 2, 1], [0, 2, 0, -1], color=\"tab:orange\", alpha=0.5)\n", - "ax.set_title(\"A filled polygon\")\n", + "canvas = Canvas()\n", + "canvas.fill([0, 1, 2, 1], [0, 2, 0, -1], color=\"tab:orange\", alpha=0.5)\n", + "canvas.set_title(\"A filled polygon\")\n", "canvas.show()" ] }, @@ -53,7 +53,7 @@ "source": [ "## Logarithmic plotting shortcuts\n", "\n", - "Use `semilogx()`, `semilogy()`, or `loglog()` when the data and axis scale should be configured together." + "Use `semilogx()`, `semilogy()`, or `loglog()` when the data and axis scale should be configured together. The three-panel example below shows the optional `fig`/`axs` style for users familiar with Matplotlib; ordinary one-panel examples use `Canvas` directly." ] }, { @@ -90,11 +90,11 @@ "metadata": {}, "outputs": [], "source": [ - "canvas, ax = Canvas.subplots()\n", - "ax.plot([0, 1, 2], [0, 4, 1])\n", - "ax.axis([0, 2, -1, 5])\n", - "ax.relim()\n", - "ax.autoscale_view(tight=True)\n", + "canvas = Canvas()\n", + "canvas.add_line([0, 1, 2], [0, 4, 1])\n", + "canvas.axis([0, 2, -1, 5])\n", + "canvas.relim()\n", + "canvas.autoscale_view(tight=True)\n", "canvas.show()" ] }, @@ -115,16 +115,16 @@ "metadata": {}, "outputs": [], "source": [ - "canvas, ax = Canvas.subplots()\n", - "ax.plot(x, x**2)\n", - "ax.set_xlabel(\"distance (m)\")\n", - "ax.set_ylabel(\"area (m²)\")\n", - "ax.secondary_xaxis(\n", + "canvas = Canvas()\n", + "canvas.add_line(x, x**2)\n", + "canvas.set_xlabel(\"distance (m)\")\n", + "canvas.set_ylabel(\"area (m²)\")\n", + "canvas.secondary_xaxis(\n", " \"top\",\n", " functions=(lambda value: value / 1000, lambda value: value * 1000),\n", " label=\"distance (km)\",\n", ")\n", - "ax.secondary_yaxis(\n", + "canvas.secondary_yaxis(\n", " \"right\", functions=(np.sqrt, lambda value: value**2), label=\"length (m)\"\n", ")\n", "canvas.show()" @@ -145,13 +145,13 @@ "metadata": {}, "outputs": [], "source": [ - "canvas, ax = Canvas.subplots()\n", - "ax.plot([0, 1, 2], [0, 1, 0], marker=\"o\")\n", - "ax.set_box_aspect(1)\n", - "ax.set_xticks([0, 1, 2])\n", - "ax.set_xticklabels([\"start\", \"middle\", \"end\"], rotation=25, color=\"navy\")\n", - "ax.set_yticks([0, 1])\n", - "ax.set_yticklabels([\"low\", \"high\"], fontweight=\"bold\")\n", + "canvas = Canvas()\n", + "canvas.add_line([0, 1, 2], [0, 1, 0], marker=\"o\")\n", + "canvas.set_box_aspect(1)\n", + "canvas.set_xticks([0, 1, 2])\n", + "canvas.set_xticklabels([\"start\", \"middle\", \"end\"], rotation=25, color=\"navy\")\n", + "canvas.set_yticks([0, 1])\n", + "canvas.set_yticklabels([\"low\", \"high\"], fontweight=\"bold\")\n", "canvas.show()" ] }, @@ -172,10 +172,10 @@ "metadata": {}, "outputs": [], "source": [ - "plotly_canvas, plotly_ax = Canvas.subplots()\n", - "plotly_ax.fill(x, np.sin(x) + 2, color=\"purple\", alpha=0.25)\n", - "plotly_ax.loglog(x, x**2, color=\"black\")\n", - "plotly_ax.set_xticklabels([\"small\", \"medium\", \"large\"], color=\"darkgreen\")\n", + "plotly_canvas = Canvas()\n", + "plotly_canvas.fill(x, np.sin(x) + 2, color=\"purple\", alpha=0.25)\n", + "plotly_canvas.loglog(x, x**2, color=\"black\")\n", + "plotly_canvas.set_xticklabels([\"small\", \"medium\", \"large\"], color=\"darkgreen\")\n", "plotly_canvas.show(backend=\"plotly\")" ] } From 816929aedb3cd8fc075fea565e5eb2ce23bfde0c Mon Sep 17 00:00:00 2001 From: Max Date: Sat, 22 Aug 2026 13:01:37 +0200 Subject: [PATCH 3/5] Formatting --- src/maxplotlib/canvas/canvas.py | 4 +--- tutorials/tutorial_01.ipynb | 8 ++++++-- tutorials/tutorial_03.ipynb | 16 ++++++++++++---- tutorials/tutorial_04.ipynb | 12 +++++++++--- tutorials/tutorial_05.ipynb | 4 +++- tutorials/tutorial_06.ipynb | 4 +++- .../tutorial_10_matplotlib_nxm_spacing.ipynb | 8 ++++++-- 7 files changed, 40 insertions(+), 16 deletions(-) diff --git a/src/maxplotlib/canvas/canvas.py b/src/maxplotlib/canvas/canvas.py index d755b4e..80d29f6 100644 --- a/src/maxplotlib/canvas/canvas.py +++ b/src/maxplotlib/canvas/canvas.py @@ -1404,9 +1404,7 @@ def colorbar( label=label, layer=layer, **kwargs ) - def add_colorbar( - self, label: str = "", layer=0, row=None, col=None, **kwargs - ): + def add_colorbar(self, label: str = "", layer=0, row=None, col=None, **kwargs): """Alias for ``colorbar``.""" self.colorbar(label=label, layer=layer, row=row, col=col, **kwargs) diff --git a/tutorials/tutorial_01.ipynb b/tutorials/tutorial_01.ipynb index 4336629..6d93db3 100644 --- a/tutorials/tutorial_01.ipynb +++ b/tutorials/tutorial_01.ipynb @@ -101,8 +101,12 @@ "source": [ "canvas = Canvas()\n", "\n", - "canvas.add_line(x, np.sin(x), label=\"sin(x)\", color=\"royalblue\", linestyle=\"solid\", linewidth=2)\n", - "canvas.add_line(x, np.cos(x), label=\"cos(x)\", color=\"tomato\", linestyle=\"dashed\", linewidth=2)\n", + "canvas.add_line(\n", + " x, np.sin(x), label=\"sin(x)\", color=\"royalblue\", linestyle=\"solid\", linewidth=2\n", + ")\n", + "canvas.add_line(\n", + " x, np.cos(x), label=\"cos(x)\", color=\"tomato\", linestyle=\"dashed\", linewidth=2\n", + ")\n", "canvas.add_line(\n", " x,\n", " np.sin(2 * x),\n", diff --git a/tutorials/tutorial_03.ipynb b/tutorials/tutorial_03.ipynb index cf5eac6..66d30d5 100644 --- a/tutorials/tutorial_03.ipynb +++ b/tutorials/tutorial_03.ipynb @@ -76,8 +76,12 @@ "source": [ "canvas = Canvas()\n", "\n", - "canvas.add_line(x, np.sin(x), label=\"sin(x)\", color=\"royalblue\", linestyle=\"solid\", linewidth=2)\n", - "canvas.add_line(x, np.cos(x), label=\"cos(x)\", color=\"tomato\", linestyle=\"dashed\", linewidth=2)\n", + "canvas.add_line(\n", + " x, np.sin(x), label=\"sin(x)\", color=\"royalblue\", linestyle=\"solid\", linewidth=2\n", + ")\n", + "canvas.add_line(\n", + " x, np.cos(x), label=\"cos(x)\", color=\"tomato\", linestyle=\"dashed\", linewidth=2\n", + ")\n", "\n", "canvas.set_xlabel(\"x\")\n", "canvas.set_ylabel(\"y\")\n", @@ -197,7 +201,9 @@ "yerr = 0.1 + 0.05 * rng.random(len(xm))\n", "\n", "canvas = Canvas()\n", - "canvas.errorbar(xm, ym, yerr=yerr, fmt=\"o\", capsize=4, color=\"tomato\", label=\"measurements\")\n", + "canvas.errorbar(\n", + " xm, ym, yerr=yerr, fmt=\"o\", capsize=4, color=\"tomato\", label=\"measurements\"\n", + ")\n", "canvas.add_line(x, np.sin(x), color=\"gray\", linestyle=\"dashed\", label=\"true sin(x)\")\n", "canvas.set_xlabel(\"x\")\n", "canvas.set_ylabel(\"y\")\n", @@ -229,7 +235,9 @@ "\n", "canvas.axhline(y=0, color=\"black\", linestyle=\"solid\", linewidth=0.8)\n", "canvas.axhline(y=0.5, color=\"green\", linestyle=\"dashed\", linewidth=1.2, label=\"y = 0.5\")\n", - "canvas.axhline(y=-0.5, color=\"green\", linestyle=\"dashed\", linewidth=1.2, label=\"y = -0.5\")\n", + "canvas.axhline(\n", + " y=-0.5, color=\"green\", linestyle=\"dashed\", linewidth=1.2, label=\"y = -0.5\"\n", + ")\n", "canvas.axvline(x=np.pi, color=\"red\", linestyle=\"dotted\", linewidth=1.5, label=\"x = π\")\n", "\n", "canvas.set_xlabel(\"x\")\n", diff --git a/tutorials/tutorial_04.ipynb b/tutorials/tutorial_04.ipynb index 52ccdbb..0535e79 100644 --- a/tutorials/tutorial_04.ipynb +++ b/tutorials/tutorial_04.ipynb @@ -177,8 +177,12 @@ "\n", "canvas = Canvas(width=\"10cm\", ratio=0.55)\n", "\n", - "canvas.add_line(x, np.sin(x), linewidth=0.8, marker=\"o\", markersize=3, label=\"thin / small\")\n", - "canvas.add_line(x, np.sin(x) - 0.6, linewidth=2.5, marker=\"o\", markersize=7, label=\"medium\")\n", + "canvas.add_line(\n", + " x, np.sin(x), linewidth=0.8, marker=\"o\", markersize=3, label=\"thin / small\"\n", + ")\n", + "canvas.add_line(\n", + " x, np.sin(x) - 0.6, linewidth=2.5, marker=\"o\", markersize=7, label=\"medium\"\n", + ")\n", "canvas.add_line(\n", " x, np.sin(x) - 1.2, linewidth=4.5, marker=\"o\", markersize=12, label=\"thick / large\"\n", ")\n", @@ -243,7 +247,9 @@ "canvas = Canvas(width=\"10cm\", ratio=0.6)\n", "\n", "# Shaded uncertainty band\n", - "canvas.fill_between(x, np.sin(x) - 0.15, np.sin(x) + 0.15, alpha=0.15, color=\"steelblue\")\n", + "canvas.fill_between(\n", + " x, np.sin(x) - 0.15, np.sin(x) + 0.15, alpha=0.15, color=\"steelblue\"\n", + ")\n", "\n", "# Noisy data\n", "canvas.scatter(\n", diff --git a/tutorials/tutorial_05.ipynb b/tutorials/tutorial_05.ipynb index 0cf0467..8c49e34 100644 --- a/tutorials/tutorial_05.ipynb +++ b/tutorials/tutorial_05.ipynb @@ -237,7 +237,9 @@ "canvas = Canvas(width=\"10cm\", ratio=0.55)\n", "canvas.add_line(x, np.sin(x), color=\"steelblue\", label=r\"$\\sin(x)$\")\n", "canvas.add_line(x, np.cos(x), color=\"tomato\", label=r\"$\\cos(x)$\")\n", - "canvas.add_line(x, np.sin(2 * x), color=\"seagreen\", label=r\"$\\sin(2x)$\", linestyle=\"dashed\")\n", + "canvas.add_line(\n", + " x, np.sin(2 * x), color=\"seagreen\", label=r\"$\\sin(2x)$\", linestyle=\"dashed\"\n", + ")\n", "\n", "canvas.set_xlabel(\"x\")\n", "canvas.set_legend(True)\n", diff --git a/tutorials/tutorial_06.ipynb b/tutorials/tutorial_06.ipynb index c24c205..bb23c82 100644 --- a/tutorials/tutorial_06.ipynb +++ b/tutorials/tutorial_06.ipynb @@ -210,7 +210,9 @@ "canvas.scatter(x, y_data, color=\"gray\", s=8, alpha=0.5, label=\"measured data\", layer=0)\n", "\n", "# Layer 1: true function\n", - "canvas.add_line(x, np.sin(x), color=\"steelblue\", linewidth=2, label=r\"true: $\\sin(x)$\", layer=1)\n", + "canvas.add_line(\n", + " x, np.sin(x), color=\"steelblue\", linewidth=2, label=r\"true: $\\sin(x)$\", layer=1\n", + ")\n", "\n", "# Layer 2: envelope\n", "canvas.fill_between(\n", diff --git a/tutorials/tutorial_10_matplotlib_nxm_spacing.ipynb b/tutorials/tutorial_10_matplotlib_nxm_spacing.ipynb index e1bded3..f92e75f 100644 --- a/tutorials/tutorial_10_matplotlib_nxm_spacing.ipynb +++ b/tutorials/tutorial_10_matplotlib_nxm_spacing.ipynb @@ -70,7 +70,9 @@ ")\n", "for i, row in enumerate(tight_axes):\n", " for j, ax in enumerate(row):\n", - " canvas.add_line(x, np.sin((i + 1) * (j + 1) * x), label=f\"sin({(i + 1) * (j + 1)}x)\")\n", + " canvas.add_line(\n", + " x, np.sin((i + 1) * (j + 1) * x), label=f\"sin({(i + 1) * (j + 1)}x)\"\n", + " )\n", " canvas.set_title(f\"line {i},{j}\")\n", "\n", "tight_fig, tight_m_axes = tight_canvas.plot(backend=\"matplotlib\")\n", @@ -88,7 +90,9 @@ ")\n", "for i, row in enumerate(loose_axes):\n", " for j, ax in enumerate(row):\n", - " canvas.add_line(x, np.sin((i + 1) * (j + 1) * x), label=f\"sin({(i + 1) * (j + 1)}x)\")\n", + " canvas.add_line(\n", + " x, np.sin((i + 1) * (j + 1) * x), label=f\"sin({(i + 1) * (j + 1)}x)\"\n", + " )\n", " canvas.set_title(f\"line {i},{j}\")\n", "\n", "loose_fig, loose_m_axes = loose_canvas.plot(backend=\"matplotlib\")\n", From 0b49b8a8a996fe6df5668fe434dfd0ab4b623ba1 Mon Sep 17 00:00:00 2001 From: Max Date: Sat, 22 Aug 2026 13:01:58 +0200 Subject: [PATCH 4/5] Formatting --- src/maxplotlib/tests/test_canvas.py | 2 -- tutorials/tutorial_11_gantt_charts.ipynb | 3 +-- tutorials/tutorial_12_flame_charts.ipynb | 3 +-- 3 files changed, 2 insertions(+), 6 deletions(-) diff --git a/src/maxplotlib/tests/test_canvas.py b/src/maxplotlib/tests/test_canvas.py index 9aa0bd6..fc2da1a 100644 --- a/src/maxplotlib/tests/test_canvas.py +++ b/src/maxplotlib/tests/test_canvas.py @@ -636,7 +636,6 @@ def test_vector_and_triangulated_plot_primitives_are_supported(): def test_stream_matrix_and_table_primitives_are_supported(): - import matplotlib.pyplot as plt import numpy as np from maxplotlib import Canvas @@ -682,7 +681,6 @@ def test_contour_labels_and_rasterization_zorder_are_supported(): def test_axis_layout_and_log_shortcuts_are_supported(): import matplotlib.pyplot as plt - import numpy as np from maxplotlib import Canvas diff --git a/tutorials/tutorial_11_gantt_charts.ipynb b/tutorials/tutorial_11_gantt_charts.ipynb index cc90229..41fb565 100644 --- a/tutorials/tutorial_11_gantt_charts.ipynb +++ b/tutorials/tutorial_11_gantt_charts.ipynb @@ -17,8 +17,7 @@ "metadata": {}, "outputs": [], "source": [ - "from maxplotlib import Canvas\n", - "import numpy as np" + "from maxplotlib import Canvas" ] }, { diff --git a/tutorials/tutorial_12_flame_charts.ipynb b/tutorials/tutorial_12_flame_charts.ipynb index 9c35492..8a35a0a 100644 --- a/tutorials/tutorial_12_flame_charts.ipynb +++ b/tutorials/tutorial_12_flame_charts.ipynb @@ -17,8 +17,7 @@ "metadata": {}, "outputs": [], "source": [ - "from maxplotlib import Canvas\n", - "import numpy as np" + "from maxplotlib import Canvas" ] }, { From af0dd359244cd92a5a79db521faf3579d2202e20 Mon Sep 17 00:00:00 2001 From: Max Date: Sat, 22 Aug 2026 13:12:20 +0200 Subject: [PATCH 5/5] fix tutorial --- .../tutorial_10_matplotlib_nxm_spacing.ipynb | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/tutorials/tutorial_10_matplotlib_nxm_spacing.ipynb b/tutorials/tutorial_10_matplotlib_nxm_spacing.ipynb index f92e75f..f573054 100644 --- a/tutorials/tutorial_10_matplotlib_nxm_spacing.ipynb +++ b/tutorials/tutorial_10_matplotlib_nxm_spacing.ipynb @@ -70,10 +70,10 @@ ")\n", "for i, row in enumerate(tight_axes):\n", " for j, ax in enumerate(row):\n", - " canvas.add_line(\n", + " tight_canvas.add_line(\n", " x, np.sin((i + 1) * (j + 1) * x), label=f\"sin({(i + 1) * (j + 1)}x)\"\n", " )\n", - " canvas.set_title(f\"line {i},{j}\")\n", + " tight_canvas.set_title(f\"line {i},{j}\")\n", "\n", "tight_fig, tight_m_axes = tight_canvas.plot(backend=\"matplotlib\")\n", "tight_fig.suptitle(\"Line plots - tight spacing\")\n", @@ -90,10 +90,10 @@ ")\n", "for i, row in enumerate(loose_axes):\n", " for j, ax in enumerate(row):\n", - " canvas.add_line(\n", + " loose_canvas.add_line(\n", " x, np.sin((i + 1) * (j + 1) * x), label=f\"sin({(i + 1) * (j + 1)}x)\"\n", " )\n", - " canvas.set_title(f\"line {i},{j}\")\n", + " loose_canvas.set_title(f\"line {i},{j}\")\n", "\n", "loose_fig, loose_m_axes = loose_canvas.plot(backend=\"matplotlib\")\n", "loose_fig.suptitle(\"Line plots - loose spacing\")\n", @@ -132,8 +132,8 @@ "idx = 0\n", "for row in tight_axes:\n", " for ax in row:\n", - " canvas.imshow(base + idx, cmap=\"viridis\")\n", - " canvas.set_title(f\"heatmap {idx}\")\n", + " tight_canvas.imshow(base + idx, cmap=\"viridis\")\n", + " tight_canvas.set_title(f\"heatmap {idx}\")\n", " idx += 1\n", "\n", "tight_fig, tight_m_axes = tight_canvas.plot(backend=\"matplotlib\")\n", @@ -152,8 +152,8 @@ "idx = 0\n", "for row in loose_axes:\n", " for ax in row:\n", - " canvas.imshow(base + idx, cmap=\"viridis\")\n", - " canvas.set_title(f\"heatmap {idx}\")\n", + " loose_canvas.imshow(base + idx, cmap=\"viridis\")\n", + " loose_canvas.set_title(f\"heatmap {idx}\")\n", " idx += 1\n", "\n", "loose_fig, loose_m_axes = loose_canvas.plot(backend=\"matplotlib\")\n",