tikzplot42 0.6.3__tar.gz → 0.6.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.
Files changed (64) hide show
  1. {tikzplot42-0.6.3 → tikzplot42-0.6.4}/PKG-INFO +1 -1
  2. {tikzplot42-0.6.3 → tikzplot42-0.6.4}/pyproject.toml +1 -1
  3. {tikzplot42-0.6.3 → tikzplot42-0.6.4}/src/tikzplot/axes.py +142 -60
  4. {tikzplot42-0.6.3 → tikzplot42-0.6.4}/src/tikzplot/axes.pyi +96 -39
  5. {tikzplot42-0.6.3 → tikzplot42-0.6.4}/src/tikzplot/axes3d.py +2 -2
  6. {tikzplot42-0.6.3 → tikzplot42-0.6.4}/src/tikzplot/elements.py +13 -4
  7. {tikzplot42-0.6.3 → tikzplot42-0.6.4}/src/tikzplot/figure.py +4 -5
  8. {tikzplot42-0.6.3 → tikzplot42-0.6.4}/src/tikzplot/figure.pyi +116 -9
  9. {tikzplot42-0.6.3 → tikzplot42-0.6.4}/src/tikzplot/plots.py +1 -1
  10. {tikzplot42-0.6.3 → tikzplot42-0.6.4}/src/tikzplot/plots.pyi +189 -36
  11. {tikzplot42-0.6.3 → tikzplot42-0.6.4}/src/tikzplot42.egg-info/PKG-INFO +1 -1
  12. {tikzplot42-0.6.3 → tikzplot42-0.6.4}/tests/test16.py +1 -1
  13. {tikzplot42-0.6.3 → tikzplot42-0.6.4}/tests/test5.py +1 -1
  14. {tikzplot42-0.6.3 → tikzplot42-0.6.4}/LICENSE +0 -0
  15. {tikzplot42-0.6.3 → tikzplot42-0.6.4}/README.md +0 -0
  16. {tikzplot42-0.6.3 → tikzplot42-0.6.4}/setup.cfg +0 -0
  17. {tikzplot42-0.6.3 → tikzplot42-0.6.4}/src/tikzplot/__init__.py +0 -0
  18. {tikzplot42-0.6.3 → tikzplot42-0.6.4}/src/tikzplot/__init__.pyi +0 -0
  19. {tikzplot42-0.6.3 → tikzplot42-0.6.4}/src/tikzplot/arrows.py +0 -0
  20. {tikzplot42-0.6.3 → tikzplot42-0.6.4}/src/tikzplot/axes3d.pyi +0 -0
  21. {tikzplot42-0.6.3 → tikzplot42-0.6.4}/src/tikzplot/border_finder.py +0 -0
  22. {tikzplot42-0.6.3 → tikzplot42-0.6.4}/src/tikzplot/colorbar.py +0 -0
  23. {tikzplot42-0.6.3 → tikzplot42-0.6.4}/src/tikzplot/colorbar.pyi +0 -0
  24. {tikzplot42-0.6.3 → tikzplot42-0.6.4}/src/tikzplot/colors.py +0 -0
  25. {tikzplot42-0.6.3 → tikzplot42-0.6.4}/src/tikzplot/config.py +0 -0
  26. {tikzplot42-0.6.3 → tikzplot42-0.6.4}/src/tikzplot/config.pyi +0 -0
  27. {tikzplot42-0.6.3 → tikzplot42-0.6.4}/src/tikzplot/elements.pyi +0 -0
  28. {tikzplot42-0.6.3 → tikzplot42-0.6.4}/src/tikzplot/latex_special.py +0 -0
  29. {tikzplot42-0.6.3 → tikzplot42-0.6.4}/src/tikzplot/pie.py +0 -0
  30. {tikzplot42-0.6.3 → tikzplot42-0.6.4}/src/tikzplot/py.typed +0 -0
  31. {tikzplot42-0.6.3 → tikzplot42-0.6.4}/src/tikzplot/state.py +0 -0
  32. {tikzplot42-0.6.3 → tikzplot42-0.6.4}/src/tikzplot/styles.py +0 -0
  33. {tikzplot42-0.6.3 → tikzplot42-0.6.4}/src/tikzplot/styles.pyi +0 -0
  34. {tikzplot42-0.6.3 → tikzplot42-0.6.4}/src/tikzplot/texts.py +0 -0
  35. {tikzplot42-0.6.3 → tikzplot42-0.6.4}/src/tikzplot42.egg-info/SOURCES.txt +0 -0
  36. {tikzplot42-0.6.3 → tikzplot42-0.6.4}/src/tikzplot42.egg-info/dependency_links.txt +0 -0
  37. {tikzplot42-0.6.3 → tikzplot42-0.6.4}/src/tikzplot42.egg-info/requires.txt +0 -0
  38. {tikzplot42-0.6.3 → tikzplot42-0.6.4}/src/tikzplot42.egg-info/top_level.txt +0 -0
  39. {tikzplot42-0.6.3 → tikzplot42-0.6.4}/tests/test1.py +0 -0
  40. {tikzplot42-0.6.3 → tikzplot42-0.6.4}/tests/test10.py +0 -0
  41. {tikzplot42-0.6.3 → tikzplot42-0.6.4}/tests/test11.py +0 -0
  42. {tikzplot42-0.6.3 → tikzplot42-0.6.4}/tests/test12.py +0 -0
  43. {tikzplot42-0.6.3 → tikzplot42-0.6.4}/tests/test13.py +0 -0
  44. {tikzplot42-0.6.3 → tikzplot42-0.6.4}/tests/test14.py +0 -0
  45. {tikzplot42-0.6.3 → tikzplot42-0.6.4}/tests/test15.py +0 -0
  46. {tikzplot42-0.6.3 → tikzplot42-0.6.4}/tests/test17.py +0 -0
  47. {tikzplot42-0.6.3 → tikzplot42-0.6.4}/tests/test18.py +0 -0
  48. {tikzplot42-0.6.3 → tikzplot42-0.6.4}/tests/test19.py +0 -0
  49. {tikzplot42-0.6.3 → tikzplot42-0.6.4}/tests/test2.py +0 -0
  50. {tikzplot42-0.6.3 → tikzplot42-0.6.4}/tests/test20.py +0 -0
  51. {tikzplot42-0.6.3 → tikzplot42-0.6.4}/tests/test21.py +0 -0
  52. {tikzplot42-0.6.3 → tikzplot42-0.6.4}/tests/test22.py +0 -0
  53. {tikzplot42-0.6.3 → tikzplot42-0.6.4}/tests/test23.py +0 -0
  54. {tikzplot42-0.6.3 → tikzplot42-0.6.4}/tests/test24.py +0 -0
  55. {tikzplot42-0.6.3 → tikzplot42-0.6.4}/tests/test25.py +0 -0
  56. {tikzplot42-0.6.3 → tikzplot42-0.6.4}/tests/test26.py +0 -0
  57. {tikzplot42-0.6.3 → tikzplot42-0.6.4}/tests/test27.py +0 -0
  58. {tikzplot42-0.6.3 → tikzplot42-0.6.4}/tests/test28.py +0 -0
  59. {tikzplot42-0.6.3 → tikzplot42-0.6.4}/tests/test3.py +0 -0
  60. {tikzplot42-0.6.3 → tikzplot42-0.6.4}/tests/test4.py +0 -0
  61. {tikzplot42-0.6.3 → tikzplot42-0.6.4}/tests/test6.py +0 -0
  62. {tikzplot42-0.6.3 → tikzplot42-0.6.4}/tests/test7.py +0 -0
  63. {tikzplot42-0.6.3 → tikzplot42-0.6.4}/tests/test8.py +0 -0
  64. {tikzplot42-0.6.3 → tikzplot42-0.6.4}/tests/test9.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: tikzplot42
3
- Version: 0.6.3
3
+ Version: 0.6.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
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "tikzplot42"
7
- version = "0.6.3"
7
+ version = "0.6.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" }
@@ -539,6 +539,7 @@ class BaseAxes:
539
539
  else:
540
540
  lines[0].append(list(zip(x_seg, y_seg)))
541
541
  ol = None
542
+ settings["empty line"] = "jump"
542
543
  if cmap is not None:
543
544
  vmin = 0
544
545
  vmax = _np.max(_np.hypot(u, v))
@@ -547,7 +548,6 @@ class BaseAxes:
547
548
  self._get_free_overlay(cb=cb)
548
549
  ol = self._get_overlay()
549
550
  self._cmap_bar[ol] = cb
550
- settings["empty line"] = "jump"
551
551
  settings["mesh"] = None
552
552
  settings["point meta"] = "explicit"
553
553
  st["color"] = True
@@ -592,7 +592,7 @@ class BaseAxes:
592
592
  arrow_u.append(pu / p_norm)
593
593
  arrow_v.append(pv / p_norm)
594
594
  arrow_c.append(p_norm)
595
- sc = 1e-5 * max(domain_dx, domain_dy) / _np.max(_np.hypot(u, v))
595
+ sc = 1e-2 * max(domain_dx, domain_dy)
596
596
  if len(arrow_x) > 0:
597
597
  if cmap is not None:
598
598
  self.quiver(_np.array(arrow_x), _np.array(arrow_y), _np.array(arrow_u), _np.array(arrow_v), _np.array(arrow_c), scale=sc, pivot="middle", lw=arrowsize/2, cmap=cmap, vmin=0, vmax=_np.max(_np.hypot(u, v)))
@@ -1332,7 +1332,7 @@ class BaseAxes:
1332
1332
  overlay = self._get_free_overlay()
1333
1333
  self._overlay_special[overlay] = {"stack plots": "y", "area style": None}
1334
1334
  if base_set != "zero":
1335
- self._plot(x, baseline, overlay=overlay, alpha=0)
1335
+ self._plot(x, baseline, overlay=overlay, alpha=0, settings={"stackplot": {}})
1336
1336
  datas = {}
1337
1337
  for kw in ["labels", "colors", "alpha", "facecolor", "fc", "edgecolor", "ec", "linewidth", "lw", "linestyle", "ls", "hatch", "hatch_color", "hatch_linewidth", "hatch_distance"]:
1338
1338
  if kw in kwargs:
@@ -1352,7 +1352,7 @@ class BaseAxes:
1352
1352
  for i in range(len(y)):
1353
1353
  kws = {kw: datas[kw][i] for kw in datas}
1354
1354
  kws["_endnotes"] = r"\closedcycle"
1355
- output.append(self._plot(x, y[i], overlay=overlay, settings={"fill": None}, **kws))
1355
+ output.append(self._plot(x, y[i], overlay=overlay, settings={"fill": None, "stackplot": {}}, **kws))
1356
1356
  return output
1357
1357
 
1358
1358
  def step(self, x, y, *args, **kwargs):
@@ -1811,7 +1811,7 @@ class BaseAxes:
1811
1811
  if "fontsize" in kwargs:
1812
1812
  st["font"] = self._tex_fontsize(kwargs["fontsize"])
1813
1813
  if st:
1814
- self._update_axis_options("y tick style", st)
1814
+ self._update_axis_options("y tick label style", st)
1815
1815
  passing = {k: kwargs[k] for k in pass_to_labels if k in kwargs}
1816
1816
  if passing:
1817
1817
  self.set_yticklabels(**passing)
@@ -1870,7 +1870,7 @@ class BaseAxes:
1870
1870
  elif ha != "center":
1871
1871
  raise Warning(f"Invalid horizontalalignment: {ha}. Must be one of 'left', 'right', or 'center'.")
1872
1872
  if st:
1873
- self._update_axis_options("y tick style", st)
1873
+ self._update_axis_options("y tick label style", st)
1874
1874
  if list(labels) != []:
1875
1875
  if len(labels) == 1 and isinstance(labels[0], (list, tuple)):
1876
1876
  if len(labels[0]) > 0:
@@ -2550,7 +2550,7 @@ class BaseAxes:
2550
2550
  kws = {"alpha", "color", "c", "fontsize", "on_top", "size", "backgroundcolor", "horizontalalignment", "ha", "verticalalignment", "va", "rotation", "label"}
2551
2551
  kwargs = self._check_kwargs("text", kws, **kwargs)
2552
2552
  if "fontsize" in kwargs or "size" in kwargs:
2553
- kwargs["fontsize"] = kwargs.pop("size", kwargs.pop("fontsize"))
2553
+ kwargs["fontsize"] = self._tex_fontsize(kwargs.pop("size", kwargs.pop("fontsize")))
2554
2554
  on_top = kwargs.pop("on_top", True)
2555
2555
  if on_top:
2556
2556
  assert self._fig is not None
@@ -2711,14 +2711,6 @@ class BaseAxes:
2711
2711
  for e in self._get_all_elements():
2712
2712
  e._filter(which, value)
2713
2713
 
2714
- def _num_points(self):
2715
- return [e._num_points() for e in self._get_all_elements()]
2716
-
2717
- def _reduce_points(self, limit):
2718
- for e in self._get_all_elements():
2719
- if e._num_points() > 0:
2720
- e._reduce_points(limit)
2721
-
2722
2714
  def _add_col(self, r,g,b):
2723
2715
  assert self._fig is not None
2724
2716
  self._fig._add_col(r,g,b)
@@ -3103,10 +3095,15 @@ class Axes(BaseAxes):
3103
3095
  self._elements[0].insert(0, Graph(self, f"graphics [xmin={xm}, xmax={xM}, ymin={ym}, ymax={yM}] {{{im_name}}}", settings={}, xerr=None, yerr=None, onlayer="axis background"))
3104
3096
  if self._hidable and self._get_all_elements() == [] and self._secondary_y is None:
3105
3097
  self._axis_options["hide axis"] = None
3106
- axis_opt_str = ""
3107
- auxiliary_opt_str = ""
3098
+ axis_opt_str: dict[int, str] = {0: "", 1: "", 2: "", 3: ""} # 0 - lower, 1 - any, 2 - top, 3 - single
3099
+ def _add_to_ax_opt(which: int|Iterable[int], entry:str):
3100
+ if isinstance(which, int):
3101
+ axis_opt_str[which] += entry
3102
+ else:
3103
+ for i in which:
3104
+ axis_opt_str[i] += entry
3108
3105
  if TikzConfig.SCHOOL_AXIS:
3109
- 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}}"
3106
+ axis_opt_str[1] += 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}}"
3110
3107
  if ("xmin" in self._axis_options and self._axis_options["xmin"] == 0) or ("xmax" in self._axis_options and self._axis_options["xmax"] == 0):
3111
3108
  self._axis_options["extra x ticks"] = r"{0}"
3112
3109
  if ("ymin" in self._axis_options and self._axis_options["ymin"] == 0) or ("ymax" in self._axis_options and self._axis_options["ymax"] == 0):
@@ -3115,16 +3112,16 @@ class Axes(BaseAxes):
3115
3112
  if "set layers" in self._axis_args:
3116
3113
  self._axis_args.remove("set layers")
3117
3114
  if TikzConfig.SCHOOL_AXIS:
3118
- axis_opt_str += f",\n set layers,\n axis line style={{on layer=axis foreground}}"
3119
- auxiliary_opt_str += ",\n set layers"
3115
+ axis_opt_str[2] += f",\n set layers,\n axis line style={{on layer=axis foreground}}"
3116
+ _add_to_ax_opt((0,1), ",\n set layers")
3120
3117
  else:
3121
3118
  if self._get_all_elements() != []:
3122
- axis_opt_str += f",\nset layers=standard, cell picture=true, grid style={{on layer=axis grid}}"
3123
- auxiliary_opt_str += "set layers=standard"
3119
+ axis_opt_str[2] += f",\nset layers=standard, cell picture=true, grid style={{on layer=axis grid}}"
3120
+ _add_to_ax_opt((0,1), "set layers=standard")
3124
3121
  if self._axis_args and not (self._hidable and self._get_all_elements() == [] and self._secondary_y is None):
3125
- axis_opt_str = ",\n".join(self._axis_args) + axis_opt_str
3122
+ axis_opt_str[2] = ",\n".join(self._axis_args) + axis_opt_str[2]
3126
3123
  if "set layers" in self._axis_args:
3127
- auxiliary_opt_str += ",\n set layers"
3124
+ _add_to_ax_opt((0,1), ",\n set layers")
3128
3125
  if self._ext_xmin or self._ext_xmax:
3129
3126
  lower = self._get_range("xmin")
3130
3127
  upper = self._get_range("xmax")
@@ -3156,16 +3153,24 @@ class Axes(BaseAxes):
3156
3153
  if self._int_ymax is not None and (upper[0] is None or upper[0] <= self._int_ymax):
3157
3154
  self._axis_options["ymax"] = self._int_ymax
3158
3155
  if self._axis_options:
3159
- if axis_opt_str: axis_opt_str += ",\n"
3160
- if auxiliary_opt_str: auxiliary_opt_str += ",\n"
3156
+ axis_opt_str[3] = axis_opt_str[2]
3157
+ for k in axis_opt_str:
3158
+ if axis_opt_str[k] and not axis_opt_str[k].endswith(",\n"):
3159
+ axis_opt_str[k] += ",\n"
3161
3160
  for k, v in self._axis_options.items():
3162
3161
  if v != {}:
3163
3162
  entry = self._parse_entry(k,v)
3164
- axis_opt_str += entry + ",\n"
3163
+ axis_opt_str[3] += entry + ",\n"
3164
+ to_back = ["grid"]
3165
+ if any(q in k for q in to_back):
3166
+ axis_opt_str[0] += entry + ",\n"
3167
+ else:
3168
+ axis_opt_str[2] += entry + ",\n"
3165
3169
  if k in ["xmin", "xmax", "ymin", "ymax", "xmode", "ymode", "log basis x", "log basis y", "width", "height", "at"]:
3166
- auxiliary_opt_str += entry + ",\n"
3167
- axis_opt_str = axis_opt_str.removesuffix(",,\n")
3168
- auxiliary_opt_str = auxiliary_opt_str.removesuffix(",,\n")
3170
+ _add_to_ax_opt((0,1), entry + ",\n")
3171
+ axis_opt_str[0] += "axis line style={draw=none},\n tick style={draw=none},\n minor tick style={draw=none},\n xticklabels={},\n yticklabels={},\n"
3172
+ for k in axis_opt_str:
3173
+ axis_opt_str[k] = axis_opt_str[k].removesuffix(",,\n").strip("\n")
3169
3174
  adds = {}
3170
3175
  for c in self._elements.keys():
3171
3176
  adds[c] = ""
@@ -3175,7 +3180,8 @@ class Axes(BaseAxes):
3175
3180
  cm = self._cmap_bar[c]
3176
3181
  assert isinstance(cm, Colorbar)
3177
3182
  adds[c] += f"colormap={cm._generate_tex_colormap(cm._cmap)},\n"
3178
- return axis_opt_str, "hide axis,\n" + auxiliary_opt_str, alias, adds
3183
+ axis_opt_str[1] = "hide axis,\n" + axis_opt_str[1]
3184
+ return axis_opt_str, alias, adds
3179
3185
 
3180
3186
  def _parse_entry(self, k, v):
3181
3187
  if v is None:
@@ -3200,12 +3206,16 @@ class Axes(BaseAxes):
3200
3206
  self._virtual = True
3201
3207
  from .border_finder import _get_sizes
3202
3208
  self._ext_xmin = self._ext_xmax = self._ext_ymin = self._ext_ymax = True
3203
- main, aux, alias, adds = self._axis_option_string()
3204
- if 0 in adds:
3209
+ main, alias, adds = self._axis_option_string()
3210
+ aux = main[1]
3211
+ main = main[2]
3212
+ if not self._fig._tight_params.get("ignore_colorbars", False) and 0 in adds:
3205
3213
  main += adds[0]
3206
3214
  main = r"""\begin{axis}[""" + main + r"]" + r"\end{axis}" + "\n"
3207
3215
  if self._secondary_y is not None:
3208
- main2, aux2 = self._secondary_y._axis_option_string()
3216
+ main2 = self._secondary_y._axis_option_string()
3217
+ aux2 = main2[1]
3218
+ main2 = main2[2]
3209
3219
  main2 = r"""\begin{axis}[""" + main2 + r"]" + r"\end{axis}" + "\n"
3210
3220
  main += main2
3211
3221
  for k in adds:
@@ -3283,12 +3293,18 @@ class Axes(BaseAxes):
3283
3293
  self._fig._add_required_package("\\usepgfplotslibrary{polar}")
3284
3294
  elif self._projection == "smith":
3285
3295
  self._fig._add_required_package("\\usepgfplotslibrary{smithchart}")
3286
- main_ax, aux_ax, alias, adds = self._axis_option_string()
3296
+ ax_opt, alias, adds = self._axis_option_string()
3297
+ aux_ax = ax_opt[1]
3298
+ if len (self._elements) <= 1:
3299
+ main_ax = ax_opt[3]
3300
+ else:
3301
+ main_ax = ax_opt[2]
3287
3302
  contents = self._content_tex(filename)
3288
3303
  if self._extend is not None:
3289
3304
  lines.append(f"\\nextgroupplot[alias={alias}, width={self._extend[0]}cm, height={self._extend[1]}cm, hide axis]")
3290
3305
  for i in self._elements.keys():
3291
- 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 ""
3306
+ spec = ",\n".join([self._parse_entry(k, v) for k, v in self._overlay_special.get(i, {}).items()]) + "," if i in self._overlay_special else ""
3307
+ spec = spec.strip("\n")
3292
3308
  if self._projection == "polar":
3293
3309
  lines2.append("\\begin{polaraxis}["+ f"\n at={{({alias}.south west)}},")
3294
3310
  elif self._projection == "smith":
@@ -3298,9 +3314,18 @@ class Axes(BaseAxes):
3298
3314
  if TikzConfig.SCALE_ONLY_AXIS:
3299
3315
  lines2.append("scale only axis,")
3300
3316
  if i == self._get_overlay():
3301
- lines2.append(f"{main_ax}{spec}\n]")
3317
+ if i in adds and adds[i] != "":
3318
+ addit = adds[i]
3319
+ addit = addit.replace(f"at={{({alias}", f"at={{({alias}a")
3320
+ addit = f"alias={alias}a,\n" + addit
3321
+ lines2.append(f"{main_ax}{spec+addit}\n]")
3322
+ else:
3323
+ lines2.append(f"{main_ax}{spec}\n]")
3302
3324
  else:
3303
- lines2.append(f"{aux_ax}{spec}\n]")
3325
+ if i == 0:
3326
+ lines2.append(f"{ax_opt[0]}{spec}\n]")
3327
+ else:
3328
+ lines2.append(f"{aux_ax}{spec}\n]")
3304
3329
  lines2.append(contents[i])
3305
3330
  if i == self._get_overlay() and self._overlay_legend:
3306
3331
  lines2 += self._overlay_legend_entries
@@ -3314,19 +3339,28 @@ class Axes(BaseAxes):
3314
3339
  else:
3315
3340
  lines2.append("\\end{axis}")
3316
3341
  if self._secondary_y is not None:
3317
- main_ax2, aux_ax2 = self._secondary_y._axis_option_string()
3342
+ ax_opt2 = self._secondary_y._axis_option_string()
3343
+ aux_ax2 = ax_opt2[1]
3344
+ if len (self._secondary_y._elements) <= 1:
3345
+ main_ax2 = ax_opt2[3]
3346
+ else:
3347
+ main_ax2 = ax_opt2[2]
3318
3348
  contents2 = self._secondary_y._content_tex(filename)
3319
3349
  for i in self._secondary_y._elements.keys():
3320
3350
  lines2.append("\\begin{axis}[")
3321
3351
  if TikzConfig.SCALE_ONLY_AXIS:
3322
3352
  lines2.append("scale only axis,")
3323
- 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 ""
3353
+ spec = ",\n".join([self._parse_entry(k, v) for k, v in self._secondary_y._overlay_special.get(i, {}).items()]) + "," if i in self._secondary_y._overlay_special else ""
3324
3354
  if i in adds:
3325
3355
  spec += adds[i]
3356
+ spec = spec.strip("\n")
3326
3357
  if i == sorted(self._secondary_y._elements.keys())[-1]:
3327
3358
  lines2.append(f"{main_ax2}{spec}\n]")
3328
3359
  else:
3329
- lines2.append(f"{aux_ax2}{spec}\n]")
3360
+ if i == 0:
3361
+ lines2.append(f"{ax_opt2[0]}{spec}\n]")
3362
+ else:
3363
+ lines2.append(f"{aux_ax2}{spec}\n]")
3330
3364
  lines2.append(contents2[i])
3331
3365
  if i == sorted(self._secondary_y._elements.keys())[-1]:
3332
3366
  lines2 += self._secondary_y._overlay_legend_entries
@@ -3337,9 +3371,10 @@ class Axes(BaseAxes):
3337
3371
  elif self._projection in ["polar", "smith"] and TikzConfig.USE_GROUPPLOTS and not single:
3338
3372
  lines.append(f"\\nextgroupplot[alias={alias}, width={self._width}, height={self._height}, hide axis]")
3339
3373
  for i in self._elements.keys():
3340
- 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 ""
3374
+ spec = ",\n".join([self._parse_entry(k, v) for k, v in self._overlay_special.get(i, {}).items()]) + "," if i in self._overlay_special else ""
3341
3375
  if i in adds:
3342
3376
  spec += adds[i]
3377
+ spec = spec.strip("\n")
3343
3378
  if self._projection == "polar":
3344
3379
  lines2.append("\\begin{polaraxis}["+ f"\n at={{({alias}.south west)}},")
3345
3380
  elif self._projection == "smith":
@@ -3371,28 +3406,31 @@ class Axes(BaseAxes):
3371
3406
  if TikzConfig.SCALE_ONLY_AXIS:
3372
3407
  lines.append("scale only axis,")
3373
3408
  if self._get_overlay() == 0:
3374
- 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 ""
3409
+ spec = ",\n".join([self._parse_entry(k, v) for k, v in self._overlay_special.get(0, {}).items()]) + "," if 0 in self._overlay_special else ""
3375
3410
  if 0 in adds:
3376
3411
  spec += adds[0]
3412
+ spec = spec.strip("\n")
3377
3413
  if self._secondary_y is not None or any([c is not None for c in self._colorbar.values()]) or self._externs:
3378
3414
  lines.append(f"{main_ax}{spec}alias={alias}\n]")
3379
3415
  else:
3380
3416
  lines.append(f"{main_ax}{spec}\n]")
3381
3417
  lines.append(contents[0])
3382
3418
  else:
3383
- 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 ""
3419
+ spec = ",\n".join([self._parse_entry(k, v) for k, v in self._overlay_special.get(0, {}).items()]) + "," if 0 in self._overlay_special else ""
3384
3420
  if 0 in adds:
3385
3421
  spec += adds[0]
3422
+ spec = spec.strip("\n")
3386
3423
  if len(contents[0]) == 0:
3387
- lines.append(f"{aux_ax}{spec}alias={alias}\n]".replace("set layers=standard,\n", ""))
3424
+ lines.append(f"{ax_opt[0]}{spec}alias={alias}\n]".replace("set layers=standard,\n", ""))
3388
3425
  else:
3389
- lines.append(f"{aux_ax}{spec}alias={alias}\n]")
3426
+ lines.append(f"{ax_opt[0]}{spec}alias={alias}\n]")
3390
3427
  lines.append(contents[0])
3391
3428
  for i in self._elements.keys():
3392
3429
  if i == 0: continue
3393
- 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 ""
3430
+ spec = ",\n".join([self._parse_entry(k, v) for k, v in self._overlay_special.get(i, {}).items()]) + "," if i in self._overlay_special else ""
3394
3431
  if i in adds:
3395
3432
  spec += adds[i]
3433
+ spec = spec.strip("\n")
3396
3434
  lines2.append("\\begin{axis}[")
3397
3435
  if TikzConfig.SCALE_ONLY_AXIS:
3398
3436
  lines2.append("scale only axis,")
@@ -3420,17 +3458,26 @@ class Axes(BaseAxes):
3420
3458
  elif not TikzConfig.USE_GROUPPLOTS or (TikzConfig.USE_GROUPPLOTS and single):
3421
3459
  lines.append("\\end{axis}")
3422
3460
  if self._secondary_y is not None:
3423
- main_ax2, aux_ax2 = self._secondary_y._axis_option_string()
3461
+ ax_opt2 = self._secondary_y._axis_option_string()
3462
+ aux_ax2 = ax_opt2[1]
3463
+ if len (self._secondary_y._elements) <= 1:
3464
+ main_ax2 = ax_opt2[3]
3465
+ else:
3466
+ main_ax2 = ax_opt2[2]
3424
3467
  contents2 = self._secondary_y._content_tex(filename)
3425
3468
  for i in self._secondary_y._elements.keys():
3426
3469
  lines2.append("\\begin{axis}[")
3427
3470
  if TikzConfig.SCALE_ONLY_AXIS:
3428
3471
  lines2.append("scale only axis,")
3429
- 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 ""
3472
+ spec = ",\n".join([self._parse_entry(k, v) for k, v in self._secondary_y._overlay_special.get(i, {}).items()]) + "," if i in self._secondary_y._overlay_special else ""
3473
+ spec = spec.strip("\n")
3430
3474
  if i == sorted(self._secondary_y._elements.keys())[-1]:
3431
3475
  lines2.append(f"{main_ax2}{spec}\n]")
3432
3476
  else:
3433
- lines2.append(f"{aux_ax2}{spec}\n]")
3477
+ if i == 0:
3478
+ lines2.append(f"{ax_opt2[0]}{spec}\n]")
3479
+ else:
3480
+ lines2.append(f"{aux_ax2}{spec}\n]")
3434
3481
  lines2.append(contents2[i])
3435
3482
  if i == sorted(self._secondary_y._elements.keys())[-1]:
3436
3483
  lines2 += self._secondary_y._overlay_legend_entries
@@ -3463,6 +3510,18 @@ class Axes(BaseAxes):
3463
3510
  if position not in ["above", "below", "left", "right"]:
3464
3511
  raise ValueError(f"Invalid position: {position}. Must be one of 'above', 'below', 'left', or 'right'.")
3465
3512
  return self._fig._inset(self, position, relsize=relsize, sharex=sharex, sharey=sharey)
3513
+
3514
+ def _num_points(self):
3515
+ if self._secondary_y is not None:
3516
+ return [e._num_points() for e in self._get_all_elements()] + self._secondary_y._num_points()
3517
+ return [e._num_points() for e in self._get_all_elements()]
3518
+
3519
+ def _reduce_points(self, limit):
3520
+ for e in self._get_all_elements():
3521
+ if e._num_points() > 0:
3522
+ e._reduce_points(limit)
3523
+ if self._secondary_y is not None:
3524
+ self._secondary_y._reduce_points(limit)
3466
3525
 
3467
3526
  class Secondary(BaseAxes):
3468
3527
  def __init__(self, primary):
@@ -3489,11 +3548,10 @@ class Secondary(BaseAxes):
3489
3548
  self._axis_options["width"] = self._primary._width
3490
3549
  if self._primary._height:
3491
3550
  self._axis_options["height"] = self._primary._height
3492
- axis_opt_str = ""
3493
- auxiliary_opt_str = ""
3551
+ axis_opt_str: dict[int, str] = {0: "", 1: "", 2: "", 3: ""} # 0 - lower, 1 - any, 2 - top, 3 - single
3494
3552
  if self._axis_args:
3495
- axis_opt_str += ",\n".join(self._axis_args)
3496
- auxiliary_opt_str += ",\n".join(self._axis_args)
3553
+ for i in [1,2,3]:
3554
+ axis_opt_str[i] += ",\n".join(self._axis_args)
3497
3555
  if self._ext_ymin or self._ext_ymax:
3498
3556
  lower = self._get_range("ymin")
3499
3557
  upper = self._get_range("ymax")
@@ -3504,9 +3562,15 @@ class Secondary(BaseAxes):
3504
3562
  self._axis_options["ymax"] = self._fig._next_limname("ymax", self._axis_options.get("ymax", yM))
3505
3563
  self._axis_options["xmin"] = self._primary._axis_options["xmin"]
3506
3564
  self._axis_options["xmax"] = self._primary._axis_options["xmax"]
3565
+ if "xmode" in self._primary._axis_options:
3566
+ self._axis_options["xmode"] = self._primary._axis_options["xmode"]
3567
+ if "log basis x" in self._primary._axis_options:
3568
+ self._axis_options["log basis x"] = self._primary._axis_options["log basis x"]
3507
3569
  if self._axis_options:
3508
- if axis_opt_str: axis_opt_str += ",\n"
3509
- if auxiliary_opt_str: auxiliary_opt_str += ",\n"
3570
+ axis_opt_str[3] = axis_opt_str[2]
3571
+ for k in axis_opt_str:
3572
+ if axis_opt_str[k] and not axis_opt_str[k].endswith(",\n"):
3573
+ axis_opt_str[k] += ",\n"
3510
3574
  def parse_entry(k,v):
3511
3575
  if isinstance(v, dict):
3512
3576
  return f"{k}={{" + ",\n".join(f"{kk}={vv}" for kk, vv in v.items()) + "}"
@@ -3514,10 +3578,20 @@ class Secondary(BaseAxes):
3514
3578
  return f"{k}={v}"
3515
3579
  for k, v in self._axis_options.items():
3516
3580
  entry = parse_entry(k,v)
3517
- axis_opt_str += entry + ",\n"
3581
+ axis_opt_str[3] += entry + ",\n"
3582
+ to_back = ["grid"]
3583
+ if any(q in k for q in to_back):
3584
+ axis_opt_str[0] += entry + ",\n"
3585
+ else:
3586
+ axis_opt_str[2] += entry + ",\n"
3518
3587
  if k in ["xmin", "xmax", "ymin", "ymax", "xmode", "ymode", "log basis x", "log basis y", "width", "height", "at", "axis y line*", "axis x line", "anchor"]:
3519
- auxiliary_opt_str += entry + ",\n"
3520
- return axis_opt_str, "hide axis,\n" + auxiliary_opt_str
3588
+ axis_opt_str[0] += entry + ",\n"
3589
+ axis_opt_str[1] += entry + ",\n"
3590
+ axis_opt_str[0] += "axis line style={draw=none},\n tick style={draw=none},\n minor tick style={draw=none},\n xticklabels={},\n yticklabels={},\n"
3591
+ for k in axis_opt_str:
3592
+ axis_opt_str[k] = axis_opt_str[k].removesuffix(",,\n").strip("\n")
3593
+ axis_opt_str[1] = "hide axis,\n" + axis_opt_str[1]
3594
+ return axis_opt_str
3521
3595
 
3522
3596
  def _padding(self):
3523
3597
  return TikzConfig.SEC_Y_PADDING + TikzConfig.YTICK_PADDING * self._yticks + TikzConfig.SEC_Y_LABEL_PADDING * ("ylabel" in self._axis_options)
@@ -3526,4 +3600,12 @@ class Secondary(BaseAxes):
3526
3600
  return self._primary._get_defcol(index)
3527
3601
 
3528
3602
  def _get_index(self):
3529
- return self._primary._get_index()
3603
+ return self._primary._get_index()
3604
+
3605
+ def _num_points(self):
3606
+ return [e._num_points() for e in self._get_all_elements()]
3607
+
3608
+ def _reduce_points(self, limit):
3609
+ for e in self._get_all_elements():
3610
+ if e._num_points() > 0:
3611
+ e._reduce_points(limit)