plotnine 0.15.0a6__py3-none-any.whl → 0.15.0a8__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/layout_manager/_engine.py +2 -2
- plotnine/_mpl/layout_manager/_layout_items.py +6 -2
- plotnine/_mpl/layout_manager/_layout_tree.py +219 -58
- plotnine/_mpl/layout_manager/_spaces.py +98 -28
- plotnine/_mpl/text.py +1 -7
- plotnine/composition/__init__.py +2 -2
- plotnine/composition/_beside.py +12 -4
- plotnine/composition/{_arrange.py → _compose.py} +118 -38
- plotnine/composition/_plot_spacer.py +6 -0
- plotnine/composition/_stack.py +12 -4
- plotnine/geoms/geom_bar.py +1 -0
- plotnine/geoms/geom_bin_2d.py +4 -0
- plotnine/geoms/geom_boxplot.py +4 -0
- plotnine/geoms/geom_count.py +4 -0
- plotnine/geoms/geom_density_2d.py +4 -0
- plotnine/geoms/geom_dotplot.py +1 -1
- plotnine/geoms/geom_histogram.py +1 -1
- plotnine/geoms/geom_pointdensity.py +4 -0
- plotnine/geoms/geom_qq.py +4 -0
- plotnine/geoms/geom_qq_line.py +4 -0
- plotnine/geoms/geom_quantile.py +4 -0
- plotnine/geoms/geom_sina.py +1 -1
- plotnine/geoms/geom_smooth.py +4 -0
- plotnine/geoms/geom_violin.py +4 -0
- plotnine/ggplot.py +4 -4
- plotnine/stats/stat_bin.py +4 -0
- plotnine/stats/stat_bin_2d.py +4 -0
- plotnine/stats/stat_bindot.py +1 -0
- plotnine/stats/stat_boxplot.py +1 -1
- plotnine/stats/stat_count.py +1 -0
- plotnine/stats/stat_density.py +1 -1
- plotnine/stats/stat_density_2d.py +1 -0
- plotnine/stats/stat_ecdf.py +1 -1
- plotnine/stats/stat_ellipse.py +4 -0
- plotnine/stats/stat_function.py +4 -0
- plotnine/stats/stat_hull.py +4 -0
- plotnine/stats/stat_identity.py +4 -0
- plotnine/stats/stat_pointdensity.py +1 -0
- plotnine/stats/stat_qq.py +1 -0
- plotnine/stats/stat_qq_line.py +1 -0
- plotnine/stats/stat_quantile.py +1 -1
- plotnine/stats/stat_sina.py +1 -1
- plotnine/stats/stat_smooth.py +1 -0
- plotnine/stats/stat_sum.py +4 -0
- plotnine/stats/stat_summary.py +1 -1
- plotnine/stats/stat_summary_bin.py +1 -1
- plotnine/stats/stat_unique.py +4 -0
- plotnine/stats/stat_ydensity.py +1 -1
- plotnine/themes/theme.py +1 -1
- plotnine/themes/theme_void.py +1 -7
- {plotnine-0.15.0a6.dist-info → plotnine-0.15.0a8.dist-info}/METADATA +1 -1
- {plotnine-0.15.0a6.dist-info → plotnine-0.15.0a8.dist-info}/RECORD +55 -55
- {plotnine-0.15.0a6.dist-info → plotnine-0.15.0a8.dist-info}/WHEEL +0 -0
- {plotnine-0.15.0a6.dist-info → plotnine-0.15.0a8.dist-info}/licenses/LICENSE +0 -0
- {plotnine-0.15.0a6.dist-info → plotnine-0.15.0a8.dist-info}/top_level.txt +0 -0
|
@@ -13,7 +13,7 @@ if TYPE_CHECKING:
|
|
|
13
13
|
from matplotlib.figure import Figure
|
|
14
14
|
|
|
15
15
|
from plotnine import ggplot
|
|
16
|
-
from plotnine.composition import
|
|
16
|
+
from plotnine.composition import Compose
|
|
17
17
|
|
|
18
18
|
|
|
19
19
|
class PlotnineLayoutEngine(LayoutEngine):
|
|
@@ -54,7 +54,7 @@ class PlotnineCompositionLayoutEngine(LayoutEngine):
|
|
|
54
54
|
_adjust_compatible = True
|
|
55
55
|
_colorbar_gridspec = False
|
|
56
56
|
|
|
57
|
-
def __init__(self, composition:
|
|
57
|
+
def __init__(self, composition: Compose):
|
|
58
58
|
self.composition = composition
|
|
59
59
|
|
|
60
60
|
def execute(self, fig: Figure):
|
|
@@ -698,7 +698,9 @@ class TextJustifier:
|
|
|
698
698
|
"""
|
|
699
699
|
Horizontally Justify text accross the panel(s) width
|
|
700
700
|
"""
|
|
701
|
-
self.horizontally(
|
|
701
|
+
self.horizontally(
|
|
702
|
+
text, ha, self.spaces.l.panel_left, self.spaces.r.panel_right
|
|
703
|
+
)
|
|
702
704
|
|
|
703
705
|
def horizontally_across_plot(
|
|
704
706
|
self, text: Text, ha: HorizontalJustification | float
|
|
@@ -716,7 +718,9 @@ class TextJustifier:
|
|
|
716
718
|
"""
|
|
717
719
|
Horizontally Justify text along the panel(s) height
|
|
718
720
|
"""
|
|
719
|
-
self.vertically(
|
|
721
|
+
self.vertically(
|
|
722
|
+
text, va, self.spaces.b.panel_bottom, self.spaces.t.panel_top
|
|
723
|
+
)
|
|
720
724
|
|
|
721
725
|
def vertically_along_plot(
|
|
722
726
|
self, text: Text, va: VerticalJustification | float
|
|
@@ -16,7 +16,7 @@ if TYPE_CHECKING:
|
|
|
16
16
|
|
|
17
17
|
from plotnine import ggplot
|
|
18
18
|
from plotnine._mpl.gridspec import p9GridSpec
|
|
19
|
-
from plotnine.composition import
|
|
19
|
+
from plotnine.composition import Compose
|
|
20
20
|
|
|
21
21
|
|
|
22
22
|
@dataclass
|
|
@@ -82,7 +82,7 @@ class LayoutTree:
|
|
|
82
82
|
|
|
83
83
|
@staticmethod
|
|
84
84
|
def create(
|
|
85
|
-
cmp:
|
|
85
|
+
cmp: Compose,
|
|
86
86
|
lookup_spaces: dict[ggplot, LayoutSpaces],
|
|
87
87
|
) -> LayoutTree:
|
|
88
88
|
"""
|
|
@@ -118,6 +118,7 @@ class LayoutTree:
|
|
|
118
118
|
"""
|
|
119
119
|
Align and resize plots in composition to look good
|
|
120
120
|
"""
|
|
121
|
+
self.align_axis_titles()
|
|
121
122
|
self.align()
|
|
122
123
|
self.resize()
|
|
123
124
|
|
|
@@ -147,6 +148,20 @@ class LayoutTree:
|
|
|
147
148
|
for tree in self.sub_compositions:
|
|
148
149
|
tree.align()
|
|
149
150
|
|
|
151
|
+
@abc.abstractmethod
|
|
152
|
+
def align_axis_titles(self):
|
|
153
|
+
"""
|
|
154
|
+
Align the axis titles along the composing dimension
|
|
155
|
+
|
|
156
|
+
Since the alignment value used to for this purpose is one of
|
|
157
|
+
the fields in the _side_space, it affects the space created
|
|
158
|
+
for the panel.
|
|
159
|
+
|
|
160
|
+
We could align the titles within self.align but we would have
|
|
161
|
+
to store the value outside the _side_space and pick it up when
|
|
162
|
+
setting the position of the texts!
|
|
163
|
+
"""
|
|
164
|
+
|
|
150
165
|
def resize_sub_compositions(self):
|
|
151
166
|
"""
|
|
152
167
|
Resize panels in the compositions contained in this one
|
|
@@ -163,62 +178,62 @@ class LayoutTree:
|
|
|
163
178
|
|
|
164
179
|
@cached_property
|
|
165
180
|
@abc.abstractmethod
|
|
166
|
-
def
|
|
181
|
+
def panel_lefts(self) -> Sequence[float]:
|
|
167
182
|
"""
|
|
168
183
|
Left values [figure space] of nodes in this tree
|
|
169
184
|
"""
|
|
170
185
|
|
|
171
186
|
@cached_property
|
|
172
187
|
@abc.abstractmethod
|
|
173
|
-
def
|
|
188
|
+
def panel_rights(self) -> Sequence[float]:
|
|
174
189
|
"""
|
|
175
190
|
Right values [figure space] of nodes in this tree
|
|
176
191
|
"""
|
|
177
192
|
|
|
178
193
|
@cached_property
|
|
179
194
|
@abc.abstractmethod
|
|
180
|
-
def
|
|
195
|
+
def panel_bottoms(self) -> Sequence[float]:
|
|
181
196
|
"""
|
|
182
197
|
Bottom values [figure space] of nodes in this tree
|
|
183
198
|
"""
|
|
184
199
|
|
|
185
200
|
@cached_property
|
|
186
201
|
@abc.abstractmethod
|
|
187
|
-
def
|
|
202
|
+
def panel_tops(self) -> Sequence[float]:
|
|
188
203
|
"""
|
|
189
204
|
Top values [figure space] of nodes in this tree
|
|
190
205
|
"""
|
|
191
206
|
|
|
192
207
|
@property
|
|
193
|
-
def
|
|
208
|
+
def panel_lefts_align(self) -> bool:
|
|
194
209
|
"""
|
|
195
210
|
Return True if panel lefts for the nodes are aligned
|
|
196
211
|
"""
|
|
197
|
-
arr = np.array(self.
|
|
212
|
+
arr = np.array(self.panel_lefts)
|
|
198
213
|
return all(arr == arr[0])
|
|
199
214
|
|
|
200
215
|
@property
|
|
201
|
-
def
|
|
216
|
+
def panel_rights_align(self) -> bool:
|
|
202
217
|
"""
|
|
203
218
|
Return True if panel rights for the nodes are aligned
|
|
204
219
|
"""
|
|
205
|
-
arr = np.array(self.
|
|
220
|
+
arr = np.array(self.panel_rights)
|
|
206
221
|
return all(arr == arr[0])
|
|
207
222
|
|
|
208
223
|
@property
|
|
209
|
-
def
|
|
224
|
+
def panel_bottoms_align(self) -> bool:
|
|
210
225
|
"""
|
|
211
226
|
Return True if panel bottoms for the nodes are aligned
|
|
212
227
|
"""
|
|
213
|
-
arr = np.array(self.
|
|
228
|
+
arr = np.array(self.panel_bottoms)
|
|
214
229
|
return all(arr == arr[0])
|
|
215
230
|
|
|
216
231
|
@property
|
|
217
|
-
def
|
|
232
|
+
def panel_tops_align(self) -> bool:
|
|
218
233
|
"""
|
|
219
234
|
Return True if panel tops for the nodes are aligned
|
|
220
235
|
"""
|
|
221
|
-
arr = np.array(self.
|
|
236
|
+
arr = np.array(self.panel_tops)
|
|
222
237
|
return all(arr == arr[0])
|
|
223
238
|
|
|
224
239
|
@property
|
|
@@ -365,6 +380,50 @@ class LayoutTree:
|
|
|
365
380
|
arr = np.array(self.top_tag_heights)
|
|
366
381
|
return all(arr == arr[0])
|
|
367
382
|
|
|
383
|
+
@property
|
|
384
|
+
def left_axis_titles_align(self) -> bool:
|
|
385
|
+
"""
|
|
386
|
+
Return True if the left axis titles align
|
|
387
|
+
"""
|
|
388
|
+
arr = np.array(self.left_axis_title_clearances)
|
|
389
|
+
return all(arr == arr[0])
|
|
390
|
+
|
|
391
|
+
@property
|
|
392
|
+
def bottom_axis_titles_align(self) -> bool:
|
|
393
|
+
"""
|
|
394
|
+
Return True if the bottom axis titles align
|
|
395
|
+
"""
|
|
396
|
+
arr = np.array(self.bottom_axis_title_clearances)
|
|
397
|
+
return all(arr == arr[0])
|
|
398
|
+
|
|
399
|
+
@cached_property
|
|
400
|
+
@abc.abstractmethod
|
|
401
|
+
def left_axis_title_clearance(self) -> float:
|
|
402
|
+
"""
|
|
403
|
+
Distance between the left y-axis title and the panel
|
|
404
|
+
"""
|
|
405
|
+
|
|
406
|
+
@cached_property
|
|
407
|
+
@abc.abstractmethod
|
|
408
|
+
def bottom_axis_title_clearance(self) -> float:
|
|
409
|
+
"""
|
|
410
|
+
Distance between the left x-axis title and the panel
|
|
411
|
+
"""
|
|
412
|
+
|
|
413
|
+
@cached_property
|
|
414
|
+
def left_axis_title_clearances(self) -> list[float]:
|
|
415
|
+
"""
|
|
416
|
+
Distances between the left y-axis titles and the panels
|
|
417
|
+
"""
|
|
418
|
+
return [node.left_axis_title_clearance for node in self.nodes]
|
|
419
|
+
|
|
420
|
+
@cached_property
|
|
421
|
+
def bottom_axis_title_clearances(self) -> list[float]:
|
|
422
|
+
"""
|
|
423
|
+
Distances between the bottom x-axis titles and the panels
|
|
424
|
+
"""
|
|
425
|
+
return [node.bottom_axis_title_clearance for node in self.nodes]
|
|
426
|
+
|
|
368
427
|
@abc.abstractmethod
|
|
369
428
|
def set_left_margin_alignment(self, value: float):
|
|
370
429
|
"""
|
|
@@ -429,6 +488,22 @@ class LayoutTree:
|
|
|
429
488
|
In figure dimenstions
|
|
430
489
|
"""
|
|
431
490
|
|
|
491
|
+
@abc.abstractmethod
|
|
492
|
+
def set_left_axis_title_alignment(self, value: float):
|
|
493
|
+
"""
|
|
494
|
+
Set the space to align the left axis titles in this composition
|
|
495
|
+
|
|
496
|
+
In figure dimenstions
|
|
497
|
+
"""
|
|
498
|
+
|
|
499
|
+
@abc.abstractmethod
|
|
500
|
+
def set_bottom_axis_title_alignment(self, value: float):
|
|
501
|
+
"""
|
|
502
|
+
Set the space to align the bottom axis titles in this composition
|
|
503
|
+
|
|
504
|
+
In figure dimenstions
|
|
505
|
+
"""
|
|
506
|
+
|
|
432
507
|
|
|
433
508
|
@dataclass
|
|
434
509
|
class ColumnsTree(LayoutTree):
|
|
@@ -454,10 +529,15 @@ class ColumnsTree(LayoutTree):
|
|
|
454
529
|
def align(self):
|
|
455
530
|
self.align_top_tags()
|
|
456
531
|
self.align_bottom_tags()
|
|
457
|
-
self.
|
|
458
|
-
self.
|
|
532
|
+
self.align_panel_tops()
|
|
533
|
+
self.align_panel_bottoms()
|
|
459
534
|
self.align_sub_compositions()
|
|
460
535
|
|
|
536
|
+
def align_axis_titles(self):
|
|
537
|
+
self.align_bottom_axis_titles()
|
|
538
|
+
for tree in self.sub_compositions:
|
|
539
|
+
tree.align_axis_titles()
|
|
540
|
+
|
|
461
541
|
def resize(self):
|
|
462
542
|
"""
|
|
463
543
|
Resize the widths of gridspec so that panels have equal widths
|
|
@@ -473,7 +553,7 @@ class ColumnsTree(LayoutTree):
|
|
|
473
553
|
self.gridspec.set_width_ratios(width_ratios)
|
|
474
554
|
self.resize_sub_compositions()
|
|
475
555
|
|
|
476
|
-
def
|
|
556
|
+
def align_panel_bottoms(self):
|
|
477
557
|
"""
|
|
478
558
|
Align the immediate bottom edges this composition
|
|
479
559
|
|
|
@@ -488,19 +568,19 @@ class ColumnsTree(LayoutTree):
|
|
|
488
568
|
# If panels are aligned and have a non-zero margin_alignment,
|
|
489
569
|
# aligning them again will set that value to zero and undoes
|
|
490
570
|
# the alignment.
|
|
491
|
-
if self.
|
|
571
|
+
if self.panel_bottoms_align:
|
|
492
572
|
return
|
|
493
573
|
|
|
494
|
-
values = max(self.
|
|
574
|
+
values = max(self.panel_bottoms) - np.array(self.panel_bottoms)
|
|
495
575
|
for item, value in zip(self.nodes, values):
|
|
496
576
|
if isinstance(item, LayoutSpaces):
|
|
497
577
|
item.b.margin_alignment = value
|
|
498
578
|
else:
|
|
499
579
|
item.set_bottom_margin_alignment(value)
|
|
500
580
|
|
|
501
|
-
del self.
|
|
581
|
+
del self.panel_bottoms
|
|
502
582
|
|
|
503
|
-
def
|
|
583
|
+
def align_panel_tops(self):
|
|
504
584
|
"""
|
|
505
585
|
Align the immediate top edges in this composition
|
|
506
586
|
|
|
@@ -512,17 +592,17 @@ class ColumnsTree(LayoutTree):
|
|
|
512
592
|
| | | | | |
|
|
513
593
|
----------- -----------
|
|
514
594
|
"""
|
|
515
|
-
if self.
|
|
595
|
+
if self.panel_tops_align:
|
|
516
596
|
return
|
|
517
597
|
|
|
518
|
-
values = np.array(self.
|
|
598
|
+
values = np.array(self.panel_tops) - min(self.panel_tops)
|
|
519
599
|
for item, value in zip(self.nodes, values):
|
|
520
600
|
if isinstance(item, LayoutSpaces):
|
|
521
601
|
item.t.margin_alignment = value
|
|
522
602
|
else:
|
|
523
603
|
item.set_top_margin_alignment(value)
|
|
524
604
|
|
|
525
|
-
del self.
|
|
605
|
+
del self.panel_tops
|
|
526
606
|
|
|
527
607
|
def align_bottom_tags(self):
|
|
528
608
|
if self.bottom_tags_align:
|
|
@@ -552,40 +632,57 @@ class ColumnsTree(LayoutTree):
|
|
|
552
632
|
else:
|
|
553
633
|
item.set_top_tag_alignment(value)
|
|
554
634
|
|
|
635
|
+
def align_bottom_axis_titles(self):
|
|
636
|
+
if self.bottom_axis_titles_align:
|
|
637
|
+
pass
|
|
638
|
+
|
|
639
|
+
values = max(self.bottom_axis_title_clearances) - np.array(
|
|
640
|
+
self.bottom_axis_title_clearances
|
|
641
|
+
)
|
|
642
|
+
# We ignore 0 values since they can undo values
|
|
643
|
+
# set to align this composition with an outer one.
|
|
644
|
+
for item, value in zip(self.nodes, values):
|
|
645
|
+
if value == 0:
|
|
646
|
+
continue
|
|
647
|
+
if isinstance(item, LayoutSpaces):
|
|
648
|
+
item.b.axis_title_alignment = value
|
|
649
|
+
else:
|
|
650
|
+
item.set_bottom_axis_title_alignment(value)
|
|
651
|
+
|
|
555
652
|
@cached_property
|
|
556
|
-
def
|
|
653
|
+
def panel_lefts(self):
|
|
557
654
|
left_item = self.nodes[0]
|
|
558
655
|
if isinstance(left_item, LayoutSpaces):
|
|
559
|
-
return [left_item.l.
|
|
656
|
+
return [left_item.l.panel_left]
|
|
560
657
|
else:
|
|
561
|
-
return left_item.
|
|
658
|
+
return left_item.panel_lefts
|
|
562
659
|
|
|
563
660
|
@cached_property
|
|
564
|
-
def
|
|
661
|
+
def panel_rights(self):
|
|
565
662
|
right_item = self.nodes[-1]
|
|
566
663
|
if isinstance(right_item, LayoutSpaces):
|
|
567
|
-
return [right_item.r.
|
|
664
|
+
return [right_item.r.panel_right]
|
|
568
665
|
else:
|
|
569
|
-
return right_item.
|
|
666
|
+
return right_item.panel_rights
|
|
570
667
|
|
|
571
668
|
@cached_property
|
|
572
|
-
def
|
|
669
|
+
def panel_bottoms(self):
|
|
573
670
|
values = []
|
|
574
671
|
for item in self.nodes:
|
|
575
672
|
if isinstance(item, LayoutSpaces):
|
|
576
|
-
values.append(item.b.
|
|
673
|
+
values.append(item.b.panel_bottom)
|
|
577
674
|
else:
|
|
578
|
-
values.append(max(item.
|
|
675
|
+
values.append(max(item.panel_bottoms))
|
|
579
676
|
return values
|
|
580
677
|
|
|
581
678
|
@cached_property
|
|
582
|
-
def
|
|
679
|
+
def panel_tops(self):
|
|
583
680
|
values = []
|
|
584
681
|
for item in self.nodes:
|
|
585
682
|
if isinstance(item, LayoutSpaces):
|
|
586
|
-
values.append(item.t.
|
|
683
|
+
values.append(item.t.panel_top)
|
|
587
684
|
else:
|
|
588
|
-
values.append(min(item.
|
|
685
|
+
values.append(min(item.panel_tops))
|
|
589
686
|
return values
|
|
590
687
|
|
|
591
688
|
@property
|
|
@@ -620,6 +717,14 @@ class ColumnsTree(LayoutTree):
|
|
|
620
717
|
def top_tag_height(self) -> float:
|
|
621
718
|
return max(self.top_tag_heights)
|
|
622
719
|
|
|
720
|
+
@cached_property
|
|
721
|
+
def left_axis_title_clearance(self) -> float:
|
|
722
|
+
return self.left_axis_title_clearances[0]
|
|
723
|
+
|
|
724
|
+
@cached_property
|
|
725
|
+
def bottom_axis_title_clearance(self) -> float:
|
|
726
|
+
return max(self.bottom_axis_title_clearances)
|
|
727
|
+
|
|
623
728
|
def set_left_margin_alignment(self, value: float):
|
|
624
729
|
left_item = self.nodes[0]
|
|
625
730
|
if isinstance(left_item, LayoutSpaces):
|
|
@@ -662,6 +767,20 @@ class ColumnsTree(LayoutTree):
|
|
|
662
767
|
else:
|
|
663
768
|
item.set_top_tag_alignment(value)
|
|
664
769
|
|
|
770
|
+
def set_bottom_axis_title_alignment(self, value: float):
|
|
771
|
+
for item in self.nodes:
|
|
772
|
+
if isinstance(item, LayoutSpaces):
|
|
773
|
+
item.b.axis_title_alignment = value
|
|
774
|
+
else:
|
|
775
|
+
item.set_bottom_axis_title_alignment(value)
|
|
776
|
+
|
|
777
|
+
def set_left_axis_title_alignment(self, value: float):
|
|
778
|
+
left_item = self.nodes[0]
|
|
779
|
+
if isinstance(left_item, LayoutSpaces):
|
|
780
|
+
left_item.l.axis_title_alignment = value
|
|
781
|
+
else:
|
|
782
|
+
left_item.set_left_axis_title_alignment(value)
|
|
783
|
+
|
|
665
784
|
|
|
666
785
|
@dataclass
|
|
667
786
|
class RowsTree(LayoutTree):
|
|
@@ -684,10 +803,15 @@ class RowsTree(LayoutTree):
|
|
|
684
803
|
def align(self):
|
|
685
804
|
self.align_left_tags()
|
|
686
805
|
self.align_right_tags()
|
|
687
|
-
self.
|
|
688
|
-
self.
|
|
806
|
+
self.align_panel_lefts()
|
|
807
|
+
self.align_panel_rights()
|
|
689
808
|
self.align_sub_compositions()
|
|
690
809
|
|
|
810
|
+
def align_axis_titles(self):
|
|
811
|
+
self.align_left_axis_titles()
|
|
812
|
+
for tree in self.sub_compositions:
|
|
813
|
+
tree.align_axis_titles()
|
|
814
|
+
|
|
691
815
|
def resize(self):
|
|
692
816
|
"""
|
|
693
817
|
Resize the heights of gridspec so that panels have equal heights
|
|
@@ -704,7 +828,7 @@ class RowsTree(LayoutTree):
|
|
|
704
828
|
self.gridspec.set_height_ratios(height_ratios)
|
|
705
829
|
self.resize_sub_compositions()
|
|
706
830
|
|
|
707
|
-
def
|
|
831
|
+
def align_panel_lefts(self):
|
|
708
832
|
"""
|
|
709
833
|
Align the immediate left edges in this composition
|
|
710
834
|
|
|
@@ -718,19 +842,19 @@ class RowsTree(LayoutTree):
|
|
|
718
842
|
| # | | # |
|
|
719
843
|
----------- -----------
|
|
720
844
|
"""
|
|
721
|
-
if self.
|
|
845
|
+
if self.panel_lefts_align:
|
|
722
846
|
return
|
|
723
847
|
|
|
724
|
-
values = max(self.
|
|
848
|
+
values = max(self.panel_lefts) - np.array(self.panel_lefts)
|
|
725
849
|
for item, value in zip(self.nodes, values):
|
|
726
850
|
if isinstance(item, LayoutSpaces):
|
|
727
851
|
item.l.margin_alignment = value
|
|
728
852
|
else:
|
|
729
853
|
item.set_left_margin_alignment(value)
|
|
730
854
|
|
|
731
|
-
del self.
|
|
855
|
+
del self.panel_lefts
|
|
732
856
|
|
|
733
|
-
def
|
|
857
|
+
def align_panel_rights(self):
|
|
734
858
|
"""
|
|
735
859
|
Align the immediate right edges in this composition
|
|
736
860
|
|
|
@@ -744,17 +868,17 @@ class RowsTree(LayoutTree):
|
|
|
744
868
|
| #| | # |
|
|
745
869
|
----------- -----------
|
|
746
870
|
"""
|
|
747
|
-
if self.
|
|
871
|
+
if self.panel_rights_align:
|
|
748
872
|
return
|
|
749
873
|
|
|
750
|
-
values = np.array(self.
|
|
874
|
+
values = np.array(self.panel_rights) - min(self.panel_rights)
|
|
751
875
|
for item, value in zip(self.nodes, values):
|
|
752
876
|
if isinstance(item, LayoutSpaces):
|
|
753
877
|
item.r.margin_alignment = value
|
|
754
878
|
else:
|
|
755
879
|
item.set_right_margin_alignment(value)
|
|
756
880
|
|
|
757
|
-
del self.
|
|
881
|
+
del self.panel_rights
|
|
758
882
|
|
|
759
883
|
def align_left_tags(self):
|
|
760
884
|
"""
|
|
@@ -804,41 +928,56 @@ class RowsTree(LayoutTree):
|
|
|
804
928
|
else:
|
|
805
929
|
item.set_right_tag_alignment(value)
|
|
806
930
|
|
|
931
|
+
def align_left_axis_titles(self):
|
|
932
|
+
if self.left_axis_titles_align:
|
|
933
|
+
pass
|
|
934
|
+
|
|
935
|
+
values = max(self.left_axis_title_clearances) - np.array(
|
|
936
|
+
self.left_axis_title_clearances
|
|
937
|
+
)
|
|
938
|
+
for item, value in zip(self.nodes, values):
|
|
939
|
+
if value == 0:
|
|
940
|
+
continue
|
|
941
|
+
if isinstance(item, LayoutSpaces):
|
|
942
|
+
item.l.axis_title_alignment = value
|
|
943
|
+
else:
|
|
944
|
+
item.set_left_axis_title_alignment(value)
|
|
945
|
+
|
|
807
946
|
@cached_property
|
|
808
|
-
def
|
|
947
|
+
def panel_lefts(self):
|
|
809
948
|
values = []
|
|
810
949
|
for item in self.nodes:
|
|
811
950
|
if isinstance(item, LayoutSpaces):
|
|
812
|
-
values.append(item.l.
|
|
951
|
+
values.append(item.l.panel_left)
|
|
813
952
|
else:
|
|
814
|
-
values.append(max(item.
|
|
953
|
+
values.append(max(item.panel_lefts))
|
|
815
954
|
return values
|
|
816
955
|
|
|
817
956
|
@cached_property
|
|
818
|
-
def
|
|
957
|
+
def panel_rights(self):
|
|
819
958
|
values = []
|
|
820
959
|
for item in self.nodes:
|
|
821
960
|
if isinstance(item, LayoutSpaces):
|
|
822
|
-
values.append(item.r.
|
|
961
|
+
values.append(item.r.panel_right)
|
|
823
962
|
else:
|
|
824
|
-
values.append(min(item.
|
|
963
|
+
values.append(min(item.panel_rights))
|
|
825
964
|
return values
|
|
826
965
|
|
|
827
966
|
@cached_property
|
|
828
|
-
def
|
|
967
|
+
def panel_bottoms(self):
|
|
829
968
|
bottom_item = self.nodes[-1]
|
|
830
969
|
if isinstance(bottom_item, LayoutSpaces):
|
|
831
|
-
return [bottom_item.b.
|
|
970
|
+
return [bottom_item.b.panel_bottom]
|
|
832
971
|
else:
|
|
833
|
-
return bottom_item.
|
|
972
|
+
return bottom_item.panel_bottoms
|
|
834
973
|
|
|
835
974
|
@cached_property
|
|
836
|
-
def
|
|
975
|
+
def panel_tops(self):
|
|
837
976
|
top_item = self.nodes[0]
|
|
838
977
|
if isinstance(top_item, LayoutSpaces):
|
|
839
|
-
return [top_item.t.
|
|
978
|
+
return [top_item.t.panel_top]
|
|
840
979
|
else:
|
|
841
|
-
return top_item.
|
|
980
|
+
return top_item.panel_tops
|
|
842
981
|
|
|
843
982
|
@property
|
|
844
983
|
def panel_width(self) -> float:
|
|
@@ -872,6 +1011,14 @@ class RowsTree(LayoutTree):
|
|
|
872
1011
|
def bottom_tag_height(self) -> float:
|
|
873
1012
|
return self.bottom_tag_heights[-1]
|
|
874
1013
|
|
|
1014
|
+
@cached_property
|
|
1015
|
+
def left_axis_title_clearance(self) -> float:
|
|
1016
|
+
return max(self.left_axis_title_clearances)
|
|
1017
|
+
|
|
1018
|
+
@cached_property
|
|
1019
|
+
def bottom_axis_title_clearance(self) -> float:
|
|
1020
|
+
return self.bottom_axis_title_clearances[-1]
|
|
1021
|
+
|
|
875
1022
|
def set_left_margin_alignment(self, value: float):
|
|
876
1023
|
for item in self.nodes:
|
|
877
1024
|
if isinstance(item, LayoutSpaces):
|
|
@@ -913,3 +1060,17 @@ class RowsTree(LayoutTree):
|
|
|
913
1060
|
item.r.tag_alignment = value
|
|
914
1061
|
else:
|
|
915
1062
|
item.set_right_tag_alignment(value)
|
|
1063
|
+
|
|
1064
|
+
def set_left_axis_title_alignment(self, value: float):
|
|
1065
|
+
for item in self.nodes:
|
|
1066
|
+
if isinstance(item, LayoutSpaces):
|
|
1067
|
+
item.l.axis_title_alignment = value
|
|
1068
|
+
else:
|
|
1069
|
+
item.set_left_axis_title_alignment(value)
|
|
1070
|
+
|
|
1071
|
+
def set_bottom_axis_title_alignment(self, value: float):
|
|
1072
|
+
bottom_item = self.nodes[-1]
|
|
1073
|
+
if isinstance(bottom_item, LayoutSpaces):
|
|
1074
|
+
bottom_item.b.axis_title_alignment = value
|
|
1075
|
+
else:
|
|
1076
|
+
bottom_item.set_bottom_axis_title_alignment(value)
|