plotnine 0.15.0.dev1__py3-none-any.whl → 0.15.0.dev3__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.
@@ -1,7 +1,6 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  import abc
4
- from contextlib import suppress
5
4
  from dataclasses import dataclass
6
5
  from functools import cached_property
7
6
  from typing import TYPE_CHECKING
@@ -81,6 +80,13 @@ class LayoutTree:
81
80
  represents.
82
81
  """
83
82
 
83
+ @cached_property
84
+ def sub_compositions(self) -> list[LayoutTree]:
85
+ """
86
+ LayoutTrees of the direct sub compositions of this one
87
+ """
88
+ return [item for item in self.nodes if isinstance(item, LayoutTree)]
89
+
84
90
  @cached_property
85
91
  @abc.abstractmethod
86
92
  def lefts(self) -> Sequence[float]:
@@ -141,89 +147,54 @@ class LayoutTree:
141
147
  In figure dimenstions
142
148
  """
143
149
 
144
- def align_lefts(self):
150
+ @abc.abstractmethod
151
+ def align(self):
145
152
  """
146
- Align the immediate left edges in this composition
153
+ Align all the edges in this composition & contained compositions
147
154
 
148
- ----------- -----------
149
- |# | | # |
150
- |# | | # |
151
- |# | | # |
152
- |-----------| -> |-----------|
153
- | # | | # |
154
- | # | | # |
155
- | # | | # |
156
- ----------- -----------
155
+ This function mutates the layout spaces, specifically the
156
+ alignment_margins along the sides of the plot.
157
157
  """
158
158
 
159
- def align_bottoms(self):
159
+ def align_sub_compositions(self):
160
160
  """
161
- Align the immediate bottom edges this composition
162
-
163
- ----------- -----------
164
- | | | | | |
165
- | | | | | |
166
- | | | -> | | |
167
- | |#####| |#####|#####|
168
- |#####| | | | |
169
- ----------- -----------
161
+ Align the compositions contained in this one
170
162
  """
163
+ # Recurse into the contained compositions
164
+ for tree in self.sub_compositions:
165
+ tree.align()
171
166
 
172
- def align_rights(self):
167
+ @property
168
+ def bottoms_align(self) -> bool:
173
169
  """
174
- Align the immediate right edges in this composition
175
-
176
- ----------- -----------
177
- | # | | # |
178
- | # | | # |
179
- | # | | # |
180
- |-----------| -> |-----------|
181
- | #| | # |
182
- | #| | # |
183
- | #| | # |
184
- ----------- -----------
170
+ Return True if panel bottoms for the nodes are aligned
185
171
  """
172
+ arr = np.array(self.bottoms)
173
+ return all(arr == arr[0])
186
174
 
187
- def align_tops(self):
175
+ @property
176
+ def lefts_align(self) -> bool:
188
177
  """
189
- Align the immediate top edges in this composition
190
-
191
- ----------- -----------
192
- |#####| | | | |
193
- | |#####| |#####|#####|
194
- | | | -> | | |
195
- | | | | | |
196
- | | | | | |
197
- ----------- -----------
178
+ Return True if panel lefts for the nodes are aligned
198
179
  """
180
+ arr = np.array(self.lefts)
181
+ return all(arr == arr[0])
199
182
 
200
- def align(self):
183
+ @property
184
+ def tops_align(self) -> bool:
201
185
  """
202
- Align all the edges in this composition & contained compositions
203
-
204
- This function mutates the layout spaces, specifically the
205
- alignment_margins along the sides of the plot.
186
+ Return True if panel tops for the nodes are aligned
206
187
  """
207
- self.align_lefts()
208
- self.align_bottoms()
209
- self.align_rights()
210
- self.align_tops()
211
-
212
- for item in self.nodes:
213
- if isinstance(item, LayoutTree):
214
- item.align()
215
-
216
- with suppress(AttributeError):
217
- del self.lefts
218
-
219
- with suppress(AttributeError):
220
- del self.bottoms
188
+ arr = np.array(self.tops)
189
+ return all(arr == arr[0])
221
190
 
222
- with suppress(AttributeError):
223
- del self.rights
224
-
225
- with suppress(AttributeError):
226
- del self.tops
191
+ @property
192
+ def rights_align(self) -> bool:
193
+ """
194
+ Return True if panel rights for the nodes are aligned
195
+ """
196
+ arr = np.array(self.rights)
197
+ return all(arr == arr[0])
227
198
 
228
199
  @property
229
200
  @abc.abstractmethod
@@ -288,22 +259,13 @@ class LayoutTree:
288
259
  This function mutates the composition gridspecs; specifically the
289
260
  width_ratios and height_ratios.
290
261
  """
291
- self.resize_widths()
292
- self.resize_heights()
293
262
 
294
- for item in self.nodes:
295
- if isinstance(item, LayoutTree):
296
- item.resize()
297
-
298
- def resize_widths(self):
263
+ def resize_sub_compositions(self):
299
264
  """
300
- Resize the widths of gridspec so that panels have equal widths
301
- """
302
-
303
- def resize_heights(self):
304
- """
305
- Resize the heights of gridspec so that panels have equal heights
265
+ Resize panels in the compositions contained in this one
306
266
  """
267
+ for tree in self.sub_compositions:
268
+ tree.resize()
307
269
 
308
270
  @staticmethod
309
271
  def create(
@@ -368,6 +330,11 @@ class ColumnsTree(LayoutTree):
368
330
  -------------------
369
331
  """
370
332
 
333
+ def align(self):
334
+ self.align_tops()
335
+ self.align_bottoms()
336
+ self.align_sub_compositions()
337
+
371
338
  @cached_property
372
339
  def lefts(self):
373
340
  left_item = self.nodes[0]
@@ -383,14 +350,6 @@ class ColumnsTree(LayoutTree):
383
350
  else:
384
351
  left_item.set_left_alignment_margin(value)
385
352
 
386
- def align_bottoms(self):
387
- values = max(self.bottoms) - np.array(self.bottoms)
388
- for item, value in zip(self.nodes, values):
389
- if isinstance(item, LayoutSpaces):
390
- item.b.alignment_margin = value
391
- else:
392
- item.set_bottom_alignment_margin(value)
393
-
394
353
  @cached_property
395
354
  def bottoms(self):
396
355
  values = []
@@ -401,6 +360,33 @@ class ColumnsTree(LayoutTree):
401
360
  values.append(max(item.bottoms))
402
361
  return values
403
362
 
363
+ def align_bottoms(self):
364
+ """
365
+ Align the immediate bottom edges this composition
366
+
367
+ ----------- -----------
368
+ | | | | | |
369
+ | | | | | |
370
+ | | | -> | | |
371
+ | |#####| |#####|#####|
372
+ |#####| | | | |
373
+ ----------- -----------
374
+ """
375
+ # If panels are aligned and have a non-zero alignment_margin,
376
+ # aligning them again will set that value to zero and undoes
377
+ # the alignment.
378
+ if self.bottoms_align:
379
+ return
380
+
381
+ values = max(self.bottoms) - np.array(self.bottoms)
382
+ for item, value in zip(self.nodes, values):
383
+ if isinstance(item, LayoutSpaces):
384
+ item.b.alignment_margin = value
385
+ else:
386
+ item.set_bottom_alignment_margin(value)
387
+
388
+ del self.bottoms
389
+
404
390
  def set_bottom_alignment_margin(self, value: float):
405
391
  for item in self.nodes:
406
392
  if isinstance(item, LayoutSpaces):
@@ -423,14 +409,6 @@ class ColumnsTree(LayoutTree):
423
409
  else:
424
410
  right_item.set_right_alignment_margin(value)
425
411
 
426
- def align_tops(self):
427
- values = np.array(self.tops) - min(self.tops)
428
- for item, value in zip(self.nodes, values):
429
- if isinstance(item, LayoutSpaces):
430
- item.t.alignment_margin = value
431
- else:
432
- item.set_top_alignment_margin(value)
433
-
434
412
  @cached_property
435
413
  def tops(self):
436
414
  values = []
@@ -441,6 +419,30 @@ class ColumnsTree(LayoutTree):
441
419
  values.append(min(item.tops))
442
420
  return values
443
421
 
422
+ def align_tops(self):
423
+ """
424
+ Align the immediate top edges in this composition
425
+
426
+ ----------- -----------
427
+ |#####| | | | |
428
+ | |#####| |#####|#####|
429
+ | | | -> | | |
430
+ | | | | | |
431
+ | | | | | |
432
+ ----------- -----------
433
+ """
434
+ if self.tops_align:
435
+ return
436
+
437
+ values = np.array(self.tops) - min(self.tops)
438
+ for item, value in zip(self.nodes, values):
439
+ if isinstance(item, LayoutSpaces):
440
+ item.t.alignment_margin = value
441
+ else:
442
+ item.set_top_alignment_margin(value)
443
+
444
+ del self.tops
445
+
444
446
  def set_top_alignment_margin(self, value: float):
445
447
  for item in self.nodes:
446
448
  if isinstance(item, LayoutSpaces):
@@ -476,7 +478,10 @@ class ColumnsTree(LayoutTree):
476
478
  """
477
479
  return max(self.plot_heights)
478
480
 
479
- def resize_widths(self):
481
+ def resize(self):
482
+ """
483
+ Resize the widths of gridspec so that panels have equal widths
484
+ """
480
485
  # The new width of each panel is the average width of all
481
486
  # the panels plus all the space to the left and right
482
487
  # of the panels.
@@ -486,6 +491,7 @@ class ColumnsTree(LayoutTree):
486
491
  new_plot_widths = panel_widths.mean() + non_panel_space
487
492
  width_ratios = new_plot_widths / new_plot_widths.min()
488
493
  self.gridspec.set_width_ratios(width_ratios)
494
+ self.resize_sub_compositions()
489
495
 
490
496
 
491
497
  @dataclass
@@ -506,13 +512,10 @@ class RowsTree(LayoutTree):
506
512
  -------------------
507
513
  """
508
514
 
509
- def align_lefts(self):
510
- values = max(self.lefts) - np.array(self.lefts)
511
- for item, value in zip(self.nodes, values):
512
- if isinstance(item, LayoutSpaces):
513
- item.l.alignment_margin = value
514
- else:
515
- item.set_left_alignment_margin(value)
515
+ def align(self):
516
+ self.align_lefts()
517
+ self.align_rights()
518
+ self.align_sub_compositions()
516
519
 
517
520
  @cached_property
518
521
  def lefts(self):
@@ -524,6 +527,32 @@ class RowsTree(LayoutTree):
524
527
  values.append(max(item.lefts))
525
528
  return values
526
529
 
530
+ def align_lefts(self):
531
+ """
532
+ Align the immediate left edges in this composition
533
+
534
+ ----------- -----------
535
+ |# | | # |
536
+ |# | | # |
537
+ |# | | # |
538
+ |-----------| -> |-----------|
539
+ | # | | # |
540
+ | # | | # |
541
+ | # | | # |
542
+ ----------- -----------
543
+ """
544
+ if self.lefts_align:
545
+ return
546
+
547
+ values = max(self.lefts) - np.array(self.lefts)
548
+ for item, value in zip(self.nodes, values):
549
+ if isinstance(item, LayoutSpaces):
550
+ item.l.alignment_margin = value
551
+ else:
552
+ item.set_left_alignment_margin(value)
553
+
554
+ del self.lefts
555
+
527
556
  def set_left_alignment_margin(self, value: float):
528
557
  for item in self.nodes:
529
558
  if isinstance(item, LayoutSpaces):
@@ -546,14 +575,6 @@ class RowsTree(LayoutTree):
546
575
  else:
547
576
  bottom_item.set_bottom_alignment_margin(value)
548
577
 
549
- def align_rights(self):
550
- values = np.array(self.rights) - min(self.rights)
551
- for item, value in zip(self.nodes, values):
552
- if isinstance(item, LayoutSpaces):
553
- item.r.alignment_margin = value
554
- else:
555
- item.set_right_alignment_margin(value)
556
-
557
578
  @cached_property
558
579
  def rights(self):
559
580
  values = []
@@ -564,6 +585,32 @@ class RowsTree(LayoutTree):
564
585
  values.append(min(item.rights))
565
586
  return values
566
587
 
588
+ def align_rights(self):
589
+ """
590
+ Align the immediate right edges in this composition
591
+
592
+ ----------- -----------
593
+ | # | | # |
594
+ | # | | # |
595
+ | # | | # |
596
+ |-----------| -> |-----------|
597
+ | #| | # |
598
+ | #| | # |
599
+ | #| | # |
600
+ ----------- -----------
601
+ """
602
+ if self.rights_align:
603
+ return
604
+
605
+ values = np.array(self.rights) - min(self.rights)
606
+ for item, value in zip(self.nodes, values):
607
+ if isinstance(item, LayoutSpaces):
608
+ item.r.alignment_margin = value
609
+ else:
610
+ item.set_right_alignment_margin(value)
611
+
612
+ del self.rights
613
+
567
614
  def set_right_alignment_margin(self, value: float):
568
615
  for item in self.nodes:
569
616
  if isinstance(item, LayoutSpaces):
@@ -614,8 +661,13 @@ class RowsTree(LayoutTree):
614
661
  """
615
662
  return sum(self.plot_heights)
616
663
 
617
- def resize_heights(self):
618
- # The new width of each panel is the average width of all
664
+ def resize(self):
665
+ """
666
+ Resize the heights of gridspec so that panels have equal heights
667
+
668
+ This method resizes (recursively) the contained compositions
669
+ """
670
+ # The new height of each panel is the average width of all
619
671
  # the panels plus all the space above and below the panels.
620
672
  plot_heights = np.array(self.plot_heights)
621
673
  panel_heights = np.array(self.panel_heights)
@@ -623,3 +675,4 @@ class RowsTree(LayoutTree):
623
675
  new_plot_heights = panel_heights.mean() + non_panel_space
624
676
  height_ratios = new_plot_heights / new_plot_heights.max()
625
677
  self.gridspec.set_height_ratios(height_ratios)
678
+ self.resize_sub_compositions()
@@ -222,7 +222,9 @@ class left_spaces(_side_spaces):
222
222
  axis_title_y_margin_left: float = 0
223
223
  axis_title_y: float = 0
224
224
  axis_title_y_margin_right: float = 0
225
+ axis_text_y_margin_left: float = 0
225
226
  axis_text_y: float = 0
227
+ axis_text_y_margin_right: float = 0
226
228
  axis_ticks_y: float = 0
227
229
 
228
230
  def _calculate(self):
@@ -255,8 +257,13 @@ class left_spaces(_side_spaces):
255
257
  self.axis_title_y_margin_right = m.r
256
258
 
257
259
  # Account for the space consumed by the axis
258
- self.axis_text_y = items.axis_text_y_max_width("first_col")
259
- self.axis_ticks_y = items.axis_ticks_y_max_width("first_col")
260
+ self.axis_text_y = items.axis_text_y_max_width_at("first_col")
261
+ if self.axis_text_y:
262
+ m = theme.get_margin("axis_text_y").fig
263
+ self.axis_text_y_margin_left = m.l
264
+ self.axis_text_y_margin_right = m.r
265
+
266
+ self.axis_ticks_y = items.axis_ticks_y_max_width_at("first_col")
260
267
 
261
268
  # Adjust plot_margin to make room for ylabels that protude well
262
269
  # beyond the axes
@@ -576,7 +583,9 @@ class bottom_spaces(_side_spaces):
576
583
  axis_title_x_margin_bottom: float = 0
577
584
  axis_title_x: float = 0
578
585
  axis_title_x_margin_top: float = 0
586
+ axis_text_x_margin_bottom: float = 0
579
587
  axis_text_x: float = 0
588
+ axis_text_x_margin_top: float = 0
580
589
  axis_ticks_x: float = 0
581
590
 
582
591
  def _calculate(self):
@@ -616,8 +625,12 @@ class bottom_spaces(_side_spaces):
616
625
  self.axis_title_x_margin_top = m.t * F
617
626
 
618
627
  # Account for the space consumed by the axis
619
- self.axis_ticks_x = items.axis_ticks_x_max_height("last_row")
620
- self.axis_text_x = items.axis_text_x_max_height("last_row")
628
+ self.axis_text_x = items.axis_text_x_max_height_at("last_row")
629
+ if self.axis_text_x:
630
+ m = theme.get_margin("axis_text_x").fig
631
+ self.axis_text_x_margin_bottom = m.b
632
+ self.axis_text_x_margin_top = m.t
633
+ self.axis_ticks_x = items.axis_ticks_x_max_height_at("last_row")
621
634
 
622
635
  # Adjust plot_margin to make room for ylabels that protude well
623
636
  # beyond the axes
@@ -736,7 +749,7 @@ class LayoutSpaces:
736
749
  sw: float = field(init=False, default=0)
737
750
  """vertical spacing btn panels w.r.t figure"""
738
751
 
739
- gsparams: GridSpecParams = field(init=False)
752
+ gsparams: GridSpecParams = field(init=False, repr=False)
740
753
  """Grid spacing btn panels w.r.t figure"""
741
754
 
742
755
  def __post_init__(self):
@@ -917,13 +930,13 @@ class LayoutSpaces:
917
930
  self.sh += self.t.strip_text_x_height_top * (1 + strip_align_x)
918
931
 
919
932
  if facet.free["x"]:
920
- self.sh += self.items.axis_text_x_max_height(
933
+ self.sh += self.items.axis_text_x_max_height_at(
921
934
  "all"
922
- ) + self.items.axis_ticks_x_max_height("all")
935
+ ) + self.items.axis_ticks_x_max_height_at("all")
923
936
  if facet.free["y"]:
924
- self.sw += self.items.axis_text_y_max_width(
937
+ self.sw += self.items.axis_text_y_max_width_at(
925
938
  "all"
926
- ) + self.items.axis_ticks_y_max_width("all")
939
+ ) + self.items.axis_ticks_y_max_width_at("all")
927
940
 
928
941
  # width and height of axes as fraction of figure width & height
929
942
  self.w = ((self.r.right - self.l.left) - self.sw * (ncol - 1)) / ncol
plotnine/_mpl/patches.py CHANGED
@@ -49,7 +49,7 @@ class StripTextPatch(FancyBboxPatch):
49
49
  return
50
50
 
51
51
  text = self.text
52
- posx, posy = text.get_transform().transform((text._x, text._y))
52
+ posx, posy = text.get_transform().transform(text.get_position())
53
53
  x, y, w, h = _get_textbox(text, renderer)
54
54
 
55
55
  self.set_bounds(0.0, 0.0, w, h)
plotnine/_mpl/text.py CHANGED
@@ -1,16 +1,17 @@
1
1
  from __future__ import annotations
2
2
 
3
- import typing
3
+ from typing import TYPE_CHECKING
4
4
 
5
5
  from matplotlib.text import Text
6
6
 
7
7
  from .patches import StripTextPatch
8
- from .utils import bbox_in_axes_space
8
+ from .utils import bbox_in_axes_space, rel_position
9
9
 
10
- if typing.TYPE_CHECKING:
10
+ if TYPE_CHECKING:
11
11
  from matplotlib.backend_bases import RendererBase
12
12
 
13
13
  from plotnine.iapi import strip_draw_info
14
+ from plotnine.typing import HorizontalJustification, VerticalJustification
14
15
 
15
16
 
16
17
  class StripText(Text):
@@ -23,8 +24,6 @@ class StripText(Text):
23
24
 
24
25
  def __init__(self, info: strip_draw_info):
25
26
  kwargs = {
26
- "ha": info.ha,
27
- "va": info.va,
28
27
  "rotation": info.rotation,
29
28
  "transform": info.ax.transAxes,
30
29
  "clip_on": False,
@@ -40,38 +39,74 @@ class StripText(Text):
40
39
  self.draw_info = info
41
40
  self.patch = StripTextPatch(self)
42
41
 
42
+ # TODO: Move these _justify methods to the layout manager
43
+ # We need to first make sure that the patch has the final size during
44
+ # layout computation. Right now, the final size is calculated during
45
+ # draw (in these justify methods)
46
+ def _justify_horizontally(self, renderer):
47
+ """
48
+ Justify the text along the strip_background
49
+ """
50
+ info = self.draw_info
51
+ lookup: dict[HorizontalJustification, float] = {
52
+ "left": 0.0,
53
+ "center": 0.5,
54
+ "right": 1.0,
55
+ }
56
+ rel = lookup.get(info.ha, 0.5) if isinstance(info.ha, str) else info.ha
57
+ patch_bbox = bbox_in_axes_space(self.patch, info.ax, renderer)
58
+ text_bbox = bbox_in_axes_space(self, info.ax, renderer)
59
+ l, b, w, h = info.x, info.y, info.box_width, patch_bbox.height
60
+ b = b + patch_bbox.height * info.strip_align
61
+ x = rel_position(rel, text_bbox.width, patch_bbox.x0, patch_bbox.x1)
62
+ y = b + h / 2
63
+ self.set_horizontalalignment("left")
64
+ self.patch.set_bounds(l, b, w, h)
65
+ self.set_position((x, y))
66
+
67
+ def _justify_vertically(self, renderer):
68
+ """
69
+ Justify the text along the strip_background
70
+ """
71
+ # Note that the strip text & background and horizontal but
72
+ # rotated to appear vertical. So we really are still justifying
73
+ # horizontally.
74
+ info = self.draw_info
75
+ lookup: dict[VerticalJustification, float] = {
76
+ "bottom": 0.0,
77
+ "center": 0.5,
78
+ "top": 1.0,
79
+ }
80
+ rel = lookup.get(info.va, 0.5) if isinstance(info.va, str) else info.va
81
+ patch_bbox = bbox_in_axes_space(self.patch, info.ax, renderer)
82
+ text_bbox = bbox_in_axes_space(self, info.ax, renderer)
83
+ l, b, w, h = info.x, info.y, patch_bbox.width, info.box_height
84
+ l = l + patch_bbox.width * info.strip_align
85
+ x = l + w / 2
86
+ y = rel_position(rel, text_bbox.height, patch_bbox.y0, patch_bbox.y1)
87
+ self.set_horizontalalignment("right") # 90CW right means bottom
88
+ self.patch.set_bounds(l, b, w, h)
89
+ self.set_position((x, y))
90
+
43
91
  def draw(self, renderer: RendererBase):
44
92
  if not self.get_visible():
45
93
  return
46
94
 
47
- info = self.draw_info
48
- # "fill up" spatch to contain the text
95
+ # expand strip_text patch to contain the text
49
96
  self.patch.update_position_size(renderer)
50
97
 
51
- # Get bbox of spatch in transAxes space
52
- patch_bbox = bbox_in_axes_space(self.patch, info.ax, renderer)
53
-
54
98
  # Align patch across the edge of the panel
55
- if info.position == "top":
56
- l, b, w, h = info.x, info.y, info.box_width, patch_bbox.height
57
- b = b + patch_bbox.height * info.strip_align
99
+ if self.draw_info.position == "top":
100
+ self._justify_horizontally(renderer)
58
101
  else: # "right"
59
- l, b, w, h = info.x, info.y, patch_bbox.width, info.box_height
60
- l = l + patch_bbox.width * info.strip_align
102
+ self._justify_vertically(renderer)
61
103
 
62
- self.patch.set_bounds(l, b, w, h)
63
- self.patch.set_transform(info.ax.transAxes)
104
+ self.patch.set_transform(self.draw_info.ax.transAxes)
64
105
  self.patch.set_mutation_scale(0)
65
106
 
66
107
  # Put text in center of patch
67
- self._x = l + w / 2
68
- self._y = b + h / 2
69
-
70
- # "anchor" aligns before rotation so the right-strip get properly
71
- # centered text
72
108
  self.set_rotation_mode("anchor")
73
- self.set_horizontalalignment("center") # right-strip
74
- self.set_verticalalignment("center_baseline") # top-strip
109
+ self.set_verticalalignment("center_baseline")
75
110
 
76
111
  # Draw spatch
77
112
  self.patch.draw(renderer)
@@ -299,7 +299,7 @@ def ninteraction(df: pd.DataFrame, drop: bool = False) -> list[int]:
299
299
  return _id_var(df[df.columns[0]], drop)
300
300
 
301
301
  # Calculate individual ids
302
- ids = df.apply(_id_var, axis=0)
302
+ ids = df.apply(_id_var, axis=0, drop=drop)
303
303
  ids = ids.reindex(columns=list(reversed(ids.columns)))
304
304
 
305
305
  # Calculate dimensions
plotnine/facets/strips.py CHANGED
@@ -63,11 +63,13 @@ class strip:
63
63
  """
64
64
  theme = self.theme
65
65
  position = self.position
66
+
66
67
  if position == "top":
67
68
  # The x & y values are just starting locations
68
69
  # The final location is determined by the layout manager.
69
70
  y = 1
70
- ha, va = "center", "bottom"
71
+ ha = theme.getp(("strip_text_x", "ha"), "center")
72
+ va = theme.getp(("strip_text_x", "va"), "bottom")
71
73
  rotation = theme.getp(("strip_text_x", "rotation"))
72
74
  box_width = 1
73
75
  box_height = 0 # Determined by the text size
@@ -88,7 +90,8 @@ class strip:
88
90
  # The x & y values are just starting locations
89
91
  # The final location is determined by the layout manager.
90
92
  x = 1
91
- ha, va = "left", "center"
93
+ ha = theme.getp(("strip_text_y", "ha"), "left")
94
+ va = theme.getp(("strip_text_y", "va"), "center")
92
95
  rotation = theme.getp(("strip_text_y", "rotation"))
93
96
  box_width = 0 # Determine by the text height
94
97
  # TODO: Allow two unique paddings for either side.