From cfabe79945743dd375db4fe8bcdbaab00330dfe8 Mon Sep 17 00:00:00 2001 From: Steffen Rehberg Date: Wed, 29 Dec 2021 12:50:40 +0100 Subject: [PATCH] FIX: Autoposition title when yaxis has offset Move any title above the y axis offset text it would overlap with the offset. If multiple titles are present, they are vertically aligned to the highest one. --- .../next_api_changes/behavior/22063-SR.rst | 7 +++++ lib/matplotlib/axes/_base.py | 6 ++++ lib/matplotlib/tests/test_axes.py | 30 +++++++++++++++++++ 3 files changed, 43 insertions(+) create mode 100644 doc/api/next_api_changes/behavior/22063-SR.rst diff --git a/doc/api/next_api_changes/behavior/22063-SR.rst b/doc/api/next_api_changes/behavior/22063-SR.rst new file mode 100644 index 000000000000..e09bcaa70706 --- /dev/null +++ b/doc/api/next_api_changes/behavior/22063-SR.rst @@ -0,0 +1,7 @@ +Move Axes title to not overlap with y axis offset +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Previously, Axes titles could overlap the y-axis offset text, which is often +in the upper left corner of the axes. Now titles are moved above the offset +text if overlapping, and autopositioning is in effect (i.e. if *y* in +`.Axes.set_title` is *None* and :rc:`axes.titley` is also *None*). diff --git a/lib/matplotlib/axes/_base.py b/lib/matplotlib/axes/_base.py index 37a3d39ed77f..52fc28902faf 100644 --- a/lib/matplotlib/axes/_base.py +++ b/lib/matplotlib/axes/_base.py @@ -2990,6 +2990,12 @@ def _update_title_position(self, renderer): if bb is None: bb = ax.get_window_extent(renderer) top = max(top, bb.ymax) + if title.get_text(): + ax.yaxis.get_tightbbox(renderer) # update offsetText + if ax.yaxis.offsetText.get_text(): + bb = ax.yaxis.offsetText.get_tightbbox(renderer) + if bb.intersection(title.get_tightbbox(renderer), bb): + top = bb.ymax if top < 0: # the top of Axes is not even on the figure, so don't try and # automatically place it. diff --git a/lib/matplotlib/tests/test_axes.py b/lib/matplotlib/tests/test_axes.py index 5da2df1455db..da6c79d2759e 100644 --- a/lib/matplotlib/tests/test_axes.py +++ b/lib/matplotlib/tests/test_axes.py @@ -6121,6 +6121,36 @@ def test_title_xticks_top_both(): assert ax.title.get_position()[1] > 1.04 +@pytest.mark.parametrize( + 'left, center', [ + ('left', ''), + ('', 'center'), + ('left', 'center') + ], ids=[ + 'left title moved', + 'center title kept', + 'both titles aligned' + ] +) +def test_title_above_offset(left, center): + # Test that title moves if overlaps with yaxis offset text. + mpl.rcParams['axes.titley'] = None + fig, ax = plt.subplots() + ax.set_ylim(1e11) + ax.set_title(left, loc='left') + ax.set_title(center) + fig.draw_without_rendering() + if left and not center: + assert ax._left_title.get_position()[1] > 1.0 + elif not left and center: + assert ax.title.get_position()[1] == 1.0 + else: + yleft = ax._left_title.get_position()[1] + ycenter = ax.title.get_position()[1] + assert yleft > 1.0 + assert ycenter == yleft + + def test_title_no_move_off_page(): # If an axes is off the figure (ie. if it is cropped during a save) # make sure that the automatic title repositioning does not get done.