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.
Files changed (55) hide show
  1. plotnine/_mpl/layout_manager/_engine.py +2 -2
  2. plotnine/_mpl/layout_manager/_layout_items.py +6 -2
  3. plotnine/_mpl/layout_manager/_layout_tree.py +219 -58
  4. plotnine/_mpl/layout_manager/_spaces.py +98 -28
  5. plotnine/_mpl/text.py +1 -7
  6. plotnine/composition/__init__.py +2 -2
  7. plotnine/composition/_beside.py +12 -4
  8. plotnine/composition/{_arrange.py → _compose.py} +118 -38
  9. plotnine/composition/_plot_spacer.py +6 -0
  10. plotnine/composition/_stack.py +12 -4
  11. plotnine/geoms/geom_bar.py +1 -0
  12. plotnine/geoms/geom_bin_2d.py +4 -0
  13. plotnine/geoms/geom_boxplot.py +4 -0
  14. plotnine/geoms/geom_count.py +4 -0
  15. plotnine/geoms/geom_density_2d.py +4 -0
  16. plotnine/geoms/geom_dotplot.py +1 -1
  17. plotnine/geoms/geom_histogram.py +1 -1
  18. plotnine/geoms/geom_pointdensity.py +4 -0
  19. plotnine/geoms/geom_qq.py +4 -0
  20. plotnine/geoms/geom_qq_line.py +4 -0
  21. plotnine/geoms/geom_quantile.py +4 -0
  22. plotnine/geoms/geom_sina.py +1 -1
  23. plotnine/geoms/geom_smooth.py +4 -0
  24. plotnine/geoms/geom_violin.py +4 -0
  25. plotnine/ggplot.py +4 -4
  26. plotnine/stats/stat_bin.py +4 -0
  27. plotnine/stats/stat_bin_2d.py +4 -0
  28. plotnine/stats/stat_bindot.py +1 -0
  29. plotnine/stats/stat_boxplot.py +1 -1
  30. plotnine/stats/stat_count.py +1 -0
  31. plotnine/stats/stat_density.py +1 -1
  32. plotnine/stats/stat_density_2d.py +1 -0
  33. plotnine/stats/stat_ecdf.py +1 -1
  34. plotnine/stats/stat_ellipse.py +4 -0
  35. plotnine/stats/stat_function.py +4 -0
  36. plotnine/stats/stat_hull.py +4 -0
  37. plotnine/stats/stat_identity.py +4 -0
  38. plotnine/stats/stat_pointdensity.py +1 -0
  39. plotnine/stats/stat_qq.py +1 -0
  40. plotnine/stats/stat_qq_line.py +1 -0
  41. plotnine/stats/stat_quantile.py +1 -1
  42. plotnine/stats/stat_sina.py +1 -1
  43. plotnine/stats/stat_smooth.py +1 -0
  44. plotnine/stats/stat_sum.py +4 -0
  45. plotnine/stats/stat_summary.py +1 -1
  46. plotnine/stats/stat_summary_bin.py +1 -1
  47. plotnine/stats/stat_unique.py +4 -0
  48. plotnine/stats/stat_ydensity.py +1 -1
  49. plotnine/themes/theme.py +1 -1
  50. plotnine/themes/theme_void.py +1 -7
  51. {plotnine-0.15.0a6.dist-info → plotnine-0.15.0a8.dist-info}/METADATA +1 -1
  52. {plotnine-0.15.0a6.dist-info → plotnine-0.15.0a8.dist-info}/RECORD +55 -55
  53. {plotnine-0.15.0a6.dist-info → plotnine-0.15.0a8.dist-info}/WHEEL +0 -0
  54. {plotnine-0.15.0a6.dist-info → plotnine-0.15.0a8.dist-info}/licenses/LICENSE +0 -0
  55. {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 Arrange
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: Arrange):
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(text, ha, self.spaces.l.left, self.spaces.r.right)
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(text, va, self.spaces.b.bottom, self.spaces.t.top)
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 Arrange
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: Arrange,
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 lefts(self) -> Sequence[float]:
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 rights(self) -> Sequence[float]:
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 bottoms(self) -> Sequence[float]:
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 tops(self) -> Sequence[float]:
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 lefts_align(self) -> bool:
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.lefts)
212
+ arr = np.array(self.panel_lefts)
198
213
  return all(arr == arr[0])
199
214
 
200
215
  @property
201
- def rights_align(self) -> bool:
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.rights)
220
+ arr = np.array(self.panel_rights)
206
221
  return all(arr == arr[0])
207
222
 
208
223
  @property
209
- def bottoms_align(self) -> bool:
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.bottoms)
228
+ arr = np.array(self.panel_bottoms)
214
229
  return all(arr == arr[0])
215
230
 
216
231
  @property
217
- def tops_align(self) -> bool:
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.tops)
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.align_tops()
458
- self.align_bottoms()
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 align_bottoms(self):
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.bottoms_align:
571
+ if self.panel_bottoms_align:
492
572
  return
493
573
 
494
- values = max(self.bottoms) - np.array(self.bottoms)
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.bottoms
581
+ del self.panel_bottoms
502
582
 
503
- def align_tops(self):
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.tops_align:
595
+ if self.panel_tops_align:
516
596
  return
517
597
 
518
- values = np.array(self.tops) - min(self.tops)
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.tops
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 lefts(self):
653
+ def panel_lefts(self):
557
654
  left_item = self.nodes[0]
558
655
  if isinstance(left_item, LayoutSpaces):
559
- return [left_item.l.left]
656
+ return [left_item.l.panel_left]
560
657
  else:
561
- return left_item.lefts
658
+ return left_item.panel_lefts
562
659
 
563
660
  @cached_property
564
- def rights(self):
661
+ def panel_rights(self):
565
662
  right_item = self.nodes[-1]
566
663
  if isinstance(right_item, LayoutSpaces):
567
- return [right_item.r.right]
664
+ return [right_item.r.panel_right]
568
665
  else:
569
- return right_item.rights
666
+ return right_item.panel_rights
570
667
 
571
668
  @cached_property
572
- def bottoms(self):
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.bottom)
673
+ values.append(item.b.panel_bottom)
577
674
  else:
578
- values.append(max(item.bottoms))
675
+ values.append(max(item.panel_bottoms))
579
676
  return values
580
677
 
581
678
  @cached_property
582
- def tops(self):
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.top)
683
+ values.append(item.t.panel_top)
587
684
  else:
588
- values.append(min(item.tops))
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.align_lefts()
688
- self.align_rights()
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 align_lefts(self):
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.lefts_align:
845
+ if self.panel_lefts_align:
722
846
  return
723
847
 
724
- values = max(self.lefts) - np.array(self.lefts)
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.lefts
855
+ del self.panel_lefts
732
856
 
733
- def align_rights(self):
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.rights_align:
871
+ if self.panel_rights_align:
748
872
  return
749
873
 
750
- values = np.array(self.rights) - min(self.rights)
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.rights
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 lefts(self):
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.left)
951
+ values.append(item.l.panel_left)
813
952
  else:
814
- values.append(max(item.lefts))
953
+ values.append(max(item.panel_lefts))
815
954
  return values
816
955
 
817
956
  @cached_property
818
- def rights(self):
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.right)
961
+ values.append(item.r.panel_right)
823
962
  else:
824
- values.append(min(item.rights))
963
+ values.append(min(item.panel_rights))
825
964
  return values
826
965
 
827
966
  @cached_property
828
- def bottoms(self):
967
+ def panel_bottoms(self):
829
968
  bottom_item = self.nodes[-1]
830
969
  if isinstance(bottom_item, LayoutSpaces):
831
- return [bottom_item.b.bottom]
970
+ return [bottom_item.b.panel_bottom]
832
971
  else:
833
- return bottom_item.bottoms
972
+ return bottom_item.panel_bottoms
834
973
 
835
974
  @cached_property
836
- def tops(self):
975
+ def panel_tops(self):
837
976
  top_item = self.nodes[0]
838
977
  if isinstance(top_item, LayoutSpaces):
839
- return [top_item.t.top]
978
+ return [top_item.t.panel_top]
840
979
  else:
841
- return top_item.tops
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)