Skip to content

Commit 42aaea3

Browse files
authored
Version 0.2.0 (#74)
* Add a include_plotlyjs param to savefig (#69) * Update README.qmd (#70) * Update README.qmd * Update README.md * Added a matplotlib parser (#71) * Added a matplotlib parser * Extende matplotlib parsing coverage * Extend matplotlib parsing * formatting * Fix bugs * Xarray support (#72) * Added xarray support * small edits like adding titles and so on * Added da.xarray accessor * Added xarray to docs + bugfixes * formatting * Preparation for tikz support in plasma-plots (#73) * Preparation for tikz support in plasma-plots * Fix tests * Fix tests * Another fix * Fix docs build (#75)
1 parent 25c9e51 commit 42aaea3

31 files changed

Lines changed: 7829 additions & 950 deletions

‎.github/workflows/ci_pipeline.yml‎

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,19 @@ jobs:
2525
# with:
2626
# python-version: ${{ matrix.python-version }}
2727

28+
- name: Install LaTeX
29+
run: |
30+
# pdflatex with pgfplots: the tikzfigure backend, its tests and tutorials
31+
sudo apt-get update
32+
sudo apt-get install -y --no-install-recommends \
33+
texlive-latex-base texlive-latex-extra texlive-pictures \
34+
texlive-fonts-recommended lmodern
35+
2836
- name: Install python dependencies
2937
run: |
3038
python -m pip install --upgrade pip
39+
# tikzfigure 0.4.0 is not on PyPI yet: install it from GitHub (drop once released)
40+
pip install "tikzfigure[vis] @ git+https://github.com/max-models/tikzfigure@c290f43ac1deb4a4ed3b5b40919f10d3a6b53e8b"
3141
pip install ".[dev]"
3242
3343
- name: Run tests
@@ -37,7 +47,5 @@ jobs:
3747
3848
- name: Test tutorials
3949
run: |
40-
# tutorial_07_tikz.ipynb requires pdflatex — skip it in CI
41-
jupyter nbconvert --to notebook --execute \
42-
$(ls tutorials/*.ipynb | grep -v tutorial_07_tikz) \
50+
jupyter nbconvert --to notebook --execute tutorials/*.ipynb \
4351
--output-dir=/tmp --ExecutePreprocessor.timeout=300

‎.github/workflows/docs.yml‎

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,14 +25,20 @@ jobs:
2525
- name: Checkout
2626
uses: actions/checkout@v4
2727

28-
- name: Install pandoc
28+
- name: Install pandoc and LaTeX
2929
run: |
3030
sudo apt-get update
3131
sudo apt-get install -y pandoc
32+
# pdflatex with pgfplots: the tutorials compile tikzfigure figures
33+
sudo apt-get install -y --no-install-recommends \
34+
texlive-latex-base texlive-latex-extra texlive-pictures \
35+
texlive-fonts-recommended lmodern
3236
3337
- name: Install Python dependencies
3438
run: |
3539
python -m pip install --upgrade pip
40+
# tikzfigure 0.4.0 is not on PyPI yet: install it from GitHub (drop once released)
41+
pip install "tikzfigure[vis] @ git+https://github.com/max-models/tikzfigure@c290f43ac1deb4a4ed3b5b40919f10d3a6b53e8b"
3642
pip install ".[docs]"
3743
3844
- name: Build Sphinx docs
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
name: Matplotlib import compatibility
2+
3+
on:
4+
push:
5+
branches: [main, devel]
6+
pull_request:
7+
8+
jobs:
9+
import-fixtures:
10+
runs-on: ubuntu-latest
11+
strategy:
12+
fail-fast: false
13+
matrix:
14+
matplotlib: ['3.8.*', '3.9.*', '3.10.*', '3.11.*']
15+
env:
16+
MPLBACKEND: Agg
17+
steps:
18+
- uses: actions/checkout@v4
19+
- uses: actions/setup-python@v5
20+
with:
21+
python-version: '3.11'
22+
# tikzfigure 0.4.0 is not on PyPI yet: install it from GitHub (drop once released)
23+
- run: python -m pip install "tikzfigure[vis] @ git+https://github.com/max-models/tikzfigure@c290f43ac1deb4a4ed3b5b40919f10d3a6b53e8b"
24+
- run: python -m pip install '.[test]' 'numpy<2' 'matplotlib==${{ matrix.matplotlib }}'
25+
- run: python -m pytest src/maxplotlib/tests/test_matplotlib_import.py src/maxplotlib/tests/test_matplotlib_import_extended.py

‎README.md‎

Lines changed: 68 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Maxlotlib
1+
# Maxplotlib
22

33

44
# Maxplotlib
@@ -219,23 +219,29 @@ canvas.show(backend="tikzfigure")
219219

220220
![](README_files/figure-commonmark/cell-14-output-1.png)
221221

222-
### Horizontal Subplots with TikZ Backend
222+
### Subplots and Meshes with the TikZ Backend
223223

224-
The tikzfigure backend supports creating side-by-side subplots (1×n
225-
layouts):
224+
The tikzfigure backend draws the canvas with Matplotlib and converts the
225+
drawn figure into pgfplots axes, so every layout converts (rows, columns,
226+
grids, twin axes), with LaTeX text, legends and colorbars. Lines,
227+
markers, bars and text are pgfplots code; meshes and images are included
228+
as images:
226229

227230
``` python
228231
x = np.linspace(0, 2 * np.pi, 200)
229-
canvas, (ax1, ax2) = Canvas.subplots(ncols=2, width="10cm", ratio=0.3)
232+
canvas, (ax1, ax2) = Canvas.subplots(ncols=2, width="12cm", ratio=0.45)
230233

231-
ax1.plot(x, np.sin(x), color="royalblue")
232-
ax1.set_title("sin(x)")
234+
ax1.plot(x, np.sin(x), color="royalblue", label="$\\sin x$")
235+
ax1.plot(x, np.cos(x), color="tomato", label="$\\cos x$")
236+
ax1.set_title("Lines")
237+
ax1.set_legend(True)
233238

234-
ax2.plot(x, np.cos(x), color="tomato")
235-
ax2.set_title("cos(x)")
239+
xx, yy = np.meshgrid(x, x)
240+
ax2.pcolormesh(xx, yy, np.sin(xx) * np.cos(yy), cmap="RdBu_r")
241+
ax2.add_colorbar(label="$\\sin x \\cos y$")
242+
ax2.set_title("A mesh")
236243

237-
canvas.suptitle("Trigonometric Functions")
238-
canvas.show(backend="tikzfigure") # Generates LaTeX subfigures
244+
canvas.show(backend="tikzfigure") # compiles with pdflatex
239245
```
240246

241247
<div id="fig-showcase-subplots">
@@ -248,9 +254,11 @@ Figure 2
248254

249255
</div>
250256

251-
**Note:** Only horizontal layouts (1×n) are currently supported with the
252-
tikzfigure backend. Vertical/grid layouts will raise
253-
`NotImplementedError`. See the tutorials for more examples.
257+
`canvas.render(backend="tikzfigure").savefig("figure.tikz")` writes the
258+
code for `\\input` in a LaTeX document, with the images next to it. Any
259+
Matplotlib figure converts the same way with
260+
`maxplotlib.backends.tikzfigure.figure_to_tikz(fig)`. See the tutorials
261+
for more examples.
254262

255263
### Terminal Backend with plotext
256264

@@ -349,3 +357,49 @@ canvas.show()
349357

350358
(<Figure size 590.551x324.803 with 1 Axes>,
351359
array([[<Axes: xlabel='x'>]], dtype=object))
360+
361+
### xarray data
362+
363+
Plot labelled [xarray](https://docs.xarray.dev) data directly
364+
(`pip install maxplotlibx[xarray]`). Axes come from the coordinates,
365+
labels from the `long_name` and `units` attributes, and titles from the
366+
coordinates you selected. `import maxplotlib.xarray` adds a `.maxplot`
367+
accessor that mirrors xarray’s own `.plot` API and returns an ordinary
368+
`Canvas`, so the backend is still chosen when rendering:
369+
370+
``` python
371+
import xarray as xr
372+
373+
import maxplotlib.xarray # registers da.maxplot and ds.maxplot
374+
375+
t = np.linspace(0, 1.5, 6)
376+
xs = np.linspace(0, 2 * np.pi, 80)
377+
ys = np.linspace(-1, 1, 50)
378+
wave = xr.DataArray(
379+
np.sin(xs - 2 * t[:, None, None]) * np.exp(-3 * ys[None, :, None] ** 2),
380+
dims=("t", "y", "x"),
381+
coords={"t": ("t", t, {"units": "s"}), "y": ys, "x": ("x", xs, {"units": "m"})},
382+
name="phi",
383+
attrs={"long_name": "Potential", "units": "V"},
384+
)
385+
386+
wave.maxplot.pcolormesh(col="t", col_wrap=3, canvas_kwargs={"width": "16cm", "ratio": 0.6}).show()
387+
```
388+
389+
![](README_files/figure-commonmark/cell-20-output-1.png)
390+
391+
(<Figure size 944.882x566.929 with 7 Axes>,
392+
array([[<Axes: title={'center': 't = 0 s'}, ylabel='y'>,
393+
<Axes: title={'center': 't = 0.3 s'}>,
394+
<Axes: title={'center': 't = 0.6 s'}>],
395+
[<Axes: title={'center': 't = 0.9 s'}, xlabel='x [m]', ylabel='y'>,
396+
<Axes: title={'center': 't = 1.2 s'}, xlabel='x [m]'>,
397+
<Axes: title={'center': 't = 1.5 s'}, xlabel='x [m]'>]],
398+
dtype=object))
399+
400+
The same works through Canvas methods,
401+
e.g. `canvas.plot(da, hue="species")`,
402+
`ax.pcolormesh(da, xcoord="R", ycoord="Z")` for curvilinear grids, or
403+
`Canvas.facet(da, col="t")`. `ds.maxplot.scatter(x=..., y=..., hue=...)`
404+
plots one Dataset variable against another. See the [xarray
405+
tutorial](tutorials/tutorial_17_xarray.ipynb) for more.

‎README.qmd‎

Lines changed: 53 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
---
2-
title: Maxlotlib
2+
title: Maxplotlib
33
format: gfm
44
fig-dpi: 150
55
---
@@ -194,29 +194,37 @@ Or plot with the TikZ backend:
194194
canvas.show(backend="tikzfigure")
195195
```
196196

197-
### Horizontal Subplots with TikZ Backend
197+
### Subplots and Meshes with the TikZ Backend
198198

199-
The tikzfigure backend supports creating side-by-side subplots (1×n layouts):
199+
The tikzfigure backend draws the canvas with Matplotlib and converts the drawn figure into
200+
pgfplots axes, so every layout converts (rows, columns, grids, twin axes), with LaTeX text,
201+
legends and colorbars. Lines, markers, bars and text are pgfplots code; meshes and images are
202+
included as images:
200203

201204
```{python}
202205
#| label: fig-showcase-subplots
203206
#| fig-width: 9
204207
#| fig-height: 6
205208
206209
x = np.linspace(0, 2 * np.pi, 200)
207-
canvas, (ax1, ax2) = Canvas.subplots(ncols=2, width="10cm", ratio=0.3)
210+
canvas, (ax1, ax2) = Canvas.subplots(ncols=2, width="12cm", ratio=0.45)
208211
209-
ax1.plot(x, np.sin(x), color="royalblue")
210-
ax1.set_title("sin(x)")
212+
ax1.plot(x, np.sin(x), color="royalblue", label="$\\sin x$")
213+
ax1.plot(x, np.cos(x), color="tomato", label="$\\cos x$")
214+
ax1.set_title("Lines")
215+
ax1.set_legend(True)
211216
212-
ax2.plot(x, np.cos(x), color="tomato")
213-
ax2.set_title("cos(x)")
217+
xx, yy = np.meshgrid(x, x)
218+
ax2.pcolormesh(xx, yy, np.sin(xx) * np.cos(yy), cmap="RdBu_r")
219+
ax2.add_colorbar(label="$\\sin x \\cos y$")
220+
ax2.set_title("A mesh")
214221
215-
canvas.suptitle("Trigonometric Functions")
216-
canvas.show(backend="tikzfigure") # Generates LaTeX subfigures
222+
canvas.show(backend="tikzfigure") # compiles with pdflatex
217223
```
218224

219-
**Note:** Only horizontal layouts (1×n) are currently supported with the tikzfigure backend. Vertical/grid layouts will raise `NotImplementedError`. See the tutorials for more examples.
225+
`canvas.render(backend="tikzfigure").savefig("figure.tikz")` writes the code for `\\input` in a
226+
LaTeX document, with the images next to it. Any Matplotlib figure converts the same way with
227+
`maxplotlib.backends.tikzfigure.figure_to_tikz(fig)`. See the tutorials for more examples.
220228

221229
### Terminal Backend with plotext
222230

@@ -276,3 +284,37 @@ Show all layers:
276284
```{python}
277285
canvas.show()
278286
```
287+
288+
### xarray data
289+
290+
Plot labelled [xarray](https://docs.xarray.dev) data directly
291+
(`pip install maxplotlibx[xarray]`). Axes come from the coordinates, labels
292+
from the `long_name` and `units` attributes, and titles from the coordinates
293+
you selected. `import maxplotlib.xarray` adds a `.maxplot` accessor that mirrors
294+
xarray's own `.plot` API and returns an ordinary `Canvas`, so the backend is
295+
still chosen when rendering:
296+
297+
```{python}
298+
import xarray as xr
299+
300+
import maxplotlib.xarray # registers da.maxplot and ds.maxplot
301+
302+
t = np.linspace(0, 1.5, 6)
303+
xs = np.linspace(0, 2 * np.pi, 80)
304+
ys = np.linspace(-1, 1, 50)
305+
wave = xr.DataArray(
306+
np.sin(xs - 2 * t[:, None, None]) * np.exp(-3 * ys[None, :, None] ** 2),
307+
dims=("t", "y", "x"),
308+
coords={"t": ("t", t, {"units": "s"}), "y": ys, "x": ("x", xs, {"units": "m"})},
309+
name="phi",
310+
attrs={"long_name": "Potential", "units": "V"},
311+
)
312+
313+
wave.maxplot.pcolormesh(col="t", col_wrap=3, canvas_kwargs={"width": "16cm", "ratio": 0.6}).show()
314+
```
315+
316+
The same works through Canvas methods, e.g. `canvas.plot(da, hue="species")`,
317+
`ax.pcolormesh(da, xcoord="R", ycoord="Z")` for curvilinear grids, or
318+
`Canvas.facet(da, col="t")`. `ds.maxplot.scatter(x=..., y=..., hue=...)` plots
319+
one Dataset variable against another. See the
320+
[xarray tutorial](tutorials/tutorial_17_xarray.ipynb) for more.
67.3 KB
Loading
79.7 KB
Loading

0 commit comments

Comments
 (0)