From ca538b407a429b7dc511571c87c4cff16801709c Mon Sep 17 00:00:00 2001 From: Max Date: Sat, 22 Aug 2026 13:46:34 +0200 Subject: [PATCH 1/3] Renamed plot to render, added plot(x, y) to canvas --- README.md | 6 +- README.qmd | 4 +- src/maxplotlib/canvas/canvas.py | 38 +++++++++- src/maxplotlib/tests/test_canvas.py | 21 ++++++ tutorials/tutorial_01.ipynb | 20 +++--- tutorials/tutorial_02.ipynb | 6 +- tutorials/tutorial_03.ipynb | 20 +++--- tutorials/tutorial_04.ipynb | 18 ++--- tutorials/tutorial_05.ipynb | 18 ++--- tutorials/tutorial_06.ipynb | 16 ++--- tutorials/tutorial_07_tikz.ipynb | 20 +++--- tutorials/tutorial_08_plotly.ipynb | 40 +++++------ tutorials/tutorial_09_plotext.ipynb | 72 +++++++++---------- .../tutorial_10_matplotlib_nxm_spacing.ipynb | 12 ++-- tutorials/tutorial_11_gantt_charts.ipynb | 14 ++-- tutorials/tutorial_12_flame_charts.ipynb | 14 ++-- .../tutorial_13_advanced_matplotlib.ipynb | 2 +- ...tutorial_14_axis_and_layout_controls.ipynb | 6 +- tutorials/tutorial_tikzfigure_subplots.ipynb | 2 +- 19 files changed, 203 insertions(+), 146 deletions(-) diff --git a/README.md b/README.md index f554af5..cf050d8 100644 --- a/README.md +++ b/README.md @@ -149,14 +149,14 @@ parts of a mixed canvas, explicitly opt into skipping unsupported primitives: ``` python -plotly_canvas.plot(backend="plotly", allow_unsupported=True) +plotly_canvas.render(backend="plotly", allow_unsupported=True) ``` Render the same line graph directly in the terminal with the `plotext` backend: ``` python -terminal_fig = canvas.plot(backend="plotext") +terminal_fig = canvas.render(backend="plotext") print(terminal_fig.build(keep_colors=False)) ``` @@ -270,7 +270,7 @@ canvas.show(backend="plotext") 1.0 1.8 3.2 5.6 10.0 y x - + ### Layers diff --git a/README.qmd b/README.qmd index 45cbd13..1cfb6ae 100644 --- a/README.qmd +++ b/README.qmd @@ -149,13 +149,13 @@ of a mixed canvas, explicitly opt into skipping unsupported primitives: ```{python} #| output: false -plotly_canvas.plot(backend="plotly", allow_unsupported=True) +plotly_canvas.render(backend="plotly", allow_unsupported=True) ``` Render the same line graph directly in the terminal with the `plotext` backend: ```{python} -terminal_fig = canvas.plot(backend="plotext") +terminal_fig = canvas.render(backend="plotext") print(terminal_fig.build(keep_colors=False)) ``` diff --git a/src/maxplotlib/canvas/canvas.py b/src/maxplotlib/canvas/canvas.py index 80d29f6..dfaff97 100644 --- a/src/maxplotlib/canvas/canvas.py +++ b/src/maxplotlib/canvas/canvas.py @@ -1781,7 +1781,7 @@ def savefig( if verbose: print(f"Saved {filename}") - def plot( + def _render( self, backend: Backends = "matplotlib", savefig: bool = False, @@ -1844,6 +1844,42 @@ def plot( else: raise ValueError(f"Invalid backend: {backend}") + def plot(self, *args, backend=None, **kwargs): + """Add a line, or render when called with backend options. + + ``canvas.plot(x, y, **style)`` is the convenient direct plotting form. + Rendering is named explicitly by ``canvas.render(...)``; the legacy + ``canvas.plot(backend=...)`` form remains supported. + """ + if args and not isinstance(args[0], str): + if len(args) < 2: + raise TypeError("plot(x, y) requires both x and y data") + if len(args) > 2: + raise TypeError("plot() accepts only x and y positional data") + layer = kwargs.pop("layer", 0) + row = kwargs.pop("row", None) + col = kwargs.pop("col", None) + self.add_line(args[0], args[1], layer=layer, row=row, col=col, **kwargs) + return self + if args: + if len(args) > 1: + raise TypeError("plot() accepts at most one backend positional argument") + if backend is not None: + raise TypeError("backend was provided both positionally and by keyword") + backend = args[0] + if backend is None: + backend = "matplotlib" + return self._render(backend=backend, **kwargs) + + def render(self, *args, **kwargs): + """Render the canvas using the selected backend. + + This is the explicit name for the operation historically exposed as + ``Canvas.plot(backend=...)``. The latter remains available for + backwards compatibility. + """ + return self._render(*args, **kwargs) + def show( self, backend: Backends = "matplotlib", diff --git a/src/maxplotlib/tests/test_canvas.py b/src/maxplotlib/tests/test_canvas.py index fc2da1a..1bdf2b9 100644 --- a/src/maxplotlib/tests/test_canvas.py +++ b/src/maxplotlib/tests/test_canvas.py @@ -880,6 +880,27 @@ def test_axis_getters_reflect_configured_state(): assert canvas.get_ymargin() == 0.2 +def test_render_is_the_explicit_rendering_alias(): + from maxplotlib import Canvas + + canvas = Canvas() + canvas.add_line([0, 1], [0, 1]) + + rendered = canvas.render(backend="plotly") + + assert rendered is not None + + +def test_plot_adds_line_data_when_given_x_and_y(): + from maxplotlib import Canvas + + canvas = Canvas() + result = canvas.plot([0, 1], [1, 2], color="purple", label="line") + + assert result is canvas + assert canvas.render(backend="plotly").data[0].name == "line" + + def test_matplotlib_postprocess_can_customize_figure_and_axes(): import matplotlib.pyplot as plt from matplotlib.colors import to_rgba diff --git a/tutorials/tutorial_01.ipynb b/tutorials/tutorial_01.ipynb index 6d93db3..21430b5 100644 --- a/tutorials/tutorial_01.ipynb +++ b/tutorials/tutorial_01.ipynb @@ -80,7 +80,7 @@ "y = np.sin(x)\n", "\n", "canvas = Canvas()\n", - "canvas.add_line(x, y)\n", + "canvas.plot(x, y)\n", "canvas.show(backend=BACKEND)" ] }, @@ -101,13 +101,13 @@ "source": [ "canvas = Canvas()\n", "\n", - "canvas.add_line(\n", + "canvas.plot(\n", " x, np.sin(x), label=\"sin(x)\", color=\"royalblue\", linestyle=\"solid\", linewidth=2\n", ")\n", - "canvas.add_line(\n", + "canvas.plot(\n", " x, np.cos(x), label=\"cos(x)\", color=\"tomato\", linestyle=\"dashed\", linewidth=2\n", ")\n", - "canvas.add_line(\n", + "canvas.plot(\n", " x,\n", " np.sin(2 * x),\n", " label=\"sin(2x)\",\n", @@ -144,8 +144,8 @@ "source": [ "canvas = Canvas(ratio=0.5, fontsize=12)\n", "\n", - "canvas.add_line(x, np.sin(x), label=\"sin(x)\", color=\"steelblue\")\n", - "canvas.add_line(x, np.cos(x), label=\"cos(x)\", color=\"darkorange\", linestyle=\"dashed\")\n", + "canvas.plot(x, np.sin(x), label=\"sin(x)\", color=\"steelblue\")\n", + "canvas.plot(x, np.cos(x), label=\"cos(x)\", color=\"darkorange\", linestyle=\"dashed\")\n", "\n", "canvas.set_xlabel(\"angle (rad)\")\n", "canvas.set_ylabel(\"amplitude\")\n", @@ -183,8 +183,8 @@ " legend=True,\n", ")\n", "\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", + "canvas.plot(x, np.sin(x), label=\"sin\", color=\"royalblue\")\n", + "canvas.plot(x, x / (2 * np.pi), label=\"x/2π\", color=\"coral\", linestyle=\"dashed\")\n", "\n", "canvas.show(backend=BACKEND)" ] @@ -209,7 +209,7 @@ "source": [ "canvas = Canvas(ratio=0.5)\n", "ax = canvas.add_subplot(xlabel=\"x\", ylabel=\"sin(x)\", grid=True)\n", - "canvas.add_line(x, np.sin(x), color=\"steelblue\")\n", + "canvas.plot(x, np.sin(x), color=\"steelblue\")\n", "\n", "canvas.savefig(\"tutorial_01_output.png\")\n", "print(\"Figure saved to tutorial_01_output.png\")" @@ -225,7 +225,7 @@ "| Task | Code |\n", "|---|---|\n", "| Create a canvas | `canvas = Canvas()` |\n", - "| Add a line | `canvas.add_line(x, y, label=..., color=..., linestyle=...)` |\n", + "| Add a line | `canvas.plot(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", diff --git a/tutorials/tutorial_02.ipynb b/tutorials/tutorial_02.ipynb index 06f79ae..e809ee6 100644 --- a/tutorials/tutorial_02.ipynb +++ b/tutorials/tutorial_02.ipynb @@ -321,8 +321,8 @@ "canvas.add_subplot(row=0, col=0, title=\"Left\", xlabel=\"x\", ylabel=\"sin\")\n", "canvas.add_subplot(row=0, col=1, title=\"Right\", xlabel=\"x\", ylabel=\"cos\")\n", "\n", - "canvas.add_line(x, np.sin(x), row=0, col=0, color=\"royalblue\", label=\"sin\")\n", - "canvas.add_line(x, np.cos(x), row=0, col=1, color=\"tomato\", label=\"cos\")\n", + "canvas.plot(x, np.sin(x), row=0, col=0, color=\"royalblue\", label=\"sin\")\n", + "canvas.plot(x, np.cos(x), row=0, col=1, color=\"tomato\", label=\"cos\")\n", "\n", "canvas.set_legend(True, row=0, col=0)\n", "canvas.set_legend(True, row=0, col=1)\n", @@ -346,7 +346,7 @@ "| Get subplot | `canvas.subplot(r, c)` or `canvas[r, c]` |\n", "| Loop panels | `for row, col, sp in canvas.iter_subplots()` |\n", "| Figure title | `canvas.suptitle('...')` |\n", - "| Route plot | `canvas.add_line(x, y, row=r, col=c)` |\n", + "| Route plot | `canvas.plot(x, y, row=r, col=c)` |\n", "\n", "Next: **Tutorial 03** covers all the available plot types." ] diff --git a/tutorials/tutorial_03.ipynb b/tutorials/tutorial_03.ipynb index 66d30d5..f6b4c18 100644 --- a/tutorials/tutorial_03.ipynb +++ b/tutorials/tutorial_03.ipynb @@ -64,7 +64,7 @@ "id": "4", "metadata": {}, "source": [ - "## 1 Line plot — `canvas.add_line()`" + "## 1 Line plot — `canvas.plot()`" ] }, { @@ -76,10 +76,10 @@ "source": [ "canvas = Canvas()\n", "\n", - "canvas.add_line(\n", + "canvas.plot(\n", " x, np.sin(x), label=\"sin(x)\", color=\"royalblue\", linestyle=\"solid\", linewidth=2\n", ")\n", - "canvas.add_line(\n", + "canvas.plot(\n", " x, np.cos(x), label=\"cos(x)\", color=\"tomato\", linestyle=\"dashed\", linewidth=2\n", ")\n", "\n", @@ -172,7 +172,7 @@ "lower = mean - 0.3 * (1 - t / (4 * np.pi))\n", "\n", "canvas = Canvas()\n", - "canvas.add_line(t, mean, color=\"royalblue\", label=\"mean\", linewidth=2)\n", + "canvas.plot(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", @@ -204,7 +204,7 @@ "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.plot(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", @@ -231,7 +231,7 @@ "outputs": [], "source": [ "canvas = Canvas()\n", - "canvas.add_line(x, np.sin(x), color=\"royalblue\", label=\"sin(x)\")\n", + "canvas.plot(x, np.sin(x), color=\"royalblue\", label=\"sin(x)\")\n", "\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", @@ -264,7 +264,7 @@ "outputs": [], "source": [ "canvas = Canvas()\n", - "canvas.add_line(x, np.sin(x), color=\"lightgray\", linewidth=1)\n", + "canvas.plot(x, np.sin(x), color=\"lightgray\", linewidth=1)\n", "\n", "# Horizontal segments spanning half the x-range\n", "canvas.hlines(\n", @@ -324,7 +324,7 @@ "canvas.fill_between(\n", " t, signal - band, signal + band, alpha=0.2, color=\"royalblue\", label=\"uncertainty\"\n", ")\n", - "canvas.add_line(t, signal, color=\"royalblue\", linewidth=2, label=\"model\")\n", + "canvas.plot(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", @@ -352,7 +352,7 @@ "outputs": [], "source": [ "canvas = Canvas()\n", - "canvas.add_line(x, np.sin(x), color=\"royalblue\")\n", + "canvas.plot(x, np.sin(x), color=\"royalblue\")\n", "\n", "# Arrow annotation pointing to the peak\n", "canvas.annotate(\n", @@ -380,7 +380,7 @@ "\n", "| Plot type | Method | Key kwargs |\n", "|---|---|---|\n", - "| Line | `canvas.add_line(x, y)` | `color`, `linestyle`, `linewidth`, `label` |\n", + "| Line | `canvas.plot(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 0535e79..972b2f6 100644 --- a/tutorials/tutorial_04.ipynb +++ b/tutorials/tutorial_04.ipynb @@ -69,9 +69,9 @@ "\n", "canvas = Canvas(width=\"10cm\", ratio=0.6)\n", "\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", + "canvas.plot(x, np.sin(x), color=\"steelblue\", label=\"named: steelblue\")\n", + "canvas.plot(x, np.sin(x - 0.5), color=\"#e74c3c\", label=\"hex: #e74c3c\")\n", + "canvas.plot(x, np.sin(x - 1.0), color=(0.2, 0.7, 0.3), label=\"RGB tuple\")\n", "\n", "canvas.set_xlabel(\"x\")\n", "canvas.set_ylabel(\"y\")\n", @@ -103,7 +103,7 @@ "canvas = Canvas(width=\"10cm\", ratio=0.6)\n", "\n", "for i, (name, ls) in enumerate(styles):\n", - " canvas.add_line(\n", + " canvas.plot(\n", " x,\n", " np.sin(x) + i * 0.4,\n", " linestyle=ls,\n", @@ -141,7 +141,7 @@ "canvas = Canvas(width=\"10cm\", ratio=0.65)\n", "\n", "for i, m in enumerate(markers):\n", - " canvas.add_line(\n", + " canvas.plot(\n", " x,\n", " np.sin(x) + i * 0.5,\n", " marker=m,\n", @@ -177,13 +177,13 @@ "\n", "canvas = Canvas(width=\"10cm\", ratio=0.55)\n", "\n", - "canvas.add_line(\n", + "canvas.plot(\n", " x, np.sin(x), linewidth=0.8, marker=\"o\", markersize=3, label=\"thin / small\"\n", ")\n", - "canvas.add_line(\n", + "canvas.plot(\n", " x, np.sin(x) - 0.6, linewidth=2.5, marker=\"o\", markersize=7, label=\"medium\"\n", ")\n", - "canvas.add_line(\n", + "canvas.plot(\n", " x, np.sin(x) - 1.2, linewidth=4.5, marker=\"o\", markersize=12, label=\"thick / large\"\n", ")\n", "\n", @@ -257,7 +257,7 @@ ")\n", "\n", "# Clean model\n", - "canvas.add_line(\n", + "canvas.plot(\n", " x,\n", " np.sin(x),\n", " color=\"#e74c3c\",\n", diff --git a/tutorials/tutorial_05.ipynb b/tutorials/tutorial_05.ipynb index 8c49e34..5b5b9fa 100644 --- a/tutorials/tutorial_05.ipynb +++ b/tutorials/tutorial_05.ipynb @@ -68,7 +68,7 @@ "x = np.linspace(0, 2 * np.pi, 200)\n", "\n", "canvas = Canvas(width=\"10cm\", ratio=0.55)\n", - "canvas.add_line(x, np.sin(x), color=\"steelblue\")\n", + "canvas.plot(x, np.sin(x), color=\"steelblue\")\n", "\n", "canvas.set_xlabel(r\"$x$ (radians)\")\n", "canvas.set_ylabel(r\"$\\sin(x)$\")\n", @@ -94,7 +94,7 @@ "x = np.linspace(0, 4 * np.pi, 300)\n", "\n", "canvas = Canvas(width=\"10cm\", ratio=0.5)\n", - "canvas.add_line(x, np.sin(x), color=\"tomato\")\n", + "canvas.plot(x, np.sin(x), color=\"tomato\")\n", "\n", "# Show only the first full period\n", "canvas.set_xlim(0, 2 * np.pi)\n", @@ -140,7 +140,7 @@ "temps = [3, 4, 7, 12, 17, 21, 23, 22, 18, 13, 7, 4]\n", "\n", "canvas = Canvas(width=\"12cm\", ratio=0.45)\n", - "canvas.add_line(range(12), temps, marker=\"o\", color=\"steelblue\", linewidth=2)\n", + "canvas.plot(range(12), temps, marker=\"o\", color=\"steelblue\", linewidth=2)\n", "\n", "canvas.set_xticks(list(range(12)), labels=months)\n", "canvas.set_ylabel(r\"Temperature ($^\\circ$C)\")\n", @@ -235,9 +235,9 @@ "x = np.linspace(0, 2 * np.pi, 200)\n", "\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(\n", + "canvas.plot(x, np.sin(x), color=\"steelblue\", label=r\"$\\sin(x)$\")\n", + "canvas.plot(x, np.cos(x), color=\"tomato\", label=r\"$\\cos(x)$\")\n", + "canvas.plot(\n", " x, np.sin(2 * x), color=\"seagreen\", label=r\"$\\sin(2x)$\", linestyle=\"dashed\"\n", ")\n", "\n", @@ -268,7 +268,7 @@ "y = np.sin(x)\n", "\n", "canvas = Canvas(width=\"10cm\", ratio=0.55)\n", - "canvas.add_line(x, y, color=\"steelblue\")\n", + "canvas.plot(x, y, color=\"steelblue\")\n", "\n", "# Annotate the maximum\n", "canvas.annotate(\n", @@ -306,7 +306,7 @@ "x = np.linspace(-2, 2, 200)\n", "\n", "canvas = Canvas(width=\"10cm\", ratio=0.55)\n", - "canvas.add_line(x, x**2, color=\"darkorange\")\n", + "canvas.plot(x, x**2, color=\"darkorange\")\n", "\n", "canvas.text(\n", " 0, 3.2, r\"$f(x) = x^2$\", ha=\"center\", va=\"bottom\", fontsize=12, color=\"darkorange\"\n", @@ -338,7 +338,7 @@ "theta = np.linspace(0, 2 * np.pi, 300)\n", "\n", "canvas = Canvas(width=\"7cm\", ratio=1.0)\n", - "canvas.add_line(np.cos(theta), np.sin(theta), color=\"steelblue\", linewidth=2)\n", + "canvas.plot(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", diff --git a/tutorials/tutorial_06.ipynb b/tutorials/tutorial_06.ipynb index bb23c82..51dc24f 100644 --- a/tutorials/tutorial_06.ipynb +++ b/tutorials/tutorial_06.ipynb @@ -69,9 +69,9 @@ "\n", "canvas = Canvas(width=\"10cm\", ratio=0.55)\n", "\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", + "canvas.plot(x, np.sin(x), color=\"steelblue\", label=r\"$\\sin(x)$\", layer=0)\n", + "canvas.plot(x, np.cos(x), color=\"tomato\", label=r\"$\\cos(x)$\", layer=1)\n", + "canvas.plot(\n", " x,\n", " np.sin(x) * np.cos(x),\n", " color=\"seagreen\",\n", @@ -107,9 +107,9 @@ "\n", "canvas = Canvas(width=\"10cm\", ratio=0.55)\n", "\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", + "canvas.plot(x, np.sin(x), color=\"steelblue\", label=r\"$\\sin(x)$\", layer=0)\n", + "canvas.plot(x, np.cos(x), color=\"tomato\", label=r\"$\\cos(x)$\", layer=1)\n", + "canvas.plot(\n", " x,\n", " np.sin(x) * np.cos(x),\n", " color=\"seagreen\",\n", @@ -210,7 +210,7 @@ "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(\n", + "canvas.plot(\n", " x, np.sin(x), color=\"steelblue\", linewidth=2, label=r\"true: $\\sin(x)$\", layer=1\n", ")\n", "\n", @@ -267,7 +267,7 @@ "\n", "| Concept | How |\n", "|---|---|\n", - "| Assign to layer | `canvas.add_line(..., layer=1)` |\n", + "| Assign to layer | `canvas.plot(..., 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 3a85ad8..cb48c04 100644 --- a/tutorials/tutorial_07_tikz.ipynb +++ b/tutorials/tutorial_07_tikz.ipynb @@ -68,14 +68,14 @@ "x = np.linspace(0, 2 * np.pi, 60)\n", "\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.plot(x, np.sin(x), label=\"sin\", color=\"steelblue\", line_width=1.5)\n", + "canvas.plot(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", + "tikz = canvas.render(backend=\"tikzfigure\")\n", "print(type(tikz))" ] }, @@ -144,7 +144,7 @@ "ax_ratio2.plot(x, np.exp(-x / np.pi), color=\"purple\", line_width=1.5)\n", "ax_ratio2.set_title(\"ratio = 2 export\")\n", "\n", - "tikz_ratio2 = canvas_ratio2.plot(backend=\"tikzfigure\")\n", + "tikz_ratio2 = canvas_ratio2.render(backend=\"tikzfigure\")\n", "ratio2_code = tikz_ratio2.generate_tikz()\n", "\n", "for line in ratio2_code.splitlines():\n", @@ -180,7 +180,7 @@ "ax2.set_xlabel(\"x\")\n", "ax2.set_title(\"Line width comparison\")\n", "\n", - "tikz2 = canvas2.plot(backend=\"tikzfigure\")\n", + "tikz2 = canvas2.render(backend=\"tikzfigure\")\n", "print(tikz2.generate_tikz())" ] }, @@ -213,12 +213,12 @@ "print(\"Available layers:\", canvas3.layers)\n", "\n", "# Render only layer 0 — one \\draw command\n", - "tikz_l0 = canvas3.plot(backend=\"tikzfigure\", layers=[0])\n", + "tikz_l0 = canvas3.render(backend=\"tikzfigure\", layers=[0])\n", "print(\"\\n--- Layer 0 only ---\")\n", "print(f\"\\\\draw count: {tikz_l0.generate_tikz().count(chr(92) + 'draw')}\")\n", "\n", "# Render layers 0 and 1\n", - "tikz_l01 = canvas3.plot(backend=\"tikzfigure\", layers=[0, 1])\n", + "tikz_l01 = canvas3.render(backend=\"tikzfigure\", layers=[0, 1])\n", "print(\"\\n--- Layers 0 & 1 ---\")\n", "print(f\"\\\\draw count: {tikz_l01.generate_tikz().count(chr(92) + 'draw')}\")" ] @@ -240,7 +240,7 @@ "metadata": {}, "outputs": [], "source": [ - "tikz_all = canvas3.plot(backend=\"tikzfigure\")\n", + "tikz_all = canvas3.render(backend=\"tikzfigure\")\n", "\n", "with open(\"figure.tex\", \"w\") as f:\n", " f.write(tikz_all.generate_tikz())\n", @@ -717,8 +717,8 @@ "### Canvas → TikZ workflow\n", "```python\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", + "canvas.plot(x, y, color='steelblue', line_width=1.5)\n", + "tikz = canvas.render(backend='tikzfigure')\n", "print(tikz.generate_tikz()) # inspect LaTeX\n", "tikz.show() # render (needs pdflatex)\n", "```\n", diff --git a/tutorials/tutorial_08_plotly.ipynb b/tutorials/tutorial_08_plotly.ipynb index a065c19..7feb299 100644 --- a/tutorials/tutorial_08_plotly.ipynb +++ b/tutorials/tutorial_08_plotly.ipynb @@ -48,7 +48,7 @@ "In notebooks, you can either:\n", "\n", "- call `canvas.show(backend=\"plotly\")` (displays and returns a Plotly figure), or\n", - "- call `fig = canvas.plot(backend=\"plotly\")` and put `fig` as the last line of a cell.\n", + "- call `fig = canvas.render(backend=\"plotly\")` and put `fig` as the last line of a cell.\n", "\n" ] }, @@ -62,7 +62,7 @@ "x = np.linspace(0, 2 * np.pi, 200)\n", "\n", "canvas = Canvas(width=\"10cm\", ratio=0.45)\n", - "canvas.add_line(x, np.sin(x), color=\"steelblue\", label=\"sin(x)\")\n", + "canvas.plot(x, np.sin(x), color=\"steelblue\", label=\"sin(x)\")\n", "canvas.set_title(\"Displayed inline\")\n", "canvas.set_legend(True)\n", "\n", @@ -90,7 +90,7 @@ "x = np.linspace(0, 2 * np.pi, 200)\n", "\n", "canvas = Canvas(width=\"10cm\", ratio=0.55)\n", - "canvas.add_line(x, np.sin(x), color=\"steelblue\", label=\"sin(x)\")\n", + "canvas.plot(x, np.sin(x), color=\"steelblue\", label=\"sin(x)\")\n", "canvas.set_xlabel(\"x\")\n", "canvas.set_ylabel(\"y\")\n", "canvas.set_title(\"Basic line plot\")\n", @@ -106,7 +106,7 @@ "source": [ "## 2 · Multiple lines\n", "\n", - "Each `canvas.add_line()` call becomes a separate Plotly trace. Enable the legend with `canvas.set_legend(True)` so trace labels appear." + "Each `canvas.plot()` call becomes a separate Plotly trace. Enable the legend with `canvas.set_legend(True)` so trace labels appear." ] }, { @@ -119,9 +119,9 @@ "x = np.linspace(0, 2 * np.pi, 200)\n", "\n", "canvas = Canvas(width=\"10cm\", ratio=0.55)\n", - "canvas.add_line(x, np.sin(x), color=\"steelblue\", label=\"sin(x)\", linewidth=2)\n", - "canvas.add_line(x, np.cos(x), color=\"tomato\", label=\"cos(x)\", linewidth=2)\n", - "canvas.add_line(\n", + "canvas.plot(x, np.sin(x), color=\"steelblue\", label=\"sin(x)\", linewidth=2)\n", + "canvas.plot(x, np.cos(x), color=\"tomato\", label=\"cos(x)\", linewidth=2)\n", + "canvas.plot(\n", " x,\n", " np.sin(2 * x),\n", " color=\"seagreen\",\n", @@ -165,7 +165,7 @@ "canvas.scatter(\n", " x_data, y_data, color=\"steelblue\", marker=\"o\", s=20, label=\"observations\"\n", ")\n", - "canvas.add_line(\n", + "canvas.plot(\n", " [0, 10],\n", " [0, 5],\n", " color=\"tomato\",\n", @@ -242,7 +242,7 @@ "canvas.bar(\n", " months, rainfall, color=\"steelblue\", alpha=0.7, label=\"monthly rainfall (mm)\"\n", ")\n", - "canvas.add_line(\n", + "canvas.plot(\n", " months,\n", " cumulative / 10,\n", " color=\"tomato\",\n", @@ -283,8 +283,8 @@ "canvas = Canvas(ncols=1) # , width=\"14cm\", ratio=0.35)\n", "\n", "# Left panel — line plot\n", - "canvas.add_line(x, np.sin(x), color=\"steelblue\", label=\"sin(x)\", linewidth=2, col=0)\n", - "canvas.add_line(x, np.cos(x), color=\"tomato\", label=\"cos(x)\", linewidth=2, col=0)\n", + "canvas.plot(x, np.sin(x), color=\"steelblue\", label=\"sin(x)\", linewidth=2, col=0)\n", + "canvas.plot(x, np.cos(x), color=\"tomato\", label=\"cos(x)\", linewidth=2, col=0)\n", "canvas.set_xlabel(\"x\", col=0)\n", "canvas.set_ylabel(\"y\", col=0)\n", "canvas.set_title(\"Trigonometric functions\", col=0)\n", @@ -294,7 +294,7 @@ "x_s = rng.uniform(0, 6, 80)\n", "y_s = np.sin(x_s) + rng.normal(0, 0.15, 80)\n", "canvas.scatter(x_s, y_s, color=\"seagreen\", marker=\"o\", s=18, label=\"noisy sin\", col=1)\n", - "canvas.add_line(\n", + "canvas.plot(\n", " x,\n", " np.sin(x),\n", " color=\"black\",\n", @@ -333,9 +333,9 @@ "x = np.linspace(0.1, 5, 200)\n", "\n", "canvas = Canvas(width=\"10cm\", ratio=0.55)\n", - "canvas.add_line(x, np.exp(x), color=\"steelblue\", label=\"exp(x)\", linewidth=2)\n", - "canvas.add_line(x, np.exp(1.5 * x), color=\"tomato\", label=\"exp(1.5x)\", linewidth=2)\n", - "canvas.add_line(x, x**2, color=\"seagreen\", label=\"x²\", linewidth=2)\n", + "canvas.plot(x, np.exp(x), color=\"steelblue\", label=\"exp(x)\", linewidth=2)\n", + "canvas.plot(x, np.exp(1.5 * x), color=\"tomato\", label=\"exp(1.5x)\", linewidth=2)\n", + "canvas.plot(x, x**2, color=\"seagreen\", label=\"x²\", linewidth=2)\n", "\n", "canvas.set_xlabel(\"x\")\n", "canvas.set_ylabel(\"y (log scale)\")\n", @@ -366,8 +366,8 @@ "x = np.linspace(0, 2 * np.pi, 200)\n", "\n", "canvas = Canvas(width=\"10cm\", ratio=0.55)\n", - "canvas.add_line(x, np.sin(x), color=\"steelblue\", label=\"sin(x)\", linewidth=2)\n", - "canvas.add_line(x, np.cos(x), color=\"tomato\", label=\"cos(x)\", linewidth=2)\n", + "canvas.plot(x, np.sin(x), color=\"steelblue\", label=\"sin(x)\", linewidth=2)\n", + "canvas.plot(x, np.cos(x), color=\"tomato\", label=\"cos(x)\", linewidth=2)\n", "canvas.set_xlabel(\"x\")\n", "canvas.set_ylabel(\"y\")\n", "canvas.set_title(\"Saved interactive figure\")\n", @@ -389,7 +389,7 @@ "\n", "| Feature | Supported | Notes |\n", "|---|---|---|\n", - "| `canvas.add_line()` — line trace | ✅ | `color`, `linestyle`, `linewidth`, `marker` all passed through |\n", + "| `canvas.plot()` — 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", @@ -409,10 +409,10 @@ "import numpy as np\n", "\n", "canvas = Canvas()\n", - "canvas.add_line(x, y, label='data')\n", + "canvas.plot(x, y, label='data')\n", "canvas.set_legend(True)\n", "\n", - "fig = canvas.plot(backend='plotly') # → plotly.graph_objects.Figure\n", + "fig = canvas.render(backend='plotly') # → plotly.graph_objects.Figure\n", "fig.show() # interactive in Jupyter\n", "fig.write_html('report.html') # share with anyone\n", "```" diff --git a/tutorials/tutorial_09_plotext.ipynb b/tutorials/tutorial_09_plotext.ipynb index 4b6276b..060a562 100644 --- a/tutorials/tutorial_09_plotext.ipynb +++ b/tutorials/tutorial_09_plotext.ipynb @@ -55,7 +55,7 @@ "source": [ "## 1 · Figure lifecycle: `plot()`, `build()`, `show()`, and `savefig()`\n", "\n", - "Use `canvas.plot(backend=\"plotext\")` when you want a reusable terminal figure object. The returned object supports:\n", + "Use `canvas.render(backend=\"plotext\")` when you want a reusable terminal figure object. The returned object supports:\n", "\n", "- `.build()` to get the rendered terminal plot as a string\n", "- `.show()` to print it immediately\n", @@ -74,12 +74,12 @@ "x = np.linspace(0, 2 * np.pi, 100)\n", "\n", "canvas = Canvas()\n", - "canvas.add_line(x, np.sin(x), color=\"cyan\", label=\"sin(x)\")\n", + "canvas.plot(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", + "terminal_fig = canvas.render(backend=\"plotext\")\n", "preview = terminal_fig.build(keep_colors=False)\n", "print(preview)\n", "\n", @@ -107,16 +107,16 @@ "x = np.linspace(0, 2 * np.pi, 120)\n", "\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.plot(x, np.sin(x), color=\"cyan\", label=\"sin(x)\")\n", + "canvas.plot(x, np.cos(x), color=\"yellow\", label=\"cos(x)\", marker=\"dot\")\n", + "canvas.plot(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))" + "print(canvas.render(backend=\"plotext\").build(keep_colors=False))" ] }, { @@ -142,14 +142,14 @@ "samples_y = np.sin(samples_x) + rng.normal(0, 0.15, len(samples_x))\n", "\n", "canvas = Canvas()\n", - "canvas.add_line(x, np.sin(x), color=\"white\", label=\"sin(x)\")\n", + "canvas.plot(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))" + "print(canvas.render(backend=\"plotext\").build(keep_colors=False))" ] }, { @@ -180,7 +180,7 @@ "canvas.set_ylabel(\"value\")\n", "canvas.set_legend(True)\n", "\n", - "print(canvas.plot(backend=\"plotext\").build(keep_colors=False))" + "print(canvas.render(backend=\"plotext\").build(keep_colors=False))" ] }, { @@ -218,7 +218,7 @@ "canvas.set_ylabel(\"amplitude\")\n", "canvas.set_legend(True)\n", "\n", - "print(canvas.plot(backend=\"plotext\").build(keep_colors=False))" + "print(canvas.render(backend=\"plotext\").build(keep_colors=False))" ] }, { @@ -234,12 +234,12 @@ "\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.plot(x, upper, color=\"white\", label=\"upper\")\n", + "canvas.plot(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))" + "print(canvas.render(backend=\"plotext\").build(keep_colors=False))" ] }, { @@ -273,7 +273,7 @@ "canvas.set_ylabel(\"y\")\n", "canvas.set_legend(True)\n", "\n", - "print(canvas.plot(backend=\"plotext\").build(keep_colors=False))" + "print(canvas.render(backend=\"plotext\").build(keep_colors=False))" ] }, { @@ -299,7 +299,7 @@ "peak_y = y.max()\n", "\n", "canvas = Canvas()\n", - "canvas.add_line(x, y, color=\"cyan\")\n", + "canvas.plot(x, y, color=\"cyan\")\n", "canvas.text(0.8, -0.8, \"terminal note\", color=\"yellow\")\n", "canvas.annotate(\n", " \"peak\",\n", @@ -310,7 +310,7 @@ ")\n", "canvas.set_title(\"Text and annotations\")\n", "\n", - "print(canvas.plot(backend=\"plotext\").build(keep_colors=False))" + "print(canvas.render(backend=\"plotext\").build(keep_colors=False))" ] }, { @@ -333,8 +333,8 @@ "x = np.linspace(1, 20, 120)\n", "\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.plot(x, x**0.5, color=\"cyan\", label=\"sqrt(x)\")\n", + "canvas.plot(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", @@ -346,7 +346,7 @@ "canvas.set_grid(True)\n", "canvas.set_legend(True)\n", "\n", - "print(canvas.plot(backend=\"plotext\").build(keep_colors=False))" + "print(canvas.render(backend=\"plotext\").build(keep_colors=False))" ] }, { @@ -369,8 +369,8 @@ "x = np.linspace(0, 2 * np.pi, 100)\n", "\n", "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.plot(x, np.sin(x), color=\"cyan\", label=\"layer 0\", layer=0)\n", + "canvas.plot(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)" @@ -383,7 +383,7 @@ "metadata": {}, "outputs": [], "source": [ - "print(canvas.plot(backend=\"plotext\", layers=[0]).build(keep_colors=False))" + "print(canvas.render(backend=\"plotext\", layers=[0]).build(keep_colors=False))" ] }, { @@ -393,7 +393,7 @@ "metadata": {}, "outputs": [], "source": [ - "print(canvas.plot(backend=\"plotext\", layers=[1]).build(keep_colors=False))" + "print(canvas.render(backend=\"plotext\", layers=[1]).build(keep_colors=False))" ] }, { @@ -403,7 +403,7 @@ "metadata": {}, "outputs": [], "source": [ - "print(canvas.plot(backend=\"plotext\", layers=[0, 1]).build(keep_colors=False))" + "print(canvas.render(backend=\"plotext\", layers=[0, 1]).build(keep_colors=False))" ] }, { @@ -445,7 +445,7 @@ "ax2.set_legend(True)\n", "\n", "canvas.suptitle(\"Terminal dashboard\")\n", - "print(canvas.plot(backend=\"plotext\").build(keep_colors=False))" + "print(canvas.render(backend=\"plotext\").build(keep_colors=False))" ] }, { @@ -473,7 +473,7 @@ "canvas.set_xlabel(\"column\")\n", "canvas.set_ylabel(\"row\")\n", "\n", - "print(canvas.plot(backend=\"plotext\").build(keep_colors=False))" + "print(canvas.render(backend=\"plotext\").build(keep_colors=False))" ] }, { @@ -528,7 +528,7 @@ "canvas.set_title(\"Supported patch types\")\n", "canvas.set_legend(True)\n", "\n", - "print(canvas.plot(backend=\"plotext\").build(keep_colors=False))" + "print(canvas.render(backend=\"plotext\").build(keep_colors=False))" ] }, { @@ -579,7 +579,7 @@ "x = np.linspace(-20, 20, 161)\n", "\n", "canvas = Canvas()\n", - "canvas.add_line(x, x**3, color=\"cyan\", label=\"x^3\")\n", + "canvas.plot(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", @@ -587,7 +587,7 @@ "canvas.set_aspect(\"equal\")\n", "canvas.set_legend(True)\n", "\n", - "print(canvas.plot(backend=\"plotext\").build(keep_colors=False))" + "print(canvas.render(backend=\"plotext\").build(keep_colors=False))" ] }, { @@ -604,7 +604,7 @@ "canvas.add_colorbar(label=\"intensity\")\n", "canvas.set_title(\"Matrix + colorbar note\")\n", "\n", - "print(canvas.plot(backend=\"plotext\").build(keep_colors=False))" + "print(canvas.render(backend=\"plotext\").build(keep_colors=False))" ] }, { @@ -649,9 +649,9 @@ "x = np.linspace(0, 2 * np.pi, 60)\n", "\n", "canvas = Canvas()\n", - "canvas.add_line(x, np.sin(x), color=\"cyan\", label=\"sin(x)\")\n", + "canvas.plot(x, np.sin(x), color=\"cyan\", label=\"sin(x)\")\n", "canvas.set_title(\"Saved terminal figure\")\n", - "terminal_fig = canvas.plot(backend=\"plotext\")\n", + "terminal_fig = canvas.render(backend=\"plotext\")\n", "\n", "output_path = Path(\"plotext_output.txt\")\n", "terminal_fig.savefig(output_path)\n", @@ -685,14 +685,14 @@ "\n", "for phase in np.linspace(0, 2 * np.pi, 24):\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.plot(x, np.sin(x + phase), color=\"cyan\", label=\"sin(x + phase)\")\n", + " canvas.plot(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", + " print(canvas.render(backend=\"plotext\").build(keep_colors=False))\n", " time.sleep(0.08)" ] }, diff --git a/tutorials/tutorial_10_matplotlib_nxm_spacing.ipynb b/tutorials/tutorial_10_matplotlib_nxm_spacing.ipynb index f573054..7044b62 100644 --- a/tutorials/tutorial_10_matplotlib_nxm_spacing.ipynb +++ b/tutorials/tutorial_10_matplotlib_nxm_spacing.ipynb @@ -70,12 +70,12 @@ ")\n", "for i, row in enumerate(tight_axes):\n", " for j, ax in enumerate(row):\n", - " tight_canvas.add_line(\n", + " tight_canvas.plot(\n", " x, np.sin((i + 1) * (j + 1) * x), label=f\"sin({(i + 1) * (j + 1)}x)\"\n", " )\n", " tight_canvas.set_title(f\"line {i},{j}\")\n", "\n", - "tight_fig, tight_m_axes = tight_canvas.plot(backend=\"matplotlib\")\n", + "tight_fig, tight_m_axes = tight_canvas.render(backend=\"matplotlib\")\n", "tight_fig.suptitle(\"Line plots - tight spacing\")\n", "tight_h, tight_v = measure_gaps(tight_m_axes)\n", "print(f\"tight line gaps: h={tight_h:.4f}, v={tight_v:.4f}\")\n", @@ -90,12 +90,12 @@ ")\n", "for i, row in enumerate(loose_axes):\n", " for j, ax in enumerate(row):\n", - " loose_canvas.add_line(\n", + " loose_canvas.plot(\n", " x, np.sin((i + 1) * (j + 1) * x), label=f\"sin({(i + 1) * (j + 1)}x)\"\n", " )\n", " loose_canvas.set_title(f\"line {i},{j}\")\n", "\n", - "loose_fig, loose_m_axes = loose_canvas.plot(backend=\"matplotlib\")\n", + "loose_fig, loose_m_axes = loose_canvas.render(backend=\"matplotlib\")\n", "loose_fig.suptitle(\"Line plots - loose spacing\")\n", "loose_h, loose_v = measure_gaps(loose_m_axes)\n", "print(f\"loose line gaps: h={loose_h:.4f}, v={loose_v:.4f}\")\n", @@ -136,7 +136,7 @@ " tight_canvas.set_title(f\"heatmap {idx}\")\n", " idx += 1\n", "\n", - "tight_fig, tight_m_axes = tight_canvas.plot(backend=\"matplotlib\")\n", + "tight_fig, tight_m_axes = tight_canvas.render(backend=\"matplotlib\")\n", "tight_fig.suptitle(\"Color plots - tight spacing\")\n", "tight_h, tight_v = measure_gaps(tight_m_axes)\n", "print(f\"tight color gaps: h={tight_h:.4f}, v={tight_v:.4f}\")\n", @@ -156,7 +156,7 @@ " loose_canvas.set_title(f\"heatmap {idx}\")\n", " idx += 1\n", "\n", - "loose_fig, loose_m_axes = loose_canvas.plot(backend=\"matplotlib\")\n", + "loose_fig, loose_m_axes = loose_canvas.render(backend=\"matplotlib\")\n", "loose_fig.suptitle(\"Color plots - loose spacing\")\n", "loose_h, loose_v = measure_gaps(loose_m_axes)\n", "print(f\"loose color gaps: h={loose_h:.4f}, v={loose_v:.4f}\")\n", diff --git a/tutorials/tutorial_11_gantt_charts.ipynb b/tutorials/tutorial_11_gantt_charts.ipynb index 41fb565..4372f19 100644 --- a/tutorials/tutorial_11_gantt_charts.ipynb +++ b/tutorials/tutorial_11_gantt_charts.ipynb @@ -53,7 +53,7 @@ "\n", "canvas.set_xlabel(\"Time (days)\")\n", "canvas.set_title(\"Project Timeline\")\n", - "canvas.plot(backend=\"matplotlib\")" + "canvas.render(backend=\"matplotlib\")" ] }, { @@ -117,7 +117,7 @@ "canvas.set_xlabel(\"Time (days)\")\n", "canvas.set_title(\"Multi-Phase Project Timeline\")\n", "canvas.set_legend(True)\n", - "canvas.plot(backend=\"matplotlib\")" + "canvas.render(backend=\"matplotlib\")" ] }, { @@ -152,7 +152,7 @@ "\n", "canvas.set_xlabel(\"Week\")\n", "canvas.set_title(\"Team Resource Allocation\")\n", - "canvas.plot(backend=\"matplotlib\")" + "canvas.render(backend=\"matplotlib\")" ] }, { @@ -185,7 +185,7 @@ "\n", "canvas.set_xlabel(\"Days\")\n", "canvas.set_title(\"Interactive Project Timeline\")\n", - "fig = canvas.plot(backend=\"plotly\")\n", + "fig = canvas.render(backend=\"plotly\")\n", "fig.show()" ] }, @@ -220,7 +220,7 @@ "\n", "canvas.set_xlabel(\"Days\")\n", "canvas.set_title(\"Project with Milestones\")\n", - "canvas.plot(backend=\"matplotlib\")" + "canvas.render(backend=\"matplotlib\")" ] }, { @@ -246,13 +246,13 @@ "canvas_mpl = Canvas(nrows=1, ncols=1, figsize=(10, 5))\n", "canvas_mpl.gantt(tasks, start_times, durations, color=\"skyblue\")\n", "canvas_mpl.set_title(\"Matplotlib Backend\")\n", - "canvas_mpl.plot(backend=\"matplotlib\")\n", + "canvas_mpl.render(backend=\"matplotlib\")\n", "\n", "# Plotly\n", "canvas_plotly = Canvas(nrows=1, ncols=1, figsize=(10, 5))\n", "canvas_plotly.gantt(tasks, start_times, durations, color=\"skyblue\")\n", "canvas_plotly.set_title(\"Plotly Backend\")\n", - "fig = canvas_plotly.plot(backend=\"plotly\")\n", + "fig = canvas_plotly.render(backend=\"plotly\")\n", "fig.show()" ] }, diff --git a/tutorials/tutorial_12_flame_charts.ipynb b/tutorials/tutorial_12_flame_charts.ipynb index 8a35a0a..74d15a3 100644 --- a/tutorials/tutorial_12_flame_charts.ipynb +++ b/tutorials/tutorial_12_flame_charts.ipynb @@ -67,7 +67,7 @@ "canvas.set_xlabel(\"Time (ms)\")\n", "canvas.set_ylabel(\"Stack Depth\")\n", "canvas.set_title(\"Function Call Hierarchy\")\n", - "canvas.plot(backend=\"matplotlib\")" + "canvas.render(backend=\"matplotlib\")" ] }, { @@ -132,7 +132,7 @@ "canvas.set_xlabel(\"Time (ms)\")\n", "canvas.set_ylabel(\"Stack Depth\")\n", "canvas.set_title(\"Complex Application Profiling\")\n", - "canvas.plot(backend=\"matplotlib\")" + "canvas.render(backend=\"matplotlib\")" ] }, { @@ -181,7 +181,7 @@ "canvas.set_xlabel(\"Time (ms)\")\n", "canvas.set_ylabel(\"Call Stack Depth\")\n", "canvas.set_title(\"CPU Profiling: Parallel Workers\")\n", - "canvas.plot(backend=\"matplotlib\")" + "canvas.render(backend=\"matplotlib\")" ] }, { @@ -228,7 +228,7 @@ "canvas.set_xlabel(\"Time (ms)\")\n", "canvas.set_ylabel(\"Stack Depth\")\n", "canvas.set_title(\"Interactive Flame Chart - Hover for Details\")\n", - "fig = canvas.plot(backend=\"plotly\")\n", + "fig = canvas.render(backend=\"plotly\")\n", "fig.show()" ] }, @@ -264,7 +264,7 @@ "canvas.set_xlabel(\"Relative Time\")\n", "canvas.set_ylabel(\"Depth\")\n", "canvas.set_title(\"Flame Chart with Auto-computed Start Times\")\n", - "canvas.plot(backend=\"matplotlib\")" + "canvas.render(backend=\"matplotlib\")" ] }, { @@ -300,7 +300,7 @@ " edgecolor=\"black\",\n", " )\n", " canvas.set_title(f\"Colormap: {cmap}\")\n", - " canvas.plot(backend=\"matplotlib\")" + " canvas.render(backend=\"matplotlib\")" ] }, { @@ -350,7 +350,7 @@ "canvas.set_xlabel(\"Time (ms)\")\n", "canvas.set_ylabel(\"Call Stack\")\n", "canvas.set_title(\"Web Request Processing Profile\")\n", - "canvas.plot(backend=\"matplotlib\")" + "canvas.render(backend=\"matplotlib\")" ] }, { diff --git a/tutorials/tutorial_13_advanced_matplotlib.ipynb b/tutorials/tutorial_13_advanced_matplotlib.ipynb index 2ce019e..47e2954 100644 --- a/tutorials/tutorial_13_advanced_matplotlib.ipynb +++ b/tutorials/tutorial_13_advanced_matplotlib.ipynb @@ -131,7 +131,7 @@ "outputs": [], "source": [ "canvas = Canvas()\n", - "canvas.add_line(x, np.sin(x), color=\"black\")\n", + "canvas.plot(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", diff --git a/tutorials/tutorial_14_axis_and_layout_controls.ipynb b/tutorials/tutorial_14_axis_and_layout_controls.ipynb index 855631c..e02300f 100644 --- a/tutorials/tutorial_14_axis_and_layout_controls.ipynb +++ b/tutorials/tutorial_14_axis_and_layout_controls.ipynb @@ -91,7 +91,7 @@ "outputs": [], "source": [ "canvas = Canvas()\n", - "canvas.add_line([0, 1, 2], [0, 4, 1])\n", + "canvas.plot([0, 1, 2], [0, 4, 1])\n", "canvas.axis([0, 2, -1, 5])\n", "canvas.relim()\n", "canvas.autoscale_view(tight=True)\n", @@ -116,7 +116,7 @@ "outputs": [], "source": [ "canvas = Canvas()\n", - "canvas.add_line(x, x**2)\n", + "canvas.plot(x, x**2)\n", "canvas.set_xlabel(\"distance (m)\")\n", "canvas.set_ylabel(\"area (m²)\")\n", "canvas.secondary_xaxis(\n", @@ -146,7 +146,7 @@ "outputs": [], "source": [ "canvas = Canvas()\n", - "canvas.add_line([0, 1, 2], [0, 1, 0], marker=\"o\")\n", + "canvas.plot([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", diff --git a/tutorials/tutorial_tikzfigure_subplots.ipynb b/tutorials/tutorial_tikzfigure_subplots.ipynb index faedb7a..1b61846 100644 --- a/tutorials/tutorial_tikzfigure_subplots.ipynb +++ b/tutorials/tutorial_tikzfigure_subplots.ipynb @@ -75,7 +75,7 @@ "metadata": {}, "outputs": [], "source": [ - "tikz = canvas.plot(backend=\"tikzfigure\")\n", + "tikz = canvas.render(backend=\"tikzfigure\")\n", "subplot_code = tikz.generate_tikz()\n", "\n", "for line in subplot_code.splitlines():\n", From e583251e37bccd8a65f66c72bf890b154eb147e2 Mon Sep 17 00:00:00 2001 From: Max Date: Sat, 22 Aug 2026 13:46:45 +0200 Subject: [PATCH 2/3] Formatting --- src/maxplotlib/canvas/canvas.py | 4 +++- tutorials/tutorial_04.ipynb | 8 ++------ tutorials/tutorial_05.ipynb | 4 +--- 3 files changed, 6 insertions(+), 10 deletions(-) diff --git a/src/maxplotlib/canvas/canvas.py b/src/maxplotlib/canvas/canvas.py index dfaff97..66f1ae2 100644 --- a/src/maxplotlib/canvas/canvas.py +++ b/src/maxplotlib/canvas/canvas.py @@ -1863,7 +1863,9 @@ def plot(self, *args, backend=None, **kwargs): return self if args: if len(args) > 1: - raise TypeError("plot() accepts at most one backend positional argument") + raise TypeError( + "plot() accepts at most one backend positional argument" + ) if backend is not None: raise TypeError("backend was provided both positionally and by keyword") backend = args[0] diff --git a/tutorials/tutorial_04.ipynb b/tutorials/tutorial_04.ipynb index 972b2f6..81209c1 100644 --- a/tutorials/tutorial_04.ipynb +++ b/tutorials/tutorial_04.ipynb @@ -177,12 +177,8 @@ "\n", "canvas = Canvas(width=\"10cm\", ratio=0.55)\n", "\n", - "canvas.plot(\n", - " x, np.sin(x), linewidth=0.8, marker=\"o\", markersize=3, label=\"thin / small\"\n", - ")\n", - "canvas.plot(\n", - " x, np.sin(x) - 0.6, linewidth=2.5, marker=\"o\", markersize=7, label=\"medium\"\n", - ")\n", + "canvas.plot(x, np.sin(x), linewidth=0.8, marker=\"o\", markersize=3, label=\"thin / small\")\n", + "canvas.plot(x, np.sin(x) - 0.6, linewidth=2.5, marker=\"o\", markersize=7, label=\"medium\")\n", "canvas.plot(\n", " x, np.sin(x) - 1.2, linewidth=4.5, marker=\"o\", markersize=12, label=\"thick / large\"\n", ")\n", diff --git a/tutorials/tutorial_05.ipynb b/tutorials/tutorial_05.ipynb index 5b5b9fa..b7c53bc 100644 --- a/tutorials/tutorial_05.ipynb +++ b/tutorials/tutorial_05.ipynb @@ -237,9 +237,7 @@ "canvas = Canvas(width=\"10cm\", ratio=0.55)\n", "canvas.plot(x, np.sin(x), color=\"steelblue\", label=r\"$\\sin(x)$\")\n", "canvas.plot(x, np.cos(x), color=\"tomato\", label=r\"$\\cos(x)$\")\n", - "canvas.plot(\n", - " x, np.sin(2 * x), color=\"seagreen\", label=r\"$\\sin(2x)$\", linestyle=\"dashed\"\n", - ")\n", + "canvas.plot(x, np.sin(2 * x), color=\"seagreen\", label=r\"$\\sin(2x)$\", linestyle=\"dashed\")\n", "\n", "canvas.set_xlabel(\"x\")\n", "canvas.set_legend(True)\n", From 316dbe27eb37d30150ba62822daf42d24e227992 Mon Sep 17 00:00:00 2001 From: Max Date: Sat, 22 Aug 2026 13:50:19 +0200 Subject: [PATCH 3/3] Raise warning --- README.md | 7 ++++++- README.qmd | 5 +++++ src/maxplotlib/canvas/canvas.py | 27 ++++++++++++++++++--------- src/maxplotlib/tests/test_canvas.py | 14 +++++++++++++- 4 files changed, 42 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index cf050d8..5e2ec5f 100644 --- a/README.md +++ b/README.md @@ -45,6 +45,11 @@ canvas.show() ![](README_files/figure-commonmark/cell-3-output-1.png) +Use `canvas.plot(x, y)` to add data directly to a canvas. When you want +to explicitly render an already-built canvas, use `canvas.render(...)`. +The older `canvas.plot(backend=...)` spelling is still supported for +compatibility, but emits a `FutureWarning`. + For Matplotlib-specific customization, pass method calls declaratively. Figure methods run once and axes methods run for every subplot, providing access to any Matplotlib API without requiring a maxplotlib @@ -270,7 +275,7 @@ canvas.show(backend="plotext") 1.0 1.8 3.2 5.6 10.0 y x - + ### Layers diff --git a/README.qmd b/README.qmd index 1cfb6ae..7d4ab21 100644 --- a/README.qmd +++ b/README.qmd @@ -42,6 +42,11 @@ Plot the figure with the default (matplotlib) backend: canvas.show() ``` +Use `canvas.plot(x, y)` to add data directly to a canvas. When you want to +explicitly render an already-built canvas, use `canvas.render(...)`. The older +`canvas.plot(backend=...)` spelling is still supported for compatibility, but +emits a `FutureWarning`. + For Matplotlib-specific customization, pass method calls declaratively. Figure methods run once and axes methods run for every subplot, providing access to any Matplotlib API without requiring a maxplotlib wrapper: diff --git a/src/maxplotlib/canvas/canvas.py b/src/maxplotlib/canvas/canvas.py index 66f1ae2..f65ff7a 100644 --- a/src/maxplotlib/canvas/canvas.py +++ b/src/maxplotlib/canvas/canvas.py @@ -1,5 +1,6 @@ import os import re +import warnings from dataclasses import dataclass from typing import Mapping @@ -1686,7 +1687,7 @@ def savefig( layers = [] for layer in self.layers: layers.append(layer) - fig, axs = self.plot( + fig, axs = self._render( show=False, backend="matplotlib", savefig=True, @@ -1707,7 +1708,7 @@ def savefig( savefig_kwargs = {"dpi": self.dpi} if self.dpi is not None else {} self._matplotlib_fig.savefig(full_filepath, **savefig_kwargs) else: - fig, axs = self.plot( + fig, axs = self._render( backend="matplotlib", savefig=True, layers=layers, @@ -1721,7 +1722,7 @@ def savefig( layers = [] for layer in self.layers: layers.append(layer) - figure = self.plot( + figure = self._render( backend="plotext", savefig=False, layers=layers, @@ -1735,7 +1736,7 @@ def savefig( full_filepath = filename else: full_filepath = f"{filename_no_extension}_{layers}.{extension}" - figure = self.plot( + figure = self._render( backend="plotext", savefig=False, layers=layers, @@ -1749,7 +1750,7 @@ def savefig( for layer in self.layers: layers.append(layer) full_filepath = f"{filename_no_extension}_{layers}{extension}" - fig = self.plot( + fig = self._render( backend="plotly", savefig=False, layers=layers, @@ -1763,7 +1764,7 @@ def savefig( full_filepath = filename else: full_filepath = f"{filename_no_extension}_{layers}{extension}" - fig = self.plot( + fig = self._render( backend="plotly", savefig=False, layers=layers, @@ -1776,7 +1777,7 @@ def savefig( raise NotImplementedError( "Layer-by-layer rendering is not supported for tikzfigure backend" ) - fig = self.plot(backend="tikzfigure", savefig=False) + fig = self._render(backend="tikzfigure", savefig=False) fig.savefig(filename) if verbose: print(f"Saved {filename}") @@ -1851,6 +1852,7 @@ def plot(self, *args, backend=None, **kwargs): Rendering is named explicitly by ``canvas.render(...)``; the legacy ``canvas.plot(backend=...)`` form remains supported. """ + explicit_render = backend is not None or (args and isinstance(args[0], str)) if args and not isinstance(args[0], str): if len(args) < 2: raise TypeError("plot(x, y) requires both x and y data") @@ -1871,6 +1873,13 @@ def plot(self, *args, backend=None, **kwargs): backend = args[0] if backend is None: backend = "matplotlib" + if explicit_render: + warnings.warn( + "canvas.plot(backend=...) is deprecated; use " + "canvas.render(backend=...) instead", + FutureWarning, + stacklevel=2, + ) return self._render(backend=backend, **kwargs) def render(self, *args, **kwargs): @@ -1921,7 +1930,7 @@ def show( if backend == "matplotlib": if verbose: print("Generating Matplotlib figure for display...") - fig, axes = self.plot( + fig, axes = self._render( backend="matplotlib", savefig=False, layers=layers, @@ -2659,5 +2668,5 @@ def __str__(self): c = Canvas(ncols=2, nrows=2) sp = c.add_subplot() sp.plot([0, 1, 2, 3], [0, 1, 4, 9], label="Line 1") - c.plot(backend="matplotlib") + c.render(backend="matplotlib") print("done") diff --git a/src/maxplotlib/tests/test_canvas.py b/src/maxplotlib/tests/test_canvas.py index 1bdf2b9..38c020e 100644 --- a/src/maxplotlib/tests/test_canvas.py +++ b/src/maxplotlib/tests/test_canvas.py @@ -376,7 +376,7 @@ def test_canvas_show_uses_ipython_display_in_jupyter(monkeypatch): monkeypatch.setitem(sys.modules, "IPython", ipython) monkeypatch.setitem(sys.modules, "IPython.display", ipython_display) monkeypatch.setattr(plt, "close", lambda value: closed.append(value)) - monkeypatch.setattr(Canvas, "plot", lambda *args, **kwargs: (fig, object())) + monkeypatch.setattr(Canvas, "_render", lambda *args, **kwargs: (fig, object())) monkeypatch.setattr(plt, "show", lambda: pytest.fail("pyplot.show was called")) canvas = Canvas() @@ -901,6 +901,18 @@ def test_plot_adds_line_data_when_given_x_and_y(): assert canvas.render(backend="plotly").data[0].name == "line" +def test_legacy_plot_backend_form_warns(): + import pytest + + from maxplotlib import Canvas + + canvas = Canvas() + canvas.add_line([0, 1], [0, 1]) + + with pytest.warns(FutureWarning, match=r"canvas\.render"): + canvas.plot(backend="plotly") + + def test_matplotlib_postprocess_can_customize_figure_and_axes(): import matplotlib.pyplot as plt from matplotlib.colors import to_rgba