tikzplot42 0.3.0__tar.gz → 0.3.3__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.
Files changed (42) hide show
  1. {tikzplot42-0.3.0 → tikzplot42-0.3.3}/PKG-INFO +10 -3
  2. {tikzplot42-0.3.0 → tikzplot42-0.3.3}/README.md +9 -2
  3. {tikzplot42-0.3.0 → tikzplot42-0.3.3}/pyproject.toml +1 -1
  4. {tikzplot42-0.3.0 → tikzplot42-0.3.3}/src/tikzplot/axes.py +73 -26
  5. {tikzplot42-0.3.0 → tikzplot42-0.3.3}/src/tikzplot/axes.pyi +88 -6
  6. {tikzplot42-0.3.0 → tikzplot42-0.3.3}/src/tikzplot/axes3d.py +7 -0
  7. {tikzplot42-0.3.0 → tikzplot42-0.3.3}/src/tikzplot/colorbar.py +1 -1
  8. {tikzplot42-0.3.0 → tikzplot42-0.3.3}/src/tikzplot/config.py +2 -1
  9. {tikzplot42-0.3.0 → tikzplot42-0.3.3}/src/tikzplot/config.pyi +1 -0
  10. {tikzplot42-0.3.0 → tikzplot42-0.3.3}/src/tikzplot/elements.py +89 -28
  11. {tikzplot42-0.3.0 → tikzplot42-0.3.3}/src/tikzplot/plots.py +25 -10
  12. {tikzplot42-0.3.0 → tikzplot42-0.3.3}/src/tikzplot/plots.pyi +85 -19
  13. tikzplot42-0.3.3/src/tikzplot/texts.py +119 -0
  14. {tikzplot42-0.3.0 → tikzplot42-0.3.3}/src/tikzplot42.egg-info/PKG-INFO +10 -3
  15. {tikzplot42-0.3.0 → tikzplot42-0.3.3}/src/tikzplot42.egg-info/SOURCES.txt +2 -0
  16. tikzplot42-0.3.3/tests/test10.py +24 -0
  17. {tikzplot42-0.3.0 → tikzplot42-0.3.3}/tests/test2.py +1 -1
  18. {tikzplot42-0.3.0 → tikzplot42-0.3.3}/tests/test7.py +1 -0
  19. {tikzplot42-0.3.0 → tikzplot42-0.3.3}/LICENSE +0 -0
  20. {tikzplot42-0.3.0 → tikzplot42-0.3.3}/setup.cfg +0 -0
  21. {tikzplot42-0.3.0 → tikzplot42-0.3.3}/src/tikzplot/__init__.py +0 -0
  22. {tikzplot42-0.3.0 → tikzplot42-0.3.3}/src/tikzplot/__init__.pyi +0 -0
  23. {tikzplot42-0.3.0 → tikzplot42-0.3.3}/src/tikzplot/colorbar.pyi +0 -0
  24. {tikzplot42-0.3.0 → tikzplot42-0.3.3}/src/tikzplot/colors.py +0 -0
  25. {tikzplot42-0.3.0 → tikzplot42-0.3.3}/src/tikzplot/colors.pyi +0 -0
  26. {tikzplot42-0.3.0 → tikzplot42-0.3.3}/src/tikzplot/elements.pyi +0 -0
  27. {tikzplot42-0.3.0 → tikzplot42-0.3.3}/src/tikzplot/figure.py +0 -0
  28. {tikzplot42-0.3.0 → tikzplot42-0.3.3}/src/tikzplot/figure.pyi +0 -0
  29. {tikzplot42-0.3.0 → tikzplot42-0.3.3}/src/tikzplot/latex_special.py +0 -0
  30. {tikzplot42-0.3.0 → tikzplot42-0.3.3}/src/tikzplot/py.typed +0 -0
  31. {tikzplot42-0.3.0 → tikzplot42-0.3.3}/src/tikzplot/state.py +0 -0
  32. {tikzplot42-0.3.0 → tikzplot42-0.3.3}/src/tikzplot/state.pyi +0 -0
  33. {tikzplot42-0.3.0 → tikzplot42-0.3.3}/src/tikzplot42.egg-info/dependency_links.txt +0 -0
  34. {tikzplot42-0.3.0 → tikzplot42-0.3.3}/src/tikzplot42.egg-info/requires.txt +0 -0
  35. {tikzplot42-0.3.0 → tikzplot42-0.3.3}/src/tikzplot42.egg-info/top_level.txt +0 -0
  36. {tikzplot42-0.3.0 → tikzplot42-0.3.3}/tests/test1.py +0 -0
  37. {tikzplot42-0.3.0 → tikzplot42-0.3.3}/tests/test3.py +0 -0
  38. {tikzplot42-0.3.0 → tikzplot42-0.3.3}/tests/test4.py +0 -0
  39. {tikzplot42-0.3.0 → tikzplot42-0.3.3}/tests/test5.py +0 -0
  40. {tikzplot42-0.3.0 → tikzplot42-0.3.3}/tests/test6.py +0 -0
  41. {tikzplot42-0.3.0 → tikzplot42-0.3.3}/tests/test8.py +0 -0
  42. {tikzplot42-0.3.0 → tikzplot42-0.3.3}/tests/test9.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: tikzplot42
3
- Version: 0.3.0
3
+ Version: 0.3.3
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
@@ -705,6 +705,10 @@ A clean version of PltToTikz, this time as Python package. Easy to use: only rep
705
705
 
706
706
  Please let me know if you find any bugs or unexpected behaviour. Examples may be found in repository under `tests/` directory.
707
707
 
708
+ <p align="center">
709
+ <img src="https://github.com/ZanAmb/TikzPlot/blob/main/tests/demo.png" width="60%">
710
+ </p>
711
+
708
712
  # Installation
709
713
  NEW: PyPI: `pip install tikzplot42`.
710
714
  Alternativley, download this package and install using: `pip install [path]`, where [path] is the path to the directory, containing `pyproject.toml`.
@@ -718,7 +722,8 @@ Instead of using `import matplotlib.pyplot (as plt)`, use `import tikzplot.plots
718
722
  - `\pgfplotsset{compat=1.18}` (may be lower, but compilation is not guaranteed),
719
723
  - `\usepgfplotslibrary{fillbetween}` (if you use fill-between plots),
720
724
  - `\usepgfplotslibrary{groupplots}` (recommended for best results, enabled by default, may be avoided by setting TikzConfig USE_GROUPPLOTS=False),
721
- - `\usepackage{xcolor}` (recommended for best colors, works without but needs change of TikzConfig USE_XCOLOR=False).
725
+ - `\usepackage{xcolor}` (recommended for best colors, works without but needs change of TikzConfig USE_XCOLOR=False),
726
+ - `\usepgfplotslibrary{polar}` required for polar axis.
722
727
 
723
728
  Export using `plt.savefig("example_graph.tex")` (recommended) or `plt.show()`.
724
729
  Then use the generated file as `\input{example_graph.tex}`.
@@ -735,7 +740,9 @@ Some basic plot commands are already implemented with commonly used arguments:
735
740
  - `fill-between()`,
736
741
  - `hlines()/vlines()`,
737
742
  - `historgam()`,
738
- - `imshow()`.
743
+ - `step()`,
744
+ - `imshow()`,
745
+ - `text()`.
739
746
 
740
747
  #### Figures
741
748
  - `plt.figure()` (currently only to give you figure object or to set `figsize`),
@@ -3,6 +3,10 @@ A clean version of PltToTikz, this time as Python package. Easy to use: only rep
3
3
 
4
4
  Please let me know if you find any bugs or unexpected behaviour. Examples may be found in repository under `tests/` directory.
5
5
 
6
+ <p align="center">
7
+ <img src="https://github.com/ZanAmb/TikzPlot/blob/main/tests/demo.png" width="60%">
8
+ </p>
9
+
6
10
  # Installation
7
11
  NEW: PyPI: `pip install tikzplot42`.
8
12
  Alternativley, download this package and install using: `pip install [path]`, where [path] is the path to the directory, containing `pyproject.toml`.
@@ -16,7 +20,8 @@ Instead of using `import matplotlib.pyplot (as plt)`, use `import tikzplot.plots
16
20
  - `\pgfplotsset{compat=1.18}` (may be lower, but compilation is not guaranteed),
17
21
  - `\usepgfplotslibrary{fillbetween}` (if you use fill-between plots),
18
22
  - `\usepgfplotslibrary{groupplots}` (recommended for best results, enabled by default, may be avoided by setting TikzConfig USE_GROUPPLOTS=False),
19
- - `\usepackage{xcolor}` (recommended for best colors, works without but needs change of TikzConfig USE_XCOLOR=False).
23
+ - `\usepackage{xcolor}` (recommended for best colors, works without but needs change of TikzConfig USE_XCOLOR=False),
24
+ - `\usepgfplotslibrary{polar}` required for polar axis.
20
25
 
21
26
  Export using `plt.savefig("example_graph.tex")` (recommended) or `plt.show()`.
22
27
  Then use the generated file as `\input{example_graph.tex}`.
@@ -33,7 +38,9 @@ Some basic plot commands are already implemented with commonly used arguments:
33
38
  - `fill-between()`,
34
39
  - `hlines()/vlines()`,
35
40
  - `historgam()`,
36
- - `imshow()`.
41
+ - `step()`,
42
+ - `imshow()`,
43
+ - `text()`.
37
44
 
38
45
  #### Figures
39
46
  - `plt.figure()` (currently only to give you figure object or to set `figsize`),
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "tikzplot42"
7
- version = "0.3.0"
7
+ version = "0.3.3"
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" }
@@ -2,7 +2,9 @@ import numpy as _np
2
2
  import matplotlib.pyplot as _plt
3
3
 
4
4
  from .elements import Graph
5
+ from .texts import Text
5
6
  from .config import TikzConfig
7
+ from .colorbar import Colorbar
6
8
  from .state import _next_imshow_num, main_name
7
9
  from .latex_special import tex_text
8
10
 
@@ -20,6 +22,8 @@ class BaseAxes:
20
22
  self._add_legend = ""
21
23
 
22
24
  def _plot(self, x, y, settings=None, xerr=None, yerr=None, **style):
25
+ if not isinstance(self, Secondary) and self._polar:
26
+ x = _np.rad2deg(x)
23
27
  e = Graph(self, (x, y), settings, xerr=xerr, yerr=yerr, **style)
24
28
  self._elements.append(e)
25
29
  return e
@@ -44,14 +48,33 @@ class BaseAxes:
44
48
  return self._plot(x,y,fmt=fmt, **kwargs)
45
49
 
46
50
  def scatter(self, x, y, *args, **kwargs):
47
- kws = {"fmt", "alpha", "color", "c", "marker", "markersize", "s", "label"}
51
+ kws = {"fmt", "alpha", "color", "c", "marker", "markersize", "s", "label", "cmap", "vmin", "vmax"}
48
52
  kwargs = self._check_kwargs("scatter", kws, **kwargs)
49
53
 
50
54
  if "s" in kwargs:
51
- kwargs["ms"] = kwargs.pop("s")
52
-
53
- return self._plot(x, y, **kwargs, ls="")
55
+ s = kwargs.pop("s")
56
+ if not isinstance(s, (int, float)):
57
+ s = [i/50 for i in s]
58
+ else:
59
+ s /= 50
60
+ kwargs["ms"] = s
54
61
 
62
+ try:
63
+ c = kwargs.get("c", kwargs.get("color", None))
64
+ if len(c) == len(x):
65
+ if isinstance(c[0], (int, float)):
66
+ if "cmap" not in kwargs:
67
+ kwargs["cmap"] = Colorbar(cmap="viridis", lower=min(c), upper=max(c))
68
+ else:
69
+ cmap = kwargs["cmap"]
70
+ if isinstance(cmap, str):
71
+ vmin = kwargs.pop("vmin", min(c))
72
+ vmax = kwargs.pop("vmax", max(c))
73
+ kwargs["cmap"] = Colorbar(cmap=cmap, lower=vmin, upper=vmax)
74
+ except: pass
75
+
76
+ return self._plot(x, y, **kwargs, ls="", settings=["scatter"])
77
+
55
78
  def semilogy(self, x, y, *args, **kwargs):
56
79
  kws = {"fmt", "base", "alpha", "color", "c", "linestyle", "ls", "linewidth", "lw", "marker", "markersize", "ms", "label"}
57
80
  kwargs = self._check_kwargs("semilogy", kws, **kwargs)
@@ -188,6 +211,16 @@ class BaseAxes:
188
211
  counts = _np.cumsum(counts)
189
212
 
190
213
  return self._plot(centers, counts, settings=settings, **kwargs)
214
+
215
+ def step(self, x, y, *args, **kwargs):
216
+ kws = {"fmt", "alpha", "color", "c", "linestyle", "ls", "linewidth", "lw", "marker", "markersize", "ms", "label", "where"}
217
+ kwargs = self._check_kwargs("step", kws, **kwargs)
218
+ WHERE_DICT = {"pre": "left", "post": "right", "mid": "mid"}
219
+ where = WHERE_DICT.get(kwargs.pop("where", "pre"), None)
220
+ settings = [f"const plot mark {where}"]
221
+ if len(args) == 1:
222
+ kwargs["fmt"] = args[0]
223
+ return self._plot(x,y,settings=settings, **kwargs)
191
224
 
192
225
  def set_ylabel(self, label):
193
226
  self._axis_options["ylabel"] = f"{{{tex_text(label)}}}"
@@ -292,6 +325,12 @@ class BaseAxes:
292
325
  for i in range(len(labs)):
293
326
  self._elements[i]._set_label(tex_text(labs[i]))
294
327
 
328
+ def text(self, x, y, s, **kwargs):
329
+ kws = {"alpha", "color", "c", "fontsize", "size", "backgroundcolor", "horizontalalignment", "ha", "verticalalignment", "va", "rotation", "label"}
330
+ kwargs = self._check_kwargs("text", kws, **kwargs)
331
+ txt = Text(self, x, y, s, **kwargs)
332
+ self._elements.append(txt)
333
+
295
334
  def _add_legend_entries(self):
296
335
  if self._add_legend == "": return ""
297
336
  axs, labs = self._add_legend
@@ -468,7 +507,7 @@ class Axes(BaseAxes):
468
507
  #kws = {"fmt", "alpha", "color", "c", "linestyle", "ls", "linewidth", "lw", "marker", "markersize", "ms", "label"}
469
508
  #kwargs = self._check_kwargs("imshow", kws, **kwargs)
470
509
  self._imshow = (args, kwargs)
471
- self._axis_args.add("axis on top")
510
+ #self._axis_args.add("axis on top")
472
511
  self._axis_options["enlargelimits"] = "false"
473
512
  #self._fig._add_global("\\pgfplotsset{set layers}")
474
513
  data = args[0]
@@ -486,7 +525,6 @@ class Axes(BaseAxes):
486
525
  self._axis_options["title"] = f"{{{tex_text(title)}}}"
487
526
 
488
527
  def grid(self, visible=True, which="major", **kwargs):
489
-
490
528
  if not visible:
491
529
  self._axis_options["grid"] = "none"
492
530
  return
@@ -512,7 +550,7 @@ class Axes(BaseAxes):
512
550
  kwargs = self._check_kwargs("grid", accepted_kwargs, **kwargs)
513
551
  g = Graph(self, None, None, None, None, **kwargs)._style_string()
514
552
  self._axis_options[f"{selector}grid style"] = f"{{{g}}}"
515
-
553
+
516
554
  def set_minorticks_num(self, num):
517
555
  self._axis_options["minor tick num"] = num
518
556
 
@@ -616,7 +654,8 @@ class Axes(BaseAxes):
616
654
  if TikzConfig.SCHOOL_AXIS:
617
655
  axis_opt_str += f",\n axis lines=middle,\n xlabel style={{at={{(ticklabel* cs:{1+TikzConfig.SCHOOL_AXIS_LABEL_MARGIN})}},anchor=north}},\n ylabel style={{at={{(ticklabel* cs:{1+TikzConfig.SCHOOL_AXIS_LABEL_MARGIN})}},anchor=east}}"
618
656
  if TikzConfig.USE_GROUPPLOTS:
619
- axis_opt_str += f",\n set layers,\n axis line style={{on layer=axis foreground}}"
657
+ #axis_opt_str += f",\n set layers,\n axis line style={{on layer=axis foreground}}"
658
+ axis_opt_str += f",\n axis on top"
620
659
  if self._axis_options:
621
660
  if axis_opt_str: axis_opt_str += ",\n"
622
661
  axis_opt_str += ",\n".join(f"{k}={v}" for k, v in self._axis_options.items())
@@ -654,23 +693,31 @@ class Axes(BaseAxes):
654
693
  def _to_tex(self, filename):
655
694
  lines = []
656
695
  lines2 = []
657
- if TikzConfig.USE_GROUPPLOTS:
658
- lines.append("\\nextgroupplot")
659
- if self._polar:
660
- lines.append("\\begin{polaraxis}")
661
- elif not TikzConfig.USE_GROUPPLOTS:
662
- lines.append("\\begin{axis}")
663
- lines.append(f"[{self._axis_option_string()}]")
664
- lines.append(self._content_tex(filename))
665
- if self._polar:
666
- lines.append("\\begin{polaraxis}")
667
- elif not TikzConfig.USE_GROUPPLOTS:
668
- lines.append("\\end{axis}")
669
- if self._secondary_y is not None:
670
- lines2.append("\\begin{axis}")
671
- lines2.append(f"[{self._secondary_y._axis_option_string()}]")
672
- lines2.append(self._secondary_y._content_tex(filename))
673
- lines2.append("\\end{axis}")
696
+ if self._polar and TikzConfig.USE_GROUPPLOTS:
697
+ lines.append(f"\\nextgroupplot[alias={self._axis_options['alias']}, width={self._width}, height={self._height}, hide axis]")
698
+ lines2.append("\\begin{polaraxis}")
699
+ lines2.append(f"[{self._axis_option_string()}]")
700
+ lines2.append(self._content_tex(filename))
701
+ lines2.append("\\end{polaraxis}")
702
+ else:
703
+ if TikzConfig.USE_GROUPPLOTS:
704
+ lines.append("\\nextgroupplot")
705
+ if self._polar:
706
+ lines.append("\\begin{polaraxis}")
707
+ elif not TikzConfig.USE_GROUPPLOTS:
708
+ lines.append("\\begin{axis}")
709
+ lines.append(f"[{self._axis_option_string()}]")
710
+ lines.append(self._content_tex(filename))
711
+ if self._polar:
712
+ lines.append("\\end{polaraxis}")
713
+ elif not TikzConfig.USE_GROUPPLOTS:
714
+
715
+ lines.append("\\end{axis}")
716
+ if self._secondary_y is not None:
717
+ lines2.append("\\begin{axis}")
718
+ lines2.append(f"[{self._secondary_y._axis_option_string()}]")
719
+ lines2.append(self._secondary_y._content_tex(filename))
720
+ lines2.append("\\end{axis}")
674
721
  return lines, lines2
675
722
 
676
723
  def set(self, **kwargs):
@@ -690,7 +737,7 @@ class Secondary(BaseAxes):
690
737
  self._axis_options["axis x line"] = "none"
691
738
  self._axis_options["at"] = f"{{({primary._axis_options['alias' if 'alias' in primary._axis_options else 'name']}.south west)}}"
692
739
  self._axis_options["anchor"] = "south west"
693
- self._axis_options["y label style"] = r"{at={(1.1,0.5)}, rotate=180}"
740
+ self._axis_options["y label style"] = r"{at={(" + str(TikzConfig.SEC_YLABEL_LOC[0]) + "," + str(TikzConfig.SEC_YLABEL_LOC[1]) + ")}, rotate=180}"
694
741
 
695
742
  self._fig = primary._fig
696
743
 
@@ -1,10 +1,12 @@
1
1
  from typing import Any, Optional, Sequence, Tuple, Union, Literal
2
2
  import numpy as np
3
+ from .colorbar import Colorbar
3
4
 
4
5
  ArrayLike = Union[Sequence[float], np.ndarray]
5
6
  ColorLike = Union[str, Sequence[float]]
6
7
  LineStyle = Literal["-", "--", "-.", ":", "solid", "dashed", "dashdot", "none", ""]
7
8
  MarkerStyle = Literal["o", "s", "^", "v", "x", "+", ".", "*", "None", ""]
9
+ FontSize = Literal["xx-small", "x-small", "small", "medium", "large", "x-large", "xx-large"]
8
10
 
9
11
 
10
12
  class BaseAxes:
@@ -45,8 +47,8 @@ class BaseAxes:
45
47
  """
46
48
  ...
47
49
 
48
- def scatter(self, x: ArrayLike = ..., y: ArrayLike = ..., fmt: Optional[str] = ..., *,alpha: Optional[float] = ..., color: Optional[ColorLike] = ..., c: Optional[ColorLike] = ...,
49
- marker: Optional[MarkerStyle] = ..., markersize: Optional[float] = ..., s: Optional[float] = ..., label:Optional[str]=...) -> None:
50
+ def scatter(self, x: ArrayLike = ..., y: ArrayLike = ..., fmt: Optional[str] = ..., *,alpha: Optional[float] = ..., color: Optional[Union[Sequence[ColorLike], ColorLike]] = ..., c: Optional[ColorLike] = ...,
51
+ marker: Optional[MarkerStyle] = ..., markersize: Optional[Union[Sequence[float], float]] = ..., s: Optional[Union[Sequence[float], float]] = ..., label:Optional[str]=..., cmap: Optional[Union[str, Colorbar]], vmin: Optional[float] = ..., vmax: Optional[float] = ...) -> None:
50
52
  """
51
53
  Draw a scatter plot to the selected axis.
52
54
 
@@ -61,8 +63,9 @@ class BaseAxes:
61
63
  alpha: float, optional
62
64
  Opacity
63
65
 
64
- color or c: all matplotlib color formats (without X11/xkcd), optional
65
- color of line and markers: RGB/RGBA (tuple), HEX (str), grayscale (float), single-char (str), name (str), default cycle ("CX", X int), none for invisible
66
+ color or c: array like or single: all matplotlib color formats (without X11/xkcd) or float for colormap, optional
67
+ color of line and markers: RGB/RGBA (tuple), HEX (str), grayscale (float), single-char (str), name (str), default cycle ("CX", X int), none for invisible. Note that if the sequence if of the same length as x, it will be interpreted as color sequence for each point, otherwise it will be interpreted as a single color for all points.
68
+
66
69
 
67
70
  label: str, optional
68
71
  Legned entry
@@ -70,8 +73,14 @@ class BaseAxes:
70
73
  marker: str, optional
71
74
  Marker type
72
75
 
73
- markersize or s: float, optional
74
- Mark size in pt
76
+ markersize or s: ArrayLike or float, optional
77
+ Mark size in pt (or in 1/50 pt for s), if a sequence of same length as x, it will be interpreted as size for each point, otherwise it will be interpreted as a single size for all points.
78
+
79
+ cmap: str or Colorbar, optional
80
+ Colormap for scatter points, if color is given as float or sequence of floats. Can be a colormap name or a Colorbar object.
81
+
82
+ vmin, vmax: float, optional
83
+ Colorbar limits for scatter points, if color is given sequence of floats and cmap is given as string, otherwise ignored. If cmap is given as str and no vmin or vmax is provided, they will be set to the min and max of color sequence.
75
84
  """
76
85
  ...
77
86
  def semilogy(self, x: ArrayLike = ..., y: ArrayLike = ..., base: Optional[float] = 10, fmt: Optional[str] = ...,*, alpha: Optional[float] = ..., color: Optional[ColorLike] = ..., c: Optional[ColorLike] = ...,
@@ -202,6 +211,41 @@ class BaseAxes:
202
211
 
203
212
  """
204
213
  ...
214
+
215
+ def text(self, x: float, y: float, s: str, color: Optional[ColorLike] = ..., c: Optional[ColorLike] = ..., fontsize: Optional[FontSize] = ..., size: Optional[FontSize] = ..., backgroundcolor: Optional[ColorLike] = ..., horizontalalignment: Optional[str] = ..., ha: Optional[str] = ..., verticalalignment: Optional[str] = ..., va: Optional[str] = ..., rotation: Optional[Union[float, str]] = ..., label: Optional[str] = ...) -> None:
216
+ """
217
+ Add text to the selected axis.
218
+
219
+ Parameters
220
+ ----------
221
+ x,y: float
222
+ Text position in axis coordinates
223
+
224
+ s: str
225
+ Text content (LaTeX format)
226
+
227
+ color or c: all matplotlib color formats (without X11/xkcd), optional
228
+ Text color: RGB/RGBA (tuple), HEX (str), grayscale (float), single-char (str), name (str), default cycle ("CX", X int), none for invisible
229
+
230
+ fontsize or size: FontSize, optional
231
+ Font size
232
+
233
+ backgroundcolor: all matplotlib color formats (without X11/xkcd), optional
234
+ Background color of text box: RGB/RGBA (tuple), HEX (str), grayscale (float), single-char (str), name (str), default cycle ("CX", X int), none for invisible
235
+
236
+ horizontalalignment or ha: {"center", "left", "right"}, optional
237
+ Horizontal alignment of text
238
+
239
+ verticalalignment or va: {"center", "top", "bottom"}, optional
240
+ Vertical alignment of text
241
+
242
+ rotation: float or {"vertical", "horizontal"}, optional
243
+ Rotation angle in degrees or preset rotation
244
+
245
+ label: str, optional
246
+ Legend entry
247
+ """
248
+ ...
205
249
  def hlines(
206
250
  self,
207
251
  y: Union[float, Sequence[float]],
@@ -231,6 +275,44 @@ class BaseAxes:
231
275
  Draw histogram to the selected axis.
232
276
  """
233
277
  ...
278
+
279
+ def step(self, x: ArrayLike, y: ArrayLike, *args: Any, where: Literal["pre","post","mid"] = "pre", **kwargs: Any) -> None:
280
+ """
281
+ Draw a step plot to the selected axis.
282
+
283
+ Parameters
284
+ ----------
285
+ x,y : ArrayLike or float
286
+ Datapoints
287
+
288
+ where: {"pre", "post", "mid"}, default "pre"
289
+ Define where the steps should be placed: before the value (pre), after the value (post), or centered on the value (mid).
290
+
291
+ fmt: str, optional
292
+ Style
293
+
294
+ alpha: float, optional
295
+ Opacity
296
+
297
+ color or c: all matplotlib color formats (without X11/xkcd), optional
298
+ color of line and markers: RGB/RGBA (tuple), HEX (str), grayscale (float), single-char (str), name (str), default cycle ("CX", X int), none for invisible
299
+
300
+ label: str, optional
301
+ Legned entry
302
+
303
+ linestyle or ls: str, optional
304
+ Line style
305
+
306
+ linewidth or lw: float, optional
307
+ Line width in pt
308
+
309
+ marker: str, optional
310
+ Marker type
311
+
312
+ markersize or ms: float, optional
313
+ Mark size in pt
314
+ """
315
+ ...
234
316
 
235
317
  def set_ylabel(self, label: str) -> None:
236
318
  """
@@ -2,6 +2,7 @@ import numpy as _np
2
2
  import matplotlib.pyplot as _plt
3
3
 
4
4
  from .elements import Graph3
5
+ from .texts import Text3
5
6
  from .config import TikzConfig
6
7
  #from .state import _next_imshow_num, main_name
7
8
  from .latex_special import tex_text
@@ -193,6 +194,12 @@ class Axes3:
193
194
  counts = _np.cumsum(counts)
194
195
 
195
196
  return self._plot(centers, counts, settings=settings, **kwargs)"""
197
+
198
+ def text(self, x, y, z, s, **kwargs):
199
+ kws = {"alpha", "color", "c", "fontsize", "size", "backgroundcolor", "horizontalalignment", "ha", "verticalalignment", "va", "rotation", "label"}
200
+ kwargs = self._check_kwargs("text", kws, **kwargs)
201
+ txt = Text3(self, x, y, z, s, **kwargs)
202
+ self._elements.append(txt)
196
203
 
197
204
  def set_title(self, title):
198
205
  self._axis_options["title"] = f"{{{tex_text(title)}}}"
@@ -100,7 +100,7 @@ class _Colorbar:
100
100
  'Spectral': [(0.6196, 0.0039, 0.2588), (0.9981, 0.9992, 0.746), (0.3686, 0.3098, 0.6353)],
101
101
  'coolwarm': [(0.2298, 0.2987, 0.7537), (0.8674, 0.8644, 0.8626), (0.7057, 0.0156, 0.1502)],
102
102
  'bwr': [(0.0, 0.0, 1.0), (1.0, 0.9961, 0.9961), (1.0, 0.0, 0.0)],
103
- 'seismic': [(0.0, 0.0, 0.3), (1.0, 0.9922, 0.9922), (0.5, 0.0, 0.0)],
103
+ 'seismic': [(0.0, 0.0, 0.3), (0.0, 0.0, 0.6953), (0.1451, 0.1451, 1.0), (0.7098, 0.7098, 1.0), (1.0, 0.7098, 0.7098), (1.0, 0.1451, 0.1451), (0.7824, 0.0, 0.0), (0.5, 0.0, 0.0)],
104
104
 
105
105
  'twilight': [(0.8858, 0.85, 0.888), (0.5383, 0.678, 0.7711), (0.3732, 0.3814, 0.706), (0.2867, 0.0824, 0.3933), (0.3154, 0.0794, 0.2681), (0.6457, 0.2616, 0.3125), (0.7905, 0.5983, 0.4862), (0.8857, 0.85, 0.8857)],
106
106
  'twilight_shifted': [(0.1874, 0.0771, 0.2162), (0.36, 0.2069, 0.6029), (0.4114, 0.5368, 0.7467), (0.7387, 0.796, 0.8214), (0.8399, 0.7604, 0.7137), (0.7388, 0.4205, 0.3491), (0.4981, 0.1357, 0.3141), (0.1849, 0.0794, 0.2131)],
@@ -21,11 +21,12 @@ class _TikzConfig:
21
21
  self.X_LABEL_PADDING: float = 0.6
22
22
  self.XTICK_PADDING: float = 0.7
23
23
  self.YTICK_PADDING: float = 0.7
24
+ self.SEC_YLABEL_LOC: tuple[float, float] = (1.2, 0.5)
24
25
 
25
26
  self.DEFAULT_WIDTH: float = 12
26
27
  self.DEFAULT_HEIGHT: float = 10
27
28
 
28
- self.SHARED_AXIS_REL_MARGIN: float = 0.03
29
+ self.SHARED_AXIS_REL_MARGIN: float = 0.08
29
30
 
30
31
  self.SAVE_DATAPOINTS: bool = True
31
32
  self.DATAPOINTS_DIR: str = "datapoints" # ignored if SAVE_DATAPOINTS == False
@@ -22,6 +22,7 @@ class _ConfigParams(TypedDict, total=False):
22
22
  X_LABEL_PADDING: float
23
23
  XTICK_PADDING: float
24
24
  YTICK_PADDING: float
25
+ SEC_YLABEL_LOC: tuple[float, float]
25
26
 
26
27
  DEFAULT_WIDTH: float
27
28
  DEFAULT_HEIGHT: float
@@ -38,7 +38,7 @@ class BaseGraph:
38
38
  if self._style_str != None:
39
39
  return self._style_str
40
40
  opts = []
41
-
41
+ cmap = None
42
42
  def match_ls(input):
43
43
  if input in self._LINE_MAP.keys():
44
44
  return self._LINE_MAP[input]
@@ -65,6 +65,10 @@ class BaseGraph:
65
65
  r,g,b=ccode
66
66
  self._axes._add_col(r,g,b)
67
67
  return f"c{r:.3f}{g:.3f}{b:.3f}".replace(".", "")
68
+
69
+ if "scatter" in self._settings:
70
+ if "cmap" in self._style:
71
+ cmap = self._style["cmap"]
68
72
 
69
73
  if "fmt" in self._style:
70
74
  fmt = self._style["fmt"]
@@ -83,42 +87,38 @@ class BaseGraph:
83
87
  if ls:
84
88
  opts.append(ls)
85
89
 
86
- if "c" in self._style:
87
- sel_col = match_color(self._style['c'])
88
- if sel_col:
89
- opts.append(f"color={{{sel_col}}}")
90
- if "color" in self._style:
91
- sel_col = match_color(self._style['color'])
92
- if sel_col:
93
- opts.append(f"color={{{sel_col}}}")
94
- if "ls" in self._style:
95
- ls = self._style["ls"]
96
- if ls == "":
97
- opts.append("only marks")
90
+ if "c" in self._style or "color" in self._style:
91
+ if "scatter" in self._settings and self._colors is not None:
92
+ if isinstance(self._colors[0], (int, float)):
93
+ self._colors = [match_color(cmap.color(p)) for p in self._colors]
94
+ else:
95
+ self._colors = [match_color(p) for p in self._colors]
98
96
  else:
99
- sel_ls = match_ls(ls)
100
- if sel_ls:
101
- opts.append(sel_ls)
102
- if "linestyle" in self._style:
103
- ls = self._style["linestyle"]
97
+ c = self._style.get("c", self._style.get("color"))
98
+ sel_col = match_color(c)
99
+ if sel_col:
100
+ opts.append(f"color={{{sel_col}}}")
101
+
102
+ if "ls" in self._style or "linestyle" in self._style:
103
+ ls = self._style.get("ls", self._style.get("linestyle"))
104
104
  if ls == "":
105
105
  opts.append("only marks")
106
106
  else:
107
107
  sel_ls = match_ls(ls)
108
108
  if sel_ls:
109
109
  opts.append(sel_ls)
110
- if "lw" in self._style:
111
- opts.append(f"line width={self._style['lw']}pt")
112
- if "linewidth" in self._style:
113
- opts.append(f"line width={self._style['linewidth']}pt")
110
+ if "lw" in self._style or "linewidth" in self._style:
111
+ if "scatter" in self._settings:
112
+ lw = self._style.get("lw", self._style.get("linewidth"))
113
+ opts.append(f"line width={lw}pt")
114
114
  if "marker" in self._style:
115
115
  sel_mark = match_mark(self._style['marker'])
116
116
  if sel_mark:
117
117
  opts.append(f"mark={sel_mark}")
118
- if "ms" in self._style:
119
- opts.append(f"mark size={self._style['ms']}pt")
120
- if "marksize" in self._style:
121
- opts.append(f"mark size={self._style['marksize']}pt")
118
+ if "ms" in self._style or "markersize" in self._style:
119
+ ms = self._style.get("ms", self._style.get("markersize"))
120
+ if not ("scatter" in self._settings and self._sizes is not None):
121
+ opts.append(f"mark size={ms}pt")
122
122
  if "markerfmt" in self._style:
123
123
  col = list(set(self._COLOR_MAP.keys()) & set(fmt))
124
124
  if col:
@@ -162,6 +162,20 @@ class BaseGraph:
162
162
  if self._path_name: self._settings.append(f"name path={self._path_name}")
163
163
  if self._settings:
164
164
  opts = self._settings + opts
165
+ if "scatter" in self._settings and (self._colors is not None or self._sizes is not None):
166
+ last = 0
167
+ for i in range(len(self._x)):
168
+ st = ""
169
+ if self._colors is not None:
170
+ st = f"color={{{self._colors[i]}}},"
171
+ if self._sizes is not None:
172
+ st += f"mark size={self._sizes[i]:.9f}pt"
173
+ if st not in self._st_dict:
174
+ self._st_dict[st] = "s" + str(last+1)
175
+ last += 1
176
+ self._p_dict[i] = self._st_dict[st]
177
+ opts.append("point meta=explicit symbolic")
178
+ opts.append(f"scatter/classes={{\n" + ',\n'.join(f"{v}={{{k}}}" for k,v in self._st_dict.items()) + "\n}")
165
179
  self._style_str = ",\n".join(str(o) for o in opts)
166
180
  return self._style_str
167
181
 
@@ -196,12 +210,21 @@ class Graph(BaseGraph):
196
210
  super().__init__()
197
211
  self._axes = axes
198
212
  self._classic = False
213
+ self._style = style
214
+ if settings is not None:
215
+ self._settings = settings
216
+ if "scatter" in self._settings:
217
+ self._st_dict = {}
218
+ self._p_dict = {}
219
+ self._colors = None
220
+ self._sizes = None
199
221
  if isinstance(coordinates, tuple):
200
222
  self._classic = True
201
223
  x,y=coordinates
202
224
  self._x = np.asarray(x)
203
225
  self._y = np.asarray(y)
204
226
  mask = np.isfinite(self._x) & np.isfinite(self._y)
227
+ n0 = len(self._x)
205
228
  self._x = self._x[mask]
206
229
  self._y = self._y[mask]
207
230
  n = len(self._x)
@@ -212,11 +235,28 @@ class Graph(BaseGraph):
212
235
 
213
236
  if self._yerr is not None:
214
237
  self._yerr = np.asarray(self._yerr)[mask]
238
+
239
+ if "scatter" in self._settings:
240
+ c = self._style.get("c", self._style.get("color", None))
241
+ if c is not None:
242
+ try:
243
+ if len(c) == n0:
244
+ self._colors = np.asarray(c)[mask]
245
+ except: pass
246
+ s = self._style.get("ms", self._style.get("markersize", None))
247
+ if s is not None:
248
+ try:
249
+ if len(s) == n0:
250
+ self._sizes = np.asarray(s)[mask]
251
+ except: pass
252
+ if self._colors is None and self._sizes is None:
253
+ self._settings.remove("scatter")
254
+ else:
255
+ if self._colors is None:
256
+ self._colors = style.get("c", style.get("color", self._axes._get_defcol())) * np.ones(len(self._x))
215
257
  else:
216
258
  self._special = coordinates
217
- self._style = style
218
259
  self._label = None
219
- self._settings = settings
220
260
  if self._settings == None: self._settings = []
221
261
 
222
262
  self._opacity = 1
@@ -236,6 +276,9 @@ class Graph(BaseGraph):
236
276
  cols += ["yerrminus", "yerrplus"]
237
277
  else:
238
278
  cols.append("yerror")
279
+ if "scatter" in self._settings:
280
+ if self._p_dict:
281
+ cols.append("label")
239
282
  return " ".join(cols)
240
283
 
241
284
  def _rows(self):
@@ -252,6 +295,9 @@ class Graph(BaseGraph):
252
295
  line += list(self._yerr[i])
253
296
  else:
254
297
  line.append(self._yerr[i])
298
+ if "scatter" in self._settings:
299
+ if self._p_dict:
300
+ line.append(self._p_dict[i])
255
301
  rows.append(" ".join(str(v) for v in line))
256
302
  return "\n".join(rows)
257
303
 
@@ -266,6 +312,8 @@ class Graph(BaseGraph):
266
312
  table_opts += ",x error=xerror"
267
313
  if self._yerr is not None:
268
314
  table_opts += ",y error=yerror"
315
+ if "scatter" in self._settings and self._p_dict:
316
+ table_opts += ",meta=label"
269
317
  datapoints = f"{header}\n{rows}\n"
270
318
  if TikzConfig.SAVE_DATAPOINTS:
271
319
  datapoints = self._save_data(datapoints, filename)
@@ -275,6 +323,8 @@ class Graph(BaseGraph):
275
323
  return f"\\addplot [forget plot,\n{style}] table [{table_opts}] {{{datapoints}}};"
276
324
  return ""
277
325
  elif TikzConfig.SAVE_DATAPOINTS or not (TikzConfig.SAVE_DATAPOINTS and not TikzConfig.UPDATE_STYLE_ONLY):
326
+ if self._label and self._axes._legend_on:
327
+ return f"\\addplot [{style}] {self._special};\\addlegendentry{{{self._label}}}"
278
328
  return f"\\addplot [forget plot,\n{style}] {self._special};"
279
329
  else:
280
330
  return ""
@@ -330,6 +380,12 @@ class Graph(BaseGraph):
330
380
  if self._yerr is not None:
331
381
  self._yerr = self._yerr[mask]
332
382
 
383
+ if "scatter" in self._settings:
384
+ if self._colors is not None:
385
+ self._colors = self._colors[mask]
386
+ if self._sizes is not None:
387
+ self._sizes = self._sizes[mask]
388
+
333
389
  def _check_equal(self, x,y):
334
390
  if self._classic:
335
391
  return np.array_equal(np.asarray(x),self._x) and np.array_equal(np.asarray(y),self._y)
@@ -397,6 +453,11 @@ class Graph(BaseGraph):
397
453
  self._xerr = self._xerr[mask]
398
454
  if self._yerr is not None:
399
455
  self._yerr = self._yerr[mask]
456
+ if "scatter" in self._settings:
457
+ if self._colors is not None:
458
+ self._colors = self._colors[mask]
459
+ if self._sizes is not None:
460
+ self._sizes = self._sizes[mask]
400
461
 
401
462
  class Graph3(BaseGraph):
402
463
  def __init__(self, axes, coordinates, settings=None, xerr=None, yerr=None, zerr=None, path_name=None, **style):
@@ -101,26 +101,26 @@ def plot(*args, **kwargs):
101
101
  _ensure_axes()
102
102
  _current_axes.plot(*args, **kwargs)
103
103
 
104
- def scatter(x, y, *args, **kwargs):
104
+ def scatter(*args, **kwargs):
105
105
  _ensure_axes()
106
- _current_axes.scatter(x, y, *args, **kwargs)
106
+ _current_axes.scatter(*args, **kwargs)
107
107
 
108
108
 
109
- def loglog(x, y, *args, **kwargs):
109
+ def loglog(*args, **kwargs):
110
110
  _ensure_axes()
111
- _current_axes.loglog(x, y, *args, **kwargs)
111
+ _current_axes.loglog(*args, **kwargs)
112
112
 
113
- def semilogx(x, y, *args, **kwargs):
113
+ def semilogx(*args, **kwargs):
114
114
  _ensure_axes()
115
- _current_axes.semilogx(x, y, *args, **kwargs)
115
+ _current_axes.semilogx(*args, **kwargs)
116
116
 
117
- def semilogy(x, y, *args, **kwargs):
117
+ def semilogy(*args, **kwargs):
118
118
  _ensure_axes()
119
- _current_axes.semilogy(x, y, *args, **kwargs)
119
+ _current_axes.semilogy(*args, **kwargs)
120
120
 
121
- def errorbar(x, y, *args, **kwargs):
121
+ def errorbar(*args, **kwargs):
122
122
  _ensure_axes()
123
- _current_axes.errorbar(x, y, *args, **kwargs)
123
+ _current_axes.errorbar(*args, **kwargs)
124
124
 
125
125
  def stem(*args, **kwargs):
126
126
  _ensure_axes()
@@ -130,6 +130,10 @@ def fill_between(*args, **kwargs):
130
130
  _ensure_axes()
131
131
  _current_axes.fill_between(*args, **kwargs)
132
132
 
133
+ def text(*args, **kwargs):
134
+ _ensure_axes()
135
+ _current_axes.text(*args, **kwargs)
136
+
133
137
  def hlines(*args, **kwargs):
134
138
  _ensure_axes()
135
139
  _current_axes.hlines(*args, **kwargs)
@@ -142,6 +146,14 @@ def imshow(*args, **kwargs):
142
146
  _ensure_axes()
143
147
  return _current_axes.imshow(*args, **kwargs)
144
148
 
149
+ def hist(*args, **kwargs):
150
+ _ensure_axes()
151
+ return _current_axes.hist(*args, **kwargs)
152
+
153
+ def step(*args, **kwargs):
154
+ _ensure_axes()
155
+ return _current_axes.step(*args, **kwargs)
156
+
145
157
  def xticks(*args, **kwargs):
146
158
  _ensure_axes()
147
159
  _current_axes.set_xticks(*args, **kwargs)
@@ -173,3 +185,6 @@ def clf():
173
185
  def gca():
174
186
  _ensure_axes()
175
187
  return _current_axes
188
+
189
+ def tight_layout():
190
+ pass
@@ -3,7 +3,8 @@
3
3
  from typing import Any, Optional, Tuple, Union, Sequence, Literal
4
4
  import numpy as np
5
5
 
6
- from .config import TikzConfig as TikzConfig
6
+ from .config import TikzConfig
7
+ from .colorbar import Colorbar
7
8
  from .figure import Figure as Figure
8
9
  from .state import main_name as main_name, next_show_num as next_show_num
9
10
  from .axes import Axes
@@ -12,6 +13,7 @@ ArrayLike = Union[Sequence[float], np.ndarray]
12
13
  ColorLike = Union[str, Sequence[float]]
13
14
  LineStyle = Literal["-", "--", "-.", ":", "solid", "dashed", "dashdot", "none", ""]
14
15
  MarkerStyle = Literal["o", "s", "^", "v", "x", "+", ".", "*", "None", ""]
16
+ FontSize = Literal["xx-small", "x-small", "small", "medium", "large", "x-large", "xx-large"]
15
17
 
16
18
  # --- Figure / Axes creation ---
17
19
 
@@ -238,15 +240,8 @@ def errorbar(self, x: ArrayLike = ..., y: ArrayLike = ..., yerr: Optional[ArrayL
238
240
  Mark size in pt
239
241
  """
240
242
  ...
241
- def scatter(
242
- x: ArrayLike = ..., y: ArrayLike = ..., fmt: Optional[str] = ...,
243
- *,
244
- alpha: Optional[float] = ...,
245
- color: Optional[ColorLike] = ..., c: Optional[ColorLike] = ...,
246
- marker: Optional[MarkerStyle] = ...,
247
- markersize: Optional[float] = ..., ms: Optional[float] = ...,
248
- label: Optional[str] = ...
249
- ) -> None:
243
+ def scatter(self, x: ArrayLike = ..., y: ArrayLike = ..., fmt: Optional[str] = ..., *,alpha: Optional[float] = ..., color: Optional[Union[Sequence[ColorLike], ColorLike]] = ..., c: Optional[ColorLike] = ...,
244
+ marker: Optional[MarkerStyle] = ..., markersize: Optional[Union[Sequence[float], float]] = ..., s: Optional[Union[Sequence[float], float]] = ..., label:Optional[str]=..., cmap: Optional[Union[str, Colorbar]], vmin: Optional[float] = ..., vmax: Optional[float] = ...) -> None:
250
245
  """
251
246
  Draw a scatter plot to the selected axis.
252
247
 
@@ -254,24 +249,23 @@ def scatter(
254
249
  ----------
255
250
  x,y : ArrayLike or float
256
251
  Datapoints
257
-
258
252
  fmt: str, optional
259
253
  Style
260
-
261
254
  alpha: float, optional
262
255
  Opacity
263
-
264
- color or c: all matplotlib color formats (without X11/xkcd), optional
265
- color of line and markers: RGB/RGBA (tuple), HEX (str), grayscale (float), single-char (str), name (str), default cycle ("CX", X int), none for invisible
266
-
256
+ color or c: array like or single: all matplotlib color formats (without X11/xkcd) or float for colormap, optional
257
+ color of line and markers: RGB/RGBA (tuple), HEX (str), grayscale (float), single-char (str), name (str), default cycle ("CX", X int), none for invisible. Note that if the sequence if of the same length as x, it will be interpreted as color sequence for each point, otherwise it will be interpreted as a single color for all points.
267
258
  label: str, optional
268
259
  Legned entry
269
260
 
270
261
  marker: str, optional
271
262
  Marker type
272
-
273
- markersize or ms: float, optional
274
- Mark size in pt
263
+ markersize or s: ArrayLike or float, optional
264
+ Mark size in pt (or in 1/50 pt for s), if a sequence of same length as x, it will be interpreted as size for each point, otherwise it will be interpreted as a single size for all points.
265
+ cmap: str or Colorbar, optional
266
+ Colormap for scatter points, if color is given as float or sequence of floats. Can be a colormap name or a Colorbar object.
267
+ vmin, vmax: float, optional
268
+ Colorbar limits for scatter points, if color is given sequence of floats and cmap is given as string, otherwise ignored. If cmap is given as str and no vmin or vmax is provided, they will be set to the min and max of color sequence.
275
269
  """
276
270
  ...
277
271
 
@@ -367,6 +361,32 @@ def fill_between(
367
361
  """
368
362
  ...
369
363
 
364
+ def text(self, x: float, y: float, s: str, color: Optional[ColorLike] = ..., c: Optional[ColorLike] = ..., fontsize: Optional[FontSize] = ..., size: Optional[FontSize] = ..., backgroundcolor: Optional[ColorLike] = ..., horizontalalignment: Optional[str] = ..., ha: Optional[str] = ..., verticalalignment: Optional[str] = ..., va: Optional[str] = ..., rotation: Optional[Union[float, str]] = ..., label: Optional[str] = ...) -> None:
365
+ """
366
+ Add text to the selected axis.
367
+ Parameters
368
+ ----------
369
+ x,y: float
370
+ Text position in axis coordinates
371
+ s: str
372
+ Text content (LaTeX format)
373
+ color or c: all matplotlib color formats (without X11/xkcd), optional
374
+ Text color: RGB/RGBA (tuple), HEX (str), grayscale (float), single-char (str), name (str), default cycle ("CX", X int), none for invisible
375
+ fontsize or size: FontSize, optional
376
+ Font size
377
+ backgroundcolor: all matplotlib color formats (without X11/xkcd), optional
378
+ Background color of text box: RGB/RGBA (tuple), HEX (str), grayscale (float), single-char (str), name (str), default cycle ("CX", X int), none for invisible
379
+ horizontalalignment or ha: {"center", "left", "right"}, optional
380
+ Horizontal alignment of text
381
+ verticalalignment or va: {"center", "top", "bottom"}, optional
382
+ Vertical alignment of text
383
+ rotation: float or {"vertical", "horizontal"}, optional
384
+ Rotation angle in degrees or preset rotation
385
+ label: str, optional
386
+ Legend entry
387
+ """
388
+ ...
389
+
370
390
  def loglog(self, x: ArrayLike = ..., y: ArrayLike = ..., base: Optional[float] = 10, fmt: Optional[str] = ...,*, alpha: Optional[float] = ..., color: Optional[ColorLike] = ..., c: Optional[ColorLike] = ...,
371
391
  linestyle: Optional[LineStyle] = ..., ls: Optional[LineStyle] = ..., linewidth: Optional[float]= ..., lw: Optional[float] = ...,
372
392
  marker: Optional[MarkerStyle] = ..., markersize: Optional[float] = ..., ms: Optional[float] = ...) -> None:
@@ -399,6 +419,52 @@ def loglog(self, x: ArrayLike = ..., y: ArrayLike = ..., base: Optional[float] =
399
419
  """
400
420
  ...
401
421
 
422
+ def hist(
423
+ self,
424
+ x: Union[ArrayLike, Sequence[ArrayLike]],
425
+ bins: int = ...,
426
+ density: bool = ...,
427
+ *,
428
+ cumulative: bool = ...,
429
+ orientation: Literal["horizontal","vertical"] = "vertical",
430
+ rwidth: Optional[float] = ...,
431
+ range: Optional[Tuple[float,float]] = ...,
432
+ color: Optional[ColorLike] = ...,
433
+ **kwargs: Any
434
+ ) -> None:
435
+ """
436
+ Draw histogram to the selected axis.
437
+ """
438
+ ...
439
+ def step(self, x: ArrayLike, y: ArrayLike, *args: Any, where: Literal["pre","post","mid"] = "pre", **kwargs: Any) -> None:
440
+ """
441
+ Draw a step plot to the selected axis.
442
+ Parameters
443
+ ----------
444
+ x,y : ArrayLike or float
445
+ Datapoints
446
+ where: {"pre", "post", "mid"}, default "pre"
447
+ Define where the steps should be placed: before the value (pre), after the value (post), or centered on the value (mid).
448
+ fmt: str, optional
449
+ Style
450
+ alpha: float, optional
451
+ Opacity
452
+ color or c: all matplotlib color formats (without X11/xkcd), optional
453
+ color of line and markers: RGB/RGBA (tuple), HEX (str), grayscale (float), single-char (str), name (str), default cycle ("CX", X int), none for invisible
454
+ label: str, optional
455
+ Legned entry
456
+ linestyle or ls: str, optional
457
+ Line style
458
+ linewidth or lw: float, optional
459
+ Line width in pt
460
+
461
+ marker: str, optional
462
+ Marker type
463
+ markersize or ms: float, optional
464
+ Mark size in pt
465
+ """
466
+ ...
467
+
402
468
  def hlines(
403
469
  self,
404
470
  y: Union[float, Sequence[float]],
@@ -0,0 +1,119 @@
1
+ from .colors import _tex_color
2
+
3
+ class Text:
4
+ def __init__(self, ax, x, y, s, **kwargs):
5
+ self._axes = ax
6
+ self._x = x
7
+ self._y = y
8
+ self._s = s
9
+ self._kwargs = kwargs
10
+ self._color = False
11
+ self._opacity = 1
12
+ self._fsize = None
13
+ self._label = kwargs.get("label", None)
14
+ self._visible = True
15
+
16
+ _FONT_SIZES = {"xx-small": r"\tiny", "x-small": r"\scriptsize", "small": r"\footnotesize", "medium": r"\normalsize", "large": r"\large", "x-large": r"\Large", "xx-large": r"\LARGE"}
17
+
18
+ def match_color(self, input):
19
+ self._has_color = True
20
+ ccode, op = _tex_color(input)
21
+ if not isinstance(op, bool):
22
+ self._opacity = op
23
+ if isinstance(ccode, str):
24
+ return ccode
25
+ r,g,b=ccode
26
+ self._axes._add_col(r,g,b)
27
+ return f"c{r:.3f}{g:.3f}{b:.3f}".replace(".", "")
28
+
29
+ def _style_string(self):
30
+ output = []
31
+ if "color" in self._kwargs or "c" in self._kwargs:
32
+ self._color = self.match_color(self._kwargs.get("color") or self._kwargs.get("c"))
33
+ if "alpha" in self._kwargs:
34
+ self._opacity = self._kwargs["alpha"]
35
+ if "fontsize" in self._kwargs or "size" in self._kwargs:
36
+ size = self._kwargs.get('fontsize') or self._kwargs.get('size')
37
+ if size in self._FONT_SIZES:
38
+ self._fsize = self._FONT_SIZES[size]
39
+ else:
40
+ raise ValueError(f"Font size {size} not recognized. Valid sizes are: {', '.join(self._FONT_SIZES.keys())}")
41
+ if "backgroundcolor" in self._kwargs:
42
+ bg_color = self.match_color(self._kwargs["backgroundcolor"])
43
+ output.append(f"fill={bg_color}")
44
+ if "horizontalalignment" in self._kwargs or "ha" in self._kwargs:
45
+ ha = self._kwargs.get("horizontalalignment") or self._kwargs.get("ha")
46
+ if ha in {"center", "left", "right"}:
47
+ if ha in {"left", "right"}:
48
+ output.append(ha)
49
+ else:
50
+ raise ValueError(f"Horizontal alignment {ha} not recognized. Valid options are: center, left, right.")
51
+ if "verticalalignment" in self._kwargs or "va" in self._kwargs:
52
+ va = self._kwargs.get("verticalalignment") or self._kwargs.get("va")
53
+ if va in {"center", "top", "bottom"}:
54
+ if va == "top":
55
+ output.append("above")
56
+ elif va == "bottom":
57
+ output.append("below")
58
+ else:
59
+ raise ValueError(f"Vertical alignment {va} not recognized. Valid options are: center, top, bottom.")
60
+ if "rotation" in self._kwargs:
61
+ if isinstance(self._kwargs["rotation"], str):
62
+ if self._kwargs["rotation"] == "vertical":
63
+ output.append("rotate=90")
64
+ elif self._kwargs["rotation"] == "horizontal":
65
+ pass
66
+ elif isinstance(self._kwargs["rotation"], (int, float)):
67
+ output.append(f"rotate={self._kwargs['rotation']}")
68
+ else:
69
+ raise ValueError(f"Rotation value {self._kwargs['rotation']} not recognized. Valid options are: vertical, horizontal, or a numeric angle.")
70
+ if self._opacity < 1:
71
+ output.insert(0,f"opacity={self._opacity}")
72
+ if self._color:
73
+ output.insert(0,f"color={self._color}")
74
+ return ", ".join(output)
75
+
76
+
77
+ def _to_tex(self, _):
78
+ if self._visible:
79
+ return f"\\node[{self._style_string()}] at (axis cs:{self._x},{self._y}) {{{self._fsize or ''}{self._s}}};"
80
+ else:
81
+ return ""
82
+
83
+ def _set_label(self, label):
84
+ self._label = label
85
+
86
+ def _filter(self, which, value):
87
+ if (which == "xmin" and self._x < value) or (which == "xmax" and self._x > value) or (which == "ymin" and self._y < value) or (which == "ymax" and self._y > value):
88
+ self._visible = False
89
+
90
+ def _get_erange(self, which):
91
+ if which in {"xmin", "xmax"}:
92
+ return self._x
93
+ elif which in {"ymin", "ymax"}:
94
+ return self._y
95
+
96
+ def _num_points(self):
97
+ return 1
98
+
99
+ def _reduce_points(self, max_points):
100
+ pass
101
+
102
+ class Text3(Text):
103
+ def __init__(self, ax, x, y, z, s, **kwargs):
104
+ super().__init__(ax, x, y, s, **kwargs)
105
+ self._z = z
106
+
107
+ def _to_tex(self, _):
108
+ if self._visible:
109
+ return f"\\node[{self._style_string()}] at (axis cs:{self._x},{self._y},{self._z}) {{{self._fsize or ''}{self._s}}};"
110
+ else:
111
+ return ""
112
+
113
+ def _get_erange(self, which):
114
+ if which in {"xmin", "xmax"}:
115
+ return self._x
116
+ elif which in {"ymin", "ymax"}:
117
+ return self._y
118
+ elif which in {"zmin", "zmax"}:
119
+ return self._z
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: tikzplot42
3
- Version: 0.3.0
3
+ Version: 0.3.3
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
@@ -705,6 +705,10 @@ A clean version of PltToTikz, this time as Python package. Easy to use: only rep
705
705
 
706
706
  Please let me know if you find any bugs or unexpected behaviour. Examples may be found in repository under `tests/` directory.
707
707
 
708
+ <p align="center">
709
+ <img src="https://github.com/ZanAmb/TikzPlot/blob/main/tests/demo.png" width="60%">
710
+ </p>
711
+
708
712
  # Installation
709
713
  NEW: PyPI: `pip install tikzplot42`.
710
714
  Alternativley, download this package and install using: `pip install [path]`, where [path] is the path to the directory, containing `pyproject.toml`.
@@ -718,7 +722,8 @@ Instead of using `import matplotlib.pyplot (as plt)`, use `import tikzplot.plots
718
722
  - `\pgfplotsset{compat=1.18}` (may be lower, but compilation is not guaranteed),
719
723
  - `\usepgfplotslibrary{fillbetween}` (if you use fill-between plots),
720
724
  - `\usepgfplotslibrary{groupplots}` (recommended for best results, enabled by default, may be avoided by setting TikzConfig USE_GROUPPLOTS=False),
721
- - `\usepackage{xcolor}` (recommended for best colors, works without but needs change of TikzConfig USE_XCOLOR=False).
725
+ - `\usepackage{xcolor}` (recommended for best colors, works without but needs change of TikzConfig USE_XCOLOR=False),
726
+ - `\usepgfplotslibrary{polar}` required for polar axis.
722
727
 
723
728
  Export using `plt.savefig("example_graph.tex")` (recommended) or `plt.show()`.
724
729
  Then use the generated file as `\input{example_graph.tex}`.
@@ -735,7 +740,9 @@ Some basic plot commands are already implemented with commonly used arguments:
735
740
  - `fill-between()`,
736
741
  - `hlines()/vlines()`,
737
742
  - `historgam()`,
738
- - `imshow()`.
743
+ - `step()`,
744
+ - `imshow()`,
745
+ - `text()`.
739
746
 
740
747
  #### Figures
741
748
  - `plt.figure()` (currently only to give you figure object or to set `figsize`),
@@ -22,12 +22,14 @@ src/tikzplot/plots.pyi
22
22
  src/tikzplot/py.typed
23
23
  src/tikzplot/state.py
24
24
  src/tikzplot/state.pyi
25
+ src/tikzplot/texts.py
25
26
  src/tikzplot42.egg-info/PKG-INFO
26
27
  src/tikzplot42.egg-info/SOURCES.txt
27
28
  src/tikzplot42.egg-info/dependency_links.txt
28
29
  src/tikzplot42.egg-info/requires.txt
29
30
  src/tikzplot42.egg-info/top_level.txt
30
31
  tests/test1.py
32
+ tests/test10.py
31
33
  tests/test2.py
32
34
  tests/test3.py
33
35
  tests/test4.py
@@ -0,0 +1,24 @@
1
+ # Example from official matplotlib documentation
2
+
3
+ import tikzplot.plots as plt
4
+ import numpy as np
5
+ #from tikzplot import Colorbar
6
+ #from tikzplot import TikzConfig
7
+
8
+ #TikzConfig.modifyParam(USE_GROUPPLOTS=False)
9
+
10
+ # Fixing random state for reproducibility
11
+ #np.random.seed(19680801)
12
+
13
+ # Compute areas and colors
14
+ N = 150
15
+ r = 2 * np.random.rand(N)
16
+ theta = 2 * np.pi * np.random.rand(N)
17
+ area = 200 * r**2
18
+ colors = theta
19
+
20
+ fig = plt.figure(figsize=(6, 6))
21
+ ax = fig.add_subplot(projection='polar')
22
+ #cbar = Colorbar(cmap='hsv', lower=0, upper=max(theta))
23
+ c = ax.scatter(theta, r, c=colors, s=area, cmap='hsv', alpha=0.75)
24
+ plt.savefig("figure.tex")
@@ -9,7 +9,7 @@ fig, ((ax1, ax2), (ax3, ax4)) = plt.subplots(2,2,sharex="row",sharey="row")
9
9
  ax1.set_xlim(left=2)
10
10
  ax1.plot(x,x)
11
11
  ax2.set_yscale("log")
12
- ax2.plot(x,y)
12
+ ax2.step(x,y,".", ms=1,where="mid")
13
13
  ax3.plot(y,y)
14
14
  ax4.plot(y,x)
15
15
  ax1.set_xlabel(r"$x$")
@@ -24,6 +24,7 @@ fig, axs = plt.subplots(3,2)
24
24
  ax = axs[0, 0]
25
25
  ax.plot(x, y, color="blue", lw=1.5, label="sin(x)")
26
26
  ax.plot(x, y2, ls="--", color="red", label="cos(x)")
27
+ ax.text(1.5, 0.5, r"text $\alpha$", color="blue", ha="center", va="center", backgroundcolor="cyan", rotation=30)
27
28
  ax.grid()
28
29
  ax.legend(loc="upper right")
29
30
 
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes