plotnine 0.15.2__py3-none-any.whl → 0.16.0a1__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.
- plotnine/_mpl/gridspec.py +50 -6
- plotnine/_mpl/layout_manager/__init__.py +2 -5
- plotnine/_mpl/layout_manager/_composition_layout_items.py +98 -0
- plotnine/_mpl/layout_manager/_composition_side_space.py +461 -0
- plotnine/_mpl/layout_manager/_engine.py +19 -58
- plotnine/_mpl/layout_manager/_grid.py +94 -0
- plotnine/_mpl/layout_manager/_layout_tree.py +402 -817
- plotnine/_mpl/layout_manager/{_layout_items.py → _plot_layout_items.py} +55 -278
- plotnine/_mpl/layout_manager/{_spaces.py → _plot_side_space.py} +111 -291
- plotnine/_mpl/layout_manager/_side_space.py +176 -0
- plotnine/_mpl/utils.py +259 -1
- plotnine/_utils/__init__.py +23 -3
- plotnine/_utils/context.py +1 -1
- plotnine/_utils/dataclasses.py +24 -0
- plotnine/animation.py +13 -12
- plotnine/composition/__init__.py +6 -0
- plotnine/composition/_beside.py +13 -11
- plotnine/composition/_compose.py +263 -99
- plotnine/composition/_plot_annotation.py +75 -0
- plotnine/composition/_plot_layout.py +143 -0
- plotnine/composition/_plot_spacer.py +1 -1
- plotnine/composition/_stack.py +13 -11
- plotnine/composition/_types.py +28 -0
- plotnine/composition/_wrap.py +60 -0
- plotnine/facets/facet.py +9 -12
- plotnine/facets/facet_grid.py +2 -2
- plotnine/facets/facet_wrap.py +1 -1
- plotnine/geoms/geom.py +2 -2
- plotnine/geoms/geom_map.py +4 -5
- plotnine/geoms/geom_path.py +8 -7
- plotnine/geoms/geom_rug.py +6 -10
- plotnine/geoms/geom_text.py +5 -5
- plotnine/ggplot.py +63 -9
- plotnine/guides/guide.py +24 -6
- plotnine/guides/guide_colorbar.py +88 -46
- plotnine/guides/guide_legend.py +47 -20
- plotnine/guides/guides.py +2 -2
- plotnine/iapi.py +17 -1
- plotnine/scales/scale.py +1 -1
- plotnine/stats/binning.py +15 -43
- plotnine/stats/smoothers.py +7 -3
- plotnine/stats/stat.py +2 -2
- plotnine/stats/stat_density_2d.py +10 -6
- plotnine/stats/stat_pointdensity.py +8 -1
- plotnine/stats/stat_qq.py +5 -5
- plotnine/stats/stat_qq_line.py +6 -1
- plotnine/stats/stat_sina.py +19 -20
- plotnine/stats/stat_summary.py +4 -2
- plotnine/stats/stat_summary_bin.py +7 -1
- plotnine/themes/elements/element_line.py +2 -0
- plotnine/themes/elements/element_text.py +12 -1
- plotnine/themes/theme.py +18 -24
- plotnine/themes/themeable.py +17 -3
- plotnine/typing.py +6 -1
- {plotnine-0.15.2.dist-info → plotnine-0.16.0a1.dist-info}/METADATA +2 -2
- {plotnine-0.15.2.dist-info → plotnine-0.16.0a1.dist-info}/RECORD +59 -51
- plotnine/composition/_plotspec.py +0 -50
- {plotnine-0.15.2.dist-info → plotnine-0.16.0a1.dist-info}/WHEEL +0 -0
- {plotnine-0.15.2.dist-info → plotnine-0.16.0a1.dist-info}/licenses/LICENSE +0 -0
- {plotnine-0.15.2.dist-info → plotnine-0.16.0a1.dist-info}/top_level.txt +0 -0
|
@@ -1,20 +1,19 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
-
from dataclasses import dataclass
|
|
4
3
|
from itertools import chain
|
|
5
|
-
from typing import TYPE_CHECKING
|
|
4
|
+
from typing import TYPE_CHECKING
|
|
6
5
|
|
|
7
6
|
from matplotlib.text import Text
|
|
8
7
|
|
|
9
8
|
from plotnine._mpl.patches import StripTextPatch
|
|
10
|
-
from plotnine._utils import ha_as_float, va_as_float
|
|
11
9
|
from plotnine.exceptions import PlotnineError
|
|
12
10
|
|
|
13
11
|
from ..utils import (
|
|
14
|
-
|
|
12
|
+
ArtistGeometry,
|
|
13
|
+
JustifyBoundaries,
|
|
14
|
+
TextJustifier,
|
|
15
15
|
get_subplotspecs,
|
|
16
16
|
rel_position,
|
|
17
|
-
tight_bbox_in_figure_space,
|
|
18
17
|
)
|
|
19
18
|
|
|
20
19
|
if TYPE_CHECKING:
|
|
@@ -22,15 +21,12 @@ if TYPE_CHECKING:
|
|
|
22
21
|
Any,
|
|
23
22
|
Iterator,
|
|
24
23
|
Literal,
|
|
25
|
-
Sequence,
|
|
26
24
|
TypeAlias,
|
|
27
25
|
)
|
|
28
26
|
|
|
29
|
-
from matplotlib.artist import Artist
|
|
30
27
|
from matplotlib.axes import Axes
|
|
31
28
|
from matplotlib.axis import Tick
|
|
32
|
-
from matplotlib.
|
|
33
|
-
from matplotlib.transforms import Bbox, Transform
|
|
29
|
+
from matplotlib.transforms import Transform
|
|
34
30
|
|
|
35
31
|
from plotnine import ggplot
|
|
36
32
|
from plotnine._mpl.offsetbox import FlexibleAnchoredOffsetbox
|
|
@@ -38,12 +34,10 @@ if TYPE_CHECKING:
|
|
|
38
34
|
from plotnine.iapi import legend_artists
|
|
39
35
|
from plotnine.themes.elements import margin as Margin
|
|
40
36
|
from plotnine.typing import (
|
|
41
|
-
HorizontalJustification,
|
|
42
37
|
StripPosition,
|
|
43
|
-
VerticalJustification,
|
|
44
38
|
)
|
|
45
39
|
|
|
46
|
-
from .
|
|
40
|
+
from ._plot_side_space import PlotSideSpaces
|
|
47
41
|
|
|
48
42
|
AxesLocation: TypeAlias = Literal[
|
|
49
43
|
"all", "first_row", "last_row", "first_col", "last_col"
|
|
@@ -64,140 +58,12 @@ if TYPE_CHECKING:
|
|
|
64
58
|
)
|
|
65
59
|
|
|
66
60
|
|
|
67
|
-
|
|
68
|
-
class Calc:
|
|
69
|
-
"""
|
|
70
|
-
Calculate space taken up by an artist
|
|
71
|
-
"""
|
|
72
|
-
|
|
73
|
-
# fig: Figure
|
|
74
|
-
# renderer: RendererBase
|
|
75
|
-
plot: ggplot
|
|
76
|
-
|
|
77
|
-
def __post_init__(self):
|
|
78
|
-
self.figure = self.plot.figure
|
|
79
|
-
self.renderer = cast("RendererBase", self.plot.figure._get_renderer()) # pyright: ignore
|
|
80
|
-
|
|
81
|
-
def bbox(self, artist: Artist) -> Bbox:
|
|
82
|
-
"""
|
|
83
|
-
Bounding box of artist in figure coordinates
|
|
84
|
-
"""
|
|
85
|
-
return bbox_in_figure_space(artist, self.figure, self.renderer)
|
|
86
|
-
|
|
87
|
-
def tight_bbox(self, artist: Artist) -> Bbox:
|
|
88
|
-
"""
|
|
89
|
-
Bounding box of artist and its children in figure coordinates
|
|
90
|
-
"""
|
|
91
|
-
return tight_bbox_in_figure_space(artist, self.figure, self.renderer)
|
|
92
|
-
|
|
93
|
-
def width(self, artist: Artist) -> float:
|
|
94
|
-
"""
|
|
95
|
-
Width of artist in figure space
|
|
96
|
-
"""
|
|
97
|
-
return self.bbox(artist).width
|
|
98
|
-
|
|
99
|
-
def tight_width(self, artist: Artist) -> float:
|
|
100
|
-
"""
|
|
101
|
-
Width of artist and its children in figure space
|
|
102
|
-
"""
|
|
103
|
-
return self.tight_bbox(artist).width
|
|
104
|
-
|
|
105
|
-
def height(self, artist: Artist) -> float:
|
|
106
|
-
"""
|
|
107
|
-
Height of artist in figure space
|
|
108
|
-
"""
|
|
109
|
-
return self.bbox(artist).height
|
|
110
|
-
|
|
111
|
-
def tight_height(self, artist: Artist) -> float:
|
|
112
|
-
"""
|
|
113
|
-
Height of artist and its children in figure space
|
|
114
|
-
"""
|
|
115
|
-
return self.tight_bbox(artist).height
|
|
116
|
-
|
|
117
|
-
def size(self, artist: Artist) -> tuple[float, float]:
|
|
118
|
-
"""
|
|
119
|
-
(width, height) of artist in figure space
|
|
120
|
-
"""
|
|
121
|
-
bbox = self.bbox(artist)
|
|
122
|
-
return (bbox.width, bbox.height)
|
|
123
|
-
|
|
124
|
-
def tight_size(self, artist: Artist) -> tuple[float, float]:
|
|
125
|
-
"""
|
|
126
|
-
(width, height) of artist and its children in figure space
|
|
127
|
-
"""
|
|
128
|
-
bbox = self.tight_bbox(artist)
|
|
129
|
-
return (bbox.width, bbox.height)
|
|
130
|
-
|
|
131
|
-
def left_x(self, artist: Artist) -> float:
|
|
132
|
-
"""
|
|
133
|
-
x value of the left edge of the artist
|
|
134
|
-
|
|
135
|
-
---
|
|
136
|
-
x |
|
|
137
|
-
---
|
|
138
|
-
"""
|
|
139
|
-
return self.bbox(artist).min[0]
|
|
140
|
-
|
|
141
|
-
def right_x(self, artist: Artist) -> float:
|
|
142
|
-
"""
|
|
143
|
-
x value of the left edge of the artist
|
|
144
|
-
|
|
145
|
-
---
|
|
146
|
-
| x
|
|
147
|
-
---
|
|
148
|
-
"""
|
|
149
|
-
return self.bbox(artist).max[0]
|
|
150
|
-
|
|
151
|
-
def top_y(self, artist: Artist) -> float:
|
|
152
|
-
"""
|
|
153
|
-
y value of the top edge of the artist
|
|
154
|
-
|
|
155
|
-
-y-
|
|
156
|
-
| |
|
|
157
|
-
---
|
|
158
|
-
"""
|
|
159
|
-
return self.bbox(artist).max[1]
|
|
160
|
-
|
|
161
|
-
def bottom_y(self, artist: Artist) -> float:
|
|
162
|
-
"""
|
|
163
|
-
y value of the bottom edge of the artist
|
|
164
|
-
|
|
165
|
-
---
|
|
166
|
-
| |
|
|
167
|
-
-y-
|
|
168
|
-
"""
|
|
169
|
-
return self.bbox(artist).min[1]
|
|
170
|
-
|
|
171
|
-
def max_width(self, artists: Sequence[Artist]) -> float:
|
|
172
|
-
"""
|
|
173
|
-
Return the maximum width of list of artists
|
|
174
|
-
"""
|
|
175
|
-
widths = [
|
|
176
|
-
bbox_in_figure_space(a, self.figure, self.renderer).width
|
|
177
|
-
for a in artists
|
|
178
|
-
]
|
|
179
|
-
return max(widths) if len(widths) else 0
|
|
180
|
-
|
|
181
|
-
def max_height(self, artists: Sequence[Artist]) -> float:
|
|
182
|
-
"""
|
|
183
|
-
Return the maximum height of list of artists
|
|
184
|
-
"""
|
|
185
|
-
heights = [
|
|
186
|
-
bbox_in_figure_space(a, self.figure, self.renderer).height
|
|
187
|
-
for a in artists
|
|
188
|
-
]
|
|
189
|
-
return max(heights) if len(heights) else 0
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
@dataclass
|
|
193
|
-
class LayoutItems:
|
|
61
|
+
class PlotLayoutItems:
|
|
194
62
|
"""
|
|
195
63
|
Objects required to compute the layout
|
|
196
64
|
"""
|
|
197
65
|
|
|
198
|
-
plot: ggplot
|
|
199
|
-
|
|
200
|
-
def __post_init__(self):
|
|
66
|
+
def __init__(self, plot: ggplot):
|
|
201
67
|
def get(name: str) -> Any:
|
|
202
68
|
"""
|
|
203
69
|
Return themeable target or None
|
|
@@ -210,7 +76,8 @@ class LayoutItems:
|
|
|
210
76
|
return None
|
|
211
77
|
return t
|
|
212
78
|
|
|
213
|
-
self.
|
|
79
|
+
self.plot = plot
|
|
80
|
+
self.geometry = ArtistGeometry(self.plot.figure)
|
|
214
81
|
|
|
215
82
|
self.axis_title_x: Text | None = get("axis_title_x")
|
|
216
83
|
self.axis_title_y: Text | None = get("axis_title_y")
|
|
@@ -326,7 +193,7 @@ class LayoutItems:
|
|
|
326
193
|
if isinstance(a, StripTextPatch)
|
|
327
194
|
else a.draw_info
|
|
328
195
|
)
|
|
329
|
-
h = self.
|
|
196
|
+
h = self.geometry.height(a)
|
|
330
197
|
heights.append(max(h + h * info.strip_align, 0))
|
|
331
198
|
|
|
332
199
|
return max(heights)
|
|
@@ -352,7 +219,7 @@ class LayoutItems:
|
|
|
352
219
|
if isinstance(a, StripTextPatch)
|
|
353
220
|
else a.draw_info
|
|
354
221
|
)
|
|
355
|
-
w = self.
|
|
222
|
+
w = self.geometry.width(a)
|
|
356
223
|
widths.append(max(w + w * info.strip_align, 0))
|
|
357
224
|
|
|
358
225
|
return max(widths)
|
|
@@ -362,7 +229,7 @@ class LayoutItems:
|
|
|
362
229
|
Return maximum height[figure space] of x ticks
|
|
363
230
|
"""
|
|
364
231
|
heights = [
|
|
365
|
-
self.
|
|
232
|
+
self.geometry.tight_height(tick.tick1line)
|
|
366
233
|
for ax in self._filter_axes(location)
|
|
367
234
|
for tick in self.axis_ticks_x(ax)
|
|
368
235
|
]
|
|
@@ -373,7 +240,7 @@ class LayoutItems:
|
|
|
373
240
|
Return maximum height[figure space] of x tick labels
|
|
374
241
|
"""
|
|
375
242
|
heights = [
|
|
376
|
-
self.
|
|
243
|
+
self.geometry.tight_height(label) for label in self.axis_text_x(ax)
|
|
377
244
|
]
|
|
378
245
|
return max(heights) if len(heights) else 0
|
|
379
246
|
|
|
@@ -392,7 +259,7 @@ class LayoutItems:
|
|
|
392
259
|
Return maximum width[figure space] of y ticks
|
|
393
260
|
"""
|
|
394
261
|
widths = [
|
|
395
|
-
self.
|
|
262
|
+
self.geometry.tight_width(tick.tick1line)
|
|
396
263
|
for ax in self._filter_axes(location)
|
|
397
264
|
for tick in self.axis_ticks_y(ax)
|
|
398
265
|
]
|
|
@@ -403,7 +270,7 @@ class LayoutItems:
|
|
|
403
270
|
Return maximum width[figure space] of y tick labels
|
|
404
271
|
"""
|
|
405
272
|
widths = [
|
|
406
|
-
self.
|
|
273
|
+
self.geometry.tight_width(label) for label in self.axis_text_y(ax)
|
|
407
274
|
]
|
|
408
275
|
return max(widths) if len(widths) else 0
|
|
409
276
|
|
|
@@ -423,9 +290,9 @@ class LayoutItems:
|
|
|
423
290
|
"""
|
|
424
291
|
extras = []
|
|
425
292
|
for ax in self._filter_axes(location):
|
|
426
|
-
ax_top_y = self.
|
|
293
|
+
ax_top_y = self.geometry.top_y(ax)
|
|
427
294
|
for label in self.axis_text_y(ax):
|
|
428
|
-
label_top_y = self.
|
|
295
|
+
label_top_y = self.geometry.top_y(label)
|
|
429
296
|
extras.append(max(0, label_top_y - ax_top_y))
|
|
430
297
|
|
|
431
298
|
return max(extras) if len(extras) else 0
|
|
@@ -436,9 +303,9 @@ class LayoutItems:
|
|
|
436
303
|
"""
|
|
437
304
|
extras = []
|
|
438
305
|
for ax in self._filter_axes(location):
|
|
439
|
-
ax_bottom_y = self.
|
|
306
|
+
ax_bottom_y = self.geometry.bottom_y(ax)
|
|
440
307
|
for label in self.axis_text_y(ax):
|
|
441
|
-
label_bottom_y = self.
|
|
308
|
+
label_bottom_y = self.geometry.bottom_y(label)
|
|
442
309
|
protrusion = abs(min(label_bottom_y - ax_bottom_y, 0))
|
|
443
310
|
extras.append(protrusion)
|
|
444
311
|
|
|
@@ -450,9 +317,9 @@ class LayoutItems:
|
|
|
450
317
|
"""
|
|
451
318
|
extras = []
|
|
452
319
|
for ax in self._filter_axes(location):
|
|
453
|
-
ax_left_x = self.
|
|
320
|
+
ax_left_x = self.geometry.left_x(ax)
|
|
454
321
|
for label in self.axis_text_x(ax):
|
|
455
|
-
label_left_x = self.
|
|
322
|
+
label_left_x = self.geometry.left_x(label)
|
|
456
323
|
protrusion = abs(min(label_left_x - ax_left_x, 0))
|
|
457
324
|
extras.append(protrusion)
|
|
458
325
|
|
|
@@ -464,21 +331,21 @@ class LayoutItems:
|
|
|
464
331
|
"""
|
|
465
332
|
extras = []
|
|
466
333
|
for ax in self._filter_axes(location):
|
|
467
|
-
ax_right_x = self.
|
|
334
|
+
ax_right_x = self.geometry.right_x(ax)
|
|
468
335
|
for label in self.axis_text_x(ax):
|
|
469
|
-
label_right_x = self.
|
|
336
|
+
label_right_x = self.geometry.right_x(label)
|
|
470
337
|
extras.append(max(0, label_right_x - ax_right_x))
|
|
471
338
|
|
|
472
339
|
return max(extras) if len(extras) else 0
|
|
473
340
|
|
|
474
|
-
def
|
|
341
|
+
def _move_artists(self, spaces: PlotSideSpaces):
|
|
475
342
|
"""
|
|
476
|
-
|
|
343
|
+
Move the artists to their final positions
|
|
477
344
|
"""
|
|
478
345
|
theme = self.plot.theme
|
|
479
346
|
plot_title_position = theme.getp("plot_title_position", "panel")
|
|
480
347
|
plot_caption_position = theme.getp("plot_caption_position", "panel")
|
|
481
|
-
justify =
|
|
348
|
+
justify = PlotTextJustifier(spaces)
|
|
482
349
|
|
|
483
350
|
if self.plot_tag:
|
|
484
351
|
set_plot_tag_position(self.plot_tag, spaces)
|
|
@@ -522,7 +389,7 @@ class LayoutItems:
|
|
|
522
389
|
self._strip_text_x_background_equal_heights()
|
|
523
390
|
self._strip_text_y_background_equal_widths()
|
|
524
391
|
|
|
525
|
-
def _adjust_axis_text_x(self, justify:
|
|
392
|
+
def _adjust_axis_text_x(self, justify: PlotTextJustifier):
|
|
526
393
|
"""
|
|
527
394
|
Adjust x-axis text, justifying vertically as necessary
|
|
528
395
|
"""
|
|
@@ -547,13 +414,13 @@ class LayoutItems:
|
|
|
547
414
|
)
|
|
548
415
|
for text in texts:
|
|
549
416
|
height = to_vertical_axis_dimensions(
|
|
550
|
-
self.
|
|
417
|
+
self.geometry.tight_height(text), ax
|
|
551
418
|
)
|
|
552
419
|
justify.vertically(
|
|
553
420
|
text, va, -axis_text_row_height, 0, height=height
|
|
554
421
|
)
|
|
555
422
|
|
|
556
|
-
def _adjust_axis_text_y(self, justify:
|
|
423
|
+
def _adjust_axis_text_y(self, justify: PlotTextJustifier):
|
|
557
424
|
"""
|
|
558
425
|
Adjust x-axis text, justifying horizontally as necessary
|
|
559
426
|
"""
|
|
@@ -600,7 +467,7 @@ class LayoutItems:
|
|
|
600
467
|
)
|
|
601
468
|
for text in texts:
|
|
602
469
|
width = to_horizontal_axis_dimensions(
|
|
603
|
-
self.
|
|
470
|
+
self.geometry.tight_width(text), ax
|
|
604
471
|
)
|
|
605
472
|
justify.horizontally(
|
|
606
473
|
text, ha, -axis_text_col_width, 0, width=width
|
|
@@ -615,7 +482,9 @@ class LayoutItems:
|
|
|
615
482
|
if not self.strip_text_x:
|
|
616
483
|
return
|
|
617
484
|
|
|
618
|
-
heights = [
|
|
485
|
+
heights = [
|
|
486
|
+
self.geometry.bbox(t.patch).height for t in self.strip_text_x
|
|
487
|
+
]
|
|
619
488
|
max_height = max(heights)
|
|
620
489
|
relative_heights = [max_height / h for h in heights]
|
|
621
490
|
for text, scale in zip(self.strip_text_x, relative_heights):
|
|
@@ -630,7 +499,7 @@ class LayoutItems:
|
|
|
630
499
|
if not self.strip_text_y:
|
|
631
500
|
return
|
|
632
501
|
|
|
633
|
-
widths = [self.
|
|
502
|
+
widths = [self.geometry.bbox(t.patch).width for t in self.strip_text_y]
|
|
634
503
|
max_width = max(widths)
|
|
635
504
|
relative_widths = [max_width / w for w in widths]
|
|
636
505
|
for text, scale in zip(self.strip_text_y, relative_widths):
|
|
@@ -644,122 +513,30 @@ def _text_is_visible(text: Text) -> bool:
|
|
|
644
513
|
return text.get_visible() and text._text # type: ignore
|
|
645
514
|
|
|
646
515
|
|
|
647
|
-
|
|
648
|
-
class TextJustifier:
|
|
516
|
+
class PlotTextJustifier(TextJustifier):
|
|
649
517
|
"""
|
|
650
|
-
Justify Text
|
|
651
|
-
|
|
652
|
-
The justification methods reinterpret alignment values to be justification
|
|
653
|
-
about a span.
|
|
518
|
+
Justify Text about a plot or it's panels
|
|
654
519
|
"""
|
|
655
520
|
|
|
656
|
-
spaces:
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
"""
|
|
667
|
-
Horizontally Justify text between left and right
|
|
668
|
-
"""
|
|
669
|
-
rel = ha_as_float(ha)
|
|
670
|
-
if width is None:
|
|
671
|
-
width = self.spaces.items.calc.width(text)
|
|
672
|
-
x = rel_position(rel, width, left, right)
|
|
673
|
-
text.set_x(x)
|
|
674
|
-
text.set_horizontalalignment("left")
|
|
675
|
-
|
|
676
|
-
def vertically(
|
|
677
|
-
self,
|
|
678
|
-
text: Text,
|
|
679
|
-
va: VerticalJustification | float,
|
|
680
|
-
bottom: float,
|
|
681
|
-
top: float,
|
|
682
|
-
height: float | None = None,
|
|
683
|
-
):
|
|
684
|
-
"""
|
|
685
|
-
Vertically Justify text between bottom and top
|
|
686
|
-
"""
|
|
687
|
-
rel = va_as_float(va)
|
|
688
|
-
|
|
689
|
-
if height is None:
|
|
690
|
-
height = self.spaces.items.calc.height(text)
|
|
691
|
-
y = rel_position(rel, height, bottom, top)
|
|
692
|
-
text.set_y(y)
|
|
693
|
-
text.set_verticalalignment("bottom")
|
|
694
|
-
|
|
695
|
-
def horizontally_across_panel(
|
|
696
|
-
self, text: Text, ha: HorizontalJustification | float
|
|
697
|
-
):
|
|
698
|
-
"""
|
|
699
|
-
Horizontally Justify text accross the panel(s) width
|
|
700
|
-
"""
|
|
701
|
-
self.horizontally(
|
|
702
|
-
text, ha, self.spaces.l.panel_left, self.spaces.r.panel_right
|
|
521
|
+
def __init__(self, spaces: PlotSideSpaces):
|
|
522
|
+
boundaries = JustifyBoundaries(
|
|
523
|
+
plot_left=spaces.l.plot_left,
|
|
524
|
+
plot_right=spaces.r.plot_right,
|
|
525
|
+
plot_bottom=spaces.b.plot_bottom,
|
|
526
|
+
plot_top=spaces.t.plot_top,
|
|
527
|
+
panel_left=spaces.l.panel_left,
|
|
528
|
+
panel_right=spaces.r.panel_right,
|
|
529
|
+
panel_bottom=spaces.b.panel_bottom,
|
|
530
|
+
panel_top=spaces.t.panel_top,
|
|
703
531
|
)
|
|
704
|
-
|
|
705
|
-
def horizontally_across_plot(
|
|
706
|
-
self, text: Text, ha: HorizontalJustification | float
|
|
707
|
-
):
|
|
708
|
-
"""
|
|
709
|
-
Horizontally Justify text across the plot's width
|
|
710
|
-
"""
|
|
711
|
-
self.horizontally(
|
|
712
|
-
text, ha, self.spaces.l.plot_left, self.spaces.r.plot_right
|
|
713
|
-
)
|
|
714
|
-
|
|
715
|
-
def vertically_along_panel(
|
|
716
|
-
self, text: Text, va: VerticalJustification | float
|
|
717
|
-
):
|
|
718
|
-
"""
|
|
719
|
-
Horizontally Justify text along the panel(s) height
|
|
720
|
-
"""
|
|
721
|
-
self.vertically(
|
|
722
|
-
text, va, self.spaces.b.panel_bottom, self.spaces.t.panel_top
|
|
723
|
-
)
|
|
724
|
-
|
|
725
|
-
def vertically_along_plot(
|
|
726
|
-
self, text: Text, va: VerticalJustification | float
|
|
727
|
-
):
|
|
728
|
-
"""
|
|
729
|
-
Vertically Justify text along the plot's height
|
|
730
|
-
"""
|
|
731
|
-
self.vertically(
|
|
732
|
-
text, va, self.spaces.b.plot_bottom, self.spaces.t.plot_top
|
|
733
|
-
)
|
|
734
|
-
|
|
735
|
-
def horizontally_about(
|
|
736
|
-
self, text: Text, ratio: float, how: Literal["panel", "plot"]
|
|
737
|
-
):
|
|
738
|
-
"""
|
|
739
|
-
Horizontally Justify text across the panel or plot
|
|
740
|
-
"""
|
|
741
|
-
if how == "panel":
|
|
742
|
-
self.horizontally_across_panel(text, ratio)
|
|
743
|
-
else:
|
|
744
|
-
self.horizontally_across_plot(text, ratio)
|
|
745
|
-
|
|
746
|
-
def vertically_about(
|
|
747
|
-
self, text: Text, ratio: float, how: Literal["panel", "plot"]
|
|
748
|
-
):
|
|
749
|
-
"""
|
|
750
|
-
Vertically Justify text along the panel or plot
|
|
751
|
-
"""
|
|
752
|
-
if how == "panel":
|
|
753
|
-
self.vertically_along_panel(text, ratio)
|
|
754
|
-
else:
|
|
755
|
-
self.vertically_along_plot(text, ratio)
|
|
532
|
+
super().__init__(spaces.plot.figure, boundaries)
|
|
756
533
|
|
|
757
534
|
|
|
758
|
-
def set_legends_position(legends: legend_artists, spaces:
|
|
535
|
+
def set_legends_position(legends: legend_artists, spaces: PlotSideSpaces):
|
|
759
536
|
"""
|
|
760
537
|
Place legend on the figure and justify is a required
|
|
761
538
|
"""
|
|
762
|
-
panels_gs = spaces.plot.
|
|
539
|
+
panels_gs = spaces.plot._sub_gridspec
|
|
763
540
|
params = panels_gs.get_subplot_params()
|
|
764
541
|
transFigure = spaces.plot.figure.transFigure
|
|
765
542
|
|
|
@@ -833,12 +610,12 @@ def set_legends_position(legends: legend_artists, spaces: LayoutSpaces):
|
|
|
833
610
|
set_position(l.box, l.position, l.justification, transPanels)
|
|
834
611
|
|
|
835
612
|
|
|
836
|
-
def set_plot_tag_position(tag: Text, spaces:
|
|
613
|
+
def set_plot_tag_position(tag: Text, spaces: PlotSideSpaces):
|
|
837
614
|
"""
|
|
838
615
|
Set the postion of the plot_tag
|
|
839
616
|
"""
|
|
840
617
|
theme = spaces.plot.theme
|
|
841
|
-
panels_gs = spaces.plot.
|
|
618
|
+
panels_gs = spaces.plot._sub_gridspec
|
|
842
619
|
location: TagLocation = theme.getp("plot_tag_location")
|
|
843
620
|
position: TagPosition = theme.getp("plot_tag_position")
|
|
844
621
|
margin = theme.get_margin("plot_tag")
|
|
@@ -866,7 +643,7 @@ def set_plot_tag_position(tag: Text, spaces: LayoutSpaces):
|
|
|
866
643
|
|
|
867
644
|
# Calculate the position when the tag has no margins
|
|
868
645
|
rel_x, rel_y = lookup[position]
|
|
869
|
-
width, height = spaces.items.
|
|
646
|
+
width, height = spaces.items.geometry.size(tag)
|
|
870
647
|
x = rel_position(rel_x, width, x1, x2)
|
|
871
648
|
y = rel_position(rel_y, height, y1, y2)
|
|
872
649
|
|
|
@@ -894,7 +671,7 @@ def set_plot_tag_position(tag: Text, spaces: LayoutSpaces):
|
|
|
894
671
|
tag.set_position(position)
|
|
895
672
|
|
|
896
673
|
|
|
897
|
-
def set_plot_tag_position_in_margin(tag: Text, spaces:
|
|
674
|
+
def set_plot_tag_position_in_margin(tag: Text, spaces: PlotSideSpaces):
|
|
898
675
|
"""
|
|
899
676
|
Place the tag in an inner margin around the plot
|
|
900
677
|
|
|
@@ -932,7 +709,7 @@ def set_plot_tag_position_in_margin(tag: Text, spaces: LayoutSpaces):
|
|
|
932
709
|
tag.set_y(y)
|
|
933
710
|
tag.set_verticalalignment("bottom")
|
|
934
711
|
|
|
935
|
-
justify =
|
|
712
|
+
justify = PlotTextJustifier(spaces)
|
|
936
713
|
if position in ("left", "right"):
|
|
937
714
|
justify.vertically_along_plot(tag, va)
|
|
938
715
|
elif position in ("top", "bottom"):
|