Skip to content

Commit 120f503

Browse files
committed
updated tutorials
1 parent c288b53 commit 120f503

12 files changed

Lines changed: 696 additions & 235 deletions

src/maxplotlib/canvas/canvas.py

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1193,10 +1193,11 @@ def plot_plotly(
11931193

11941194
# Axis limits
11951195
if line_plot._xmin is not None or line_plot._xmax is not None:
1196-
x_range = [
1197-
line_plot._xmin if line_plot._xmin is not None else None,
1198-
line_plot._xmax if line_plot._xmax is not None else None,
1199-
]
1196+
x_range = [line_plot._xmin, line_plot._xmax]
1197+
if x_range[0] is not None:
1198+
x_range[0] = line_plot._transform_scalar_x(x_range[0])
1199+
if x_range[1] is not None:
1200+
x_range[1] = line_plot._transform_scalar_x(x_range[1])
12001201
if (
12011202
line_plot._xaxis_scale == "log"
12021203
and x_range[0] is not None
@@ -1211,10 +1212,11 @@ def plot_plotly(
12111212
col=col + 1,
12121213
)
12131214
if line_plot._ymin is not None or line_plot._ymax is not None:
1214-
y_range = [
1215-
line_plot._ymin if line_plot._ymin is not None else None,
1216-
line_plot._ymax if line_plot._ymax is not None else None,
1217-
]
1215+
y_range = [line_plot._ymin, line_plot._ymax]
1216+
if y_range[0] is not None:
1217+
y_range[0] = line_plot._transform_scalar_y(y_range[0])
1218+
if y_range[1] is not None:
1219+
y_range[1] = line_plot._transform_scalar_y(y_range[1])
12181220
if (
12191221
line_plot._yaxis_scale == "log"
12201222
and y_range[0] is not None
@@ -1231,17 +1233,19 @@ def plot_plotly(
12311233

12321234
# Custom ticks (positions + optional labels)
12331235
if line_plot._xticks is not None:
1236+
tickvals = [line_plot._transform_scalar_x(v) for v in line_plot._xticks]
12341237
fig.update_xaxes(
12351238
tickmode="array",
1236-
tickvals=line_plot._xticks,
1239+
tickvals=tickvals,
12371240
ticktext=line_plot._xticklabels,
12381241
row=row + 1,
12391242
col=col + 1,
12401243
)
12411244
if line_plot._yticks is not None:
1245+
tickvals = [line_plot._transform_scalar_y(v) for v in line_plot._yticks]
12421246
fig.update_yaxes(
12431247
tickmode="array",
1244-
tickvals=line_plot._yticks,
1248+
tickvals=tickvals,
12451249
ticktext=line_plot._yticklabels,
12461250
row=row + 1,
12471251
col=col + 1,
@@ -1250,6 +1254,13 @@ def plot_plotly(
12501254
# Aspect ratio
12511255
if line_plot._aspect == "equal":
12521256
fig.update_yaxes(scaleanchor=xref, row=row + 1, col=col + 1)
1257+
elif isinstance(line_plot._aspect, (int, float)):
1258+
fig.update_yaxes(
1259+
scaleanchor=xref,
1260+
scaleratio=float(line_plot._aspect),
1261+
row=row + 1,
1262+
col=col + 1,
1263+
)
12531264

12541265
# Update layout settings
12551266
fig.update_layout(

src/maxplotlib/subfigure/line_plot.py

Lines changed: 170 additions & 59 deletions
Large diffs are not rendered by default.

src/maxplotlib/tests/test_plotly_backend.py

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,3 +40,41 @@ def test_plotly_backend_respects_layers():
4040
assert len(fig0.data) == 1
4141
assert len(fig1.data) == 1
4242

43+
44+
def test_plotly_backend_supports_common_patches_and_symlog():
45+
import matplotlib.patches as mpatches
46+
47+
from maxplotlib import Canvas
48+
49+
canvas, ax = Canvas.subplots()
50+
ax.add_patch(
51+
mpatches.Rectangle((0.2, 0.2), 1.3, 0.7, fill=False, edgecolor="yellow", label="r")
52+
)
53+
ax.add_patch(mpatches.Circle((2.2, 1.6), 0.45, fill=False, edgecolor="cyan", label="c"))
54+
ax.add_patch(
55+
mpatches.Polygon(
56+
[[3.0, 0.5], [3.8, 1.2], [3.4, 2.0]],
57+
fill=True,
58+
facecolor="green",
59+
label="p",
60+
)
61+
)
62+
ax.add_patch(
63+
mpatches.Ellipse((2.8, 1.0), 0.8, 0.5, fill=False, edgecolor="white", label="e")
64+
)
65+
ax.set_title("patches")
66+
ax.set_legend(True)
67+
68+
fig = canvas.plot(backend="plotly")
69+
assert fig is not None
70+
assert len(getattr(fig.layout, "shapes", []) or []) >= 4
71+
# patch labels become dummy legend traces
72+
assert any(getattr(t, "name", "") == "p" for t in fig.data)
73+
74+
canvas2, ax2 = Canvas.subplots()
75+
x = np.linspace(-20, 20, 41)
76+
ax2.plot(x, x**3, color="cyan", label="x^3")
77+
ax2.set_xscale("symlog")
78+
ax2.set_yscale("symlog")
79+
fig2 = canvas2.plot(backend="plotly")
80+
assert fig2 is not None

tutorials/tutorial_01.ipynb

Lines changed: 46 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,34 @@
3535
"cell_type": "markdown",
3636
"id": "2",
3737
"metadata": {},
38+
"source": [
39+
"## Backend selection\n",
40+
"\n",
41+
"All examples in this tutorial use the same `Canvas` API; you can switch rendering backends at any time:\n",
42+
"\n",
43+
"- `BACKEND = \"matplotlib\"` for static Matplotlib output\n",
44+
"- `BACKEND = \"plotly\"` for interactive Plotly output (Jupyter-friendly)\n",
45+
"\n",
46+
"Most cells end with `canvas.show(backend=BACKEND)` so you can re-run the whole notebook with a different backend.\n",
47+
"\n"
48+
]
49+
},
50+
{
51+
"cell_type": "code",
52+
"execution_count": null,
53+
"id": "3",
54+
"metadata": {},
55+
"outputs": [],
56+
"source": [
57+
"# Change to \"plotly\" for interactive output\n",
58+
"BACKEND = \"matplotlib\"\n",
59+
"\n"
60+
]
61+
},
62+
{
63+
"cell_type": "markdown",
64+
"id": "4",
65+
"metadata": {},
3866
"source": [
3967
"## 1 Minimal example\n",
4068
"\n",
@@ -45,7 +73,7 @@
4573
{
4674
"cell_type": "code",
4775
"execution_count": null,
48-
"id": "3",
76+
"id": "5",
4977
"metadata": {},
5078
"outputs": [],
5179
"source": [
@@ -54,12 +82,13 @@
5482
"\n",
5583
"canvas, ax = Canvas.subplots()\n",
5684
"ax.plot(x, y)\n",
57-
"canvas.show()"
85+
"canvas.show(backend=BACKEND)\n",
86+
"\n"
5887
]
5988
},
6089
{
6190
"cell_type": "markdown",
62-
"id": "4",
91+
"id": "6",
6392
"metadata": {},
6493
"source": [
6594
"## 2 Multiple lines with labels, colors, and linestyles"
@@ -68,7 +97,7 @@
6897
{
6998
"cell_type": "code",
7099
"execution_count": null,
71-
"id": "5",
100+
"id": "7",
72101
"metadata": {},
73102
"outputs": [],
74103
"source": [
@@ -90,12 +119,13 @@
90119
"ax.set_title(\"Sine and Cosine\")\n",
91120
"ax.set_legend(True)\n",
92121
"\n",
93-
"canvas.show()"
122+
"canvas.show(backend=BACKEND)\n",
123+
"\n"
94124
]
95125
},
96126
{
97127
"cell_type": "markdown",
98-
"id": "6",
128+
"id": "8",
99129
"metadata": {},
100130
"source": [
101131
"## 3 Canvas-level shortcut API\n",
@@ -107,7 +137,7 @@
107137
{
108138
"cell_type": "code",
109139
"execution_count": null,
110-
"id": "7",
140+
"id": "9",
111141
"metadata": {},
112142
"outputs": [],
113143
"source": [
@@ -122,12 +152,13 @@
122152
"canvas.set_legend(True)\n",
123153
"canvas.set_grid(True)\n",
124154
"\n",
125-
"canvas.show()"
155+
"canvas.show(backend=BACKEND)\n",
156+
"\n"
126157
]
127158
},
128159
{
129160
"cell_type": "markdown",
130-
"id": "8",
161+
"id": "10",
131162
"metadata": {},
132163
"source": [
133164
"## 4 Configuring the subplot at creation time\n",
@@ -139,7 +170,7 @@
139170
{
140171
"cell_type": "code",
141172
"execution_count": null,
142-
"id": "9",
173+
"id": "11",
143174
"metadata": {},
144175
"outputs": [],
145176
"source": [
@@ -155,12 +186,13 @@
155186
"ax.plot(x, np.sin(x), label=\"sin\", color=\"royalblue\")\n",
156187
"ax.plot(x, x / (2 * np.pi), label=\"x/2π\", color=\"coral\", linestyle=\"dashed\")\n",
157188
"\n",
158-
"canvas.show()"
189+
"canvas.show(backend=BACKEND)\n",
190+
"\n"
159191
]
160192
},
161193
{
162194
"cell_type": "markdown",
163-
"id": "10",
195+
"id": "12",
164196
"metadata": {},
165197
"source": [
166198
"## 5 Saving a figure\n",
@@ -172,7 +204,7 @@
172204
{
173205
"cell_type": "code",
174206
"execution_count": null,
175-
"id": "11",
207+
"id": "13",
176208
"metadata": {},
177209
"outputs": [],
178210
"source": [
@@ -186,7 +218,7 @@
186218
},
187219
{
188220
"cell_type": "markdown",
189-
"id": "12",
221+
"id": "14",
190222
"metadata": {},
191223
"source": [
192224
"## Summary\n",

0 commit comments

Comments
 (0)