Skip to content

FIX: turn off title autopos if pad is set #16862

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 4 commits into from
Closed
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
14 changes: 13 additions & 1 deletion doc/api/api_changes_3.3/behaviour.rst
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ deprecation warning.
`~.Axes.errorbar` now color cycles when only errorbar color is set
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Previously setting the *ecolor* would turn off automatic color cycling for the plot, leading to the
Previously setting the *ecolor* would turn off automatic color cycling for the plot, leading to
the lines and markers defaulting to whatever the first color in the color cycle was in the case of
multiple plot calls.

Expand Down Expand Up @@ -171,3 +171,15 @@ The default method used to format `.Slider` values has been changed to use a
values are displayed with an appropriate number of significant digits even if
they are much smaller or much bigger than 1. To restore the old behavior,
explicitly pass a "%1.2f" as the *valfmt* parameter to `.Slider`.

:rc:`axes.titlepad` and *pad* argument of `~.Axes.set_title` now work
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Since 3.0, Axes titles are automatically repositioned, primarily to avoid
xlabels or xticks at the top of the axes. The user could turn this
off using the optional *y* argument to `~.Axes.set_title`). However, that
made it impossible to manually set the *pad* argument (without also setting the
*y* argument). Now the *pad* argument and :rc:`axes.titlepad` are used, and
are relative to the top decorator on the axis. If users want the old
behavior of the pad being relative to the top of axis, set ``y=1.001``
in `~.Axes.set_title` to bypas the auto-positioning.
4 changes: 4 additions & 0 deletions lib/matplotlib/axes/_axes.py
Original file line number Diff line number Diff line change
Expand Up @@ -169,8 +169,12 @@ def set_title(self, label, fontdict=None, loc=None, pad=None, **kwargs):
titlecolor = rcParams['axes.titlecolor']
if not cbook._str_lower_equal(titlecolor, 'auto'):
default["color"] = titlecolor

if pad is None:
pad = rcParams['axes.titlepad']
if pad is None:
pad = 6 # default.

self._set_title_offset_trans(float(pad))
title.set_text(label)
title.update(default)
Expand Down
41 changes: 22 additions & 19 deletions lib/matplotlib/axes/_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -1139,11 +1139,9 @@ def cla(self):
verticalalignment='baseline',
horizontalalignment='right',
)
title_offset_points = mpl.rcParams['axes.titlepad']
# refactor this out so it can be called in ax.set_title if
# pad argument used...
self._set_title_offset_trans(title_offset_points)
# determine if the title position has been set manually:
# this needs to be called in case cla is not called on
# axes later...
self._set_title_offset_trans(mpl.rcParams['axes.titlepad'])
self._autotitlepos = None

for _title in (self.title, self._left_title, self._right_title):
Expand Down Expand Up @@ -1200,6 +1198,8 @@ def _set_title_offset_trans(self, title_offset_points):
Set the offset for the title either from :rc:`axes.titlepad`
or from set_title kwarg ``pad``.
"""
if title_offset_points is None:
title_offset_points = 6
self.titleOffsetTrans = mtransforms.ScaledTranslation(
0.0, title_offset_points / 72,
self.figure.dpi_scale_trans)
Expand Down Expand Up @@ -2648,7 +2648,7 @@ def _update_title_position(self, renderer):
else:
ax.apply_aspect()
axs = axs + [ax]
top = 0
top = 0.0
for ax in axs:
if (ax.xaxis.get_ticks_position() in ['top', 'unknown']
or ax.xaxis.get_label_position() == 'top'):
Expand All @@ -2657,21 +2657,24 @@ def _update_title_position(self, renderer):
bb = ax.get_window_extent(renderer)
if bb is not None:
top = max(top, bb.ymax)
if title.get_window_extent(renderer).ymin < top:
_, y = self.transAxes.inverted().transform((0, top))
title.set_position((x, y))
# empirically, this doesn't always get the min to top,
# so we need to adjust again.
_, y = self.transAxes.inverted().transform((0, top))
title.set_position((x, y))
if 0:
if title.get_window_extent(renderer).ymin < top:
_, y = self.transAxes.inverted().transform(
(0., 2 * top - title.get_window_extent(renderer).ymin))
_, y = self.transAxes.inverted().transform((0, top))
title.set_position((x, y))

ymax = max(title.get_position()[1] for title in titles)
for title in titles:
# now line up all the titles at the highest baseline.
x, _ = title.get_position()
title.set_position((x, ymax))
# empirically, this doesn't always get the min to top,
# so we need to adjust again.
if title.get_window_extent(renderer).ymin < top:
_, y = self.transAxes.inverted().transform(
(0., 2 * top - title.get_window_extent(renderer).ymin))
title.set_position((x, y))

ymax = max(title.get_position()[1] for title in titles)
for title in titles:
# now line up all the titles at the highest baseline.
x, _ = title.get_position()
title.set_position((x, ymax))

# Drawing
@martist.allow_rasterization
Expand Down
2 changes: 1 addition & 1 deletion lib/matplotlib/rcsetup.py
Original file line number Diff line number Diff line change
Expand Up @@ -1219,7 +1219,7 @@ def _convert_validator_spec(key, conv):
'axes.titlelocation': ['center', ['left', 'center', 'right']], # alignment of axes title
'axes.titleweight': ['normal', validate_fontweight], # font weight of axes title
'axes.titlecolor': ['auto', validate_color_or_auto], # font color of axes title
'axes.titlepad': [6.0, validate_float], # pad from axes top to title in points
'axes.titlepad': [6.0, validate_float], # pad from axes top to title in points;
'axes.grid': [False, validate_bool], # display grid or not
'axes.grid.which': ['major', ['minor', 'both', 'major']], # set whether the grid is drawn on
# 'major' 'minor' or 'both' ticks
Expand Down
1 change: 1 addition & 0 deletions lib/matplotlib/tests/test_axes.py
Original file line number Diff line number Diff line change
Expand Up @@ -5523,6 +5523,7 @@ def test_titlesetpos():
def test_title_xticks_top():
# Test that title moves if xticks on top of axes.
fig, ax = plt.subplots()
# set to the new default (from 5, which will suppress title reposition)
ax.xaxis.set_ticks_position('top')
ax.set_title('xlabel top')
fig.canvas.draw()
Expand Down
4 changes: 2 additions & 2 deletions lib/matplotlib/tests/test_tightlayout.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ def example_plot(ax, fontsize=12):
ax.set_title('Title', fontsize=fontsize)


@image_comparison(['tight_layout1'])
@image_comparison(['tight_layout1'], tol=1.87)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you need to increase the tolerance, or can you not set the rcParam like the other test?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, its really strange - the whole figure is the same except for the blue line.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was the macOS failure with new Ghostscript? So this can now be rebased out.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think so, but maybe...

def test_tight_layout1():
"""Test tight_layout for a single subplot."""
fig, ax = plt.subplots()
Expand Down Expand Up @@ -115,7 +115,7 @@ def test_tight_layout6():
h_pad=0.45)


@image_comparison(['tight_layout7'])
@image_comparison(['tight_layout7'], tol=1.87)
def test_tight_layout7():
# tight layout with left and right titles
fontsize = 24
Expand Down
2 changes: 1 addition & 1 deletion matplotlibrc.template
Original file line number Diff line number Diff line change
Expand Up @@ -326,7 +326,7 @@
#mathtext.sf: sans
#mathtext.tt: monospace
#mathtext.fallback: cm # Select fallback font from ['cm' (Computer Modern), 'stix'
# 'stixsans'] when a symbol can not be found in one of the
# 'stixsans'] when a symbol can not be found in one of the
# custom math fonts. Select 'None' to not perform fallback
# and replace the missing character by a dummy symbol.
#mathtext.default: it # The default font to use for math.
Expand Down