1515from functools import cached_property
1616from typing import TYPE_CHECKING , Literal
1717
18- from plotnine ._utils import MARGIN_SIDE
1918from plotnine .exceptions import PlotnineError
2019from plotnine .facets import facet_grid , facet_null , facet_wrap
2120
@@ -255,9 +254,11 @@ class left_space(_plot_side_space):
255254 """
256255 legend : float = 0
257256 legend_box_spacing : float = 0
257+ axis_title_margin_left : float = 0
258+ """Outer (edge-facing) margin of the y-axis title"""
258259 axis_title : float = 0
259- axis_title_margin : float = 0
260- """Margin to the right of the y-axis title (panel-facing side) """
260+ axis_title_margin_right : float = 0
261+ """Panel-facing margin of the y-axis title"""
261262 axis_title_alignment : float = 0
262263 """
263264 Space added to align the axis title with others in a composition
@@ -266,9 +267,11 @@ class left_space(_plot_side_space):
266267 the difference between the largest and smallest axis_title_clearance
267268 among the items in the composition.
268269 """
270+ axis_text_margin_left : float = 0
271+ """Outer (edge-facing) margin of the y-axis text"""
269272 axis_text : float = 0
270- axis_text_margin : float = 0
271- """Margin to the right of the y-axis text (panel-facing side) """
273+ axis_text_margin_right : float = 0
274+ """Panel-facing margin of the y-axis text"""
272275 axis_ticks : float = 0
273276 strip_switch_pad : float = 0
274277 """Gap between a shared axis and a strip beyond it (outside placement)"""
@@ -292,21 +295,19 @@ def _calculate(self):
292295 self .legend = self .legend_width
293296 self .legend_box_spacing = theme .getp ("legend_box_spacing" )
294297
295- # The text<->panel gap is the right margin of the y text/title; it
296- # sits on the panel-facing (right) side of the left axis .
298+ # A left y-axis reads its left (outer) and right (panel-facing)
299+ # margins directly .
297300 if items .axis_title_y_left :
298301 self .axis_title = geometry .width (items .axis_title_y_left )
299- self .axis_title_margin = getattr (
300- theme .get_margin ("axis_title_y_left" ).fig ,
301- MARGIN_SIDE ["left" ],
302- )
302+ m = theme .get_margin ("axis_title_y_left" ).fig
303+ self .axis_title_margin_left = m .l
304+ self .axis_title_margin_right = m .r
303305
304306 self .axis_text = items .axis_text_y_left
305307 if self .axis_text :
306- self .axis_text_margin = getattr (
307- theme .get_margin ("axis_text_y_left" ).fig ,
308- MARGIN_SIDE ["left" ],
309- )
308+ m = theme .get_margin ("axis_text_y_left" ).fig
309+ self .axis_text_margin_left = m .l
310+ self .axis_text_margin_right = m .r
310311
311312 self .axis_ticks = items .axis_ticks_y_left
312313 self .strip_text = items .strip_text_y ("left" )
@@ -396,13 +397,17 @@ class right_space(_plot_side_space):
396397 margin_alignment : float = 0
397398 legend : float = 0
398399 legend_box_spacing : float = 0
400+ axis_title_margin_right : float = 0
401+ """Outer (edge-facing) margin of the y-axis title"""
399402 axis_title : float = 0
400- axis_title_margin : float = 0
401- """Margin to the left of the y-axis title (panel-facing side) """
403+ axis_title_margin_left : float = 0
404+ """Panel-facing margin of the y-axis title"""
402405 axis_title_alignment : float = 0
406+ axis_text_margin_right : float = 0
407+ """Outer (edge-facing) margin of the y-axis text"""
403408 axis_text : float = 0
404- axis_text_margin : float = 0
405- """Margin to the left of the y-axis text (panel-facing side) """
409+ axis_text_margin_left : float = 0
410+ """Panel-facing margin of the y-axis text"""
406411 axis_ticks : float = 0
407412 strip_switch_pad : float = 0
408413 """Gap between a shared axis and a strip beyond it (outside placement)"""
@@ -428,22 +433,19 @@ def _calculate(self):
428433
429434 self .strip_text = items .strip_text_y ("right" )
430435
431- # Space consumed by a y-axis on the right. The text<->panel gap is the
432- # left margin of the y text/title (the edge facing the panel to the
433- # left).
436+ # A right y-axis reads its right (outer) and left (panel-facing)
437+ # margins directly.
434438 if items .axis_title_y_right :
435439 self .axis_title = geometry .width (items .axis_title_y_right )
436- self .axis_title_margin = getattr (
437- theme .get_margin ("axis_title_y_right" ).fig ,
438- MARGIN_SIDE ["right" ],
439- )
440+ m = theme .get_margin ("axis_title_y_right" ).fig
441+ self .axis_title_margin_right = m .r
442+ self .axis_title_margin_left = m .l
440443
441444 self .axis_text = items .axis_text_y_right
442445 if self .axis_text :
443- self .axis_text_margin = getattr (
444- theme .get_margin ("axis_text_y_right" ).fig ,
445- MARGIN_SIDE ["right" ],
446- )
446+ m = theme .get_margin ("axis_text_y_right" ).fig
447+ self .axis_text_margin_right = m .r
448+ self .axis_text_margin_left = m .l
447449 self .axis_ticks = items .axis_ticks_y_right
448450 self .strip_switch_pad = self ._strip_switch_pad ("y" )
449451
@@ -547,13 +549,17 @@ class top_space(_plot_side_space):
547549 plot_subtitle_margin_bottom : float = 0
548550 legend : float = 0
549551 legend_box_spacing : float = 0
552+ axis_title_margin_top : float = 0
553+ """Outer (edge-facing) margin of the x-axis title"""
550554 axis_title : float = 0
551- axis_title_margin : float = 0
552- """Margin below the x-axis title (panel-facing side) """
555+ axis_title_margin_bottom : float = 0
556+ """Panel-facing margin of the x-axis title"""
553557 axis_title_alignment : float = 0
558+ axis_text_margin_top : float = 0
559+ """Outer (edge-facing) margin of the x-axis text"""
554560 axis_text : float = 0
555- axis_text_margin : float = 0
556- """Margin below the x-axis text (panel-facing side) """
561+ axis_text_margin_bottom : float = 0
562+ """Panel-facing margin of the x-axis text"""
557563 axis_ticks : float = 0
558564 strip_switch_pad : float = 0
559565 """Gap between a shared axis and a strip beyond it (outside placement)"""
@@ -593,21 +599,19 @@ def _calculate(self):
593599
594600 self .strip_text = items .strip_text_x ("top" )
595601
596- # Space consumed by an x-axis on the top. The text<->panel gap is the
597- # bottom margin of the x text/title (the edge facing the panel below) .
602+ # A top x-axis reads its top (outer) and bottom (panel-facing)
603+ # margins directly .
598604 if items .axis_title_x_top :
599605 self .axis_title = geometry .height (items .axis_title_x_top )
600- self .axis_title_margin = getattr (
601- theme .get_margin ("axis_title_x_top" ).fig ,
602- MARGIN_SIDE ["top" ],
603- )
606+ m = theme .get_margin ("axis_title_x_top" ).fig
607+ self .axis_title_margin_top = m .t
608+ self .axis_title_margin_bottom = m .b
604609
605610 self .axis_text = items .axis_text_x_top
606611 if self .axis_text :
607- self .axis_text_margin = getattr (
608- theme .get_margin ("axis_text_x_top" ).fig ,
609- MARGIN_SIDE ["top" ],
610- )
612+ m = theme .get_margin ("axis_text_x_top" ).fig
613+ self .axis_text_margin_top = m .t
614+ self .axis_text_margin_bottom = m .b
611615 self .axis_ticks = items .axis_ticks_x_top
612616 self .strip_switch_pad = self ._strip_switch_pad ("x" )
613617
@@ -714,9 +718,11 @@ class bottom_space(_plot_side_space):
714718 plot_caption_margin_top : float = 0
715719 legend : float = 0
716720 legend_box_spacing : float = 0
721+ axis_title_margin_bottom : float = 0
722+ """Outer (edge-facing) margin of the x-axis title"""
717723 axis_title : float = 0
718- axis_title_margin : float = 0
719- """Margin above the x-axis title (panel-facing side) """
724+ axis_title_margin_top : float = 0
725+ """Panel-facing margin of the x-axis title"""
720726 axis_title_alignment : float = 0
721727 """
722728 Space added to align the axis title with others in a composition
@@ -726,9 +732,11 @@ class bottom_space(_plot_side_space):
726732 composition. It's amount is the difference in height between this axis
727733 text (and it's margins) and the tallest axis text (and it's margin).
728734 """
735+ axis_text_margin_bottom : float = 0
736+ """Outer (edge-facing) margin of the x-axis text"""
729737 axis_text : float = 0
730- axis_text_margin : float = 0
731- """Margin above the x-axis text (panel-facing side) """
738+ axis_text_margin_top : float = 0
739+ """Panel-facing margin of the x-axis text"""
732740 axis_ticks : float = 0
733741 strip_switch_pad : float = 0
734742 """Gap between a shared axis and a strip beyond it (outside placement)"""
@@ -766,21 +774,19 @@ def _calculate(self):
766774 self .legend = self .legend_height
767775 self .legend_box_spacing = theme .getp ("legend_box_spacing" ) * F
768776
769- # The text<->panel gap is the top margin of the x text/title; it
770- # sits on the panel-facing (top) side of the bottom axis .
777+ # A bottom x-axis reads its bottom (outer) and top (panel-facing)
778+ # margins directly .
771779 if items .axis_title_x_bottom :
772780 self .axis_title = geometry .height (items .axis_title_x_bottom )
773- self .axis_title_margin = getattr (
774- theme .get_margin ("axis_title_x_bottom" ).fig ,
775- MARGIN_SIDE ["bottom" ],
776- )
781+ m = theme .get_margin ("axis_title_x_bottom" ).fig
782+ self .axis_title_margin_bottom = m .b
783+ self .axis_title_margin_top = m .t
777784
778785 self .axis_text = items .axis_text_x_bottom
779786 if self .axis_text :
780- self .axis_text_margin = getattr (
781- theme .get_margin ("axis_text_x_bottom" ).fig ,
782- MARGIN_SIDE ["bottom" ],
783- )
787+ m = theme .get_margin ("axis_text_x_bottom" ).fig
788+ self .axis_text_margin_bottom = m .b
789+ self .axis_text_margin_top = m .t
784790 self .axis_ticks = items .axis_ticks_x_bottom
785791 self .strip_text = items .strip_text_x ("bottom" )
786792 self .strip_switch_pad = self ._strip_switch_pad ("x" )
0 commit comments