plotnine 0.14.5__py3-none-any.whl → 0.15.0.dev2__py3-none-any.whl

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. plotnine/__init__.py +31 -37
  2. plotnine/_mpl/gridspec.py +265 -0
  3. plotnine/_mpl/layout_manager/__init__.py +6 -0
  4. plotnine/_mpl/layout_manager/_engine.py +87 -0
  5. plotnine/_mpl/layout_manager/_layout_items.py +916 -0
  6. plotnine/_mpl/layout_manager/_layout_tree.py +625 -0
  7. plotnine/_mpl/layout_manager/_spaces.py +1007 -0
  8. plotnine/_mpl/patches.py +1 -1
  9. plotnine/_mpl/text.py +59 -24
  10. plotnine/_mpl/utils.py +78 -10
  11. plotnine/_utils/__init__.py +5 -5
  12. plotnine/_utils/dev.py +45 -27
  13. plotnine/animation.py +1 -1
  14. plotnine/coords/coord_trans.py +1 -1
  15. plotnine/data/__init__.py +12 -8
  16. plotnine/doctools.py +1 -1
  17. plotnine/facets/facet.py +30 -39
  18. plotnine/facets/facet_grid.py +14 -6
  19. plotnine/facets/facet_wrap.py +3 -5
  20. plotnine/facets/strips.py +7 -9
  21. plotnine/geoms/geom_crossbar.py +2 -3
  22. plotnine/geoms/geom_path.py +1 -1
  23. plotnine/ggplot.py +94 -65
  24. plotnine/guides/guide.py +12 -10
  25. plotnine/guides/guide_colorbar.py +3 -3
  26. plotnine/guides/guide_legend.py +12 -13
  27. plotnine/guides/guides.py +3 -3
  28. plotnine/iapi.py +5 -2
  29. plotnine/labels.py +5 -0
  30. plotnine/mapping/aes.py +4 -3
  31. plotnine/options.py +14 -7
  32. plotnine/plot_composition/__init__.py +10 -0
  33. plotnine/plot_composition/_compose.py +436 -0
  34. plotnine/plot_composition/_plotspec.py +50 -0
  35. plotnine/plot_composition/_spacer.py +32 -0
  36. plotnine/positions/position_dodge.py +1 -1
  37. plotnine/positions/position_dodge2.py +1 -1
  38. plotnine/positions/position_stack.py +1 -2
  39. plotnine/qplot.py +1 -2
  40. plotnine/scales/__init__.py +0 -6
  41. plotnine/scales/scale.py +1 -1
  42. plotnine/stats/binning.py +1 -1
  43. plotnine/stats/smoothers.py +3 -5
  44. plotnine/stats/stat_density.py +1 -1
  45. plotnine/stats/stat_qq_line.py +1 -1
  46. plotnine/stats/stat_sina.py +1 -1
  47. plotnine/themes/elements/__init__.py +2 -0
  48. plotnine/themes/elements/element_text.py +35 -24
  49. plotnine/themes/elements/margin.py +73 -60
  50. plotnine/themes/targets.py +3 -1
  51. plotnine/themes/theme.py +13 -7
  52. plotnine/themes/theme_gray.py +28 -31
  53. plotnine/themes/theme_matplotlib.py +25 -28
  54. plotnine/themes/theme_seaborn.py +31 -34
  55. plotnine/themes/theme_void.py +17 -26
  56. plotnine/themes/themeable.py +290 -157
  57. {plotnine-0.14.5.dist-info → plotnine-0.15.0.dev2.dist-info}/METADATA +4 -3
  58. {plotnine-0.14.5.dist-info → plotnine-0.15.0.dev2.dist-info}/RECORD +61 -54
  59. {plotnine-0.14.5.dist-info → plotnine-0.15.0.dev2.dist-info}/WHEEL +1 -1
  60. plotnine/_mpl/_plot_side_space.py +0 -888
  61. plotnine/_mpl/_plotnine_tight_layout.py +0 -293
  62. plotnine/_mpl/layout_engine.py +0 -110
  63. {plotnine-0.14.5.dist-info → plotnine-0.15.0.dev2.dist-info/licenses}/LICENSE +0 -0
  64. {plotnine-0.14.5.dist-info → plotnine-0.15.0.dev2.dist-info}/top_level.txt +0 -0
@@ -171,7 +171,7 @@ def compute_density(x, weight, range, **params):
171
171
  x = np.asarray(x, dtype=float)
172
172
  not_nan = ~np.isnan(x)
173
173
  x = x[not_nan]
174
- bw = cast(str | float, params["bw"])
174
+ bw = cast("str | float", params["bw"])
175
175
  kernel = params["kernel"]
176
176
  bounds = params["bounds"]
177
177
  has_bounds = not (np.isneginf(bounds[0]) and np.isposinf(bounds[1]))
@@ -62,7 +62,7 @@ class stat_qq_line(stat):
62
62
  def setup_params(self, data):
63
63
  if len(self.params["line_p"]) != 2:
64
64
  raise PlotnineError(
65
- "Cannot fit line quantiles. " "'line_p' must be of length 2"
65
+ "Cannot fit line quantiles. 'line_p' must be of length 2"
66
66
  )
67
67
  return self.params
68
68
 
@@ -101,7 +101,7 @@ class stat_sina(stat):
101
101
  and (data["x"] != data["x"].iloc[0]).any()
102
102
  ):
103
103
  raise TypeError(
104
- "Continuous x aesthetic -- did you forget " "aes(group=...)?"
104
+ "Continuous x aesthetic -- did you forget aes(group=...)?"
105
105
  )
106
106
  return data
107
107
 
@@ -2,10 +2,12 @@ from .element_blank import element_blank
2
2
  from .element_line import element_line
3
3
  from .element_rect import element_rect
4
4
  from .element_text import element_text
5
+ from .margin import margin
5
6
 
6
7
  __all__ = (
7
8
  "element_blank",
8
9
  "element_line",
9
10
  "element_rect",
10
11
  "element_text",
12
+ "margin",
11
13
  )
@@ -8,10 +8,10 @@ from contextlib import suppress
8
8
  from typing import TYPE_CHECKING
9
9
 
10
10
  from .element_base import element_base
11
- from .margin import Margin
11
+ from .margin import margin as Margin
12
12
 
13
13
  if TYPE_CHECKING:
14
- from typing import Any, Literal, Optional, Sequence
14
+ from typing import Any, Literal, Sequence
15
15
 
16
16
  from plotnine import theme
17
17
 
@@ -56,7 +56,7 @@ class element_text(element_base):
56
56
  Margin around the text. The keys are
57
57
  `t`, `b`, `l`, `r` and `units`.
58
58
  The `tblr` keys are floats.
59
- The `units` is one of `pt`, `lines` or `in`.
59
+ The `unit` is one of `pt`, `lines` or `in`.
60
60
  Not all text themeables support margin parameters and other
61
61
  than the `units`, only some of the other keys may apply.
62
62
  kwargs :
@@ -71,10 +71,10 @@ class element_text(element_base):
71
71
 
72
72
  def __init__(
73
73
  self,
74
- family: Optional[str | list[str]] = None,
75
- style: Optional[str | Sequence[str]] = None,
76
- weight: Optional[int | str | Sequence[int | str]] = None,
77
- color: Optional[
74
+ family: str | list[str] | None = None,
75
+ style: str | Sequence[str] | None = None,
76
+ weight: int | str | Sequence[int | str] | None = None,
77
+ color: (
78
78
  str
79
79
  | tuple[float, float, float]
80
80
  | tuple[float, float, float, float]
@@ -83,22 +83,25 @@ class element_text(element_base):
83
83
  | tuple[float, float, float]
84
84
  | tuple[float, float, float, float]
85
85
  ]
86
- ] = None,
87
- size: Optional[float | Sequence[float]] = None,
88
- ha: Optional[Literal["center", "left", "right"] | float] = None,
89
- va: Optional[
86
+ | None
87
+ ) = None,
88
+ size: float | Sequence[float] | None = None,
89
+ ha: Literal["center", "left", "right"] | float | None = None,
90
+ va: (
90
91
  Literal["center", "top", "bottom", "baseline", "center_baseline"]
91
92
  | float
92
- ] = None,
93
- ma: Optional[Literal["center", "left", "right"] | float] = None,
94
- rotation: Optional[
93
+ | None
94
+ ) = None,
95
+ ma: Literal["center", "left", "right"] | float | None = None,
96
+ rotation: (
95
97
  Literal["vertical", "horizontal"]
96
98
  | float
97
99
  | Sequence[Literal["vertical", "horizontal"]]
98
100
  | Sequence[float]
99
- ] = None,
100
- linespacing: Optional[float] = None,
101
- backgroundcolor: Optional[
101
+ | None
102
+ ) = None,
103
+ linespacing: float | None = None,
104
+ backgroundcolor: (
102
105
  str
103
106
  | tuple[float, float, float]
104
107
  | tuple[float, float, float, float]
@@ -107,10 +110,11 @@ class element_text(element_base):
107
110
  | tuple[float, float, float]
108
111
  | tuple[float, float, float, float]
109
112
  ]
110
- ] = None,
111
- margin: Optional[
112
- dict[Literal["t", "b", "l", "r", "units"], Any]
113
- ] = None,
113
+ | None
114
+ ) = None,
115
+ margin: (
116
+ Margin | dict[Literal["t", "b", "l", "r", "unit"], Any] | None
117
+ ) = None,
114
118
  rotation_mode: Literal["default", "anchor"] | None = None,
115
119
  **kwargs: Any,
116
120
  ):
@@ -139,8 +143,15 @@ class element_text(element_base):
139
143
 
140
144
  super().__init__()
141
145
  self.properties.update(**kwargs)
146
+
142
147
  if margin is not None:
143
- self.properties["margin"] = Margin(self, **margin)
148
+ if isinstance(margin, dict):
149
+ if "units" in margin:
150
+ # for backward compatibility
151
+ margin["unit"] = margin.pop("units") # pyright: ignore[reportArgumentType]
152
+ margin = Margin(**margin)
153
+
154
+ self.properties["margin"] = margin
144
155
 
145
156
  # Use the parameters that have been set
146
157
  names = (
@@ -153,6 +164,7 @@ class element_text(element_base):
153
164
  "size",
154
165
  "style",
155
166
  "va",
167
+ "ma",
156
168
  "weight",
157
169
  "rotation_mode",
158
170
  )
@@ -166,8 +178,7 @@ class element_text(element_base):
166
178
  Setup the theme_element before drawing
167
179
  """
168
180
  if m := self.properties.get("margin"):
169
- m.theme = theme
170
- m.themeable_name = themeable_name
181
+ m = m.setup(theme, themeable_name)
171
182
 
172
183
  def _translate_hjust(
173
184
  self, just: float
@@ -4,7 +4,9 @@ Theme elements used to decorate the graph.
4
4
 
5
5
  from __future__ import annotations
6
6
 
7
- from dataclasses import dataclass
7
+ from contextlib import suppress
8
+ from copy import copy
9
+ from dataclasses import dataclass, field
8
10
  from typing import TYPE_CHECKING
9
11
 
10
12
  if TYPE_CHECKING:
@@ -12,80 +14,91 @@ if TYPE_CHECKING:
12
14
 
13
15
  from plotnine import theme
14
16
 
15
- from .element_base import element_base
16
-
17
17
 
18
18
  @dataclass
19
- class Margin:
20
- element: element_base
19
+ class margin:
21
20
  t: float = 0
21
+ r: float = 0
22
22
  b: float = 0
23
23
  l: float = 0
24
- r: float = 0
25
- units: Literal["pt", "in", "lines", "fig"] = "pt"
26
-
27
- def __post_init__(self):
28
- self.theme: theme
29
- self.themeable_name: str
30
-
31
- if self.units in ("pts", "points", "px", "pixels"):
32
- self.units = "pt"
33
- elif self.units in ("in", "inch", "inches"):
34
- self.units = "in"
35
- elif self.units in ("line", "lines"):
36
- self.units = "lines"
37
-
38
- def __eq__(self, other: object) -> bool:
39
- def _size(m: Margin):
40
- return m.element.properties.get("size")
41
-
42
- return other is self or (
43
- isinstance(other, type(self))
44
- and other.t == self.t
45
- and other.b == self.b
46
- and other.l == self.l
47
- and other.r == self.r
48
- and other.units == self.units
49
- and _size(other) == _size(self)
50
- )
51
-
52
- def get_as(
53
- self,
54
- loc: Literal["t", "b", "l", "r"],
55
- units: Literal["pt", "in", "lines", "fig"] = "pt",
56
- ) -> float:
24
+ unit: Literal["pt", "in", "lines", "fig"] = "pt"
25
+
26
+ # These are set by the themeable when it is applied
27
+ fontsize: float = field(init=False, default=0)
28
+ figure_size: tuple[float, float] = field(init=False, default=(0, 0))
29
+
30
+ def setup(self, theme: theme, themeable_name: str):
31
+ self.fontsize = theme.getp((themeable_name, "size"), 11)
32
+ self.figure_size = theme.getp("figure_size")
33
+
34
+ @property
35
+ def pt(self) -> margin:
36
+ """
37
+ Return margin in points
38
+ """
39
+ return self.to("pt")
40
+
41
+ @property
42
+ def inch(self) -> margin:
43
+ """
44
+ Return margin in inches
45
+ """
46
+ return self.to("in")
47
+
48
+ @property
49
+ def lines(self) -> margin:
50
+ """
51
+ Return margin in lines units
52
+ """
53
+ return self.to("lines")
54
+
55
+ @property
56
+ def fig(self) -> margin:
57
+ """
58
+ Return margin in figure units
57
59
  """
58
- Return key in given units
60
+ return self.to("fig")
61
+
62
+ def to(self, unit: Literal["pt", "in", "lines", "fig"]) -> margin:
59
63
  """
64
+ Return margin in request unit
65
+ """
66
+ m = copy(self)
67
+ if self.unit == unit:
68
+ return m
69
+
70
+ conversion = f"{self.unit}-{unit}"
71
+ W, H = self.figure_size
72
+
73
+ with suppress(ZeroDivisionError):
74
+ m.t = self._convert(conversion, H, self.t)
75
+ with suppress(ZeroDivisionError):
76
+ m.r = self._convert(conversion, W, self.r)
77
+ with suppress(ZeroDivisionError):
78
+ m.b = self._convert(conversion, H, self.b)
79
+ with suppress(ZeroDivisionError):
80
+ m.l = self._convert(conversion, W, self.l)
81
+
82
+ m.unit = unit
83
+ return m
84
+
85
+ def _convert(self, conversion: str, D: float, value: float) -> float:
60
86
  dpi = 72
61
- size: float = self.theme.getp((self.themeable_name, "size"), 11)
62
- from_units = self.units
63
- to_units = units
64
- W: float
65
- H: float
66
- W, H = self.theme.getp("figure_size") # inches
67
- L = (W * dpi) if loc in "tb" else (H * dpi) # pts
87
+ L = D * dpi # pts
68
88
 
69
89
  functions: dict[str, Callable[[float], float]] = {
70
90
  "fig-in": lambda x: x * L / dpi,
71
- "fig-lines": lambda x: x * L / size,
91
+ "fig-lines": lambda x: x * L / self.fontsize,
72
92
  "fig-pt": lambda x: x * L,
73
93
  "in-fig": lambda x: x * dpi / L,
74
- "in-lines": lambda x: x * dpi / size,
94
+ "in-lines": lambda x: x * dpi / self.fontsize,
75
95
  "in-pt": lambda x: x * dpi,
76
- "lines-fig": lambda x: x * size / L,
77
- "lines-in": lambda x: x * size / dpi,
78
- "lines-pt": lambda x: x * size,
96
+ "lines-fig": lambda x: x * self.fontsize / L,
97
+ "lines-in": lambda x: x * self.fontsize / dpi,
98
+ "lines-pt": lambda x: x * self.fontsize,
79
99
  "pt-fig": lambda x: x / L,
80
100
  "pt-in": lambda x: x / dpi,
81
- "pt-lines": lambda x: x / size,
101
+ "pt-lines": lambda x: x / self.fontsize,
82
102
  }
83
103
 
84
- value: float = getattr(self, loc)
85
- if from_units != to_units:
86
- conversion = f"{self.units}-{units}"
87
- try:
88
- value = functions[conversion](value)
89
- except ZeroDivisionError:
90
- value = 0
91
- return value
104
+ return functions[conversion](value)
@@ -21,7 +21,7 @@ class ThemeTargets:
21
21
  """
22
22
  Artists that will be themed
23
23
 
24
- This includes only artist that cannot be accessed easily from
24
+ This includes only artist that cannot be easily accessed from
25
25
  the figure or the axes.
26
26
  """
27
27
 
@@ -37,7 +37,9 @@ class ThemeTargets:
37
37
  panel_border: list[Rectangle] = field(default_factory=list)
38
38
  plot_caption: Optional[Text] = None
39
39
  plot_subtitle: Optional[Text] = None
40
+ plot_tag: Optional[Text] = None
40
41
  plot_title: Optional[Text] = None
42
+ plot_background: Optional[Rectangle] = None
41
43
  strip_background_x: list[StripTextPatch] = field(default_factory=list)
42
44
  strip_background_y: list[StripTextPatch] = field(default_factory=list)
43
45
  strip_text_x: list[StripText] = field(default_factory=list)
plotnine/themes/theme.py CHANGED
@@ -19,6 +19,8 @@ if typing.TYPE_CHECKING:
19
19
 
20
20
  from plotnine import ggplot
21
21
 
22
+ from .elements import margin
23
+
22
24
 
23
25
  # All complete themes are initiated with these rcparams. They
24
26
  # can be overridden.
@@ -122,6 +124,11 @@ class theme:
122
124
  plot_title=None,
123
125
  plot_subtitle=None,
124
126
  plot_caption=None,
127
+ plot_tag=None,
128
+ plot_title_position=None,
129
+ plot_caption_position=None,
130
+ plot_tag_location=None,
131
+ plot_tag_position=None,
125
132
  strip_text_x=None,
126
133
  strip_text_y=None,
127
134
  strip_text=None,
@@ -169,13 +176,6 @@ class theme:
169
176
  axis_ticks_length_minor_y=None,
170
177
  axis_ticks_length_minor=None,
171
178
  axis_ticks_length=None,
172
- axis_ticks_pad_major_x=None,
173
- axis_ticks_pad_major_y=None,
174
- axis_ticks_pad_major=None,
175
- axis_ticks_pad_minor_x=None,
176
- axis_ticks_pad_minor_y=None,
177
- axis_ticks_pad_minor=None,
178
- axis_ticks_pad=None,
179
179
  panel_spacing_x=None,
180
180
  panel_spacing_y=None,
181
181
  panel_spacing=None,
@@ -270,6 +270,12 @@ class theme:
270
270
  """
271
271
  return self.themeables.getp
272
272
 
273
+ def get_margin(self, name: str) -> margin:
274
+ """
275
+ Return the margin propery of a element_text themeables
276
+ """
277
+ return self.themeables.getp((name, "margin"))
278
+
273
279
  def apply(self):
274
280
  """
275
281
  Apply this theme, then apply additional modifications in order.
@@ -1,6 +1,12 @@
1
1
  from .._utils.registry import alias
2
2
  from ..options import get_option
3
- from .elements import element_blank, element_line, element_rect, element_text
3
+ from .elements import (
4
+ element_blank,
5
+ element_line,
6
+ element_rect,
7
+ element_text,
8
+ margin,
9
+ )
4
10
  from .theme import theme
5
11
 
6
12
 
@@ -37,32 +43,32 @@ class theme_gray(theme):
37
43
  family=base_family,
38
44
  style="normal",
39
45
  color="black",
46
+ ma="center",
40
47
  size=base_size,
41
48
  linespacing=0.9,
42
49
  rotation=0,
43
- margin={},
50
+ margin=margin(),
44
51
  ),
45
52
  aspect_ratio=get_option("aspect_ratio"),
46
53
  axis_line=element_line(),
47
54
  axis_line_x=element_blank(),
48
55
  axis_line_y=element_blank(),
49
56
  axis_text=element_text(size=base_size * 0.8, color="#4D4D4D"),
50
- axis_text_x=element_text(va="top", margin={"t": fifth_line}),
51
- axis_text_y=element_text(ha="right", margin={"r": fifth_line}),
57
+ axis_text_x=element_text(va="top", margin=margin(t=fifth_line)),
58
+ axis_text_y=element_text(ha="right", margin=margin(r=fifth_line)),
52
59
  axis_ticks=element_line(color="#333333"),
53
60
  axis_ticks_length=0,
54
61
  axis_ticks_length_major=quarter_line,
55
62
  axis_ticks_length_minor=eighth_line,
56
63
  axis_ticks_minor=element_blank(),
57
- axis_ticks_pad=2,
58
64
  axis_title_x=element_text(
59
- va="bottom", ha="center", margin={"t": m, "units": "fig"}
65
+ va="bottom", ha="center", margin=margin(t=m, unit="fig")
60
66
  ),
61
67
  axis_title_y=element_text(
62
68
  angle=90,
63
69
  va="center",
64
70
  ha="left",
65
- margin={"r": m, "units": "fig"},
71
+ margin=margin(r=m, unit="fig"),
66
72
  ),
67
73
  dpi=get_option("dpi"),
68
74
  figure_size=get_option("figure_size"),
@@ -83,23 +89,11 @@ class theme_gray(theme):
83
89
  legend_spacing=10, # points
84
90
  legend_text=element_text(
85
91
  size=base_size * 0.8,
86
- margin={
87
- "t": m / 1.5,
88
- "b": m / 1.5,
89
- "l": m / 1.5,
90
- "r": m / 1.5,
91
- "units": "fig",
92
- },
92
+ margin=margin(m / 1.5, m / 1.5, m / 1.5, m / 1.5, "fig"),
93
93
  ),
94
94
  legend_ticks=element_line(color="#CCCCCC", size=1),
95
95
  legend_title=element_text(
96
- margin={
97
- "t": m,
98
- "b": m / 2,
99
- "l": m * 2,
100
- "r": m * 2,
101
- "units": "fig",
102
- },
96
+ margin=margin(t=m, l=m * 2, b=m / 2, r=m * 2, unit="fig")
103
97
  ),
104
98
  panel_background=element_rect(fill="#EBEBEB"),
105
99
  panel_border=element_blank(),
@@ -112,20 +106,29 @@ class theme_gray(theme):
112
106
  ha="right",
113
107
  va="bottom",
114
108
  ma="left",
115
- margin={"t": m, "units": "fig"},
109
+ margin=margin(t=m, unit="fig"),
116
110
  ),
117
111
  plot_margin=m,
118
112
  plot_subtitle=element_text(
119
113
  va="top",
120
114
  ma="left",
121
- margin={"b": m, "units": "fig"},
115
+ margin=margin(b=m, unit="fig"),
122
116
  ),
123
117
  plot_title=element_text(
124
118
  size=base_size * 1.2,
125
119
  va="top",
126
120
  ma="left",
127
- margin={"b": m, "units": "fig"},
121
+ margin=margin(b=m, unit="fig"),
128
122
  ),
123
+ plot_tag=element_text(
124
+ size=base_size * 1.2,
125
+ va="center",
126
+ ha="center",
127
+ ),
128
+ plot_title_position="panel",
129
+ plot_caption_position="panel",
130
+ plot_tag_location="margin",
131
+ plot_tag_position="topleft",
129
132
  strip_align=0,
130
133
  strip_background=element_rect(color="none", fill="#D9D9D9"),
131
134
  strip_background_x=element_rect(width=1),
@@ -134,13 +137,7 @@ class theme_gray(theme):
134
137
  color="#1A1A1A",
135
138
  size=base_size * 0.8,
136
139
  linespacing=1.0,
137
- margin={
138
- "t": 1 / 3,
139
- "b": 1 / 3,
140
- "l": 1 / 3,
141
- "r": 1 / 3,
142
- "units": "lines",
143
- },
140
+ margin=margin(1 / 3, 1 / 3, 1 / 3, 1 / 3, "lines"),
144
141
  ),
145
142
  strip_text_y=element_text(rotation=-90),
146
143
  complete=True,
@@ -1,5 +1,11 @@
1
1
  from ..options import get_option
2
- from .elements import element_blank, element_line, element_rect, element_text
2
+ from .elements import (
3
+ element_blank,
4
+ element_line,
5
+ element_rect,
6
+ element_text,
7
+ margin,
8
+ )
3
9
  from .theme import theme
4
10
 
5
11
 
@@ -38,16 +44,16 @@ class theme_matplotlib(theme):
38
44
  margin={},
39
45
  ),
40
46
  aspect_ratio=get_option("aspect_ratio"),
41
- axis_text=element_text(margin={"t": 2.4, "r": 2.4, "units": "pt"}),
47
+ axis_text=element_text(margin=margin(t=2.4, r=2.4, unit="pt")),
42
48
  axis_title_x=element_text(
43
- va="bottom", ha="center", margin={"t": m, "units": "fig"}
49
+ va="bottom", ha="center", margin=margin(t=m, unit="fig")
44
50
  ),
45
51
  axis_line=element_blank(),
46
52
  axis_title_y=element_text(
47
53
  angle=90,
48
54
  va="center",
49
55
  ha="left",
50
- margin={"r": m, "units": "fig"},
56
+ margin=margin(r=m, unit="fig"),
51
57
  ),
52
58
  dpi=get_option("dpi"),
53
59
  figure_size=get_option("figure_size"),
@@ -64,24 +70,12 @@ class theme_matplotlib(theme):
64
70
  legend_position="right",
65
71
  legend_spacing=10,
66
72
  legend_text=element_text(
67
- margin={
68
- "t": m / 2,
69
- "b": m / 2,
70
- "l": m / 2,
71
- "r": m / 2,
72
- "units": "fig",
73
- }
73
+ margin=margin(m / 2, m / 2, m / 2, m / 2, "fig")
74
74
  ),
75
75
  legend_ticks=element_line(color="black"),
76
76
  legend_title=element_text(
77
77
  ha="left",
78
- margin={
79
- "t": m,
80
- "b": m / 2,
81
- "l": m * 2,
82
- "r": m * 2,
83
- "units": "fig",
84
- },
78
+ margin=margin(t=m, l=m * 2, b=m / 2, r=m * 2, unit="fig"),
85
79
  ),
86
80
  panel_border=element_rect(color="black"),
87
81
  panel_grid=element_blank(),
@@ -90,32 +84,35 @@ class theme_matplotlib(theme):
90
84
  ha="right",
91
85
  va="bottom",
92
86
  ma="left",
93
- margin={"t": m, "units": "fig"},
87
+ margin=margin(t=m, unit="fig"),
94
88
  ),
95
89
  plot_margin=m,
96
90
  plot_subtitle=element_text(
97
91
  size=base_size * 0.9,
98
92
  va="top",
99
93
  ma="left",
100
- margin={"b": m, "units": "fig"},
94
+ margin=margin(b=m, unit="fig"),
101
95
  ),
102
96
  plot_title=element_text(
103
97
  va="top",
104
98
  ma="left",
105
- margin={"b": m, "units": "fig"},
99
+ margin=margin(b=m, unit="fig"),
106
100
  ),
101
+ plot_tag=element_text(
102
+ size=base_size * 1.2,
103
+ va="center",
104
+ ha="center",
105
+ ),
106
+ plot_title_position="panel",
107
+ plot_caption_position="panel",
108
+ plot_tag_location="margin",
109
+ plot_tag_position="topleft",
107
110
  strip_align=0,
108
111
  strip_background=element_rect(
109
112
  fill="#D9D9D9", color="black", size=linewidth
110
113
  ),
111
114
  strip_text=element_text(
112
- margin={
113
- "t": 1 / 3,
114
- "b": 1 / 3,
115
- "l": 1 / 3,
116
- "r": 1 / 3,
117
- "units": "lines",
118
- },
115
+ margin=margin(1 / 3, 1 / 3, 1 / 3, 1 / 3, "lines"),
119
116
  ),
120
117
  strip_text_y=element_text(rotation=-90),
121
118
  complete=True,