tikzplot42 0.5.1__tar.gz → 0.5.4__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.5.1/src/tikzplot42.egg-info → tikzplot42-0.5.4}/PKG-INFO +25 -2
- {tikzplot42-0.5.1 → tikzplot42-0.5.4}/README.md +24 -1
- {tikzplot42-0.5.1 → tikzplot42-0.5.4}/pyproject.toml +1 -1
- {tikzplot42-0.5.1 → tikzplot42-0.5.4}/src/tikzplot/axes.py +255 -42
- {tikzplot42-0.5.1 → tikzplot42-0.5.4}/src/tikzplot/axes.pyi +150 -40
- tikzplot42-0.5.4/src/tikzplot/axes3d.py +1273 -0
- tikzplot42-0.5.4/src/tikzplot/axes3d.pyi +582 -0
- {tikzplot42-0.5.1 → tikzplot42-0.5.4}/src/tikzplot/colorbar.py +1 -1
- {tikzplot42-0.5.1 → tikzplot42-0.5.4}/src/tikzplot/colors.py +64 -6
- {tikzplot42-0.5.1 → tikzplot42-0.5.4}/src/tikzplot/config.py +2 -2
- {tikzplot42-0.5.1 → tikzplot42-0.5.4}/src/tikzplot/elements.py +217 -62
- {tikzplot42-0.5.1 → tikzplot42-0.5.4}/src/tikzplot/figure.py +18 -5
- {tikzplot42-0.5.1 → tikzplot42-0.5.4}/src/tikzplot/figure.pyi +34 -5
- {tikzplot42-0.5.1 → tikzplot42-0.5.4}/src/tikzplot/plots.py +19 -4
- {tikzplot42-0.5.1 → tikzplot42-0.5.4}/src/tikzplot/plots.pyi +102 -8
- {tikzplot42-0.5.1 → tikzplot42-0.5.4/src/tikzplot42.egg-info}/PKG-INFO +25 -2
- {tikzplot42-0.5.1 → tikzplot42-0.5.4}/src/tikzplot42.egg-info/SOURCES.txt +3 -0
- {tikzplot42-0.5.1 → tikzplot42-0.5.4}/tests/test11.py +1 -1
- {tikzplot42-0.5.1 → tikzplot42-0.5.4}/tests/test14.py +1 -1
- tikzplot42-0.5.4/tests/test16.py +24 -0
- tikzplot42-0.5.4/tests/test17.py +40 -0
- tikzplot42-0.5.4/tests/test18.py +24 -0
- tikzplot42-0.5.1/src/tikzplot/axes3d.py +0 -591
- tikzplot42-0.5.1/src/tikzplot/axes3d.pyi +0 -43
- {tikzplot42-0.5.1 → tikzplot42-0.5.4}/LICENSE +0 -0
- {tikzplot42-0.5.1 → tikzplot42-0.5.4}/setup.cfg +0 -0
- {tikzplot42-0.5.1 → tikzplot42-0.5.4}/src/tikzplot/__init__.py +0 -0
- {tikzplot42-0.5.1 → tikzplot42-0.5.4}/src/tikzplot/__init__.pyi +0 -0
- {tikzplot42-0.5.1 → tikzplot42-0.5.4}/src/tikzplot/colorbar.pyi +0 -0
- {tikzplot42-0.5.1 → tikzplot42-0.5.4}/src/tikzplot/config.pyi +0 -0
- {tikzplot42-0.5.1 → tikzplot42-0.5.4}/src/tikzplot/elements.pyi +0 -0
- {tikzplot42-0.5.1 → tikzplot42-0.5.4}/src/tikzplot/latex_special.py +0 -0
- {tikzplot42-0.5.1 → tikzplot42-0.5.4}/src/tikzplot/py.typed +0 -0
- {tikzplot42-0.5.1 → tikzplot42-0.5.4}/src/tikzplot/state.py +0 -0
- {tikzplot42-0.5.1 → tikzplot42-0.5.4}/src/tikzplot/styles.py +0 -0
- {tikzplot42-0.5.1 → tikzplot42-0.5.4}/src/tikzplot/styles.pyi +0 -0
- {tikzplot42-0.5.1 → tikzplot42-0.5.4}/src/tikzplot/texts.py +0 -0
- {tikzplot42-0.5.1 → tikzplot42-0.5.4}/src/tikzplot42.egg-info/dependency_links.txt +0 -0
- {tikzplot42-0.5.1 → tikzplot42-0.5.4}/src/tikzplot42.egg-info/requires.txt +0 -0
- {tikzplot42-0.5.1 → tikzplot42-0.5.4}/src/tikzplot42.egg-info/top_level.txt +0 -0
- {tikzplot42-0.5.1 → tikzplot42-0.5.4}/tests/test1.py +0 -0
- {tikzplot42-0.5.1 → tikzplot42-0.5.4}/tests/test10.py +0 -0
- {tikzplot42-0.5.1 → tikzplot42-0.5.4}/tests/test12.py +0 -0
- {tikzplot42-0.5.1 → tikzplot42-0.5.4}/tests/test13.py +0 -0
- {tikzplot42-0.5.1 → tikzplot42-0.5.4}/tests/test15.py +0 -0
- {tikzplot42-0.5.1 → tikzplot42-0.5.4}/tests/test2.py +0 -0
- {tikzplot42-0.5.1 → tikzplot42-0.5.4}/tests/test3.py +0 -0
- {tikzplot42-0.5.1 → tikzplot42-0.5.4}/tests/test4.py +0 -0
- {tikzplot42-0.5.1 → tikzplot42-0.5.4}/tests/test5.py +0 -0
- {tikzplot42-0.5.1 → tikzplot42-0.5.4}/tests/test6.py +0 -0
- {tikzplot42-0.5.1 → tikzplot42-0.5.4}/tests/test7.py +0 -0
- {tikzplot42-0.5.1 → tikzplot42-0.5.4}/tests/test8.py +0 -0
- {tikzplot42-0.5.1 → tikzplot42-0.5.4}/tests/test9.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: tikzplot42
|
|
3
|
-
Version: 0.5.
|
|
3
|
+
Version: 0.5.4
|
|
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
|
|
@@ -706,6 +706,18 @@ Please report any bugs or unexpected behaviour in Issues. Examples may be found
|
|
|
706
706
|
<img src="https://raw.githubusercontent.com/ZanAmb/TikzPlot/main/tests/demo.png" width="60%">
|
|
707
707
|
</p>
|
|
708
708
|
|
|
709
|
+
## Why use pgfplots instead of matplotlib?
|
|
710
|
+
- Tikz/pgfplots is a LaTeX package, so it is easy to integrate into your LaTeX document, and the fonts will match your document, rescaling will not affect font sizes.
|
|
711
|
+
- Tikz/pgfplots graph is easy to edit, especially if only minor style changes are needed, while matplotlib requires re-running the code to generate a new graph.
|
|
712
|
+
- Full math mode is supported, so you can use LaTeX math in your labels, legends, etc.
|
|
713
|
+
|
|
714
|
+
## Why use this package instead of other available?
|
|
715
|
+
- It is easy to use, with code being very similar to matplotlib and only minor changes are needed to switch from matplotlib to this package.
|
|
716
|
+
- It relies on frontend commands, which is less likley to change in matplotlib, so new updates do not break it.
|
|
717
|
+
- It generates clean and readable Tikz code, which is easy to edit and understand. Code is also efficient and does not contain unnecessary commands, which is important escpecially for large graphs.
|
|
718
|
+
- If you use LLMs to generate pgfplots code, you will often get code that is not compilable, since for more complex requirements, LLMs make up commands that do not exist. This package covers many use cases and generates compilable code.
|
|
719
|
+
|
|
720
|
+
|
|
709
721
|
# Installation
|
|
710
722
|
PyPI: `pip install tikzplot42`.
|
|
711
723
|
Alternativley, download this package and install using: `pip install [path]`, where [path] is the path to the directory, containing `pyproject.toml`.
|
|
@@ -741,6 +753,7 @@ Some basic plot commands are already implemented with commonly used arguments:
|
|
|
741
753
|
- `hist()`,
|
|
742
754
|
- `bar()/barh()`,
|
|
743
755
|
- `bar_label()`,
|
|
756
|
+
- `stackplot()`,
|
|
744
757
|
- `step()`,
|
|
745
758
|
- `imshow()`,
|
|
746
759
|
- `text()`,
|
|
@@ -748,6 +761,16 @@ Some basic plot commands are already implemented with commonly used arguments:
|
|
|
748
761
|
- `axvline()/axhline()`,
|
|
749
762
|
- `axvspan()/axhspan()` (background span).
|
|
750
763
|
|
|
764
|
+
#### 3D plotting
|
|
765
|
+
- `plot()`,
|
|
766
|
+
- `scatter()`,
|
|
767
|
+
- `errorbar()`,
|
|
768
|
+
- `fill_between()`,
|
|
769
|
+
- `plot_wireframe()`,
|
|
770
|
+
- `plot_surface()`,
|
|
771
|
+
- `bar3d()`,
|
|
772
|
+
- `text()`.
|
|
773
|
+
|
|
751
774
|
#### Figures
|
|
752
775
|
- `plt.figure()` (currently only to give you figure object or to set `figsize`),
|
|
753
776
|
- `plt.subplot()`, `plt.subplots()` (with `sharex/sharey` fully implemented, projection `polar` and `3d` with basic support),
|
|
@@ -793,5 +816,5 @@ Currently supported parameters are listed with their default values in `src/tikz
|
|
|
793
816
|
|
|
794
817
|
## More features coming soon...
|
|
795
818
|
- additional arguments support for implemented commands,
|
|
796
|
-
- improved 3D
|
|
819
|
+
- improved 3D and polar plots,
|
|
797
820
|
- ...
|
|
@@ -7,6 +7,18 @@ Please report any bugs or unexpected behaviour in Issues. Examples may be found
|
|
|
7
7
|
<img src="https://raw.githubusercontent.com/ZanAmb/TikzPlot/main/tests/demo.png" width="60%">
|
|
8
8
|
</p>
|
|
9
9
|
|
|
10
|
+
## Why use pgfplots instead of matplotlib?
|
|
11
|
+
- Tikz/pgfplots is a LaTeX package, so it is easy to integrate into your LaTeX document, and the fonts will match your document, rescaling will not affect font sizes.
|
|
12
|
+
- Tikz/pgfplots graph is easy to edit, especially if only minor style changes are needed, while matplotlib requires re-running the code to generate a new graph.
|
|
13
|
+
- Full math mode is supported, so you can use LaTeX math in your labels, legends, etc.
|
|
14
|
+
|
|
15
|
+
## Why use this package instead of other available?
|
|
16
|
+
- It is easy to use, with code being very similar to matplotlib and only minor changes are needed to switch from matplotlib to this package.
|
|
17
|
+
- It relies on frontend commands, which is less likley to change in matplotlib, so new updates do not break it.
|
|
18
|
+
- It generates clean and readable Tikz code, which is easy to edit and understand. Code is also efficient and does not contain unnecessary commands, which is important escpecially for large graphs.
|
|
19
|
+
- If you use LLMs to generate pgfplots code, you will often get code that is not compilable, since for more complex requirements, LLMs make up commands that do not exist. This package covers many use cases and generates compilable code.
|
|
20
|
+
|
|
21
|
+
|
|
10
22
|
# Installation
|
|
11
23
|
PyPI: `pip install tikzplot42`.
|
|
12
24
|
Alternativley, download this package and install using: `pip install [path]`, where [path] is the path to the directory, containing `pyproject.toml`.
|
|
@@ -42,6 +54,7 @@ Some basic plot commands are already implemented with commonly used arguments:
|
|
|
42
54
|
- `hist()`,
|
|
43
55
|
- `bar()/barh()`,
|
|
44
56
|
- `bar_label()`,
|
|
57
|
+
- `stackplot()`,
|
|
45
58
|
- `step()`,
|
|
46
59
|
- `imshow()`,
|
|
47
60
|
- `text()`,
|
|
@@ -49,6 +62,16 @@ Some basic plot commands are already implemented with commonly used arguments:
|
|
|
49
62
|
- `axvline()/axhline()`,
|
|
50
63
|
- `axvspan()/axhspan()` (background span).
|
|
51
64
|
|
|
65
|
+
#### 3D plotting
|
|
66
|
+
- `plot()`,
|
|
67
|
+
- `scatter()`,
|
|
68
|
+
- `errorbar()`,
|
|
69
|
+
- `fill_between()`,
|
|
70
|
+
- `plot_wireframe()`,
|
|
71
|
+
- `plot_surface()`,
|
|
72
|
+
- `bar3d()`,
|
|
73
|
+
- `text()`.
|
|
74
|
+
|
|
52
75
|
#### Figures
|
|
53
76
|
- `plt.figure()` (currently only to give you figure object or to set `figsize`),
|
|
54
77
|
- `plt.subplot()`, `plt.subplots()` (with `sharex/sharey` fully implemented, projection `polar` and `3d` with basic support),
|
|
@@ -94,5 +117,5 @@ Currently supported parameters are listed with their default values in `src/tikz
|
|
|
94
117
|
|
|
95
118
|
## More features coming soon...
|
|
96
119
|
- additional arguments support for implemented commands,
|
|
97
|
-
- improved 3D
|
|
120
|
+
- improved 3D and polar plots,
|
|
98
121
|
- ...
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "tikzplot42"
|
|
7
|
-
version = "0.5.
|
|
7
|
+
version = "0.5.4"
|
|
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,4 +1,3 @@
|
|
|
1
|
-
from multiprocessing import parent_process
|
|
2
1
|
from typing import Any, Iterable
|
|
3
2
|
import copy
|
|
4
3
|
|
|
@@ -21,7 +20,7 @@ class BaseAxes:
|
|
|
21
20
|
self._legend_on = False
|
|
22
21
|
self._overlay_legend = False
|
|
23
22
|
self._overlay_legend_entries = []
|
|
24
|
-
self._overlay_special = {}
|
|
23
|
+
self._overlay_special: dict[int, dict[str, Any]] = {}
|
|
25
24
|
self._yticks = True
|
|
26
25
|
self._fig = None
|
|
27
26
|
if TikzConfig.USE_DECIMAL_COMMA:
|
|
@@ -145,10 +144,17 @@ class BaseAxes:
|
|
|
145
144
|
self._axis_options[key].update(value)
|
|
146
145
|
self._axis_options[key] = value
|
|
147
146
|
|
|
147
|
+
def _parse_entry(self, k, v):
|
|
148
|
+
if v is None:
|
|
149
|
+
return f"{k}"
|
|
150
|
+
if isinstance(v, dict):
|
|
151
|
+
return f"{k}={{" + ",\n".join(f"{kk}={vv}" for kk, vv in v.items() if vv != {}) + "}"
|
|
152
|
+
return f"{k}={v}"
|
|
153
|
+
|
|
148
154
|
def _plot(self, x, y, settings={}, xerr=None, yerr=None, overlay=None, note=None, **style):
|
|
149
155
|
spec = None
|
|
150
156
|
if self._get_overlay() in self._overlay_special:
|
|
151
|
-
spec = self._overlay_special[self._get_overlay()]
|
|
157
|
+
spec = ",\n".join([self._parse_entry(k, v) for k, v in self._overlay_special[self._get_overlay()].items()])
|
|
152
158
|
if note != spec:
|
|
153
159
|
self._get_free_overlay()
|
|
154
160
|
|
|
@@ -256,7 +262,7 @@ class BaseAxes:
|
|
|
256
262
|
return self._plot(y,x,settings={"xcomb": None}, **kwargs)
|
|
257
263
|
|
|
258
264
|
def fill_between(self, x, y1, y2=None, **kwargs):
|
|
259
|
-
kws = {"fmt", "alpha", "color", "c", "label", "hatch", "hatch_color", "hatch_linewidth", "hatch_distance"}
|
|
265
|
+
kws = {"fmt", "alpha", "color", "c", "facecolor", "fc", "label", "hatch", "hatch_color", "hatch_linewidth", "hatch_distance"}
|
|
260
266
|
kwargs = self._check_kwargs("fill_between", kws, **kwargs)
|
|
261
267
|
def _check_instance(xs, ys, pname):
|
|
262
268
|
for el in self._elements[self._get_overlay()]:
|
|
@@ -277,7 +283,7 @@ class BaseAxes:
|
|
|
277
283
|
name1 = inst
|
|
278
284
|
|
|
279
285
|
if y2 is not None:
|
|
280
|
-
if isinstance(
|
|
286
|
+
if isinstance(y2, (int, float)):
|
|
281
287
|
y2 = _np.asarray([y2] * len(x))
|
|
282
288
|
inst = _check_instance(x,y2,name2)
|
|
283
289
|
if inst is None:
|
|
@@ -292,6 +298,59 @@ class BaseAxes:
|
|
|
292
298
|
self._plot(xs,ys,path_name=name2, alpha=0)
|
|
293
299
|
else:
|
|
294
300
|
name2 = inst
|
|
301
|
+
if "facecolor" in kwargs or "fc" in kwargs:
|
|
302
|
+
kwargs["color"] = kwargs.pop("facecolor", kwargs.pop("fc", None))
|
|
303
|
+
kwargs.pop("fc", None)
|
|
304
|
+
if not("color" in kwargs or "c" in kwargs):
|
|
305
|
+
assert isinstance(self, Axes) or isinstance(self, Secondary)
|
|
306
|
+
kwargs["color"] = f"C{self._get_defcol(1)}"
|
|
307
|
+
e = Graph(self, f"fill between [of={name1} and {name2}]",settings={}, xerr=None, yerr=None, **kwargs)
|
|
308
|
+
self._elements[self._get_overlay()].append(e)
|
|
309
|
+
return e
|
|
310
|
+
|
|
311
|
+
def fill_betweenx(self, y, x1, x2=None, **kwargs):
|
|
312
|
+
kws = {"fmt", "alpha", "color", "c", "facecolor", "fc", "label", "hatch", "hatch_color", "hatch_linewidth", "hatch_distance"}
|
|
313
|
+
kwargs = self._check_kwargs("fill_between", kws, **kwargs)
|
|
314
|
+
def _check_instance(xs, ys, pname):
|
|
315
|
+
for el in self._elements[self._get_overlay()]:
|
|
316
|
+
if el._check_equal(xs,ys):
|
|
317
|
+
return el._try_set_pname(pname)
|
|
318
|
+
else:
|
|
319
|
+
return None
|
|
320
|
+
assert self._fig is not None
|
|
321
|
+
self._fig._add_required_package("\\usepgfplotslibrary{fillbetween}")
|
|
322
|
+
name1 = self._fig._get_free_path_name()
|
|
323
|
+
name2 = self._fig._get_free_path_name()
|
|
324
|
+
if isinstance(x1, (int, float)):
|
|
325
|
+
x1 = _np.asarray([x1] * len(y))
|
|
326
|
+
inst = _check_instance(x1,y,name1)
|
|
327
|
+
if inst is None:
|
|
328
|
+
self._plot(x1,y,path_name=name1, alpha=0)
|
|
329
|
+
else:
|
|
330
|
+
name1 = inst
|
|
331
|
+
|
|
332
|
+
if x2 is not None:
|
|
333
|
+
if isinstance(x2, (int, float)):
|
|
334
|
+
x2 = _np.asarray([x2] * len(y))
|
|
335
|
+
inst = _check_instance(x2,y,name2)
|
|
336
|
+
if inst is None:
|
|
337
|
+
self._plot(x2,y,path_name=name2, alpha=0)
|
|
338
|
+
else:
|
|
339
|
+
name2 = inst
|
|
340
|
+
else:
|
|
341
|
+
xs = [0, 0]
|
|
342
|
+
ys = [min(y), max(y)]
|
|
343
|
+
inst = _check_instance(xs,ys,name2)
|
|
344
|
+
if inst is None:
|
|
345
|
+
self._plot(xs,ys,path_name=name2, alpha=0)
|
|
346
|
+
else:
|
|
347
|
+
name2 = inst
|
|
348
|
+
if "facecolor" in kwargs or "fc" in kwargs:
|
|
349
|
+
kwargs["color"] = kwargs.pop("facecolor", kwargs.pop("fc", None))
|
|
350
|
+
kwargs.pop("fc", None)
|
|
351
|
+
if not("color" in kwargs or "c" in kwargs):
|
|
352
|
+
assert isinstance(self, Axes) or isinstance(self, Secondary)
|
|
353
|
+
kwargs["color"] = f"C{self._get_defcol(1)}"
|
|
295
354
|
e = Graph(self, f"fill between [of={name1} and {name2}]",settings={}, xerr=None, yerr=None, **kwargs)
|
|
296
355
|
self._elements[self._get_overlay()].append(e)
|
|
297
356
|
return e
|
|
@@ -351,7 +410,7 @@ class BaseAxes:
|
|
|
351
410
|
except (ValueError, TypeError):
|
|
352
411
|
x_arr = _np.asarray(x)
|
|
353
412
|
if x_arr.ndim == 2:
|
|
354
|
-
datasets = [
|
|
413
|
+
datasets = [col for col in x_arr.T]
|
|
355
414
|
else:
|
|
356
415
|
raise ValueError("Invalid dataset structure.")
|
|
357
416
|
else:
|
|
@@ -359,7 +418,7 @@ class BaseAxes:
|
|
|
359
418
|
if x_arr.ndim == 1:
|
|
360
419
|
datasets = [x_arr]
|
|
361
420
|
elif x_arr.ndim == 2:
|
|
362
|
-
datasets = [
|
|
421
|
+
datasets = [col for col in x_arr.T]
|
|
363
422
|
else:
|
|
364
423
|
raise ValueError(f"Input must be 1D or 2D, got {x_arr.ndim}D.")
|
|
365
424
|
|
|
@@ -409,13 +468,6 @@ class BaseAxes:
|
|
|
409
468
|
offset = widths.mean() / (len(datasets) + 1)
|
|
410
469
|
else:
|
|
411
470
|
intervals = True
|
|
412
|
-
if "range" in kwargs:
|
|
413
|
-
if orientation == "horizontal":
|
|
414
|
-
self.set_ylim(kwargs["range"])
|
|
415
|
-
elif isinstance(self, Axes):
|
|
416
|
-
self.set_xlim(kwargs["range"])
|
|
417
|
-
elif isinstance(self, Secondary):
|
|
418
|
-
self._primary.set_xlim(kwargs["range"])
|
|
419
471
|
base_settings = settings.copy()
|
|
420
472
|
outputs = []
|
|
421
473
|
totals, _ = _np.histogram(all_data, edges, density=False, weights=kwargs.get("weights", None), range=kwargs.get("range", None))
|
|
@@ -489,24 +541,112 @@ class BaseAxes:
|
|
|
489
541
|
outputs.append(e)
|
|
490
542
|
return outputs
|
|
491
543
|
|
|
492
|
-
def bar(self, x, height,
|
|
493
|
-
kws = {"alpha", "
|
|
544
|
+
def bar(self, x, height, width=0.8, bottom=None, **kwargs):
|
|
545
|
+
kws = {"alpha", "align", "color", "c", "facecolor", "fc", "edgecolor", "ec", "linewidth", "lw", "tick_label", "label", "xerr", "yerr", "ecolor", "capsize", "hatch", "hatch_color", "hatch_linewidth", "hatch_distance", "tick_label"}
|
|
494
546
|
kwargs = self._check_kwargs("bar", kws, **kwargs)
|
|
547
|
+
kwargs["width"] = width
|
|
548
|
+
if bottom is not None:
|
|
549
|
+
kwargs["bottom"] = bottom
|
|
495
550
|
if "width" in kwargs:
|
|
496
551
|
kwargs["thickness"] = kwargs.pop("width")
|
|
497
552
|
kwargs["edge"] = kwargs.pop("bottom", 0)
|
|
498
553
|
|
|
499
554
|
return self._common_bar(x, height, orientation="vertical", **kwargs)
|
|
500
555
|
|
|
501
|
-
def barh(self, y, width,
|
|
502
|
-
kws = {"alpha", "
|
|
556
|
+
def barh(self, y, width, height=0.8, left=None, **kwargs):
|
|
557
|
+
kws = {"alpha", "align", "color", "c", "facecolor", "fc", "edgecolor", "ec", "linewidth", "lw", "tick_label", "label", "xerr", "yerr", "ecolor", "capsize", "hatch", "hatch_color", "hatch_linewidth", "hatch_distance"}
|
|
503
558
|
kwargs = self._check_kwargs("barh", kws, **kwargs)
|
|
559
|
+
kwargs["height"] = height
|
|
560
|
+
if left is not None:
|
|
561
|
+
kwargs["left"] = left
|
|
504
562
|
if "height" in kwargs:
|
|
505
563
|
kwargs["thickness"] = kwargs.pop("height")
|
|
506
564
|
kwargs["edge"] = kwargs.pop("left", 0)
|
|
507
565
|
|
|
508
566
|
return self._common_bar(y, width, orientation="horizontal", **kwargs)
|
|
509
567
|
|
|
568
|
+
def grouped_bar(self, heights, **kwargs):
|
|
569
|
+
kws = {"positions", "tick_labels", "labels", "group_spacing", "bar_spacing", "orientation", "colors", "alpha", "edgecolor", "ec", "facecolor", "fc", "linewidth", "lw", "linestyle", "ls", "hatch", "hatch_color", "hatch_linewidth", "hatch_distance"}
|
|
570
|
+
kwargs = self._check_kwargs("grouped_bar", kws, **kwargs)
|
|
571
|
+
if isinstance(heights, dict):
|
|
572
|
+
if "labels" not in kwargs:
|
|
573
|
+
kwargs["labels"] = list(heights.keys())
|
|
574
|
+
heights = list(heights.values())
|
|
575
|
+
if isinstance(heights, (list, tuple)) and len(heights) > 0 and isinstance(heights[0], (list, tuple, _np.ndarray)):
|
|
576
|
+
try:
|
|
577
|
+
datasets = [_np.asarray(ds, dtype=_np.float64) for ds in heights]
|
|
578
|
+
if any(ds.ndim != 1 for ds in datasets):
|
|
579
|
+
raise ValueError("Nested datasets must all be 1-dimensional.")
|
|
580
|
+
except (ValueError, TypeError):
|
|
581
|
+
h_arr = _np.asarray(heights)
|
|
582
|
+
if h_arr.ndim == 2:
|
|
583
|
+
datasets = [col for col in h_arr.T]
|
|
584
|
+
else:
|
|
585
|
+
raise ValueError("Invalid dataset structure.")
|
|
586
|
+
else:
|
|
587
|
+
h_arr = _np.asarray(heights)
|
|
588
|
+
if h_arr.ndim == 1:
|
|
589
|
+
datasets = [h_arr]
|
|
590
|
+
elif h_arr.ndim == 2:
|
|
591
|
+
datasets = [col for col in h_arr.T]
|
|
592
|
+
else:
|
|
593
|
+
raise ValueError(f"Input must be 1D or 2D, got {h_arr.ndim}D.")
|
|
594
|
+
|
|
595
|
+
xs = kwargs.pop("positions", range(len(datasets)))
|
|
596
|
+
if len(xs) != len(datasets):
|
|
597
|
+
raise Warning("Length of positions does not match length of datasets.")
|
|
598
|
+
if _np.diff(xs).min() != _np.diff(xs).max():
|
|
599
|
+
raise Warning("Positions must be equidistant.")
|
|
600
|
+
dist = _np.diff(xs).min()
|
|
601
|
+
settings = {}
|
|
602
|
+
if "rwidth" not in kwargs:
|
|
603
|
+
kwargs["rwidth"] = 1
|
|
604
|
+
orientation = kwargs.pop("orientation", "vertical")
|
|
605
|
+
group_spacing = kwargs.pop("group_spacing", 1.5)
|
|
606
|
+
bar_spacing = kwargs.pop("bar_spacing", 0.0)
|
|
607
|
+
bar_widths_num = len(datasets) * (1 + bar_spacing) + group_spacing
|
|
608
|
+
bar_width = dist / bar_widths_num
|
|
609
|
+
settings["thickness"] = bar_width
|
|
610
|
+
|
|
611
|
+
if "tick_labels" in kwargs:
|
|
612
|
+
tick_labels = kwargs.pop("tick_labels")
|
|
613
|
+
if len(tick_labels) != len(xs):
|
|
614
|
+
raise Warning("Length of tick_labels does not match length of positions.")
|
|
615
|
+
if orientation == "vertical":
|
|
616
|
+
if isinstance(self, Axes):
|
|
617
|
+
self.set_xticks(xs, tick_labels)
|
|
618
|
+
elif isinstance(self, Secondary):
|
|
619
|
+
self._primary.set_xticks(xs, tick_labels)
|
|
620
|
+
else:
|
|
621
|
+
self.set_yticks(xs, tick_labels)
|
|
622
|
+
|
|
623
|
+
datas = {}
|
|
624
|
+
for kw in ["colors", "alpha", "facecolor", "fc", "edgecolor", "ec", "labels", "linestyle", "ls", "hatch", "hatch_color", "hatch_linewidth", "hatch_distance"]:
|
|
625
|
+
if kw in kwargs:
|
|
626
|
+
if isinstance(kwargs[kw], (list)):
|
|
627
|
+
if len(kwargs[kw]) != len(datasets):
|
|
628
|
+
raise Warning(f"Length of {kw} does not match number of datasets.")
|
|
629
|
+
prop = kwargs.pop(kw)
|
|
630
|
+
else:
|
|
631
|
+
prop = [kwargs.pop(kw)] * len(datasets)
|
|
632
|
+
for i in range(len(datasets)):
|
|
633
|
+
if i not in datas:
|
|
634
|
+
datas[i] = {}
|
|
635
|
+
datas[i][kw.removesuffix("s")] = prop[i]
|
|
636
|
+
base_settings = settings.copy()
|
|
637
|
+
bars = []
|
|
638
|
+
for i in range(len(datasets)):
|
|
639
|
+
offset = (i - len(datasets)/2 + 0.5) * bar_width * (1 + bar_spacing)
|
|
640
|
+
data = datasets[i]
|
|
641
|
+
settings = base_settings.copy()
|
|
642
|
+
kws = datas.get(i, {})
|
|
643
|
+
passing_args = ["alpha", "facecolor", "fc", "color", "c", "edgecolor", "ec", "label", "hatch", "hatch_color", "hatch_linewidth", "hatch_distance"]
|
|
644
|
+
for a in passing_args:
|
|
645
|
+
if a in kws:
|
|
646
|
+
settings[a] = kws[a]
|
|
647
|
+
bars.append(self._common_bar(xs, data, orientation=orientation, **settings, group_offset=offset))
|
|
648
|
+
return bars
|
|
649
|
+
|
|
510
650
|
def _common_bar(self, k, v, orientation="vertical", **kwargs):
|
|
511
651
|
#if orientation == "vertical":
|
|
512
652
|
# self._int_ymax = self._int_ymin = 0
|
|
@@ -593,7 +733,7 @@ class BaseAxes:
|
|
|
593
733
|
|
|
594
734
|
if _np.count_nonzero(edge) > 0:
|
|
595
735
|
lower = self._get_overlay()
|
|
596
|
-
if self._overlay_special.get(lower,
|
|
736
|
+
if bar_type + " stacked" in self._overlay_special.get(lower, {}):
|
|
597
737
|
bedx = _np.zeros_like(edge, dtype=_np.float64)
|
|
598
738
|
bedy = _np.zeros_like(edge, dtype=_np.float64)
|
|
599
739
|
for el in self._elements[lower]:
|
|
@@ -612,16 +752,18 @@ class BaseAxes:
|
|
|
612
752
|
if overlay is None:
|
|
613
753
|
if len(self._elements[self._get_overlay()]) > 0 and self._elements[self._get_overlay()][-1]._check_equal(k, edge):
|
|
614
754
|
if len(self._elements[lower]) == 1:
|
|
615
|
-
|
|
755
|
+
if lower not in self._overlay_special:
|
|
756
|
+
self._overlay_special[lower] = {}
|
|
757
|
+
self._overlay_special[lower].update({bar_type + " stacked": None})
|
|
616
758
|
overlay = lower
|
|
617
759
|
else:
|
|
618
760
|
current = self._get_free_overlay()
|
|
619
761
|
self._elements[current].append(self._elements[lower].pop()) # move the stacking bed to new overlay
|
|
620
|
-
self._overlay_special[current] = bar_type + " stacked"
|
|
762
|
+
self._overlay_special[current] = {bar_type + " stacked": None}
|
|
621
763
|
overlay = current
|
|
622
764
|
else: # no bed, plot invisible bed
|
|
623
765
|
current = self._get_free_overlay()
|
|
624
|
-
self._overlay_special[current] = bar_type + " stacked"
|
|
766
|
+
self._overlay_special[current] = {bar_type + " stacked": None}
|
|
625
767
|
self._plot(k, edge, alpha=0)
|
|
626
768
|
overlay = current
|
|
627
769
|
|
|
@@ -638,7 +780,7 @@ class BaseAxes:
|
|
|
638
780
|
for kw in ["label", "hatch", "hatch_color", "hatch_linewidth", "hatch_distance"]:
|
|
639
781
|
if kw in kwargs:
|
|
640
782
|
element_args[kw] = kwargs.pop(kw)
|
|
641
|
-
note = self._overlay_special.get(overlay, None
|
|
783
|
+
note = ",\n".join([self._parse_entry(k, v) for k, v in self._overlay_special.get(overlay, {}).items()]) if overlay in self._overlay_special else None
|
|
642
784
|
if "label" in element_args:
|
|
643
785
|
if orientation == "vertical":
|
|
644
786
|
settings["ybar legend"] = None
|
|
@@ -648,7 +790,7 @@ class BaseAxes:
|
|
|
648
790
|
return self._plot(k, v, yerr=kwargs.get("yerr", None), xerr=kwargs.get("xerr", None), overlay=overlay, settings=settings, note=note, **element_args)
|
|
649
791
|
|
|
650
792
|
def bar_label(self, container, labels=None, **kwargs):
|
|
651
|
-
kws = {"color", "c", "fontsize", "rotation", "fmt", "padding"}
|
|
793
|
+
kws = {"alpha", "color", "c", "fontsize", "rotation", "fmt", "padding"}
|
|
652
794
|
kwargs = self._check_kwargs("bar_label", kws, **kwargs)
|
|
653
795
|
if not isinstance(container, Graph):
|
|
654
796
|
raise Warning("Container must be a Graph object.")
|
|
@@ -659,6 +801,8 @@ class BaseAxes:
|
|
|
659
801
|
if "color" in kwargs or "c" in kwargs:
|
|
660
802
|
c = kwargs.pop("color", kwargs.pop("c", None))
|
|
661
803
|
kwargs["color_parsed"] = self._match_color(c)
|
|
804
|
+
if "alpha" in kwargs:
|
|
805
|
+
kwargs["opacity"] = kwargs.pop("alpha")
|
|
662
806
|
if "fontsize" in kwargs:
|
|
663
807
|
kwargs["fontsize_parsed"] = self._tex_fontsize(kwargs["fontsize"])
|
|
664
808
|
o = self._get_element_overlay(container)
|
|
@@ -683,7 +827,68 @@ class BaseAxes:
|
|
|
683
827
|
if labels is not None and labels != []:
|
|
684
828
|
container._add_meta_column(labels)
|
|
685
829
|
self._bar_labels[self._get_element_overlay(container)][container] = kwargs | {"bar_labels": labels}
|
|
686
|
-
|
|
830
|
+
|
|
831
|
+
def stackplot(self, x, *args, **kwargs):
|
|
832
|
+
kws = {"baseline", "labels", "colors", "alpha", "facecolor", "fc", "edgecolor", "ec", "linewidth", "lw", "linestyle", "ls", "hatch", "hatch_color", "hatch_linewidth", "hatch_distance"}
|
|
833
|
+
kwargs = self._check_kwargs("stackplot", kws, **kwargs)
|
|
834
|
+
n = len(x)
|
|
835
|
+
x = _np.asarray(x, dtype=_np.float64)
|
|
836
|
+
if len(args) == 1:
|
|
837
|
+
y = list(args[0])
|
|
838
|
+
else:
|
|
839
|
+
y = list(args)
|
|
840
|
+
if isinstance(list(y)[0], int | float):
|
|
841
|
+
y = [list(y)]
|
|
842
|
+
y = _np.asarray(y, dtype=_np.float64)
|
|
843
|
+
base_set = kwargs.pop("baseline", "zero")
|
|
844
|
+
if base_set not in ["zero", "sym", "wiggle", "weighted_wiggle"]:
|
|
845
|
+
raise Warning(f"Invalid baseline: {base_set}. Must be one of 'zero', 'sym', 'wiggle', or 'weighted_wiggle'.")
|
|
846
|
+
if base_set == "zero":
|
|
847
|
+
baseline = _np.zeros(n, dtype=_np.float64)
|
|
848
|
+
elif base_set == "sym":
|
|
849
|
+
baseline = -_np.sum(y, axis=0)/2
|
|
850
|
+
elif base_set == "wiggle": # from matplotlib source
|
|
851
|
+
m = y.shape[0]
|
|
852
|
+
baseline = (y * (m - 0.5 - _np.arange(m)[:, None])).sum(0)
|
|
853
|
+
baseline /= -m
|
|
854
|
+
else: # weighted_wiggle; from matplotlib source
|
|
855
|
+
total = _np.sum(y, 0)
|
|
856
|
+
inv_total = _np.zeros_like(total)
|
|
857
|
+
mask = total > 0
|
|
858
|
+
inv_total[mask] = 1.0 / total[mask]
|
|
859
|
+
increase = _np.hstack((y[:, 0:1], _np.diff(y)))
|
|
860
|
+
below_size = total - _np.cumsum(y, axis=0, dtype=_np.promote_types(y.dtype, _np.float32))
|
|
861
|
+
below_size += 0.5 * y
|
|
862
|
+
move_up = below_size * inv_total
|
|
863
|
+
move_up[:, 0] = 0.5
|
|
864
|
+
center = (move_up - 0.5) * increase
|
|
865
|
+
center = _np.cumsum(center.sum(0))
|
|
866
|
+
baseline = center - 0.5 * total
|
|
867
|
+
overlay = self._get_free_overlay()
|
|
868
|
+
self._overlay_special[overlay] = {"stack plots": "y", "area style": None}
|
|
869
|
+
if base_set != "zero":
|
|
870
|
+
self._plot(x, baseline, overlay=overlay, alpha=0)
|
|
871
|
+
datas = {}
|
|
872
|
+
for kw in ["labels", "colors", "alpha", "facecolor", "fc", "edgecolor", "ec", "linewidth", "lw", "linestyle", "ls", "hatch", "hatch_color", "hatch_linewidth", "hatch_distance"]:
|
|
873
|
+
if kw in kwargs:
|
|
874
|
+
prop = kwargs.pop(kw)
|
|
875
|
+
try:
|
|
876
|
+
prop = list(prop)
|
|
877
|
+
except: pass
|
|
878
|
+
if isinstance(prop, (list, tuple)):
|
|
879
|
+
if len(prop) != len(y):
|
|
880
|
+
raise Warning(f"Length of {kw} does not match number of datasets.")
|
|
881
|
+
else:
|
|
882
|
+
prop = [prop] * len(y)
|
|
883
|
+
datas[kw.removesuffix("s")] = prop
|
|
884
|
+
if "label" in datas:
|
|
885
|
+
self._overlay_special[overlay]["area legend"] = None
|
|
886
|
+
output = []
|
|
887
|
+
for i in range(len(y)):
|
|
888
|
+
kws = {kw: datas[kw][i] for kw in datas}
|
|
889
|
+
kws["_endnotes"] = r"\closedcycle"
|
|
890
|
+
output.append(self._plot(x, y[i], overlay=overlay, settings={"fill": None}, **kws))
|
|
891
|
+
return output
|
|
687
892
|
|
|
688
893
|
def step(self, x, y, *args, **kwargs):
|
|
689
894
|
kws = {"fmt", "alpha", "color", "c", "linestyle", "ls", "linewidth", "lw", "marker", "markersize", "ms", "label", "where"}
|
|
@@ -876,8 +1081,6 @@ class BaseAxes:
|
|
|
876
1081
|
Y_INV = {v: k for k, v in Y_POS_MAP.items()}
|
|
877
1082
|
self._axis_options["xtick pos"] = X_INV[(xt_t, xt_b)]
|
|
878
1083
|
self._axis_options["ytick pos"] = Y_INV[(yt_l, yt_r)]
|
|
879
|
-
if self._axis_options["xtick pos"] == "both":
|
|
880
|
-
self._axis_options.pop("xtick pos")
|
|
881
1084
|
if "colors" in kwargs:
|
|
882
1085
|
c = self._match_color(kwargs.pop("colors"))
|
|
883
1086
|
self._update_axis_options(prefix + " tick style", {"draw": c})
|
|
@@ -897,6 +1100,14 @@ class BaseAxes:
|
|
|
897
1100
|
raise Warning(f"Invalid direction: {direction}. Must be one of 'in', 'out', or 'inout'.")
|
|
898
1101
|
TICK_DIR_MAP = {"in": "inside", "out": "outside", "inout": "center"}
|
|
899
1102
|
self._update_axis_options(prefix + "tick align", TICK_DIR_MAP[direction])
|
|
1103
|
+
if self._axis_options["xtick pos"] == "both":
|
|
1104
|
+
self._axis_options.pop("xtick pos")
|
|
1105
|
+
elif self._axis_options["xtick pos"] == "none":
|
|
1106
|
+
self._update_axis_options("xtick style", {"draw": self._axis_options.pop("xtick pos")})
|
|
1107
|
+
if self._axis_options["ytick pos"] == "both":
|
|
1108
|
+
self._axis_options.pop("ytick pos")
|
|
1109
|
+
elif self._axis_options["ytick pos"] == "none":
|
|
1110
|
+
self._update_axis_options("ytick style", {"draw": self._axis_options.pop("ytick pos")})
|
|
900
1111
|
|
|
901
1112
|
_LEGEND_LOC_MAP = ["best", "upper right", "upper left", "lower_left", "lower right", "right", "center left", "center right", "lower center", "upper center", "center"]
|
|
902
1113
|
_ANCHOR_MAP = {"top": "north", "bottom": "south", "upper": "north", "lower": "south", "left": "west", "right": "east", "center": "center"}
|
|
@@ -1140,7 +1351,7 @@ class Axes(BaseAxes):
|
|
|
1140
1351
|
self._style = self._fig._style
|
|
1141
1352
|
self._imshow = None
|
|
1142
1353
|
|
|
1143
|
-
self._defcol_counter = 0
|
|
1354
|
+
self._defcol_counter = {0: 0}
|
|
1144
1355
|
self._colorbar = ""
|
|
1145
1356
|
self._cbar_h = False
|
|
1146
1357
|
self._polar = polar
|
|
@@ -1537,9 +1748,11 @@ class Axes(BaseAxes):
|
|
|
1537
1748
|
return self._nrows
|
|
1538
1749
|
def _get_ncols(self):
|
|
1539
1750
|
return self._ncols
|
|
1540
|
-
def _get_defcol(self):
|
|
1541
|
-
self._defcol_counter
|
|
1542
|
-
|
|
1751
|
+
def _get_defcol(self, index = 0):
|
|
1752
|
+
if index not in self._defcol_counter:
|
|
1753
|
+
self._defcol_counter[index] = 0
|
|
1754
|
+
self._defcol_counter[index] += 1
|
|
1755
|
+
return self._defcol_counter[index] - 1
|
|
1543
1756
|
def _show_colorbar(self, cbar, horizontal=False):
|
|
1544
1757
|
self._colorbar = ",\n" + cbar
|
|
1545
1758
|
self._cbar_h = horizontal
|
|
@@ -1550,7 +1763,7 @@ class Axes(BaseAxes):
|
|
|
1550
1763
|
for k,v in self._elements.items():
|
|
1551
1764
|
if k in self._bar_labels and len(self._bar_labels[k]) > 0:
|
|
1552
1765
|
if k in self._overlay_special and ("xbar stacked" in self._overlay_special[k] or "ybar stacked" in self._overlay_special[k]):
|
|
1553
|
-
self._overlay_special[k]
|
|
1766
|
+
self._overlay_special[k].update({"nodes near coords": None})
|
|
1554
1767
|
for e in self._elements[k].copy():
|
|
1555
1768
|
if e not in self._bar_labels[k]:
|
|
1556
1769
|
self.bar_label(e, labels=[])
|
|
@@ -1561,13 +1774,13 @@ class Axes(BaseAxes):
|
|
|
1561
1774
|
"""if isinstance(v, list) and len(v) > 1:
|
|
1562
1775
|
reference = getattr(v[0], "_settings", {}) or {}
|
|
1563
1776
|
common_style = {s: val for s, val in reference.items() if all((getattr(obj, "_settings", {}) or {}).get(s) == val for obj in v[1:])}
|
|
1564
|
-
|
|
1565
|
-
for f in
|
|
1777
|
+
forbidden = {"draw", "fill", "xbar", "ybar"}
|
|
1778
|
+
for f in forbidden:
|
|
1566
1779
|
common_style.pop(f, None)
|
|
1567
1780
|
for key, val in common_style.items():
|
|
1568
1781
|
for e in v:
|
|
1569
1782
|
e._settings.pop(key, None)
|
|
1570
|
-
self._overlay_special[k]
|
|
1783
|
+
self._overlay_special[k].update({key: val}) """
|
|
1571
1784
|
lines = []
|
|
1572
1785
|
lines2 = []
|
|
1573
1786
|
if self._polar:
|
|
@@ -1577,7 +1790,7 @@ class Axes(BaseAxes):
|
|
|
1577
1790
|
if self._polar and TikzConfig.USE_GROUPPLOTS and not single:
|
|
1578
1791
|
lines.append(f"\\nextgroupplot[alias={self._axis_options['alias']}, width={self._width}, height={self._height}, hide axis]")
|
|
1579
1792
|
for i in self._elements.keys():
|
|
1580
|
-
spec = self._overlay_special
|
|
1793
|
+
spec = ",\n".join([self._parse_entry(k, v) for k, v in self._overlay_special.get(i, {}).items()]) + ",\n" if i in self._overlay_special else ""
|
|
1581
1794
|
lines2.append("\\begin{polaraxis}[")
|
|
1582
1795
|
if i == self._get_overlay():
|
|
1583
1796
|
lines2.append(f"{main_ax}{spec}\n]")
|
|
@@ -1593,18 +1806,18 @@ class Axes(BaseAxes):
|
|
|
1593
1806
|
elif not TikzConfig.USE_GROUPPLOTS or (TikzConfig.USE_GROUPPLOTS and single):
|
|
1594
1807
|
lines.append("\\begin{axis}[")
|
|
1595
1808
|
if self._get_overlay() == 0:
|
|
1596
|
-
spec = self._overlay_special
|
|
1809
|
+
spec = ",\n".join([self._parse_entry(k, v) for k, v in self._overlay_special.get(0, {}).items()]) + ",\n" if 0 in self._overlay_special else ""
|
|
1597
1810
|
if self._secondary_y is not None or self._colorbar is not None:
|
|
1598
1811
|
lines.append(f"{main_ax}{spec}alias={alias}\n]")
|
|
1599
1812
|
else:
|
|
1600
1813
|
lines.append(f"{main_ax}{spec}\n]")
|
|
1601
1814
|
lines.append(contents[0])
|
|
1602
1815
|
else:
|
|
1603
|
-
spec = self._overlay_special
|
|
1816
|
+
spec = ",\n".join([self._parse_entry(k, v) for k, v in self._overlay_special.get(0, {}).items()]) + ",\n" if 0 in self._overlay_special else ""
|
|
1604
1817
|
lines.append(f"{aux_ax}{spec}alias={alias}\n]")
|
|
1605
1818
|
lines.append(contents[0])
|
|
1606
1819
|
for i in self._elements.keys():
|
|
1607
|
-
spec = self._overlay_special
|
|
1820
|
+
spec = ",\n".join([self._parse_entry(k, v) for k, v in self._overlay_special.get(i, {}).items()]) + ",\n" if i in self._overlay_special else ""
|
|
1608
1821
|
if i == 0: continue
|
|
1609
1822
|
lines2.append("\\begin{axis}[")
|
|
1610
1823
|
if i == self._get_overlay():
|
|
@@ -1627,7 +1840,7 @@ class Axes(BaseAxes):
|
|
|
1627
1840
|
contents2 = self._secondary_y._content_tex(filename)
|
|
1628
1841
|
for i in self._secondary_y._elements.keys():
|
|
1629
1842
|
lines2.append("\\begin{axis}[")
|
|
1630
|
-
spec = self._secondary_y._overlay_special
|
|
1843
|
+
spec = ",\n".join([self._parse_entry(k, v) for k, v in self._secondary_y._overlay_special.get(i, {}).items()]) + ",\n" if i in self._secondary_y._overlay_special else ""
|
|
1631
1844
|
if i == sorted(self._secondary_y._elements.keys())[-1]:
|
|
1632
1845
|
lines2.append(f"{main_ax2}{spec}\n]")
|
|
1633
1846
|
else:
|
|
@@ -1715,8 +1928,8 @@ class Secondary(BaseAxes):
|
|
|
1715
1928
|
def _padding(self):
|
|
1716
1929
|
return TikzConfig.SEC_Y_PADDING + TikzConfig.YTICK_PADDING * self._yticks + TikzConfig.SEC_Y_LABEL_PADDING * ("ylabel" in self._axis_options)
|
|
1717
1930
|
|
|
1718
|
-
def _get_defcol(self):
|
|
1719
|
-
return self._primary._get_defcol()
|
|
1931
|
+
def _get_defcol(self, index = 0):
|
|
1932
|
+
return self._primary._get_defcol(index)
|
|
1720
1933
|
|
|
1721
1934
|
def _get_index(self):
|
|
1722
1935
|
return self._primary._get_index()
|