tikzplot42 0.6.2__tar.gz → 0.6.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 (64) hide show
  1. {tikzplot42-0.6.2 → tikzplot42-0.6.3}/PKG-INFO +2 -1
  2. {tikzplot42-0.6.2 → tikzplot42-0.6.3}/README.md +1 -0
  3. {tikzplot42-0.6.2 → tikzplot42-0.6.3}/pyproject.toml +1 -1
  4. tikzplot42-0.6.3/src/tikzplot/arrows.py +87 -0
  5. {tikzplot42-0.6.2 → tikzplot42-0.6.3}/src/tikzplot/axes.py +30 -0
  6. {tikzplot42-0.6.2 → tikzplot42-0.6.3}/src/tikzplot/axes.pyi +52 -1
  7. {tikzplot42-0.6.2 → tikzplot42-0.6.3}/src/tikzplot/axes3d.py +21 -7
  8. {tikzplot42-0.6.2 → tikzplot42-0.6.3}/src/tikzplot/axes3d.pyi +6 -0
  9. {tikzplot42-0.6.2 → tikzplot42-0.6.3}/src/tikzplot/figure.py +6 -0
  10. {tikzplot42-0.6.2 → tikzplot42-0.6.3}/src/tikzplot/latex_special.py +1 -1
  11. {tikzplot42-0.6.2 → tikzplot42-0.6.3}/src/tikzplot/plots.py +5 -0
  12. {tikzplot42-0.6.2 → tikzplot42-0.6.3}/src/tikzplot/plots.pyi +45 -1
  13. {tikzplot42-0.6.2 → tikzplot42-0.6.3}/src/tikzplot/texts.py +3 -3
  14. {tikzplot42-0.6.2 → tikzplot42-0.6.3}/src/tikzplot42.egg-info/PKG-INFO +2 -1
  15. {tikzplot42-0.6.2 → tikzplot42-0.6.3}/src/tikzplot42.egg-info/SOURCES.txt +1 -0
  16. {tikzplot42-0.6.2 → tikzplot42-0.6.3}/tests/test7.py +1 -0
  17. {tikzplot42-0.6.2 → tikzplot42-0.6.3}/LICENSE +0 -0
  18. {tikzplot42-0.6.2 → tikzplot42-0.6.3}/setup.cfg +0 -0
  19. {tikzplot42-0.6.2 → tikzplot42-0.6.3}/src/tikzplot/__init__.py +0 -0
  20. {tikzplot42-0.6.2 → tikzplot42-0.6.3}/src/tikzplot/__init__.pyi +0 -0
  21. {tikzplot42-0.6.2 → tikzplot42-0.6.3}/src/tikzplot/border_finder.py +0 -0
  22. {tikzplot42-0.6.2 → tikzplot42-0.6.3}/src/tikzplot/colorbar.py +0 -0
  23. {tikzplot42-0.6.2 → tikzplot42-0.6.3}/src/tikzplot/colorbar.pyi +0 -0
  24. {tikzplot42-0.6.2 → tikzplot42-0.6.3}/src/tikzplot/colors.py +0 -0
  25. {tikzplot42-0.6.2 → tikzplot42-0.6.3}/src/tikzplot/config.py +0 -0
  26. {tikzplot42-0.6.2 → tikzplot42-0.6.3}/src/tikzplot/config.pyi +0 -0
  27. {tikzplot42-0.6.2 → tikzplot42-0.6.3}/src/tikzplot/elements.py +0 -0
  28. {tikzplot42-0.6.2 → tikzplot42-0.6.3}/src/tikzplot/elements.pyi +0 -0
  29. {tikzplot42-0.6.2 → tikzplot42-0.6.3}/src/tikzplot/figure.pyi +0 -0
  30. {tikzplot42-0.6.2 → tikzplot42-0.6.3}/src/tikzplot/pie.py +0 -0
  31. {tikzplot42-0.6.2 → tikzplot42-0.6.3}/src/tikzplot/py.typed +0 -0
  32. {tikzplot42-0.6.2 → tikzplot42-0.6.3}/src/tikzplot/state.py +0 -0
  33. {tikzplot42-0.6.2 → tikzplot42-0.6.3}/src/tikzplot/styles.py +0 -0
  34. {tikzplot42-0.6.2 → tikzplot42-0.6.3}/src/tikzplot/styles.pyi +0 -0
  35. {tikzplot42-0.6.2 → tikzplot42-0.6.3}/src/tikzplot42.egg-info/dependency_links.txt +0 -0
  36. {tikzplot42-0.6.2 → tikzplot42-0.6.3}/src/tikzplot42.egg-info/requires.txt +0 -0
  37. {tikzplot42-0.6.2 → tikzplot42-0.6.3}/src/tikzplot42.egg-info/top_level.txt +0 -0
  38. {tikzplot42-0.6.2 → tikzplot42-0.6.3}/tests/test1.py +0 -0
  39. {tikzplot42-0.6.2 → tikzplot42-0.6.3}/tests/test10.py +0 -0
  40. {tikzplot42-0.6.2 → tikzplot42-0.6.3}/tests/test11.py +0 -0
  41. {tikzplot42-0.6.2 → tikzplot42-0.6.3}/tests/test12.py +0 -0
  42. {tikzplot42-0.6.2 → tikzplot42-0.6.3}/tests/test13.py +0 -0
  43. {tikzplot42-0.6.2 → tikzplot42-0.6.3}/tests/test14.py +0 -0
  44. {tikzplot42-0.6.2 → tikzplot42-0.6.3}/tests/test15.py +0 -0
  45. {tikzplot42-0.6.2 → tikzplot42-0.6.3}/tests/test16.py +0 -0
  46. {tikzplot42-0.6.2 → tikzplot42-0.6.3}/tests/test17.py +0 -0
  47. {tikzplot42-0.6.2 → tikzplot42-0.6.3}/tests/test18.py +0 -0
  48. {tikzplot42-0.6.2 → tikzplot42-0.6.3}/tests/test19.py +0 -0
  49. {tikzplot42-0.6.2 → tikzplot42-0.6.3}/tests/test2.py +0 -0
  50. {tikzplot42-0.6.2 → tikzplot42-0.6.3}/tests/test20.py +0 -0
  51. {tikzplot42-0.6.2 → tikzplot42-0.6.3}/tests/test21.py +0 -0
  52. {tikzplot42-0.6.2 → tikzplot42-0.6.3}/tests/test22.py +0 -0
  53. {tikzplot42-0.6.2 → tikzplot42-0.6.3}/tests/test23.py +0 -0
  54. {tikzplot42-0.6.2 → tikzplot42-0.6.3}/tests/test24.py +0 -0
  55. {tikzplot42-0.6.2 → tikzplot42-0.6.3}/tests/test25.py +0 -0
  56. {tikzplot42-0.6.2 → tikzplot42-0.6.3}/tests/test26.py +0 -0
  57. {tikzplot42-0.6.2 → tikzplot42-0.6.3}/tests/test27.py +0 -0
  58. {tikzplot42-0.6.2 → tikzplot42-0.6.3}/tests/test28.py +0 -0
  59. {tikzplot42-0.6.2 → tikzplot42-0.6.3}/tests/test3.py +0 -0
  60. {tikzplot42-0.6.2 → tikzplot42-0.6.3}/tests/test4.py +0 -0
  61. {tikzplot42-0.6.2 → tikzplot42-0.6.3}/tests/test5.py +0 -0
  62. {tikzplot42-0.6.2 → tikzplot42-0.6.3}/tests/test6.py +0 -0
  63. {tikzplot42-0.6.2 → tikzplot42-0.6.3}/tests/test8.py +0 -0
  64. {tikzplot42-0.6.2 → tikzplot42-0.6.3}/tests/test9.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: tikzplot42
3
- Version: 0.6.2
3
+ Version: 0.6.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
@@ -764,6 +764,7 @@ Some basic plot commands are already implemented with commonly used arguments:
764
764
  - `imshow()`,
765
765
  - `matshow()`,
766
766
  - `text()`,
767
+ - `annotate()`,
767
768
  - `bxp()` (without notches),
768
769
  - `boxplot()` (without notches),
769
770
  - `violin()`,
@@ -64,6 +64,7 @@ Some basic plot commands are already implemented with commonly used arguments:
64
64
  - `imshow()`,
65
65
  - `matshow()`,
66
66
  - `text()`,
67
+ - `annotate()`,
67
68
  - `bxp()` (without notches),
68
69
  - `boxplot()` (without notches),
69
70
  - `violin()`,
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "tikzplot42"
7
- version = "0.6.2"
7
+ version = "0.6.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" }
@@ -0,0 +1,87 @@
1
+ from .colors import _tex_color
2
+
3
+ class Arrow:
4
+ _LINE_MAP = {"--": "dashed", ":": "dotted", "-.": "dashdotted", "-":"solid"}
5
+ def __init__(self, ax, x1, y1, x2, y2, coordinate1, coordinate2, **kwargs):
6
+ self._axes = ax
7
+ self._x1 = x1
8
+ self._y1 = y1
9
+ self._x2 = x2
10
+ self._y2 = y2
11
+ self._coordinate1 = coordinate1
12
+ self._coordinate2 = coordinate2
13
+ self._kwargs = kwargs
14
+ self._opacity = 1
15
+ self._visible = True
16
+
17
+ def match_color(self, input):
18
+ self._has_color = True
19
+ ccode, op = _tex_color(input)
20
+ if not isinstance(op, bool):
21
+ self._opacity = op
22
+ if isinstance(ccode, str):
23
+ return ccode
24
+ r,g,b=ccode
25
+ self._axes._add_col(r,g,b)
26
+ return f"c{r:.3f}{g:.3f}{b:.3f}".replace(".", "")
27
+
28
+ def _style_string(self):
29
+ output = []
30
+ if "arrowstyle" in self._kwargs:
31
+ allowed = {"<", ">", "|", "stealth", "latex"}
32
+ arstyle = self._kwargs["arrowstyle"]
33
+ arstyle = arstyle.split("-")
34
+ if not all(s in allowed for s in arstyle):
35
+ raise ValueError(f"Arrow style {self._kwargs['arrowstyle']} not recognized. Valid options should consist of: {allowed}, separated by -.")
36
+ output.append(self._kwargs["arrowstyle"])
37
+ if "color" in self._kwargs or "c" in self._kwargs:
38
+ self._color = self.match_color(self._kwargs.get("color") or self._kwargs.get("c"))
39
+ if "alpha" in self._kwargs:
40
+ self._opacity = self._kwargs["alpha"]
41
+ if "line width" in self._kwargs or "lw" in self._kwargs:
42
+ output.append("line width=" + str(self._kwargs.get("line width") or self._kwargs.get("lw")))
43
+ if "linestyle" in self._kwargs or "ls" in self._kwargs:
44
+ ls = self._kwargs.get("linestyle") or self._kwargs.get("ls")
45
+ if ls in self._LINE_MAP:
46
+ ls = self._LINE_MAP[ls]
47
+ elif ls not in self._LINE_MAP.values():
48
+ raise ValueError(f"Line style {ls} not recognized. Valid options are: {list(self._LINE_MAP.keys())}.")
49
+ output.append("line style=" + str(ls))
50
+ if self._opacity < 1:
51
+ output.insert(0,f"opacity={self._opacity}")
52
+ if self._color:
53
+ output.insert(0,f"color={self._color}")
54
+ return ", ".join(output)
55
+
56
+ def _to_tex(self, *args, **kwargs):
57
+ if self._visible:
58
+ if self._coordinate1 is not None:
59
+ return f"\\coordinate {self._coordinate1} at (axis cs:{self._x1},{self._y1});"
60
+ else:
61
+ return ""
62
+
63
+ def _to_tex_fin(self):
64
+ if self._visible:
65
+ if self._coordinate1 is not None and self._coordinate2 is not None:
66
+ return f"\\draw[{self._style_string()}] {self._coordinate2} -- {self._coordinate1};"
67
+ else:
68
+ return ""
69
+
70
+ def _filter(self, which, label):
71
+ pass
72
+
73
+ def _get_erange(self, which):
74
+ if which == "xmin":
75
+ return min(self._x1, self._x2)
76
+ elif which == "xmax":
77
+ return max(self._x1, self._x2)
78
+ elif which == "ymin":
79
+ return min(self._y1, self._y2)
80
+ elif which == "ymax":
81
+ return max(self._y1, self._y2)
82
+
83
+ def _num_points(self):
84
+ return 2
85
+
86
+ def _reduce_points(self, max_points):
87
+ pass
@@ -9,6 +9,7 @@ from skimage import measure
9
9
 
10
10
  from .elements import Graph, Single
11
11
  from .texts import Text
12
+ from .arrows import Arrow
12
13
  from .config import TikzConfig
13
14
  from .colorbar import Colorbar
14
15
  from .state import _next_imshow_num, main_name
@@ -2560,6 +2561,32 @@ class BaseAxes:
2560
2561
  txt = Text(self, x, y, None, s, **kwargs)
2561
2562
  self._elements[self._get_overlay()].append(txt)
2562
2563
 
2564
+ def annotate(self, text, xy, xytext=None, arrowprops=None, **kwargs):
2565
+ kws = {"alpha", "color", "c", "fontsize", "size", "backgroundcolor", "horizontalalignment", "ha", "verticalalignment", "va", "rotation", "label"}
2566
+ kwargs = self._check_kwargs("annotate", kws, **kwargs)
2567
+ akws = {"arrowstyle", "alpha", "color", "c", "linewidth", "lw", "linestyle", "ls"}
2568
+ passing_kwargs = {"alpha", "color", "c"}
2569
+ ap0 = {k: kwargs[k] for k in passing_kwargs if k in kwargs}
2570
+ if arrowprops is not None:
2571
+ arrowprops = self._check_kwargs("annotate: arrowprops", akws, **arrowprops)
2572
+ else:
2573
+ arrowprops = {}
2574
+ arrowprops = ap0 | arrowprops
2575
+ assert self._fig is not None
2576
+ xa, ya = xy
2577
+ if xytext is not None:
2578
+ xt, yt = xytext
2579
+ else:
2580
+ return self.text(xa, ya, text, **kwargs)
2581
+ ca = self._fig._next_coordinate_name()
2582
+ ct = self._fig._next_coordinate_name()
2583
+ txt = Text(self, xt, yt, ct, text, **kwargs)
2584
+ self._fig._add_text(txt)
2585
+ arr = Arrow(self, xa, ya, xt, yt, ca, ct, **arrowprops)
2586
+ self._fig._add_arrow(arr)
2587
+ self._elements[self._get_overlay()].append(txt)
2588
+ self._elements[self._get_overlay()].append(arr)
2589
+
2563
2590
  def magnify(self, x_p, y_p, x_m, y_m, zoom, size, **kwargs):
2564
2591
  kws = {"shape", "connect"}
2565
2592
  kwargs = self._check_kwargs("magnify", kws, **kwargs)
@@ -2568,6 +2595,9 @@ class BaseAxes:
2568
2595
  self._coordinates.update({f"spypoint{n}": (x_p,y_p)})
2569
2596
  self._coordinates.update({f"spyviewr{n}": (x_m,y_m)})
2570
2597
 
2598
+ def set_axis_off(self):
2599
+ self._axis_options["hide axis"] = None
2600
+
2571
2601
  def _add_legend_entries(self):
2572
2602
  if self._add_legend == []: return ""
2573
2603
  axs, labs = self._add_legend
@@ -368,7 +368,7 @@ class BaseAxes:
368
368
  Text position in axis coordinates
369
369
 
370
370
  s: str
371
- Text content (LaTeX format)
371
+ Text content
372
372
 
373
373
  color or c: all matplotlib color formats (without X11/xkcd), optional
374
374
  Text color: RGB/RGBA (tuple), HEX (str), grayscale (float), single-char (str), name (str), default cycle ("CX", X int), none for invisible
@@ -395,6 +395,51 @@ class BaseAxes:
395
395
  Legend entry
396
396
  """
397
397
  ...
398
+
399
+ def annotate(self, text: str, xy: Tuple[float|int, float|int], xytext: Optional[Tuple[float|int, float|int]] = None, arrowprops: Optional[dict] = None, alpha: float = 1, color: Optional[ColorLike] = ..., c: Optional[ColorLike] = ..., fontsize: Optional[FontSize] = ..., size: Optional[FontSize] = ..., backgroundcolor: Optional[ColorLike] = ..., horizontalalignment: Literal["left", "center", "right"] = "center", ha: Literal["left", "center", "right"] = "center", verticalalignment: Literal["bottom", "center", "top"] = "center", va: Literal["bottom", "center", "top"] = "center", rotation: float = 0, label: Optional[str] = ...) -> None:
400
+ """
401
+ Add an annotation with optional arrow to the selected axis.
402
+
403
+ Parameters
404
+ ----------
405
+ text: str
406
+ Annotation text
407
+
408
+ xy: tuple of float
409
+ Point (x,y) to annotate in axis coordinates
410
+
411
+ xytext: tuple of float, optional
412
+ Position (x,y) of the text in axis coordinates. If not provided, only text will be displayed at specified location (same as using text() method).
413
+
414
+ arrowprops: dict, optional
415
+ Dictionary of properties for the arrow. If not provided, no arrow will be drawn. Possible keys include 'arrowstyle', 'color', 'c', 'linewidth', 'lw', 'linestyle', 'ls', 'alpha'. For 'arrowstyle', basic LaTeX arrow styles are allowed ('>', '<', '|', 'stealth', 'latex', etc., separated by '-' to indicate side).
416
+
417
+ alpha: float, optional
418
+ Opacity
419
+
420
+ color or c: all matplotlib color formats (without X11/xkcd), optional
421
+ Text color: RGB/RGBA (tuple), HEX (str), grayscale (float), single-char (str), name (str), default cycle ("CX", X int), none for invisible
422
+
423
+ fontsize or size: FontSize, optional
424
+ Font size
425
+
426
+ backgroundcolor: all matplotlib color formats (without X11/xkcd), optional
427
+ 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
428
+
429
+ horizontalalignment or ha: {"center", "left", "right"}, optional
430
+ Horizontal alignment of text
431
+
432
+ verticalalignment or va: {"center", "top", "bottom"}, optional
433
+ Vertical alignment of text
434
+
435
+ rotation: float or {"vertical", "horizontal"}, optional
436
+ Rotation angle in degrees or preset rotation
437
+
438
+ label: str, optional
439
+ Legend entry
440
+ """
441
+ ...
442
+
398
443
  def hlines(
399
444
  self,
400
445
  y: Union[float, ArrayLike],
@@ -2094,6 +2139,12 @@ class BaseAxes:
2094
2139
  """
2095
2140
  ...
2096
2141
 
2142
+ def set_axis_off(self) -> None:
2143
+ """
2144
+ Turn off axis (no ticks, no labels, no frame)
2145
+ """
2146
+ ...
2147
+
2097
2148
  def _add_legend_entries(self) -> str: ...
2098
2149
  def _content_tex(self, filename: str) -> str: ...
2099
2150
  def _get_hard_range(self, which: Literal["xmin","xmax","ymin","ymax"]) -> Tuple[float,str]: ...
@@ -86,7 +86,6 @@ class Axes3:
86
86
  self._width= f"{self._fig._get_width() / ncols}cm"
87
87
  if self._fig._get_height():
88
88
  self._height = f"{self._fig._get_height() / nrows}cm"
89
-
90
89
  self._style_defaults()
91
90
 
92
91
  def _new_pos(self, nrows, ncols, index):
@@ -1020,14 +1019,26 @@ class Axes3:
1020
1019
  mode = "lin"
1021
1020
  if arg in self._axis_options:
1022
1021
  mode = self._axis_options[arg]
1023
- if which in self._axis_options:
1024
- for e in self._elements[self._get_overlay()]:
1025
- e._filter(which, self._axis_options[which])
1022
+ common = self._get_all_elements().copy()
1023
+ if which in self._axis_options and isinstance(self._axis_options[which], (int, float)):
1024
+ other = which.replace("min", "max") if "min" in which else which.replace("max", "min")
1025
+ if other in self._axis_options and (("min" in which and self._axis_options[which] > self._axis_options[other]) or ("max" in which and self._axis_options[which] < self._axis_options[other])):
1026
+ for e in common:
1027
+ e._filter(other, self._axis_options[which])
1028
+ else:
1029
+ for e in common:
1030
+ e._filter(which, self._axis_options[which])
1026
1031
  return (self._axis_options[which], True, mode)
1032
+ values = [e._get_erange(which) for e in common]
1033
+ if which in self._preferred_lims:
1034
+ values.append(self._preferred_lims[which])
1035
+ values = [v for v in values if v is not None]
1036
+ if not values:
1037
+ return (None, False, mode)
1027
1038
  if "min" in which:
1028
- return (min([e._get_erange(which) for e in self._get_all_elements()]), False, mode)
1029
- return (max([e._get_erange(which) for e in self._get_all_elements()]), False, mode)
1030
-
1039
+ return (min(values), False, mode)
1040
+ return (max(values), False, mode)
1041
+
1031
1042
  def _set_range(self, which, value):
1032
1043
  self._axis_options[which] = value
1033
1044
  for e in self._get_all_elements():
@@ -1100,6 +1111,9 @@ class Axes3:
1100
1111
  def set_minorticks_num(self, num):
1101
1112
  self._axis_options["minor tick num"] = num
1102
1113
 
1114
+ def set_axis_off(self):
1115
+ self._axis_options["hide axis"] = None
1116
+
1103
1117
  def _axis_option_string(self):
1104
1118
  if self._extend:
1105
1119
  self._axis_options.pop("alias", self._axis_options.pop("name", None))
@@ -581,6 +581,12 @@ class Axes3:
581
581
  """
582
582
  ...
583
583
 
584
+ def set_axis_off(self) -> None:
585
+ """
586
+ Turn off the axis lines, ticks, and labels.
587
+ """
588
+ ...
589
+
584
590
  def _add_legend_entries(self) -> str: ...
585
591
  def _content_tex(self, filename: str) -> str: ...
586
592
  def _get_hard_range(self, which: Literal["xmin","xmax","ymin","ymax"]) -> Tuple[float,str]: ...
@@ -37,6 +37,7 @@ class Figure:
37
37
  self._num_coordinates = 0
38
38
 
39
39
  self._texts = []
40
+ self._arrows = []
40
41
 
41
42
  self._lims = {"xmin": {}, "xmax": {}, "ymin": {}, "ymax": {}, "zmin": {}, "zmax": {}}
42
43
 
@@ -628,6 +629,8 @@ class Figure:
628
629
  lines.append(spy)
629
630
  for text in self._texts:
630
631
  lines.append(text._to_tex_fin())
632
+ for arr in self._arrows:
633
+ lines.append(arr._to_tex_fin())
631
634
  for ext in self._external:
632
635
  lines.append(ext._to_tex())
633
636
  lines.append("\\end{tikzpicture}")
@@ -730,6 +733,9 @@ class Figure:
730
733
  def _add_text(self, text):
731
734
  self._texts.append(text)
732
735
 
736
+ def _add_arrow(self, arrow):
737
+ self._arrows.append(arrow)
738
+
733
739
  def tight_layout(self, h_pad=0, w_pad=0, rect=(0,0,1,1)):
734
740
  TikzConfig.SCALE_ONLY_AXIS = True
735
741
  if not TikzConfig.USE_GROUPPLOTS:
@@ -59,4 +59,4 @@ def tex_text(sa: str) -> str:
59
59
 
60
60
  i += 1
61
61
 
62
- return "".join(out)
62
+ return "".join(out) if len(out) > 0 else ""
@@ -195,6 +195,11 @@ def text(*args, **kwargs):
195
195
  assert _current_axes
196
196
  return _current_axes.text(*args, **kwargs)
197
197
 
198
+ def annotate(*args, **kwargs):
199
+ _ensure_axes()
200
+ assert _current_axes
201
+ return _current_axes.annotate(*args, **kwargs)
202
+
198
203
  def hlines(*args, **kwargs):
199
204
  _ensure_axes()
200
205
  assert _current_axes
@@ -754,7 +754,7 @@ def text(x: float, y: float, s: str, color: Optional[ColorLike] = ..., c: Option
754
754
  Text position in axis coordinates
755
755
 
756
756
  s: str
757
- Text content (LaTeX format)
757
+ Text content
758
758
 
759
759
  color or c: all matplotlib color formats (without X11/xkcd), optional
760
760
  Text color: RGB/RGBA (tuple), HEX (str), grayscale (float), single-char (str), name (str), default cycle ("CX", X int), none for invisible
@@ -782,6 +782,50 @@ def text(x: float, y: float, s: str, color: Optional[ColorLike] = ..., c: Option
782
782
  """
783
783
  ...
784
784
 
785
+ def annotate(self, text: str, xy: Tuple[float|int, float|int], xytext: Optional[Tuple[float|int, float|int]] = None, arrowprops: Optional[dict] = None, alpha: float = 1, color: Optional[ColorLike] = ..., c: Optional[ColorLike] = ..., fontsize: Optional[FontSize] = ..., size: Optional[FontSize] = ..., backgroundcolor: Optional[ColorLike] = ..., horizontalalignment: Literal["left", "center", "right"] = "center", ha: Literal["left", "center", "right"] = "center", verticalalignment: Literal["bottom", "center", "top"] = "center", va: Literal["bottom", "center", "top"] = "center", rotation: float = 0, label: Optional[str] = ...) -> None:
786
+ """
787
+ Add an annotation with optional arrow to the selected axis.
788
+
789
+ Parameters
790
+ ----------
791
+ text: str
792
+ Annotation text
793
+
794
+ xy: tuple of float
795
+ Point (x,y) to annotate in axis coordinates
796
+
797
+ xytext: tuple of float, optional
798
+ Position (x,y) of the text in axis coordinates. If not provided, only text will be displayed at specified location (same as using text() method).
799
+
800
+ arrowprops: dict, optional
801
+ Dictionary of properties for the arrow. If not provided, no arrow will be drawn. Possible keys include 'arrowstyle', 'color', 'c', 'linewidth', 'lw', 'linestyle', 'ls', 'alpha'. For 'arrowstyle', basic LaTeX arrow styles are allowed ('>', '<', '|', 'stealth', 'latex', etc., separated by '-' to indicate side).
802
+
803
+ alpha: float, optional
804
+ Opacity
805
+
806
+ color or c: all matplotlib color formats (without X11/xkcd), optional
807
+ Text color: RGB/RGBA (tuple), HEX (str), grayscale (float), single-char (str), name (str), default cycle ("CX", X int), none for invisible
808
+
809
+ fontsize or size: FontSize, optional
810
+ Font size
811
+
812
+ backgroundcolor: all matplotlib color formats (without X11/xkcd), optional
813
+ 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
814
+
815
+ horizontalalignment or ha: {"center", "left", "right"}, optional
816
+ Horizontal alignment of text
817
+
818
+ verticalalignment or va: {"center", "top", "bottom"}, optional
819
+ Vertical alignment of text
820
+
821
+ rotation: float or {"vertical", "horizontal"}, optional
822
+ Rotation angle in degrees or preset rotation
823
+
824
+ label: str, optional
825
+ Legend entry
826
+ """
827
+ ...
828
+
785
829
  def loglog(x: ArrayLike = ..., y: ArrayLike = ..., base: Optional[float] = 10, fmt: Optional[str] = ...,*, alpha: Optional[float] = ..., color: Optional[ColorLike] = ..., c: Optional[ColorLike] = ...,
786
830
  linestyle: Optional[LineStyle] = ..., ls: Optional[LineStyle] = ..., linewidth: Optional[float]= ..., lw: Optional[float] = ...,
787
831
  marker: Optional[MarkerStyle] = ..., markersize: Optional[float] = ..., ms: Optional[float] = ...) -> Graph:
@@ -1,4 +1,5 @@
1
1
  from .colors import _tex_color
2
+ from .latex_special import tex_text
2
3
 
3
4
  class Text:
4
5
  def __init__(self, ax, x, y, coordinate, s, **kwargs):
@@ -6,7 +7,7 @@ class Text:
6
7
  self._x = x
7
8
  self._y = y
8
9
  self._coordinate = coordinate
9
- self._s = s
10
+ self._s = tex_text(s)
10
11
  self._kwargs = kwargs
11
12
  self._color = False
12
13
  self._opacity = 1
@@ -14,7 +15,6 @@ class Text:
14
15
  self._label = kwargs.get("label", None)
15
16
  self._visible = True
16
17
 
17
-
18
18
  def match_color(self, input):
19
19
  self._has_color = True
20
20
  ccode, op = _tex_color(input)
@@ -71,7 +71,6 @@ class Text:
71
71
  output.insert(0,f"color={self._color}")
72
72
  return ", ".join(output)
73
73
 
74
-
75
74
  def _to_tex(self, *args, **kwargs):
76
75
  if self._visible:
77
76
  if self._coordinate is not None:
@@ -87,6 +86,7 @@ class Text:
87
86
  return f"\\node[{self._style_string()}] at {self._coordinate} {{{self._fsize or ''}{self._s}}};"
88
87
  else:
89
88
  return ""
89
+
90
90
  def _set_label(self, label):
91
91
  self._label = label
92
92
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: tikzplot42
3
- Version: 0.6.2
3
+ Version: 0.6.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
@@ -764,6 +764,7 @@ Some basic plot commands are already implemented with commonly used arguments:
764
764
  - `imshow()`,
765
765
  - `matshow()`,
766
766
  - `text()`,
767
+ - `annotate()`,
767
768
  - `bxp()` (without notches),
768
769
  - `boxplot()` (without notches),
769
770
  - `violin()`,
@@ -3,6 +3,7 @@ README.md
3
3
  pyproject.toml
4
4
  src/tikzplot/__init__.py
5
5
  src/tikzplot/__init__.pyi
6
+ src/tikzplot/arrows.py
6
7
  src/tikzplot/axes.py
7
8
  src/tikzplot/axes.pyi
8
9
  src/tikzplot/axes3d.py
@@ -27,6 +27,7 @@ ax.plot(x, y, color="blue", lw=1.5, label="sin(x)")
27
27
  ax.text(1.5, 0.5, r"text $\alpha$", color="blue", ha="center", on_top=False, va="center", backgroundcolor="cyan", rotation=30)
28
28
  ax.plot(x, y2, ls="--", color="red", label="cos(x)")
29
29
  ax.text(1.5, -0.5, r"text $\beta$", color="teal", ha="center", va="center", rotation=-70)
30
+ ax.annotate(r"min", xy=(4.7, -1), xytext=(5, -0.5), arrowprops={"arrowstyle": "|-stealth", "color": "grey", "lw": 1.5}, c="cyan", va="bottom", rotation=-10)
30
31
 
31
32
  ax.grid()
32
33
  ax.legend(loc="upper right")
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
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
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
File without changes
File without changes