Skip to content

Commit eef1772

Browse files
authored
Version 0.1.8 (#65)
* Rewrite of tutorials using the canvas object mainly (#58) * More coverage of mpl * Rewrote notebooks using the canvas style * Formatting * Formatting * fix tutorial * Rename plot to render (#59) * Renamed plot to render, added plot(x, y) to canvas * Formatting * Raise warning * Improve configuration (#60) * plotting config * fmt * Add missing tutorials (#62) * Added missing tutorial * Added missing tutorials * Added more tikz primitives (#61) * Added more tikz primitives * formatting * Do not return anything when running show with plotly * Fix tutorials (#63) * Added missing tutorial * Added missing tutorials * execute tutorials * execute docs * Set plotext dependency (#64) * plotext >= 5, < 6 * Update version number * Update to plotext 6 (#66) * Update plotext to 6.0 * formatting
1 parent 8d872be commit eef1772

29 files changed

Lines changed: 2589 additions & 638 deletions

‎README.md‎

Lines changed: 53 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,33 @@ canvas.show()
4545

4646
![](README_files/figure-commonmark/cell-3-output-1.png)
4747

48+
Use `canvas.plot(x, y)` to add data directly to a canvas. When you want
49+
to explicitly render an already-built canvas, use `canvas.render(...)`.
50+
The older `canvas.plot(backend=...)` spelling is still supported for
51+
compatibility, but emits a `FutureWarning`.
52+
53+
Add several lines at once with shared styling:
54+
55+
``` python
56+
canvas.plot_many(
57+
[(x, np.sin(x)), (x, np.cos(x))],
58+
labels=["sin(x)", "cos(x)"],
59+
linewidth=2,
60+
)
61+
```
62+
63+
Common figure and axis settings can be grouped with `configure()`:
64+
65+
``` python
66+
canvas.configure(
67+
title="Trigonometry",
68+
xlabel="Angle",
69+
ylabel="Value",
70+
grid=True,
71+
facecolor="whitesmoke",
72+
)
73+
```
74+
4875
For Matplotlib-specific customization, pass method calls declaratively.
4976
Figure methods run once and axes methods run for every subplot,
5077
providing access to any Matplotlib API without requiring a maxplotlib
@@ -149,37 +176,38 @@ parts of a mixed canvas, explicitly opt into skipping unsupported
149176
primitives:
150177

151178
``` python
152-
plotly_canvas.plot(backend="plotly", allow_unsupported=True)
179+
plotly_canvas.render(backend="plotly", allow_unsupported=True)
153180
```
154181

155182
Render the same line graph directly in the terminal with the `plotext`
156183
backend:
157184

158185
``` python
159-
terminal_fig = canvas.plot(backend="plotext")
186+
terminal_fig = canvas.render(backend="plotext")
160187
print(terminal_fig.build(keep_colors=False))
161188
```
162189

190+
Trigonometry
163191
Runtime
164-
┌─────────────────────────────────────────────────────────────────────────┐
165-
1.00┤ ▗▄▞▀▀▀▀▀▙▄▖ │
166-
│ ▗▄▀▘ ▝▀▄ │
167-
│ ▗▞▘ ▀▄ │
168-
0.67┤ ▟▀ ▀▄ │
169-
│ ▄▛ ▚▖ │
170-
0.33┤ ▗▞ ▝▄ │
171-
│ ▄▀ ▚▖ │
172-
│▗▞▘ ▀▄ │
173-
0.00┤▀ ▝▚▖ ▞│
174-
│ ▀▄ ▗▞▘│
175-
│ ▝▚ ▄▀ │
176-
-0.33┤ ▀▖ ▞▘ │
177-
│ ▝▚ ▟▀ │
178-
-0.67┤ ▀▄ ▄▛ │
179-
│ ▀▄ ▗▞▘ │
180-
│ ▀▄▖ ▗▄▀▘ │
181-
-1.00┤ ▝▀▜▄▄▄▄▄▞▀▘ │
182-
└┬─────────────────┬─────────────────┬─────────────────┬─────────────────┬┘
192+
┌┬─────────────────┬─────────────────┬─────────────────┬─────────────────┬┐
193+
1.00┼ ▞▞ sin(x) ──▗▄▞▀▀▀▀▀▙▄▖────────────┼─────────────────┼─────────────▄▄▀▀▀┤
194+
│ ▞▞ cos(x) ▄▀▘ │ ▝▀▄ │ │ ▄▞▀ ││
195+
││ ▜▄▘ │ ▀▄ │ │ ▄▛ ││
196+
0.67┼┼──────▟▀─▀▄──────┼─────────▀▄──────┼─────────────────┼──────▄▀─────────┼┤
197+
││ ▄▛ ▝▚▖ │ ▚▖ │ │ ▗▞▘ ││
198+
0.33┼┼──▗▞────────▀▖───┼────────────▝▄───┼─────────────────┼───▗▀────────────┼┤
199+
││ ▄▀ ▝▚ │ ▚▖ │ │ ▞▘ ││
200+
│▗▞▘ ▀▖│ ▀▄│ │▗▀ ││
201+
0.00┼▞────────────────▝▙────────────────▝▚▖────────────────▟▘────────────────▄┤
202+
││ │▜▖ │▀▄ ▗▛│ ▗▞▘│
203+
││ │ ▝▙ │ ▝▚ ▟▘ │ ▄▀ ││
204+
-0.33┼┼─────────────────┼───▚▖────────────┼───▀▖───────▗▞───┼─────────────▞▘──┼┤
205+
││ │ ▝▄▖ │ ▝▚ ▗▄▘ │ ▟▀ ││
206+
-0.67┼┼─────────────────┼──────▀▖─────────┼──────▀▄─▗▀──────┼─────────▄▛──────┼┤
207+
││ │ ▝▜▄ │ ▄▛▘ │ ▗▞▘ ││
208+
││ │ ▀▄▖ │ ▗▄▀ ▀▄▖ │ ▗▄▀▘ ││
209+
-1.00┼┼─────────────────┼────────────▝▀▚▄▄▄▄▄▞▀▘───────▝▀▜▄▄▄▄▄▞▀▘────────────┼┤
210+
└┼─────────────────┼─────────────────┼─────────────────┼─────────────────┼┘
183211
0.0 1.6 3.1 4.7 6.3
184212
Duration Time
185213

@@ -189,7 +217,7 @@ Or plot with the TikZ backend:
189217
canvas.show(backend="tikzfigure")
190218
```
191219

192-
![](README_files/figure-commonmark/cell-12-output-1.png)
220+
![](README_files/figure-commonmark/cell-14-output-1.png)
193221

194222
### Horizontal Subplots with TikZ Backend
195223

@@ -270,7 +298,7 @@ canvas.show(backend="plotext")
270298
1.0 1.8 3.2 5.6 10.0
271299
y x
272300

273-
<maxplotlib.backends.plotext.figure.PlotextFigure at 0x110a30550>
301+
<maxplotlib.backends.plotext.figure.PlotextFigure at 0x1102a0690>
274302

275303
### Layers
276304

@@ -306,7 +334,7 @@ Show layer 0 only, then layers 0 and 1, then everything:
306334
canvas.show(layers=[0])
307335
```
308336

309-
![](README_files/figure-commonmark/cell-16-output-1.png)
337+
![](README_files/figure-commonmark/cell-18-output-1.png)
310338

311339
(<Figure size 590.551x324.803 with 1 Axes>,
312340
array([[<Axes: xlabel='x'>]], dtype=object))
@@ -317,7 +345,7 @@ Show all layers:
317345
canvas.show()
318346
```
319347

320-
![](README_files/figure-commonmark/cell-17-output-1.png)
348+
![](README_files/figure-commonmark/cell-19-output-1.png)
321349

322350
(<Figure size 590.551x324.803 with 1 Axes>,
323351
array([[<Axes: xlabel='x'>]], dtype=object))

‎README.qmd‎

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,35 @@ Plot the figure with the default (matplotlib) backend:
4242
canvas.show()
4343
```
4444

45+
Use `canvas.plot(x, y)` to add data directly to a canvas. When you want to
46+
explicitly render an already-built canvas, use `canvas.render(...)`. The older
47+
`canvas.plot(backend=...)` spelling is still supported for compatibility, but
48+
emits a `FutureWarning`.
49+
50+
Add several lines at once with shared styling:
51+
52+
```{python}
53+
#| output: false
54+
canvas.plot_many(
55+
[(x, np.sin(x)), (x, np.cos(x))],
56+
labels=["sin(x)", "cos(x)"],
57+
linewidth=2,
58+
)
59+
```
60+
61+
Common figure and axis settings can be grouped with `configure()`:
62+
63+
```{python}
64+
#| output: false
65+
canvas.configure(
66+
title="Trigonometry",
67+
xlabel="Angle",
68+
ylabel="Value",
69+
grid=True,
70+
facecolor="whitesmoke",
71+
)
72+
```
73+
4574
For Matplotlib-specific customization, pass method calls declaratively. Figure
4675
methods run once and axes methods run for every subplot, providing access to
4776
any Matplotlib API without requiring a maxplotlib wrapper:
@@ -149,13 +178,13 @@ of a mixed canvas, explicitly opt into skipping unsupported primitives:
149178

150179
```{python}
151180
#| output: false
152-
plotly_canvas.plot(backend="plotly", allow_unsupported=True)
181+
plotly_canvas.render(backend="plotly", allow_unsupported=True)
153182
```
154183

155184
Render the same line graph directly in the terminal with the `plotext` backend:
156185

157186
```{python}
158-
terminal_fig = canvas.plot(backend="plotext")
187+
terminal_fig = canvas.render(backend="plotext")
159188
print(terminal_fig.build(keep_colors=False))
160189
```
161190

38.5 KB
Loading

‎docs/source/conf.py‎

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -38,11 +38,10 @@ def setup(app):
3838
"sphinx.ext.autodoc",
3939
]
4040

41+
# Execute every tutorial notebook when building the documentation.
42+
nbsphinx_execute = "always"
43+
4144
templates_path = ["_templates"]
42-
exclude_patterns = [
43-
# tutorial_07_tikz.ipynb requires pdflatex to render — skip during docs build
44-
"tutorials/tutorial_07_tikz.ipynb",
45-
]
4645

4746

4847
# -- Options for HTML output -------------------------------------------------

‎docs/source/index.rst‎

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,10 @@ documentation for details.
2424
tutorials/tutorial_07_tikz
2525
tutorials/tutorial_08_plotly
2626
tutorials/tutorial_09_plotext
27+
tutorials/tutorial_10_matplotlib_nxm_spacing
28+
tutorials/tutorial_11_gantt_charts
29+
tutorials/tutorial_12_flame_charts
2730
tutorials/tutorial_13_advanced_matplotlib
2831
tutorials/tutorial_14_axis_and_layout_controls
29-
tutorials/tutorial_tikzfigure_subplots
32+
tutorials/tutorial_15_tikzfigure_subplots
33+
tutorials/tutorial_16_plotext_advanced

‎pyproject.toml‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
44

55
[project]
66
name = "maxplotlibx"
7-
version = "0.1.7"
7+
version = "0.1.8"
88
description = "A reproducible plotting module with various backends and export options."
99
readme = "README.md"
1010
requires-python = ">=3.8"
@@ -18,7 +18,7 @@ dependencies = [
1818
"matplotlib",
1919
"pint",
2020
"plotly",
21-
"plotext",
21+
"plotext >= 6.0, < 7",
2222
"tikzfigure[vis]>=0.3.0",
2323
]
2424
[project.optional-dependencies]

‎src/maxplotlib/backends/plotext/figure.py‎

Lines changed: 101 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,9 @@
22

33
import re
44
from pathlib import Path
5+
from typing import Any
56

6-
from plotext._figure import _figure_class
7+
from plotext import figure as _plotext_figure
78

89
_ANSI_ESCAPE_RE = re.compile(r"\x1B\[[0-?]*[ -/]*[@-~]")
910

@@ -12,20 +13,115 @@ def strip_ansi(text: str) -> str:
1213
return _ANSI_ESCAPE_RE.sub("", text)
1314

1415

15-
def create_plotext_figure(nrows: int = 1, ncols: int = 1) -> _figure_class:
16-
figure = _figure_class()
16+
class _Plotext6Axes:
17+
"""Small compatibility surface for maxplotlib's plotext renderer."""
18+
19+
def __init__(self, figure):
20+
self._figure = figure
21+
22+
def _draw(self, signal, label=None):
23+
if label is not None:
24+
signal.label(label)
25+
self._figure.draw(signal)
26+
27+
def plot(self, x, y, **kwargs):
28+
signal = self._figure.signal(x, y, marker=kwargs.get("marker"))
29+
self._draw(signal, kwargs.get("label"))
30+
31+
scatter = plot
32+
33+
def bar(self, *args, **kwargs):
34+
label = kwargs.pop("label", None)
35+
kwargs.pop("color", None)
36+
kwargs.pop("fill", None)
37+
signal = self._figure.bar(*args, **kwargs)
38+
self._draw(signal, label)
39+
40+
def error(self, x, y, *, xerr=None, yerr=None, color=None, label=None):
41+
signal = self._figure.error(x, y, yerr, xerr, pixel=color)
42+
self._draw(signal, label)
43+
44+
def matrix_plot(self, data, **kwargs):
45+
signal = self._figure.heatmap(data, symbol=kwargs.get("marker"))
46+
self._draw(signal)
47+
48+
def text(self, label, x, y, **kwargs):
49+
# Plotext 6 keeps text colour in its marker object; the renderer only
50+
# needs the portable text/alignment arguments here.
51+
kwargs.pop("color", None)
52+
signal = self._figure.text(x, y, label, **kwargs)
53+
self._figure.draw(signal)
54+
55+
def title(self, label):
56+
self._figure.title(label)
57+
58+
def xlabel(self, label):
59+
self._figure.label(label, axis=0)
60+
61+
def ylabel(self, label):
62+
self._figure.label(label, axis=1)
63+
64+
def grid(self, active=True, *_args):
65+
self._figure.ruler("x").grid(active)
66+
self._figure.ruler("y").grid(active)
67+
68+
def xlim(self, lower=None, upper=None):
69+
self._figure.ruler("x").lim(lower, upper)
70+
71+
def ylim(self, lower=None, upper=None):
72+
self._figure.ruler("y").lim(lower, upper)
73+
74+
def xscale(self, scale):
75+
self._figure.ruler("x").scale(scale)
76+
77+
def yscale(self, scale):
78+
self._figure.ruler("y").scale(scale)
79+
80+
def xticks(self, positions=None, labels=None):
81+
self._figure.ruler("x").ticks(positions, labels)
82+
83+
def yticks(self, positions=None, labels=None):
84+
self._figure.ruler("y").ticks(positions, labels)
85+
86+
def plotsize(self, width=None, height=None):
87+
self._figure.plot_size(width, height)
88+
89+
def horizontal_line(self, position, **kwargs):
90+
kwargs.pop("color", None)
91+
self._figure.line(position, orientation=0, **kwargs)
92+
93+
def vertical_line(self, position, **kwargs):
94+
kwargs.pop("color", None)
95+
self._figure.line(position, orientation=1, **kwargs)
96+
97+
def subplots(self, rows=None, cols=None):
98+
self._figure.subplots(rows, cols)
99+
return self
100+
101+
def subplot(self, row=None, col=None):
102+
return _Plotext6Axes(self._figure.subplot(row, col))
103+
104+
def __getattr__(self, name):
105+
return getattr(self._figure, name)
106+
107+
108+
def create_plotext_figure(nrows: int = 1, ncols: int = 1):
109+
# Plotext 6 exposes the figure through its public API rather than the
110+
# removed private ``plotext._figure._figure_class``. It is a singleton,
111+
# so reset it before handing it to maxplotlib as a fresh canvas.
112+
figure = _Plotext6Axes(_plotext_figure.clear())
17113
if nrows > 1 or ncols > 1:
18114
figure.subplots(nrows, ncols)
19115
return figure
20116

21117

22118
class PlotextFigure:
23-
def __init__(self, figure: _figure_class, suptitle: str | None = None):
119+
def __init__(self, figure: Any, suptitle: str | None = None):
24120
self.figure = figure
25121
self.suptitle = suptitle
26122

27123
def build(self, keep_colors: bool = True) -> str:
28-
output = self.figure.build()
124+
output = str(self.figure.build())
29125
if self.suptitle:
30126
output = f"{self.suptitle}\n{output}"
31127
return output if keep_colors else strip_ansi(output)

0 commit comments

Comments
 (0)