tikzplot42 0.4.3__tar.gz → 0.4.6__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.4.3/src/tikzplot42.egg-info → tikzplot42-0.4.6}/PKG-INFO +1 -1
- {tikzplot42-0.4.3 → tikzplot42-0.4.6}/pyproject.toml +1 -1
- {tikzplot42-0.4.3 → tikzplot42-0.4.6}/src/tikzplot/axes.py +245 -53
- {tikzplot42-0.4.3 → tikzplot42-0.4.6}/src/tikzplot/axes.pyi +127 -13
- {tikzplot42-0.4.3 → tikzplot42-0.4.6}/src/tikzplot/axes3d.py +4 -4
- tikzplot42-0.4.6/src/tikzplot/colors.py +228 -0
- {tikzplot42-0.4.3 → tikzplot42-0.4.6}/src/tikzplot/elements.py +115 -51
- {tikzplot42-0.4.3 → tikzplot42-0.4.6}/src/tikzplot/elements.pyi +3 -3
- {tikzplot42-0.4.3 → tikzplot42-0.4.6}/src/tikzplot/figure.py +14 -2
- {tikzplot42-0.4.3 → tikzplot42-0.4.6}/src/tikzplot/figure.pyi +7 -1
- {tikzplot42-0.4.3 → tikzplot42-0.4.6}/src/tikzplot/plots.py +14 -2
- {tikzplot42-0.4.3 → tikzplot42-0.4.6}/src/tikzplot/plots.pyi +122 -16
- {tikzplot42-0.4.3 → tikzplot42-0.4.6}/src/tikzplot/texts.py +2 -2
- {tikzplot42-0.4.3 → tikzplot42-0.4.6/src/tikzplot42.egg-info}/PKG-INFO +1 -1
- {tikzplot42-0.4.3 → tikzplot42-0.4.6}/src/tikzplot42.egg-info/SOURCES.txt +2 -0
- tikzplot42-0.4.6/tests/test12.py +32 -0
- tikzplot42-0.4.6/tests/test13.py +29 -0
- {tikzplot42-0.4.3 → tikzplot42-0.4.6}/tests/test2.py +2 -1
- tikzplot42-0.4.6/tests/test4.py +9 -0
- tikzplot42-0.4.3/src/tikzplot/colors.py +0 -60
- tikzplot42-0.4.3/tests/test4.py +0 -8
- {tikzplot42-0.4.3 → tikzplot42-0.4.6}/LICENSE +0 -0
- {tikzplot42-0.4.3 → tikzplot42-0.4.6}/README.md +0 -0
- {tikzplot42-0.4.3 → tikzplot42-0.4.6}/setup.cfg +0 -0
- {tikzplot42-0.4.3 → tikzplot42-0.4.6}/src/tikzplot/__init__.py +0 -0
- {tikzplot42-0.4.3 → tikzplot42-0.4.6}/src/tikzplot/__init__.pyi +0 -0
- {tikzplot42-0.4.3 → tikzplot42-0.4.6}/src/tikzplot/axes3d.pyi +0 -0
- {tikzplot42-0.4.3 → tikzplot42-0.4.6}/src/tikzplot/colorbar.py +0 -0
- {tikzplot42-0.4.3 → tikzplot42-0.4.6}/src/tikzplot/colorbar.pyi +0 -0
- {tikzplot42-0.4.3 → tikzplot42-0.4.6}/src/tikzplot/config.py +0 -0
- {tikzplot42-0.4.3 → tikzplot42-0.4.6}/src/tikzplot/config.pyi +0 -0
- {tikzplot42-0.4.3 → tikzplot42-0.4.6}/src/tikzplot/latex_special.py +0 -0
- {tikzplot42-0.4.3 → tikzplot42-0.4.6}/src/tikzplot/py.typed +0 -0
- {tikzplot42-0.4.3 → tikzplot42-0.4.6}/src/tikzplot/state.py +0 -0
- {tikzplot42-0.4.3 → tikzplot42-0.4.6}/src/tikzplot/styles.py +0 -0
- {tikzplot42-0.4.3 → tikzplot42-0.4.6}/src/tikzplot/styles.pyi +0 -0
- {tikzplot42-0.4.3 → tikzplot42-0.4.6}/src/tikzplot42.egg-info/dependency_links.txt +0 -0
- {tikzplot42-0.4.3 → tikzplot42-0.4.6}/src/tikzplot42.egg-info/requires.txt +0 -0
- {tikzplot42-0.4.3 → tikzplot42-0.4.6}/src/tikzplot42.egg-info/top_level.txt +0 -0
- {tikzplot42-0.4.3 → tikzplot42-0.4.6}/tests/test1.py +0 -0
- {tikzplot42-0.4.3 → tikzplot42-0.4.6}/tests/test10.py +0 -0
- {tikzplot42-0.4.3 → tikzplot42-0.4.6}/tests/test11.py +0 -0
- {tikzplot42-0.4.3 → tikzplot42-0.4.6}/tests/test3.py +0 -0
- {tikzplot42-0.4.3 → tikzplot42-0.4.6}/tests/test5.py +0 -0
- {tikzplot42-0.4.3 → tikzplot42-0.4.6}/tests/test6.py +0 -0
- {tikzplot42-0.4.3 → tikzplot42-0.4.6}/tests/test7.py +0 -0
- {tikzplot42-0.4.3 → tikzplot42-0.4.6}/tests/test8.py +0 -0
- {tikzplot42-0.4.3 → tikzplot42-0.4.6}/tests/test9.py +0 -0
- {tikzplot42-0.4.3 → tikzplot42-0.4.6}/tests/test_styles.py +0 -0
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "tikzplot42"
|
|
7
|
-
version = "0.4.
|
|
7
|
+
version = "0.4.6"
|
|
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):
|
|
@@ -22,17 +26,20 @@ class BaseAxes:
|
|
|
22
26
|
self._axis_args.add(f"/pgf/number format/.cd, 1000 sep={{{TikzConfig.THOUSANDS_SEP}}}")
|
|
23
27
|
|
|
24
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
|
-
|
|
36
|
+
self._reverse_elements = []
|
|
37
|
+
|
|
38
|
+
def _plot(self, x, y, settings={}, xerr=None, yerr=None, **style):
|
|
32
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)
|
|
@@ -88,7 +95,7 @@ class BaseAxes:
|
|
|
88
95
|
self._cmap_bar = kwargs["cmap"]
|
|
89
96
|
except: pass
|
|
90
97
|
|
|
91
|
-
return self._plot(x, y, **kwargs, ls="", settings=
|
|
98
|
+
return self._plot(x, y, **kwargs, ls="", settings={"scatter": None})
|
|
92
99
|
|
|
93
100
|
def semilogy(self, x, y, *args, **kwargs):
|
|
94
101
|
kws = {"fmt", "base", "alpha", "color", "c", "linestyle", "ls", "linewidth", "lw", "marker", "markersize", "ms", "label"}
|
|
@@ -126,12 +133,12 @@ class BaseAxes:
|
|
|
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
|
-
kws = {"fmt", "alpha", "color", "c", "label"}
|
|
141
|
+
kws = {"fmt", "alpha", "color", "c", "label", "hatch", "hatch_color", "hatch_linewidth", "hatch_distance"}
|
|
135
142
|
kwargs = self._check_kwargs("fill_between", kws, **kwargs)
|
|
136
143
|
def _check_instance(xs, ys, pname):
|
|
137
144
|
for el in self._elements:
|
|
@@ -166,7 +173,7 @@ class BaseAxes:
|
|
|
166
173
|
self._plot(xs,ys,path_name=name2, alpha=0)
|
|
167
174
|
else:
|
|
168
175
|
name2 = inst
|
|
169
|
-
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)
|
|
170
177
|
self._elements.append(e)
|
|
171
178
|
return e
|
|
172
179
|
|
|
@@ -215,41 +222,155 @@ class BaseAxes:
|
|
|
215
222
|
self._plot([xs[i]]*2, [ymins[i], ymaxs[i]], None, None, None, c=colorss[i], ls=lss[i])
|
|
216
223
|
|
|
217
224
|
def hist(self, x, bins=10, density=False,**kwargs):
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
225
|
+
kws = {"alpha", "color", "c", "label", "facecolor", "fc", "edgecolor", "ec", "orientation", "rwidth", "cumulative", "range", "histtype", "weights", "cumulative", "align", "stacked", "fill", "hatch", "hatch_color", "hatch_linewidth", "hatch_distance"}
|
|
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", "hatch", "hatch_color", "hatch_linewidth", "hatch_distance"]:
|
|
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]
|
|
226
261
|
all_data = _np.concatenate(datasets)
|
|
227
|
-
edges = _np.histogram_bin_edges(all_data, bins=bins)
|
|
262
|
+
edges = _np.histogram_bin_edges(all_data, bins=bins, weights=kwargs.get("weights", None), range=kwargs.get("range", None))
|
|
228
263
|
widths = edges[1:] - edges[:-1]
|
|
229
|
-
|
|
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}.")
|
|
230
269
|
if "orientation" in kwargs and kwargs["orientation"] == "horizontal":
|
|
231
|
-
settings
|
|
270
|
+
settings["xbar"] = None
|
|
232
271
|
else:
|
|
233
|
-
settings
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
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)
|
|
237
283
|
else:
|
|
238
|
-
|
|
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
|
|
239
290
|
if "range" in kwargs:
|
|
240
|
-
if
|
|
291
|
+
if "xbar" in settings:
|
|
241
292
|
self.set_ylim(kwargs["range"])
|
|
242
293
|
elif isinstance(self, Axes):
|
|
243
294
|
self.set_xlim(kwargs["range"])
|
|
244
295
|
elif isinstance(self, Secondary):
|
|
245
296
|
self._primary.set_xlim(kwargs["range"])
|
|
297
|
+
base_settings = settings.copy()
|
|
246
298
|
outputs = []
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
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
|
+
align_offset = 0
|
|
303
|
+
if "align" in kwargs:
|
|
304
|
+
if kwargs["align"] not in ["left", "mid", "right"]:
|
|
305
|
+
raise Warning(f"Invalid align value: {kwargs['align']}. Must be 'left', 'mid', or 'right'.")
|
|
306
|
+
if kwargs["align"] == "left":
|
|
307
|
+
align_offset = -widths.mean()/2
|
|
308
|
+
elif kwargs["align"] == "mid":
|
|
309
|
+
align_offset = 0
|
|
310
|
+
elif kwargs["align"] == "right":
|
|
311
|
+
align_offset = widths.mean()/2
|
|
312
|
+
for i in range(len(datasets)):
|
|
313
|
+
data = datasets[i]
|
|
314
|
+
settings = base_settings.copy()
|
|
315
|
+
kws = datas.get(i, {})
|
|
316
|
+
if "label" in kws:
|
|
317
|
+
if "xbar" in settings:
|
|
318
|
+
settings["xbar legend"] = None
|
|
319
|
+
elif "xbar interval" in settings:
|
|
320
|
+
settings["xbar interval legend"] = None
|
|
321
|
+
elif "ybar" in settings:
|
|
322
|
+
settings["ybar legend"] = None
|
|
323
|
+
else:
|
|
324
|
+
settings["ybar interval legend"] = None
|
|
325
|
+
fill = kws.pop("facecolor", kws.pop("fc", kws.pop("color", kws.pop("c", None))))
|
|
326
|
+
draw = kws.pop("edgecolor", kws.pop("ec", None))
|
|
327
|
+
if fill:
|
|
328
|
+
fill = self._match_color(fill)
|
|
329
|
+
settings["fill"] = fill
|
|
330
|
+
if draw and hist_type != "stepfilled":
|
|
331
|
+
draw = self._match_color(draw)
|
|
332
|
+
settings["draw"] = draw
|
|
333
|
+
else:
|
|
334
|
+
settings["draw"] = "none"
|
|
335
|
+
counts, _ = _np.histogram(data, edges, density=density, weights=kwargs.get("weights", None), range=kwargs.get("range", None))
|
|
336
|
+
if "xbar interval" in settings or "ybar interval" in settings: # edges for interval
|
|
337
|
+
if "rwidth" in kwargs:
|
|
338
|
+
xs = [edges[0] + widths[0]*(1-kwargs["rwidth"])/2]
|
|
339
|
+
new_counts = []
|
|
340
|
+
for j in range(len(widths)):
|
|
341
|
+
xs.append(xs[-1] + widths[j]*kwargs["rwidth"])
|
|
342
|
+
new_counts.append(counts[j])
|
|
343
|
+
if j < len(counts)-1:
|
|
344
|
+
xs.append(xs[-1] + (widths[j] + widths[j+1])*(1-kwargs["rwidth"])/2)
|
|
345
|
+
new_counts.append(0)
|
|
346
|
+
counts = new_counts + [0]
|
|
347
|
+
else:
|
|
348
|
+
xs = edges
|
|
349
|
+
counts = _np.concatenate([counts, [0]])
|
|
350
|
+
else: # centers
|
|
351
|
+
xs = (edges[:-1] + edges[1:]) / 2
|
|
352
|
+
if offset > 0:
|
|
353
|
+
settings["bar shift"] = f"{offset*(i - len(datasets)/2 + 0.5)}"
|
|
354
|
+
xs = xs + align_offset * _np.ones_like(xs)
|
|
250
355
|
if "cumulative" in kwargs and kwargs["cumulative"]:
|
|
251
356
|
counts = _np.cumsum(counts)
|
|
252
|
-
|
|
357
|
+
if stack:
|
|
358
|
+
if density:
|
|
359
|
+
set_counts, _ = _np.histogram(data, edges, density=False, weights=kwargs.get("weights", None), range=kwargs.get("range", None))
|
|
360
|
+
counts = counts * _np.sum(set_counts) / tot_sum
|
|
361
|
+
counts = _np.asarray(counts, dtype=_np.float64)
|
|
362
|
+
counts += old_counts
|
|
363
|
+
old_counts = counts.copy()
|
|
364
|
+
if hist_type == "step":
|
|
365
|
+
kwargs.pop("facecolor", None)
|
|
366
|
+
kwargs.pop("fc", None)
|
|
367
|
+
kwargs.pop("fill", None)
|
|
368
|
+
self.step([edges[0]] + list(edges), [0] + list(counts), where="pre", **kws)
|
|
369
|
+
else:
|
|
370
|
+
e = self._plot(xs, counts, settings=settings, **kws)
|
|
371
|
+
outputs.append(e)
|
|
372
|
+
if outputs and stack:
|
|
373
|
+
self._reverse_elements.append([id(e) for e in outputs])
|
|
253
374
|
return outputs
|
|
254
375
|
|
|
255
376
|
def step(self, x, y, *args, **kwargs):
|
|
@@ -257,7 +378,7 @@ class BaseAxes:
|
|
|
257
378
|
kwargs = self._check_kwargs("step", kws, **kwargs)
|
|
258
379
|
WHERE_DICT = {"pre": "left", "post": "right", "mid": "mid"}
|
|
259
380
|
where = WHERE_DICT.get(kwargs.pop("where", "pre"), None)
|
|
260
|
-
settings =
|
|
381
|
+
settings = {f"const plot mark {where}": None}
|
|
261
382
|
if len(args) == 1:
|
|
262
383
|
kwargs["fmt"] = args[0]
|
|
263
384
|
return self._plot(x,y,settings=settings, **kwargs)
|
|
@@ -266,7 +387,7 @@ class BaseAxes:
|
|
|
266
387
|
kws = {"fmt", "base", "alpha", "color", "c", "linestyle", "ls", "linewidth", "lw", "label"}
|
|
267
388
|
kwargs = self._check_kwargs("axvline", kws, **kwargs)
|
|
268
389
|
self._ext_ymin = self._ext_ymax = True
|
|
269
|
-
self._plot(x, (ymin, ymax), settings="axvline", **kwargs)
|
|
390
|
+
self._plot(x, (ymin, ymax), settings={"axvline": None}, **kwargs)
|
|
270
391
|
|
|
271
392
|
def axhline(self, y, xmin=0, xmax=1, **kwargs):
|
|
272
393
|
kws = {"fmt", "base", "alpha", "color", "c", "linestyle", "ls", "linewidth", "lw", "label"}
|
|
@@ -275,18 +396,18 @@ class BaseAxes:
|
|
|
275
396
|
self._primary._ext_xmin = self._primary._ext_xmax = True
|
|
276
397
|
else:
|
|
277
398
|
self._ext_xmin = self._ext_xmax = True
|
|
278
|
-
self._plot((xmin, xmax), y, settings="axhline", **kwargs)
|
|
399
|
+
self._plot((xmin, xmax), y, settings={"axhline": None}, **kwargs)
|
|
279
400
|
|
|
280
401
|
def axvspan(self, xmin, xmax, ymin=0, ymax=1, **kwargs):
|
|
281
|
-
kws = {"c", "color", "alpha", "label"}
|
|
402
|
+
kws = {"c", "color", "alpha", "label", "hatch", "hatch_color", "hatch_linewidth", "hatch_distance"}
|
|
282
403
|
kwargs = self._check_kwargs("axvspan", kws, **kwargs)
|
|
283
404
|
self._ext_ymin = self._ext_ymax = True
|
|
284
405
|
if TikzConfig.USE_GROUPPLOTS:
|
|
285
406
|
self._axis_args.add("set layers")
|
|
286
|
-
self._plot([xmin, xmax], [ymin, ymax], settings="axvspan", **kwargs)
|
|
407
|
+
self._plot([xmin, xmax], [ymin, ymax], settings={"axvspan": None}, **kwargs)
|
|
287
408
|
|
|
288
409
|
def axhspan(self, ymin, ymax, xmin=0, xmax=1, **kwargs):
|
|
289
|
-
kws = {"c", "color", "alpha", "label"}
|
|
410
|
+
kws = {"c", "color", "alpha", "label", "hatch", "hatch_color", "hatch_linewidth", "hatch_distance"}
|
|
290
411
|
kwargs = self._check_kwargs("axhspan", kws, **kwargs)
|
|
291
412
|
if isinstance(self, Secondary):
|
|
292
413
|
self._primary._ext_xmin = self._primary._ext_xmax = True
|
|
@@ -294,7 +415,7 @@ class BaseAxes:
|
|
|
294
415
|
self._ext_xmin = self._ext_xmax = True
|
|
295
416
|
if TikzConfig.USE_GROUPPLOTS:
|
|
296
417
|
self._axis_args.add("set layers")
|
|
297
|
-
self._plot([xmin, xmax], [ymin, ymax], settings="axhspan", **kwargs)
|
|
418
|
+
self._plot([xmin, xmax], [ymin, ymax], settings={"axhspan": None}, **kwargs)
|
|
298
419
|
|
|
299
420
|
def set_ylabel(self, label):
|
|
300
421
|
self._axis_options["ylabel"] = f"{{{tex_text(label)}}}"
|
|
@@ -354,7 +475,19 @@ class BaseAxes:
|
|
|
354
475
|
_LEGEND_LOC_MAP = ["best", "upper right", "upper left", "lower_left", "lower right", "right", "center left", "center right", "lower center", "upper center", "center"]
|
|
355
476
|
_ANCHOR_MAP = {"top": "north", "bottom": "south", "upper": "north", "lower": "south", "left": "west", "right": "east", "center": "center"}
|
|
356
477
|
|
|
478
|
+
def _match_color(self, input):
|
|
479
|
+
if isinstance(self, Axes) or isinstance(self, Secondary):
|
|
480
|
+
if input == "none":
|
|
481
|
+
return "none"
|
|
482
|
+
ccode, op = _tex_color(input, self._style)
|
|
483
|
+
if isinstance(ccode, str):
|
|
484
|
+
return ccode
|
|
485
|
+
r,g,b = ccode
|
|
486
|
+
self._add_col(r,g,b)
|
|
487
|
+
return f"c{r:.3f}{g:.3f}{b:.3f}".replace(".", "")
|
|
488
|
+
|
|
357
489
|
def legend(self, *args, **kwargs):
|
|
490
|
+
legend_string = {}
|
|
358
491
|
if "loc" in kwargs:
|
|
359
492
|
loc = kwargs["loc"]
|
|
360
493
|
lx = ly = posit = None
|
|
@@ -381,20 +514,34 @@ class BaseAxes:
|
|
|
381
514
|
elif "east" in posit:
|
|
382
515
|
lx = 1 - TikzConfig.LEGEND_REL_X
|
|
383
516
|
|
|
384
|
-
legend_string = []
|
|
385
517
|
if lx is not None and ly is not None:
|
|
386
|
-
legend_string
|
|
518
|
+
legend_string["at"] = "{(" + f"{lx},{ly}" + r")}"
|
|
387
519
|
if posit is not None and len(posit):
|
|
388
|
-
legend_string
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
520
|
+
legend_string["anchor"] = posit
|
|
521
|
+
|
|
522
|
+
if "facecolor" in kwargs and (isinstance(self, Axes) or isinstance(self, Secondary)):
|
|
523
|
+
ccode = self._match_color(kwargs["facecolor"])
|
|
524
|
+
if ccode is not None:
|
|
525
|
+
legend_string["fill"] = ccode
|
|
526
|
+
if "edgecolor" in kwargs and (isinstance(self, Axes) or isinstance(self, Secondary)):
|
|
527
|
+
ccode = self._match_color(kwargs["edgecolor"])
|
|
528
|
+
if ccode is not None:
|
|
529
|
+
legend_string["draw"] = ccode
|
|
530
|
+
if "labelcolor" in kwargs and (isinstance(self, Axes) or isinstance(self, Secondary)):
|
|
531
|
+
ccode = self._match_color(kwargs["labelcolor"])
|
|
532
|
+
if ccode is not None:
|
|
533
|
+
self._legend_lab_col = ccode
|
|
534
|
+
if "frameon" in kwargs and not kwargs["frameon"]:
|
|
535
|
+
legend_string["draw"] = "none"
|
|
536
|
+
if "legend style" in self._axis_options:
|
|
537
|
+
self._axis_options["legend style"].update(legend_string)
|
|
538
|
+
else:
|
|
539
|
+
self._axis_options["legend style"] = legend_string
|
|
393
540
|
self._legend_on = True
|
|
394
541
|
if "ncols" in kwargs:
|
|
395
542
|
self._axis_options["legend columns"] = kwargs["ncols"]
|
|
396
543
|
if len(args) == 2:
|
|
397
|
-
self._add_legend = args
|
|
544
|
+
self._add_legend = list(args)
|
|
398
545
|
elif len(args) == 1:
|
|
399
546
|
labs = args[0]
|
|
400
547
|
if len(labs) > len(self._elements):
|
|
@@ -433,16 +580,36 @@ class BaseAxes:
|
|
|
433
580
|
return ""
|
|
434
581
|
for i in range(len(axs)):
|
|
435
582
|
output += f"\n\\addlegendimage{{{axs[i]._style_string()}}}"
|
|
436
|
-
|
|
583
|
+
if self._legend_lab_col:
|
|
584
|
+
output += f"\n\\addlegendentry[{self._legend_lab_col}]{{{tex_text(labs[i])}}}"
|
|
585
|
+
else:
|
|
586
|
+
output += f"\n\\addlegendentry{{{tex_text(labs[i])}}}"
|
|
437
587
|
return output
|
|
438
588
|
|
|
439
589
|
def _content_tex(self, filename):
|
|
440
|
-
|
|
441
|
-
|
|
590
|
+
element_strings = {id(e): e._to_tex(filename, self._legend_lab_col) for e in self._elements}
|
|
591
|
+
seq_map = {seq[0]: seq for seq in self._reverse_elements}
|
|
592
|
+
output_list = []
|
|
593
|
+
visited = set()
|
|
594
|
+
for e in self._elements:
|
|
595
|
+
e_id = id(e)
|
|
596
|
+
if e_id in visited:
|
|
597
|
+
continue
|
|
598
|
+
if e_id in seq_map:
|
|
599
|
+
seq = seq_map[e_id]
|
|
600
|
+
for el in reversed(seq):
|
|
601
|
+
output_list.append(element_strings[el])
|
|
602
|
+
visited.add(el)
|
|
603
|
+
else:
|
|
604
|
+
output_list.append(element_strings[e_id])
|
|
605
|
+
visited.add(e_id)
|
|
606
|
+
|
|
607
|
+
output = "\n".join(output_list)
|
|
608
|
+
output += self._add_legend_entries()
|
|
442
609
|
for coord in self._coordinates:
|
|
443
610
|
x,y = self._coordinates[coord]
|
|
444
|
-
|
|
445
|
-
return
|
|
611
|
+
output += f"\n\\coordinate ({coord}) at ({x},{y});"
|
|
612
|
+
return output
|
|
446
613
|
|
|
447
614
|
def _get_hard_range(self,which):
|
|
448
615
|
arg = f"{which[0]}mode"
|
|
@@ -519,6 +686,10 @@ class BaseAxes:
|
|
|
519
686
|
if attr in kwargs:
|
|
520
687
|
defined[attr](kwargs.pop(attr))
|
|
521
688
|
|
|
689
|
+
def _reoreder_last_elements(self, n):
|
|
690
|
+
if n <= 0: return
|
|
691
|
+
self._elements = self._elements[:-n] + self._elements[:-n-1:-1]
|
|
692
|
+
|
|
522
693
|
class Axes(BaseAxes):
|
|
523
694
|
|
|
524
695
|
def __init__(self, nrows, ncols, index, fig, polar):
|
|
@@ -654,7 +825,7 @@ class Axes(BaseAxes):
|
|
|
654
825
|
if kwargs:
|
|
655
826
|
accepted_kwargs = {"color", "c", "linestyle", "ls", "linewidth", "lw", "alpha"}
|
|
656
827
|
kwargs = self._check_kwargs("grid", accepted_kwargs, **kwargs)
|
|
657
|
-
g = Graph(self, None,
|
|
828
|
+
g = Graph(self, None, {}, None, None, **kwargs)._style_string()
|
|
658
829
|
self._axis_options[f"{selector}grid style"] = f"{{{g}}}"
|
|
659
830
|
|
|
660
831
|
def set_minorticks_num(self, num):
|
|
@@ -733,7 +904,7 @@ class Axes(BaseAxes):
|
|
|
733
904
|
_plt.axis("off")
|
|
734
905
|
_plt.imshow(*args, **kwargs)
|
|
735
906
|
im_name = f"{str(main_name()[1]).removesuffix('.py')}_{TikzConfig.IMSHOW_SAVENAME}{_next_imshow_num()}.pdf"
|
|
736
|
-
_plt.savefig(im_name,bbox_inches='tight', pad_inches=0)
|
|
907
|
+
_plt.savefig(im_name, bbox_inches='tight', pad_inches=0)
|
|
737
908
|
return im_name
|
|
738
909
|
|
|
739
910
|
def _axis_option_string(self):
|
|
@@ -754,7 +925,7 @@ class Axes(BaseAxes):
|
|
|
754
925
|
if "extent" in self._imshow[1]:
|
|
755
926
|
bounds = self._imshow[1]["extent"]
|
|
756
927
|
xm, xM, ym, yM = bounds
|
|
757
|
-
self._elements.insert(0, Graph(self, f"graphics [xmin={xm}, xmax={xM}, ymin={ym}, ymax={yM}] {{{im_name}}}",settings=
|
|
928
|
+
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"))
|
|
758
929
|
axis_opt_str = ""
|
|
759
930
|
if self._axis_args:
|
|
760
931
|
axis_opt_str += ",\n".join(self._axis_args)
|
|
@@ -787,7 +958,13 @@ class Axes(BaseAxes):
|
|
|
787
958
|
self._axis_options["ymax"] = self._fig._next_limname("ymax", self._axis_options.get("ymax", yM))
|
|
788
959
|
if self._axis_options:
|
|
789
960
|
if axis_opt_str: axis_opt_str += ",\n"
|
|
790
|
-
|
|
961
|
+
for k, v in self._axis_options.items():
|
|
962
|
+
if isinstance(v, dict):
|
|
963
|
+
axis_opt_str += f"{k}={{"
|
|
964
|
+
axis_opt_str += ",\n".join(f"{kk}={vv}" for kk, vv in v.items())
|
|
965
|
+
axis_opt_str += "},\n"
|
|
966
|
+
else:
|
|
967
|
+
axis_opt_str += f"{k}={v},\n"
|
|
791
968
|
if self._colorbar:
|
|
792
969
|
axis_opt_str += self._colorbar
|
|
793
970
|
elif self._cmap_bar:
|
|
@@ -859,6 +1036,15 @@ class Axes(BaseAxes):
|
|
|
859
1036
|
defined[attr](kwargs.pop(attr))
|
|
860
1037
|
|
|
861
1038
|
super().set(**kwargs)
|
|
1039
|
+
|
|
1040
|
+
def set_facecolor(self, color):
|
|
1041
|
+
ccode, _ = _tex_color(color, self._style)
|
|
1042
|
+
if isinstance(ccode, str):
|
|
1043
|
+
self._axis_options["axis background/.style"] = f"{{fill={ccode}}}"
|
|
1044
|
+
else:
|
|
1045
|
+
r,g,b = ccode
|
|
1046
|
+
self._add_col(r,g,b)
|
|
1047
|
+
self._axis_options["axis background/.style"] = f"{{fill=c{r:.3f}{g:.3f}{b:.3f}}}".replace(".", "")
|
|
862
1048
|
|
|
863
1049
|
class Secondary(BaseAxes):
|
|
864
1050
|
def __init__(self, primary):
|
|
@@ -900,7 +1086,13 @@ class Secondary(BaseAxes):
|
|
|
900
1086
|
self._axis_options["xmax"] = self._primary._axis_options["xmax"]
|
|
901
1087
|
if self._axis_options:
|
|
902
1088
|
if axis_opt_str: axis_opt_str += ",\n"
|
|
903
|
-
|
|
1089
|
+
for k, v in self._axis_options.items():
|
|
1090
|
+
if isinstance(v, dict):
|
|
1091
|
+
axis_opt_str += f"{k}={{"
|
|
1092
|
+
axis_opt_str += ",\n".join(f"{kk}={vv}" for kk, vv in v.items())
|
|
1093
|
+
axis_opt_str += "},\n"
|
|
1094
|
+
else:
|
|
1095
|
+
axis_opt_str += f"{k}={v},\n"
|
|
904
1096
|
return axis_opt_str
|
|
905
1097
|
|
|
906
1098
|
def _padding(self):
|