Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 20 additions & 5 deletions lib/matplotlib/axis.py
Original file line number Diff line number Diff line change
Expand Up @@ -1831,6 +1831,13 @@ def _get_tick_label_size(self, axis_name):
mpl.rcParams[f'{axis_name}tick.labelsize'])
return mtext.FontProperties(size=size).get_size_in_points()

def _get_tick_label_rotation(self):
"""
Return the rotation (in degrees) applied to tick labels on this
Axis, as set via `.Axis.set_tick_params(rotation=...)`.
"""
return float(self._major_tick_kw.get('labelrotation', 0))

def _copy_tick_props(self, src, dest):
"""Copy the properties from *src* tick to *dest* tick."""
if src is None or dest is None:
Expand Down Expand Up @@ -2828,9 +2835,13 @@ def get_tick_space(self):
ends = mtransforms.Bbox.unit().transformed(
self.axes.transAxes - self.get_figure(root=False).dpi_scale_trans)
length = ends.width * 72
# There is a heuristic here that the aspect ratio of tick text
# is no more than 3:1
size = self._get_tick_label_size('x') * 3
# There is a heuristic here that the aspect ratio of horizontal
# tick text is no more than 3:1 (width:height); as the label is
# rotated towards vertical, its footprint along the x-axis shrinks
# towards a single line-height (aspect ratio ~1:1).
rotation = np.deg2rad(self._get_tick_label_rotation())
aspect = abs(3 * np.cos(rotation)) + abs(np.sin(rotation))
size = self._get_tick_label_size('x') * aspect
if size > 0:
return int(np.floor(length / size))
else:
Expand Down Expand Up @@ -3058,8 +3069,12 @@ def get_tick_space(self):
ends = mtransforms.Bbox.unit().transformed(
self.axes.transAxes - self.get_figure(root=False).dpi_scale_trans)
length = ends.height * 72
# Having a spacing of at least 2 just looks good.
size = self._get_tick_label_size('y') * 2
# Having a spacing of at least 2 just looks good, for horizontal
# labels; as the label rotates towards vertical, its footprint
# along the y-axis grows towards a horizontal-text-like 3:1 ratio.
rotation = np.deg2rad(self._get_tick_label_rotation())
aspect = abs(2 * np.cos(rotation)) + abs(3 * np.sin(rotation))
size = self._get_tick_label_size('y') * aspect
if size > 0:
return int(np.floor(length / size))
else:
Expand Down
20 changes: 20 additions & 0 deletions lib/matplotlib/tests/test_axis.py
Original file line number Diff line number Diff line change
Expand Up @@ -128,3 +128,23 @@ def test_set_ticks_emits_lim_changed():
ax2.callbacks.connect("ylim_changed", called_polar.append)
ax2.set_rticks([1, 2, 3])
assert called_polar


def test_tick_space_rotation():
# Rotating x tick labels towards vertical should let more x ticks fit
# (their horizontal footprint shrinks), while rotating y tick labels
# towards vertical should let fewer y ticks fit (their vertical
# footprint grows). See issue #32005.
fig, ax = plt.subplots(figsize=(1.8, 1.8), layout="constrained")
fig.canvas.draw()
xspace_horizontal = ax.xaxis.get_tick_space()
yspace_horizontal = ax.yaxis.get_tick_space()

fig2, ax2 = plt.subplots(figsize=(1.8, 1.8), layout="constrained")
ax2.tick_params(rotation=90)
fig2.canvas.draw()
xspace_vertical = ax2.xaxis.get_tick_space()
yspace_vertical = ax2.yaxis.get_tick_space()

assert xspace_vertical > xspace_horizontal
assert yspace_vertical < yspace_horizontal
Loading