tikzplot42 0.3.9__tar.gz → 0.4.5__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {tikzplot42-0.3.9/src/tikzplot42.egg-info → tikzplot42-0.4.5}/PKG-INFO +4 -2
- {tikzplot42-0.3.9 → tikzplot42-0.4.5}/README.md +3 -1
- {tikzplot42-0.3.9 → tikzplot42-0.4.5}/pyproject.toml +1 -1
- {tikzplot42-0.3.9 → tikzplot42-0.4.5}/src/tikzplot/axes.py +272 -61
- {tikzplot42-0.3.9 → tikzplot42-0.4.5}/src/tikzplot/axes.pyi +69 -23
- {tikzplot42-0.3.9 → tikzplot42-0.4.5}/src/tikzplot/axes3d.py +26 -8
- tikzplot42-0.4.5/src/tikzplot/axes3d.pyi +43 -0
- {tikzplot42-0.3.9 → tikzplot42-0.4.5}/src/tikzplot/colorbar.py +14 -2
- {tikzplot42-0.3.9 → tikzplot42-0.4.5}/src/tikzplot/colorbar.pyi +13 -13
- tikzplot42-0.4.5/src/tikzplot/colors.py +228 -0
- tikzplot42-0.4.5/src/tikzplot/config.py +156 -0
- {tikzplot42-0.3.9 → tikzplot42-0.4.5}/src/tikzplot/config.pyi +63 -4
- {tikzplot42-0.3.9 → tikzplot42-0.4.5}/src/tikzplot/elements.py +89 -58
- tikzplot42-0.4.5/src/tikzplot/elements.pyi +92 -0
- {tikzplot42-0.3.9 → tikzplot42-0.4.5}/src/tikzplot/figure.py +23 -6
- tikzplot42-0.4.5/src/tikzplot/figure.pyi +82 -0
- {tikzplot42-0.3.9 → tikzplot42-0.4.5}/src/tikzplot/plots.py +92 -9
- {tikzplot42-0.3.9 → tikzplot42-0.4.5}/src/tikzplot/plots.pyi +53 -57
- tikzplot42-0.4.5/src/tikzplot/py.typed +2 -0
- {tikzplot42-0.3.9 → tikzplot42-0.4.5}/src/tikzplot/state.py +6 -5
- tikzplot42-0.4.5/src/tikzplot/styles.py +94 -0
- tikzplot42-0.4.5/src/tikzplot/styles.pyi +41 -0
- {tikzplot42-0.3.9 → tikzplot42-0.4.5}/src/tikzplot/texts.py +2 -2
- {tikzplot42-0.3.9 → tikzplot42-0.4.5/src/tikzplot42.egg-info}/PKG-INFO +4 -2
- {tikzplot42-0.3.9 → tikzplot42-0.4.5}/src/tikzplot42.egg-info/SOURCES.txt +8 -3
- tikzplot42-0.4.5/tests/test11.py +100 -0
- tikzplot42-0.4.5/tests/test12.py +32 -0
- tikzplot42-0.4.5/tests/test13.py +28 -0
- {tikzplot42-0.3.9 → tikzplot42-0.4.5}/tests/test3.py +1 -1
- {tikzplot42-0.3.9 → tikzplot42-0.4.5}/tests/test8.py +1 -3
- tikzplot42-0.4.5/tests/test_styles.py +17 -0
- tikzplot42-0.3.9/src/tikzplot/colors.py +0 -58
- tikzplot42-0.3.9/src/tikzplot/colors.pyi +0 -1
- tikzplot42-0.3.9/src/tikzplot/config.py +0 -103
- tikzplot42-0.3.9/src/tikzplot/elements.pyi +0 -11
- tikzplot42-0.3.9/src/tikzplot/figure.pyi +0 -34
- tikzplot42-0.3.9/src/tikzplot/py.typed +0 -0
- tikzplot42-0.3.9/src/tikzplot/state.pyi +0 -3
- {tikzplot42-0.3.9 → tikzplot42-0.4.5}/LICENSE +0 -0
- {tikzplot42-0.3.9 → tikzplot42-0.4.5}/setup.cfg +0 -0
- {tikzplot42-0.3.9 → tikzplot42-0.4.5}/src/tikzplot/__init__.py +0 -0
- {tikzplot42-0.3.9 → tikzplot42-0.4.5}/src/tikzplot/__init__.pyi +0 -0
- {tikzplot42-0.3.9 → tikzplot42-0.4.5}/src/tikzplot/latex_special.py +0 -0
- {tikzplot42-0.3.9 → tikzplot42-0.4.5}/src/tikzplot42.egg-info/dependency_links.txt +0 -0
- {tikzplot42-0.3.9 → tikzplot42-0.4.5}/src/tikzplot42.egg-info/requires.txt +0 -0
- {tikzplot42-0.3.9 → tikzplot42-0.4.5}/src/tikzplot42.egg-info/top_level.txt +0 -0
- {tikzplot42-0.3.9 → tikzplot42-0.4.5}/tests/test1.py +0 -0
- {tikzplot42-0.3.9 → tikzplot42-0.4.5}/tests/test10.py +0 -0
- {tikzplot42-0.3.9 → tikzplot42-0.4.5}/tests/test2.py +0 -0
- {tikzplot42-0.3.9 → tikzplot42-0.4.5}/tests/test4.py +0 -0
- {tikzplot42-0.3.9 → tikzplot42-0.4.5}/tests/test5.py +0 -0
- {tikzplot42-0.3.9 → tikzplot42-0.4.5}/tests/test6.py +0 -0
- {tikzplot42-0.3.9 → tikzplot42-0.4.5}/tests/test7.py +0 -0
- {tikzplot42-0.3.9 → tikzplot42-0.4.5}/tests/test9.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: tikzplot42
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.4.5
|
|
4
4
|
Summary: TikzPlot to make TikZ/PGFPlots plots with matplotlib.pyplot-like syntax.
|
|
5
5
|
Author-email: Zan Ambrozic <zan.ambrozic7@gmail.com>
|
|
6
6
|
License: GNU GENERAL PUBLIC LICENSE
|
|
@@ -765,6 +765,8 @@ If axes and plot have different name for command with same effect, both are impl
|
|
|
765
765
|
- `ax.twinx()`,
|
|
766
766
|
- `ax.set()`.
|
|
767
767
|
|
|
768
|
+
There is a limited support for built-in styles (e.g. `plt.style.use("default")`), you may also define your own style using `plt.style.set_profile()`. Currently supported features are: color cycle (hex colors sequence), line width (in pt), grid (with matplotlib kwargs), background (latex style key=value), additional settings (raw latex code for optional arguments to axis: key=value).
|
|
769
|
+
|
|
768
770
|
#### Supported common **kwargs
|
|
769
771
|
- `color/c` (all matplotlib formats, except color schemes which are not yet implemented),
|
|
770
772
|
- `linestyle/ls`,
|
|
@@ -788,6 +790,6 @@ For plot configurations (default sizes, paddings, etc.), use `from tikzplot impo
|
|
|
788
790
|
Currently supported parameters are listed with their default values in `src/tikzplot/config.py`.
|
|
789
791
|
|
|
790
792
|
## More features coming soon...
|
|
791
|
-
-
|
|
793
|
+
- more developed styles,
|
|
792
794
|
- improved 3D plots (currently only basic support: plot, errorbar, fill_between, scatter, plot_wireframe, plot_surface),
|
|
793
795
|
- ...
|
|
@@ -63,6 +63,8 @@ If axes and plot have different name for command with same effect, both are impl
|
|
|
63
63
|
- `ax.twinx()`,
|
|
64
64
|
- `ax.set()`.
|
|
65
65
|
|
|
66
|
+
There is a limited support for built-in styles (e.g. `plt.style.use("default")`), you may also define your own style using `plt.style.set_profile()`. Currently supported features are: color cycle (hex colors sequence), line width (in pt), grid (with matplotlib kwargs), background (latex style key=value), additional settings (raw latex code for optional arguments to axis: key=value).
|
|
67
|
+
|
|
66
68
|
#### Supported common **kwargs
|
|
67
69
|
- `color/c` (all matplotlib formats, except color schemes which are not yet implemented),
|
|
68
70
|
- `linestyle/ls`,
|
|
@@ -86,6 +88,6 @@ For plot configurations (default sizes, paddings, etc.), use `from tikzplot impo
|
|
|
86
88
|
Currently supported parameters are listed with their default values in `src/tikzplot/config.py`.
|
|
87
89
|
|
|
88
90
|
## More features coming soon...
|
|
89
|
-
-
|
|
91
|
+
- more developed styles,
|
|
90
92
|
- improved 3D plots (currently only basic support: plot, errorbar, fill_between, scatter, plot_wireframe, plot_surface),
|
|
91
93
|
- ...
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "tikzplot42"
|
|
7
|
-
version = "0.
|
|
7
|
+
version = "0.4.5"
|
|
8
8
|
description = "TikzPlot to make TikZ/PGFPlots plots with matplotlib.pyplot-like syntax."
|
|
9
9
|
authors = [
|
|
10
10
|
{ name = "Zan Ambrozic", email = "zan.ambrozic7@gmail.com" }
|
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
from typing import Any
|
|
2
|
+
from xml.dom import XMLNS_NAMESPACE
|
|
3
|
+
|
|
1
4
|
import numpy as _np
|
|
2
5
|
import matplotlib.pyplot as _plt
|
|
3
6
|
|
|
@@ -7,6 +10,7 @@ from .config import TikzConfig
|
|
|
7
10
|
from .colorbar import Colorbar
|
|
8
11
|
from .state import _next_imshow_num, main_name
|
|
9
12
|
from .latex_special import tex_text
|
|
13
|
+
from .colors import _tex_color
|
|
10
14
|
|
|
11
15
|
class BaseAxes:
|
|
12
16
|
def __init__(self):
|
|
@@ -21,18 +25,21 @@ class BaseAxes:
|
|
|
21
25
|
else:
|
|
22
26
|
self._axis_args.add(f"/pgf/number format/.cd, 1000 sep={{{TikzConfig.THOUSANDS_SEP}}}")
|
|
23
27
|
|
|
24
|
-
self._add_legend =
|
|
28
|
+
self._add_legend = []
|
|
29
|
+
self._legend_lab_col: Any = None
|
|
25
30
|
self._coordinates = {}
|
|
26
31
|
self._cmap_bar = None
|
|
27
32
|
|
|
28
33
|
self._ext_ymin = False
|
|
29
34
|
self._ext_ymax = False
|
|
30
35
|
|
|
31
|
-
|
|
32
|
-
|
|
36
|
+
self._reverse_elements = []
|
|
37
|
+
|
|
38
|
+
def _plot(self, x, y, settings={}, xerr=None, yerr=None, **style):
|
|
39
|
+
if isinstance(self, Axes) and self._polar:
|
|
33
40
|
x = _np.rad2deg(x)
|
|
34
41
|
e = Graph(self, (x, y), settings, xerr=xerr, yerr=yerr, **style)
|
|
35
|
-
if TikzConfig.USE_GROUPPLOTS and ("axvspan"
|
|
42
|
+
if TikzConfig.USE_GROUPPLOTS and ("axvspan" in settings or "axhspan" in settings):
|
|
36
43
|
self._elements.insert(0, e)
|
|
37
44
|
else:
|
|
38
45
|
self._elements.append(e)
|
|
@@ -71,6 +78,7 @@ class BaseAxes:
|
|
|
71
78
|
|
|
72
79
|
try:
|
|
73
80
|
c = kwargs.get("c", kwargs.get("color", None))
|
|
81
|
+
if c is None: raise ValueError("No color specified")
|
|
74
82
|
if len(c) == len(x):
|
|
75
83
|
if isinstance(c[0], (int, float)):
|
|
76
84
|
if "cmap" not in kwargs:
|
|
@@ -87,7 +95,7 @@ class BaseAxes:
|
|
|
87
95
|
self._cmap_bar = kwargs["cmap"]
|
|
88
96
|
except: pass
|
|
89
97
|
|
|
90
|
-
return self._plot(x, y, **kwargs, ls="", settings=
|
|
98
|
+
return self._plot(x, y, **kwargs, ls="", settings={"scatter": None})
|
|
91
99
|
|
|
92
100
|
def semilogy(self, x, y, *args, **kwargs):
|
|
93
101
|
kws = {"fmt", "base", "alpha", "color", "c", "linestyle", "ls", "linewidth", "lw", "marker", "markersize", "ms", "label"}
|
|
@@ -118,17 +126,16 @@ class BaseAxes:
|
|
|
118
126
|
x = range(len(y))
|
|
119
127
|
elif len(args) == 2:
|
|
120
128
|
x,y=args
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
kwargs["fmt"]=fmt
|
|
129
|
+
else:
|
|
130
|
+
raise Warning("Invalid number of args for stem.")
|
|
124
131
|
if "orientation" in kwargs:
|
|
125
132
|
o = kwargs.pop("orientation")
|
|
126
133
|
if o == "horizontal":
|
|
127
134
|
vert = False
|
|
128
135
|
if vert:
|
|
129
|
-
return self._plot(x,y,settings=
|
|
136
|
+
return self._plot(x,y,settings={"ycomb": None}, **kwargs)
|
|
130
137
|
else:
|
|
131
|
-
return self._plot(y,x,settings=
|
|
138
|
+
return self._plot(y,x,settings={"xcomb": None}, **kwargs)
|
|
132
139
|
|
|
133
140
|
def fill_between(self, x, y1, y2=None, **kwargs):
|
|
134
141
|
kws = {"fmt", "alpha", "color", "c", "label"}
|
|
@@ -139,6 +146,7 @@ class BaseAxes:
|
|
|
139
146
|
return el._try_set_pname(pname)
|
|
140
147
|
else:
|
|
141
148
|
return None
|
|
149
|
+
assert self._fig is not None
|
|
142
150
|
name1 = self._fig._get_free_path_name()
|
|
143
151
|
name2 = self._fig._get_free_path_name()
|
|
144
152
|
if isinstance(y1, (int, float)):
|
|
@@ -165,7 +173,7 @@ class BaseAxes:
|
|
|
165
173
|
self._plot(xs,ys,path_name=name2, alpha=0)
|
|
166
174
|
else:
|
|
167
175
|
name2 = inst
|
|
168
|
-
e = Graph(self, f"fill between [of={name1} and {name2}]",settings=
|
|
176
|
+
e = Graph(self, f"fill between [of={name1} and {name2}]",settings={}, xerr=None, yerr=None, **kwargs)
|
|
169
177
|
self._elements.append(e)
|
|
170
178
|
return e
|
|
171
179
|
|
|
@@ -214,46 +222,150 @@ class BaseAxes:
|
|
|
214
222
|
self._plot([xs[i]]*2, [ymins[i], ymaxs[i]], None, None, None, c=colorss[i], ls=lss[i])
|
|
215
223
|
|
|
216
224
|
def hist(self, x, bins=10, density=False,**kwargs):
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
+
kws = {"alpha", "color", "c", "label", "facecolor", "fc", "edgecolor", "ec", "orientation", "rwidth", "cumulative", "range", "histtype", "weights", "cumulative", "align", "stacked", "fill"}
|
|
226
|
+
kwargs = self._check_kwargs("hist", kws, **kwargs)
|
|
227
|
+
if isinstance(x, (list, tuple)) and len(x) > 0 and isinstance(x[0], (list, tuple, _np.ndarray)):
|
|
228
|
+
try:
|
|
229
|
+
datasets = [_np.asarray(ds, dtype=_np.float64) for ds in x]
|
|
230
|
+
if any(ds.ndim != 1 for ds in datasets):
|
|
231
|
+
raise ValueError("Nested datasets must all be 1-dimensional.")
|
|
232
|
+
except (ValueError, TypeError):
|
|
233
|
+
x_arr = _np.asarray(x)
|
|
234
|
+
if x_arr.ndim == 2:
|
|
235
|
+
datasets = [x_arr[:, i] for i in range(x_arr.shape[1])]
|
|
236
|
+
else:
|
|
237
|
+
raise ValueError("Invalid dataset structure.")
|
|
238
|
+
else:
|
|
239
|
+
x_arr = _np.asarray(x)
|
|
240
|
+
if x_arr.ndim == 1:
|
|
241
|
+
datasets = [x_arr]
|
|
242
|
+
elif x_arr.ndim == 2:
|
|
243
|
+
datasets = [x_arr[:, i] for i in range(x_arr.shape[1])]
|
|
244
|
+
else:
|
|
245
|
+
raise ValueError(f"Input must be 1D or 2D, got {x_arr.ndim}D.")
|
|
246
|
+
|
|
247
|
+
stack = kwargs.pop("stacked", False)
|
|
248
|
+
datas = {}
|
|
249
|
+
for kw in ["color", "c", "facecolor", "fc", "edgecolor", "ec", "label"]:
|
|
250
|
+
if kw in kwargs:
|
|
251
|
+
if isinstance(kwargs[kw], (list)):
|
|
252
|
+
if len(kwargs[kw]) != len(datasets):
|
|
253
|
+
raise Warning(f"Length of {kw} does not match number of datasets.")
|
|
254
|
+
prop = kwargs.pop(kw)
|
|
255
|
+
else:
|
|
256
|
+
prop = [kwargs.pop(kw)] * len(datasets)
|
|
257
|
+
for i in range(len(datasets)):
|
|
258
|
+
if i not in datas:
|
|
259
|
+
datas[i] = {}
|
|
260
|
+
datas[i][kw] = prop[i]
|
|
225
261
|
all_data = _np.concatenate(datasets)
|
|
226
|
-
edges = _np.histogram_bin_edges(all_data, bins=bins)
|
|
227
|
-
for data in datasets:
|
|
228
|
-
counts, _ = _np.histogram(data, edges, density=density)
|
|
229
|
-
centers = (edges[:-1] + edges[1:]) / 2
|
|
262
|
+
edges = _np.histogram_bin_edges(all_data, bins=bins, weights=kwargs.get("weights", None), range=kwargs.get("range", None))
|
|
230
263
|
widths = edges[1:] - edges[:-1]
|
|
231
|
-
|
|
264
|
+
offset = 0
|
|
265
|
+
settings = {}
|
|
266
|
+
hist_type = kwargs.pop("histtype", "bar")
|
|
267
|
+
if hist_type not in ["bar", "barstacked", "step", "stepfilled"]:
|
|
268
|
+
raise Warning(f"Invalid histtype: {hist_type}.")
|
|
232
269
|
if "orientation" in kwargs and kwargs["orientation"] == "horizontal":
|
|
233
|
-
settings
|
|
270
|
+
settings["xbar"] = None
|
|
234
271
|
else:
|
|
235
|
-
settings
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
272
|
+
settings["ybar"] = None
|
|
273
|
+
if ("rwidth" in kwargs or (len(datasets) > 1 and not stack)) and isinstance(bins, int):
|
|
274
|
+
if stack or len(datasets) == 1:
|
|
275
|
+
settings["bar width"] = f"{widths.mean()*kwargs['rwidth']}"
|
|
276
|
+
else:
|
|
277
|
+
if "rwidth" in kwargs:
|
|
278
|
+
settings["bar width"] = f"{widths.mean()*kwargs['rwidth']/(len(datasets)+1)}"
|
|
279
|
+
offset = widths.mean() * kwargs['rwidth'] / (len(datasets) + 1)
|
|
280
|
+
else:
|
|
281
|
+
settings["bar width"] = f"{widths.mean()/(len(datasets)+1)}"
|
|
282
|
+
offset = widths.mean() / (len(datasets) + 1)
|
|
239
283
|
else:
|
|
240
|
-
|
|
284
|
+
if "xbar" in settings:
|
|
285
|
+
settings.pop("xbar")
|
|
286
|
+
settings["xbar interval"] = None
|
|
287
|
+
elif "ybar" in settings:
|
|
288
|
+
settings.pop("ybar")
|
|
289
|
+
settings["ybar interval"] = None
|
|
241
290
|
if "range" in kwargs:
|
|
242
|
-
if
|
|
291
|
+
if "xbar" in settings:
|
|
243
292
|
self.set_ylim(kwargs["range"])
|
|
244
|
-
|
|
293
|
+
elif isinstance(self, Axes):
|
|
245
294
|
self.set_xlim(kwargs["range"])
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
295
|
+
elif isinstance(self, Secondary):
|
|
296
|
+
self._primary.set_xlim(kwargs["range"])
|
|
297
|
+
base_settings = settings.copy()
|
|
298
|
+
outputs = []
|
|
299
|
+
old_counts = _np.zeros(len(edges), dtype=_np.float64)
|
|
300
|
+
totals, _ = _np.histogram(all_data, edges, density=False, weights=kwargs.get("weights", None), range=kwargs.get("range", None))
|
|
301
|
+
tot_sum = totals.sum()
|
|
302
|
+
for i in range(len(datasets)):
|
|
303
|
+
data = datasets[i]
|
|
304
|
+
settings = base_settings.copy()
|
|
305
|
+
kws = datas.get(i, {})
|
|
306
|
+
if "label" in kws:
|
|
307
|
+
if "xbar" in settings or "xbar interval" in settings:
|
|
308
|
+
settings["xbar legend"] = None
|
|
309
|
+
else:
|
|
310
|
+
settings["ybar legend"] = None
|
|
311
|
+
else:
|
|
312
|
+
settings["forget plot"] = None
|
|
313
|
+
fill = kws.pop("facecolor", kws.pop("fc", kws.pop("color", kws.pop("c", None))))
|
|
314
|
+
draw = kws.pop("edgecolor", kws.pop("ec", None))
|
|
315
|
+
if fill:
|
|
316
|
+
fill = self._match_color(fill)
|
|
317
|
+
settings["fill"] = fill
|
|
318
|
+
if draw and hist_type != "stepfilled":
|
|
319
|
+
draw = self._match_color(draw)
|
|
320
|
+
settings["draw"] = draw
|
|
321
|
+
else:
|
|
322
|
+
settings["draw"] = "none"
|
|
323
|
+
counts, _ = _np.histogram(data, edges, density=density, weights=kwargs.get("weights", None), range=kwargs.get("range", None))
|
|
324
|
+
if "xbar interval" in settings or "ybar interval" in settings: # edges for interval
|
|
325
|
+
if "rwidth" in kwargs:
|
|
326
|
+
xs = [edges[0] + widths[0]*(1-kwargs["rwidth"])/2]
|
|
327
|
+
new_counts = []
|
|
328
|
+
for j in range(len(widths)): # Changed 'i' to 'j' to avoid overwriting dataset index 'i'
|
|
329
|
+
xs.append(xs[-1] + widths[j]*kwargs["rwidth"])
|
|
330
|
+
new_counts.append(counts[j])
|
|
331
|
+
if j < len(counts)-1:
|
|
332
|
+
xs.append(xs[-1] + (widths[j] + widths[j+1])*(1-kwargs["rwidth"])/2)
|
|
333
|
+
new_counts.append(0)
|
|
334
|
+
counts = new_counts + [0]
|
|
335
|
+
else:
|
|
336
|
+
xs = edges
|
|
337
|
+
counts = _np.concatenate([counts, [0]])
|
|
338
|
+
else: # centers
|
|
339
|
+
xs = (edges[:-1] + edges[1:]) / 2
|
|
340
|
+
if offset > 0:
|
|
341
|
+
settings["bar shift"] = f"{offset*(i - len(datasets)/2 + 0.5)}"
|
|
342
|
+
if "cumulative" in kwargs and kwargs["cumulative"]:
|
|
343
|
+
counts = _np.cumsum(counts)
|
|
344
|
+
if stack:
|
|
345
|
+
if density:
|
|
346
|
+
set_counts, _ = _np.histogram(data, edges, density=False, weights=kwargs.get("weights", None), range=kwargs.get("range", None))
|
|
347
|
+
counts = counts * _np.sum(set_counts) / tot_sum
|
|
348
|
+
counts = _np.asarray(counts, dtype=_np.float64)
|
|
349
|
+
counts += old_counts
|
|
350
|
+
old_counts = counts.copy()
|
|
351
|
+
if hist_type == "step":
|
|
352
|
+
kwargs.pop("facecolor", None)
|
|
353
|
+
kwargs.pop("fc", None)
|
|
354
|
+
kwargs.pop("fill", None)
|
|
355
|
+
self.step([edges[0]] + list(edges), [0] + list(counts), where="pre", **kws)
|
|
356
|
+
else:
|
|
357
|
+
e = self._plot(xs, counts, settings=settings, **kws)
|
|
358
|
+
outputs.append(e)
|
|
359
|
+
if outputs and stack:
|
|
360
|
+
self._reverse_elements.append([id(e) for e in outputs])
|
|
361
|
+
return outputs
|
|
250
362
|
|
|
251
363
|
def step(self, x, y, *args, **kwargs):
|
|
252
364
|
kws = {"fmt", "alpha", "color", "c", "linestyle", "ls", "linewidth", "lw", "marker", "markersize", "ms", "label", "where"}
|
|
253
365
|
kwargs = self._check_kwargs("step", kws, **kwargs)
|
|
254
366
|
WHERE_DICT = {"pre": "left", "post": "right", "mid": "mid"}
|
|
255
367
|
where = WHERE_DICT.get(kwargs.pop("where", "pre"), None)
|
|
256
|
-
settings =
|
|
368
|
+
settings = {f"const plot mark {where}": None}
|
|
257
369
|
if len(args) == 1:
|
|
258
370
|
kwargs["fmt"] = args[0]
|
|
259
371
|
return self._plot(x,y,settings=settings, **kwargs)
|
|
@@ -262,7 +374,7 @@ class BaseAxes:
|
|
|
262
374
|
kws = {"fmt", "base", "alpha", "color", "c", "linestyle", "ls", "linewidth", "lw", "label"}
|
|
263
375
|
kwargs = self._check_kwargs("axvline", kws, **kwargs)
|
|
264
376
|
self._ext_ymin = self._ext_ymax = True
|
|
265
|
-
self._plot(x, (ymin, ymax), settings="axvline", **kwargs)
|
|
377
|
+
self._plot(x, (ymin, ymax), settings={"axvline": None}, **kwargs)
|
|
266
378
|
|
|
267
379
|
def axhline(self, y, xmin=0, xmax=1, **kwargs):
|
|
268
380
|
kws = {"fmt", "base", "alpha", "color", "c", "linestyle", "ls", "linewidth", "lw", "label"}
|
|
@@ -271,7 +383,7 @@ class BaseAxes:
|
|
|
271
383
|
self._primary._ext_xmin = self._primary._ext_xmax = True
|
|
272
384
|
else:
|
|
273
385
|
self._ext_xmin = self._ext_xmax = True
|
|
274
|
-
self._plot((xmin, xmax), y, settings="axhline", **kwargs)
|
|
386
|
+
self._plot((xmin, xmax), y, settings={"axhline": None}, **kwargs)
|
|
275
387
|
|
|
276
388
|
def axvspan(self, xmin, xmax, ymin=0, ymax=1, **kwargs):
|
|
277
389
|
kws = {"c", "color", "alpha", "label"}
|
|
@@ -279,7 +391,7 @@ class BaseAxes:
|
|
|
279
391
|
self._ext_ymin = self._ext_ymax = True
|
|
280
392
|
if TikzConfig.USE_GROUPPLOTS:
|
|
281
393
|
self._axis_args.add("set layers")
|
|
282
|
-
self._plot([xmin, xmax], [ymin, ymax], settings="axvspan", **kwargs)
|
|
394
|
+
self._plot([xmin, xmax], [ymin, ymax], settings={"axvspan": None}, **kwargs)
|
|
283
395
|
|
|
284
396
|
def axhspan(self, ymin, ymax, xmin=0, xmax=1, **kwargs):
|
|
285
397
|
kws = {"c", "color", "alpha", "label"}
|
|
@@ -290,7 +402,7 @@ class BaseAxes:
|
|
|
290
402
|
self._ext_xmin = self._ext_xmax = True
|
|
291
403
|
if TikzConfig.USE_GROUPPLOTS:
|
|
292
404
|
self._axis_args.add("set layers")
|
|
293
|
-
self._plot([xmin, xmax], [ymin, ymax], settings="axhspan", **kwargs)
|
|
405
|
+
self._plot([xmin, xmax], [ymin, ymax], settings={"axhspan": None}, **kwargs)
|
|
294
406
|
|
|
295
407
|
def set_ylabel(self, label):
|
|
296
408
|
self._axis_options["ylabel"] = f"{{{tex_text(label)}}}"
|
|
@@ -350,7 +462,19 @@ class BaseAxes:
|
|
|
350
462
|
_LEGEND_LOC_MAP = ["best", "upper right", "upper left", "lower_left", "lower right", "right", "center left", "center right", "lower center", "upper center", "center"]
|
|
351
463
|
_ANCHOR_MAP = {"top": "north", "bottom": "south", "upper": "north", "lower": "south", "left": "west", "right": "east", "center": "center"}
|
|
352
464
|
|
|
465
|
+
def _match_color(self, input):
|
|
466
|
+
if isinstance(self, Axes) or isinstance(self, Secondary):
|
|
467
|
+
if input == "none":
|
|
468
|
+
return "none"
|
|
469
|
+
ccode, op = _tex_color(input, self._style)
|
|
470
|
+
if isinstance(ccode, str):
|
|
471
|
+
return ccode
|
|
472
|
+
r,g,b = ccode
|
|
473
|
+
self._add_col(r,g,b)
|
|
474
|
+
return f"c{r:.3f}{g:.3f}{b:.3f}".replace(".", "")
|
|
475
|
+
|
|
353
476
|
def legend(self, *args, **kwargs):
|
|
477
|
+
legend_string = {}
|
|
354
478
|
if "loc" in kwargs:
|
|
355
479
|
loc = kwargs["loc"]
|
|
356
480
|
lx = ly = posit = None
|
|
@@ -358,7 +482,8 @@ class BaseAxes:
|
|
|
358
482
|
try:
|
|
359
483
|
lx,ly=float(loc[0]), float(loc[1])
|
|
360
484
|
posit = "south west"
|
|
361
|
-
except:
|
|
485
|
+
except:
|
|
486
|
+
print(f"Error parsing legend location: {loc}")
|
|
362
487
|
else:
|
|
363
488
|
if isinstance(loc, int):
|
|
364
489
|
loc = self._LEGEND_LOC_MAP[loc]
|
|
@@ -376,17 +501,34 @@ class BaseAxes:
|
|
|
376
501
|
elif "east" in posit:
|
|
377
502
|
lx = 1 - TikzConfig.LEGEND_REL_X
|
|
378
503
|
|
|
379
|
-
legend_string = []
|
|
380
504
|
if lx is not None and ly is not None:
|
|
381
|
-
legend_string
|
|
382
|
-
if len(posit):
|
|
383
|
-
legend_string
|
|
384
|
-
|
|
505
|
+
legend_string["at"] = "{(" + f"{lx},{ly}" + r")}"
|
|
506
|
+
if posit is not None and len(posit):
|
|
507
|
+
legend_string["anchor"] = posit
|
|
508
|
+
|
|
509
|
+
if "facecolor" in kwargs and (isinstance(self, Axes) or isinstance(self, Secondary)):
|
|
510
|
+
ccode = self._match_color(kwargs["facecolor"])
|
|
511
|
+
if ccode is not None:
|
|
512
|
+
legend_string["fill"] = ccode
|
|
513
|
+
if "edgecolor" in kwargs and (isinstance(self, Axes) or isinstance(self, Secondary)):
|
|
514
|
+
ccode = self._match_color(kwargs["edgecolor"])
|
|
515
|
+
if ccode is not None:
|
|
516
|
+
legend_string["draw"] = ccode
|
|
517
|
+
if "labelcolor" in kwargs and (isinstance(self, Axes) or isinstance(self, Secondary)):
|
|
518
|
+
ccode = self._match_color(kwargs["labelcolor"])
|
|
519
|
+
if ccode is not None:
|
|
520
|
+
self._legend_lab_col = ccode
|
|
521
|
+
if "frameon" in kwargs and not kwargs["frameon"]:
|
|
522
|
+
legend_string["draw"] = "none"
|
|
523
|
+
if "legend style" in self._axis_options:
|
|
524
|
+
self._axis_options["legend style"].update(legend_string)
|
|
525
|
+
else:
|
|
526
|
+
self._axis_options["legend style"] = legend_string
|
|
385
527
|
self._legend_on = True
|
|
386
528
|
if "ncols" in kwargs:
|
|
387
529
|
self._axis_options["legend columns"] = kwargs["ncols"]
|
|
388
530
|
if len(args) == 2:
|
|
389
|
-
self._add_legend = args
|
|
531
|
+
self._add_legend = list(args)
|
|
390
532
|
elif len(args) == 1:
|
|
391
533
|
labs = args[0]
|
|
392
534
|
if len(labs) > len(self._elements):
|
|
@@ -395,10 +537,12 @@ class BaseAxes:
|
|
|
395
537
|
for i in range(len(labs)):
|
|
396
538
|
self._elements[i]._set_label(tex_text(labs[i]))
|
|
397
539
|
|
|
398
|
-
def text(self, x, y, s,
|
|
399
|
-
kws = {"alpha", "color", "c", "fontsize", "size", "backgroundcolor", "horizontalalignment", "ha", "verticalalignment", "va", "rotation", "label"}
|
|
540
|
+
def text(self, x, y, s, **kwargs):
|
|
541
|
+
kws = {"alpha", "color", "c", "fontsize", "on_top", "size", "backgroundcolor", "horizontalalignment", "ha", "verticalalignment", "va", "rotation", "label"}
|
|
400
542
|
kwargs = self._check_kwargs("text", kws, **kwargs)
|
|
543
|
+
on_top = kwargs.pop("on_top", True)
|
|
401
544
|
if on_top:
|
|
545
|
+
assert self._fig is not None
|
|
402
546
|
coord = self._fig._next_coordinate_name()
|
|
403
547
|
txt = Text(self, x, y, coord, s, **kwargs)
|
|
404
548
|
self._fig._add_text(txt)
|
|
@@ -409,12 +553,13 @@ class BaseAxes:
|
|
|
409
553
|
def magnify(self, x_p, y_p, x_m, y_m, zoom, size, **kwargs):
|
|
410
554
|
kws = {"shape", "connect"}
|
|
411
555
|
kwargs = self._check_kwargs("magnify", kws, **kwargs)
|
|
556
|
+
assert self._fig is not None
|
|
412
557
|
n = self._fig._add_spy(zoom, size, **kwargs)
|
|
413
558
|
self._coordinates.update({f"spypoint{n}": (x_p,y_p)})
|
|
414
559
|
self._coordinates.update({f"spyviewr{n}": (x_m,y_m)})
|
|
415
560
|
|
|
416
561
|
def _add_legend_entries(self):
|
|
417
|
-
if self._add_legend ==
|
|
562
|
+
if self._add_legend == []: return ""
|
|
418
563
|
axs, labs = self._add_legend
|
|
419
564
|
output = ""
|
|
420
565
|
if len(axs) != len(labs):
|
|
@@ -422,16 +567,36 @@ class BaseAxes:
|
|
|
422
567
|
return ""
|
|
423
568
|
for i in range(len(axs)):
|
|
424
569
|
output += f"\n\\addlegendimage{{{axs[i]._style_string()}}}"
|
|
425
|
-
|
|
570
|
+
if self._legend_lab_col:
|
|
571
|
+
output += f"\n\\addlegendentry[{self._legend_lab_col}]{{{tex_text(labs[i])}}}"
|
|
572
|
+
else:
|
|
573
|
+
output += f"\n\\addlegendentry{{{tex_text(labs[i])}}}"
|
|
426
574
|
return output
|
|
427
575
|
|
|
428
576
|
def _content_tex(self, filename):
|
|
429
|
-
|
|
430
|
-
|
|
577
|
+
element_strings = {id(e): e._to_tex(filename, self._legend_lab_col) for e in self._elements}
|
|
578
|
+
seq_map = {seq[0]: seq for seq in self._reverse_elements}
|
|
579
|
+
output_list = []
|
|
580
|
+
visited = set()
|
|
581
|
+
for e in self._elements:
|
|
582
|
+
e_id = id(e)
|
|
583
|
+
if e_id in visited:
|
|
584
|
+
continue
|
|
585
|
+
if e_id in seq_map:
|
|
586
|
+
seq = seq_map[e_id]
|
|
587
|
+
for el in reversed(seq):
|
|
588
|
+
output_list.append(element_strings[el])
|
|
589
|
+
visited.add(el)
|
|
590
|
+
else:
|
|
591
|
+
output_list.append(element_strings[e_id])
|
|
592
|
+
visited.add(e_id)
|
|
593
|
+
|
|
594
|
+
output = "\n".join(output_list)
|
|
595
|
+
output += self._add_legend_entries()
|
|
431
596
|
for coord in self._coordinates:
|
|
432
597
|
x,y = self._coordinates[coord]
|
|
433
|
-
|
|
434
|
-
return
|
|
598
|
+
output += f"\n\\coordinate ({coord}) at ({x},{y});"
|
|
599
|
+
return output
|
|
435
600
|
|
|
436
601
|
def _get_hard_range(self,which):
|
|
437
602
|
arg = f"{which[0]}mode"
|
|
@@ -499,6 +664,7 @@ class BaseAxes:
|
|
|
499
664
|
e._reduce_points(limit)
|
|
500
665
|
|
|
501
666
|
def _add_col(self, r,g,b):
|
|
667
|
+
assert self._fig is not None
|
|
502
668
|
self._fig._add_col(r,g,b)
|
|
503
669
|
|
|
504
670
|
def set(self, **kwargs):
|
|
@@ -507,6 +673,10 @@ class BaseAxes:
|
|
|
507
673
|
if attr in kwargs:
|
|
508
674
|
defined[attr](kwargs.pop(attr))
|
|
509
675
|
|
|
676
|
+
def _reoreder_last_elements(self, n):
|
|
677
|
+
if n <= 0: return
|
|
678
|
+
self._elements = self._elements[:-n] + self._elements[:-n-1:-1]
|
|
679
|
+
|
|
510
680
|
class Axes(BaseAxes):
|
|
511
681
|
|
|
512
682
|
def __init__(self, nrows, ncols, index, fig, polar):
|
|
@@ -521,6 +691,7 @@ class Axes(BaseAxes):
|
|
|
521
691
|
self._col = self._index - self._row * self._ncols
|
|
522
692
|
|
|
523
693
|
self._fig = fig
|
|
694
|
+
self._style = self._fig._style
|
|
524
695
|
self._imshow = None
|
|
525
696
|
|
|
526
697
|
self._defcol_counter = 0
|
|
@@ -559,6 +730,18 @@ class Axes(BaseAxes):
|
|
|
559
730
|
|
|
560
731
|
self._xticks = True
|
|
561
732
|
|
|
733
|
+
self._style_defaults()
|
|
734
|
+
|
|
735
|
+
def _style_defaults(self):
|
|
736
|
+
_gs = self._style._get_grid_cycle()
|
|
737
|
+
if _gs is not None:
|
|
738
|
+
self.grid(**_gs)
|
|
739
|
+
_bcgnd = self._style._get_background_cycle()
|
|
740
|
+
if _bcgnd is not None:
|
|
741
|
+
self._axis_options["axis background/.style"] = f"{{{_bcgnd}}}"
|
|
742
|
+
_add_settgs = self._style._get_additional_settings()
|
|
743
|
+
if _add_settgs is not None:
|
|
744
|
+
self._axis_options = _add_settgs | self._axis_options
|
|
562
745
|
|
|
563
746
|
def _update_size(self):
|
|
564
747
|
if self._fig._get_width():
|
|
@@ -629,7 +812,7 @@ class Axes(BaseAxes):
|
|
|
629
812
|
if kwargs:
|
|
630
813
|
accepted_kwargs = {"color", "c", "linestyle", "ls", "linewidth", "lw", "alpha"}
|
|
631
814
|
kwargs = self._check_kwargs("grid", accepted_kwargs, **kwargs)
|
|
632
|
-
g = Graph(self, None,
|
|
815
|
+
g = Graph(self, None, {}, None, None, **kwargs)._style_string()
|
|
633
816
|
self._axis_options[f"{selector}grid style"] = f"{{{g}}}"
|
|
634
817
|
|
|
635
818
|
def set_minorticks_num(self, num):
|
|
@@ -708,7 +891,7 @@ class Axes(BaseAxes):
|
|
|
708
891
|
_plt.axis("off")
|
|
709
892
|
_plt.imshow(*args, **kwargs)
|
|
710
893
|
im_name = f"{str(main_name()[1]).removesuffix('.py')}_{TikzConfig.IMSHOW_SAVENAME}{_next_imshow_num()}.pdf"
|
|
711
|
-
_plt.savefig(im_name,bbox_inches='tight', pad_inches=0)
|
|
894
|
+
_plt.savefig(im_name, bbox_inches='tight', pad_inches=0)
|
|
712
895
|
return im_name
|
|
713
896
|
|
|
714
897
|
def _axis_option_string(self):
|
|
@@ -729,7 +912,7 @@ class Axes(BaseAxes):
|
|
|
729
912
|
if "extent" in self._imshow[1]:
|
|
730
913
|
bounds = self._imshow[1]["extent"]
|
|
731
914
|
xm, xM, ym, yM = bounds
|
|
732
|
-
self._elements.insert(0, Graph(self, f"graphics [xmin={xm}, xmax={xM}, ymin={ym}, ymax={yM}] {{{im_name}}}",settings=
|
|
915
|
+
self._elements.insert(0, Graph(self, f"graphics [xmin={xm}, xmax={xM}, ymin={ym}, ymax={yM}] {{{im_name}}}", settings={}, xerr=None, yerr=None, onlayer="axis background"))
|
|
733
916
|
axis_opt_str = ""
|
|
734
917
|
if self._axis_args:
|
|
735
918
|
axis_opt_str += ",\n".join(self._axis_args)
|
|
@@ -762,7 +945,13 @@ class Axes(BaseAxes):
|
|
|
762
945
|
self._axis_options["ymax"] = self._fig._next_limname("ymax", self._axis_options.get("ymax", yM))
|
|
763
946
|
if self._axis_options:
|
|
764
947
|
if axis_opt_str: axis_opt_str += ",\n"
|
|
765
|
-
|
|
948
|
+
for k, v in self._axis_options.items():
|
|
949
|
+
if isinstance(v, dict):
|
|
950
|
+
axis_opt_str += f"{k}={{"
|
|
951
|
+
axis_opt_str += ",\n".join(f"{kk}={vv}" for kk, vv in v.items())
|
|
952
|
+
axis_opt_str += "},\n"
|
|
953
|
+
else:
|
|
954
|
+
axis_opt_str += f"{k}={v},\n"
|
|
766
955
|
if self._colorbar:
|
|
767
956
|
axis_opt_str += self._colorbar
|
|
768
957
|
elif self._cmap_bar:
|
|
@@ -834,6 +1023,15 @@ class Axes(BaseAxes):
|
|
|
834
1023
|
defined[attr](kwargs.pop(attr))
|
|
835
1024
|
|
|
836
1025
|
super().set(**kwargs)
|
|
1026
|
+
|
|
1027
|
+
def set_facecolor(self, color):
|
|
1028
|
+
ccode, _ = _tex_color(color, self._style)
|
|
1029
|
+
if isinstance(ccode, str):
|
|
1030
|
+
self._axis_options["axis background/.style"] = f"{{fill={ccode}}}"
|
|
1031
|
+
else:
|
|
1032
|
+
r,g,b = ccode
|
|
1033
|
+
self._add_col(r,g,b)
|
|
1034
|
+
self._axis_options["axis background/.style"] = f"{{fill=c{r:.3f}{g:.3f}{b:.3f}}}".replace(".", "")
|
|
837
1035
|
|
|
838
1036
|
class Secondary(BaseAxes):
|
|
839
1037
|
def __init__(self, primary):
|
|
@@ -847,6 +1045,13 @@ class Secondary(BaseAxes):
|
|
|
847
1045
|
self._axis_options["y label style"] = r"{at={(" + str(TikzConfig.SEC_YLABEL_LOC[0]) + "," + str(TikzConfig.SEC_YLABEL_LOC[1]) + ")}, rotate=180}"
|
|
848
1046
|
|
|
849
1047
|
self._fig = primary._fig
|
|
1048
|
+
self._style = self._fig._style
|
|
1049
|
+
self._style_defaults()
|
|
1050
|
+
|
|
1051
|
+
def _style_defaults(self):
|
|
1052
|
+
_add_settgs = self._style._get_additional_settings()
|
|
1053
|
+
if _add_settgs is not None:
|
|
1054
|
+
self._axis_options = _add_settgs | self._axis_options
|
|
850
1055
|
|
|
851
1056
|
def _axis_option_string(self):
|
|
852
1057
|
if self._primary._width:
|
|
@@ -868,7 +1073,13 @@ class Secondary(BaseAxes):
|
|
|
868
1073
|
self._axis_options["xmax"] = self._primary._axis_options["xmax"]
|
|
869
1074
|
if self._axis_options:
|
|
870
1075
|
if axis_opt_str: axis_opt_str += ",\n"
|
|
871
|
-
|
|
1076
|
+
for k, v in self._axis_options.items():
|
|
1077
|
+
if isinstance(v, dict):
|
|
1078
|
+
axis_opt_str += f"{k}={{"
|
|
1079
|
+
axis_opt_str += ",\n".join(f"{kk}={vv}" for kk, vv in v.items())
|
|
1080
|
+
axis_opt_str += "},\n"
|
|
1081
|
+
else:
|
|
1082
|
+
axis_opt_str += f"{k}={v},\n"
|
|
872
1083
|
return axis_opt_str
|
|
873
1084
|
|
|
874
1085
|
def _padding(self):
|