Skip to content

Commit ca31b48

Browse files
committed
fix(layout): reserve axis text margins in facet gullies
The free-scale gully terms added the tick and label extents but not the label margins, though the drawn labels honor them (the margin is applied as the tick pad). With a large margin and small panel_spacing the labels of one panel overlapped the neighbouring panel.
1 parent 00fe299 commit ca31b48

3 files changed

Lines changed: 33 additions & 4 deletions

File tree

doc/changelog.qmd

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,10 @@ title: Changelog
108108

109109
### Bug Fixes
110110

111+
- The space between facet panels now accounts for the margins of the axis
112+
text, so with free scales large margins no longer push the tick labels
113+
into the neighbouring panel.
114+
111115
- Subclass geoms now inherit their parent geom's default parameters, so
112116
parameters that a parent geom supports are no longer rejected.
113117
[](:class:`~plotnine.geom_step`) accepts `lineend`, `linejoin` and `arrow`,

plotnine/_mpl/layout_manager/_plot_side_space.py

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1241,16 +1241,26 @@ def _calculate_panel_spacing_facet_wrap(self) -> tuple[float, float]:
12411241
else:
12421242
self.sw += space.strip_text + space.strip_switch_pad
12431243

1244+
# Per-panel axes claim their ticks, labels and label margins in
1245+
# the gullies.
12441246
if facet.free["x"]:
12451247
for side in ("bottom", "top"):
1246-
self.sh += self.items.axis_text_x_max_height_at(
1248+
text = self.items.axis_text_x_max_height_at("all", side)
1249+
if text:
1250+
m = theme.get_margin(f"axis_text_x_{side}").fig
1251+
text += m.t + m.b
1252+
self.sh += text + self.items.axis_ticks_x_max_height_at(
12471253
"all", side
1248-
) + self.items.axis_ticks_x_max_height_at("all", side)
1254+
)
12491255
if facet.free["y"]:
12501256
for side in ("left", "right"):
1251-
self.sw += self.items.axis_text_y_max_width_at(
1257+
text = self.items.axis_text_y_max_width_at("all", side)
1258+
if text:
1259+
m = theme.get_margin(f"axis_text_y_{side}").fig
1260+
text += m.l + m.r
1261+
self.sw += text + self.items.axis_ticks_y_max_width_at(
12521262
"all", side
1253-
) + self.items.axis_ticks_y_max_width_at("all", side)
1263+
)
12541264

12551265
# width and height of axes as fraction of figure width & height
12561266
self.w = (self.panel_width - self.sw * (ncol - 1)) / ncol

tests/test_layout.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,21 @@ def test_facet_wrap_scales_free(self):
115115
p = self.g + facet_wrap("carb", scales="free")
116116
assert p == "facet_wrap_scales_free"
117117

118+
def test_facet_wrap_scales_free_text_margin(self):
119+
# The gullies fit the axis text margins; with zero panel
120+
# spacing the labels touch the neighbouring panel but do not
121+
# overlap it.
122+
p = (
123+
self.g
124+
+ facet_wrap("carb", scales="free")
125+
+ theme(
126+
panel_spacing=0,
127+
axis_text_x=element_text(margin={"t": 5}),
128+
axis_text_y=element_text(margin={"r": 5}),
129+
)
130+
)
131+
assert p == "facet_wrap_scales_free_text_margin"
132+
118133
def test_plot_margin_aspect_ratio(self):
119134
# The margin should be exact in both directions even if
120135
# the figure has an aspect ratio != 1.

0 commit comments

Comments
 (0)