Skip to content

Commit 15162f1

Browse files
committed
Extend matplotlib parsing
1 parent 9a55990 commit 15162f1

7 files changed

Lines changed: 1084 additions & 6 deletions

File tree

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
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+
- run: python -m pip install '.[test]' 'numpy<2' 'matplotlib==${{ matrix.matplotlib }}'
23+
- run: python -m pytest src/maxplotlib/tests/test_matplotlib_import.py src/maxplotlib/tests/test_matplotlib_import_extended.py

‎docs/matplotlib-import-support.md‎

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -48,9 +48,12 @@ conversion is not possible.
4848
(subfigure rectangles/decorations are flattened into the destination figure).
4949
- [x] Grid width/height ratios, margins, spacing, constrained/tight layout
5050
for ordinary/nested GridSpec; subfigures retain their snapshot rectangles.
51-
- [ ] Arbitrary axes rectangles, overlapping axes, inset axes, inset connectors.
52-
Rectangles, overlaps and child insets are implemented; connectors referring to
53-
other axes still need live-reference rebinding.
51+
- [x] Arbitrary axes rectangles, overlapping axes, inset axes, inset-zoom
52+
connectors (`indicate_inset_zoom`/`indicate_inset`, Matplotlib 3.10+). The
53+
connector spans two Axes and recomputes its geometry from live limits on
54+
every draw, so it is rebuilt against the reconstructed parent/inset pair
55+
rather than snapshotted. Matplotlib < 3.10's tuple-returning API still falls
56+
back to native geometry.
5457
- [x] Secondary axes with forward/inverse coordinate functions.
5558
- [x] Figure backgrounds, frame styling, and figure-level text/patches/images.
5659
- [x] Figure title/shared-label typography and placement.
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
"""Measure import time and peak Python allocation for reproducible fixtures.
2+
3+
Run from an installed checkout: python scripts/benchmark_matplotlib_import.py
4+
Timings are observations, not brittle pass/fail thresholds. Native renderer
5+
allocations outside Python are not included in tracemalloc's peak measurement.
6+
"""
7+
8+
import argparse
9+
import json
10+
import time
11+
import tracemalloc
12+
13+
import matplotlib
14+
15+
matplotlib.use("Agg")
16+
import matplotlib.pyplot as plt
17+
import numpy as np
18+
19+
from maxplotlib import Canvas
20+
21+
22+
def benchmark(points, panels):
23+
fig, axes = plt.subplots(panels, 1, figsize=(8, max(3, panels * 2)))
24+
x = np.linspace(0, 10, points)
25+
for index, ax in enumerate(np.atleast_1d(axes)):
26+
ax.plot(x, np.sin(x + index))
27+
ax.scatter([], [])
28+
tracemalloc.start()
29+
started = time.perf_counter()
30+
canvas = Canvas.from_matplotlib(fig, strict=True)
31+
imported = time.perf_counter()
32+
_, peak = tracemalloc.get_traced_memory()
33+
tracemalloc.stop()
34+
result, _ = canvas.render()
35+
result.canvas.draw()
36+
finished = time.perf_counter()
37+
stats = dict(
38+
matplotlib=matplotlib.__version__,
39+
points_per_panel=points,
40+
panels=panels,
41+
import_seconds=imported - started,
42+
render_seconds=finished - imported,
43+
import_peak_python_mib=peak / 1024**2,
44+
entries=sum(len(plot.line_data) for _, _, plot in canvas.iter_subplots()),
45+
)
46+
plt.close(fig)
47+
plt.close(result)
48+
return stats
49+
50+
51+
if __name__ == "__main__":
52+
parser = argparse.ArgumentParser(description=__doc__)
53+
parser.add_argument("--points", type=int, default=100_000)
54+
parser.add_argument("--panels", type=int, default=4)
55+
arguments = parser.parse_args()
56+
if arguments.points < 1 or arguments.panels < 1:
57+
parser.error("points and panels must be positive")
58+
print(json.dumps(benchmark(arguments.points, arguments.panels), indent=2))

0 commit comments

Comments
 (0)