Skip to content

Commit c88e7c8

Browse files
committed
ENH/FIX: Don't auto reposition axes if axes.titlepad not None
Automatic title repositioning is now suppressed if the title padding is set to a non-None value by the user (either in the pad kwarg, or the rcParam axes.titlepad)
1 parent 2227aa3 commit c88e7c8

File tree

7 files changed

+45
-11
lines changed

7 files changed

+45
-11
lines changed

doc/api/api_changes_3.3/behaviour.rst

+13-1
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ deprecation warning.
9898
`~.Axes.errorbar` now color cycles when only errorbar color is set
9999
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
100100

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

@@ -171,3 +171,15 @@ The default method used to format `.Slider` values has been changed to use a
171171
values are displayed with an appropriate number of significant digits even if
172172
they are much smaller or much bigger than 1. To restore the old behavior,
173173
explicitly pass a "%1.2f" as the *valfmt* parameter to `.Slider`.
174+
175+
:rc:`axes.titlepad` and *pad* argument of `~.Axes.set_title` now default to ``None``
176+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
177+
178+
Since 3.0, Axes titles are automatically repositioned, primarily to avoid
179+
xlabels or xticks at the top of the axes. The user could turn this
180+
off using the optional *y* argument to `~.Axes.set_title`). However, that
181+
made it impossible to manually set the *pad* argument (without also setting the
182+
*y* argument). Now *pad* defaults to ``None`` and the
183+
rcParam :rc:`axes.titlepad` defaults to ``None``, which will
184+
allow automatic title placement. However, if these are set to a float, then
185+
the automatic placement of the title is turned off.

lib/matplotlib/axes/_axes.py

+6
Original file line numberDiff line numberDiff line change
@@ -169,8 +169,14 @@ def set_title(self, label, fontdict=None, loc=None, pad=None, **kwargs):
169169
titlecolor = rcParams['axes.titlecolor']
170170
if not cbook._str_lower_equal(titlecolor, 'auto'):
171171
default["color"] = titlecolor
172+
172173
if pad is None:
173174
pad = rcParams['axes.titlepad']
175+
if pad is not None:
176+
self._autotitlepos = False
177+
else:
178+
pad = 6 # default.
179+
174180
self._set_title_offset_trans(float(pad))
175181
title.set_text(label)
176182
title.update(default)

lib/matplotlib/axes/_base.py

+6-5
Original file line numberDiff line numberDiff line change
@@ -1139,11 +1139,9 @@ def cla(self):
11391139
verticalalignment='baseline',
11401140
horizontalalignment='right',
11411141
)
1142-
title_offset_points = mpl.rcParams['axes.titlepad']
1143-
# refactor this out so it can be called in ax.set_title if
1144-
# pad argument used...
1145-
self._set_title_offset_trans(title_offset_points)
1146-
# determine if the title position has been set manually:
1142+
# this needs to be called in case cla is not called on
1143+
# axes later...
1144+
self._set_title_offset_trans(mpl.rcParams['axes.titlepad'])
11471145
self._autotitlepos = None
11481146

11491147
for _title in (self.title, self._left_title, self._right_title):
@@ -1200,6 +1198,9 @@ def _set_title_offset_trans(self, title_offset_points):
12001198
Set the offset for the title either from :rc:`axes.titlepad`
12011199
or from set_title kwarg ``pad``.
12021200
"""
1201+
if title_offset_points is None:
1202+
# dummy default in case cla hasn't been called.
1203+
title_offset_points = 0
12031204
self.titleOffsetTrans = mtransforms.ScaledTranslation(
12041205
0.0, title_offset_points / 72,
12051206
self.figure.dpi_scale_trans)

lib/matplotlib/rcsetup.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -1219,7 +1219,7 @@ def _convert_validator_spec(key, conv):
12191219
'axes.titlelocation': ['center', ['left', 'center', 'right']], # alignment of axes title
12201220
'axes.titleweight': ['normal', validate_fontweight], # font weight of axes title
12211221
'axes.titlecolor': ['auto', validate_color_or_auto], # font color of axes title
1222-
'axes.titlepad': [6.0, validate_float], # pad from axes top to title in points
1222+
'axes.titlepad': [None, validate_float_or_None], # pad from axes top to title in points; None means allow auto position of title
12231223
'axes.grid': [False, validate_bool], # display grid or not
12241224
'axes.grid.which': ['major', ['minor', 'both', 'major']], # set whether the grid is drawn on
12251225
# 'major' 'minor' or 'both' ticks

lib/matplotlib/tests/test_axes.py

+15
Original file line numberDiff line numberDiff line change
@@ -5523,6 +5523,8 @@ def test_titlesetpos():
55235523
def test_title_xticks_top():
55245524
# Test that title moves if xticks on top of axes.
55255525
fig, ax = plt.subplots()
5526+
# set to the new default (from 5, which will suppress title reposition)
5527+
mpl.rcParams['axes.titlepad'] = None
55265528
ax.xaxis.set_ticks_position('top')
55275529
ax.set_title('xlabel top')
55285530
fig.canvas.draw()
@@ -5532,13 +5534,26 @@ def test_title_xticks_top():
55325534
def test_title_xticks_top_both():
55335535
# Test that title moves if xticks on top of axes.
55345536
fig, ax = plt.subplots()
5537+
# set to the new default (from 5, which will suppress title reposition)
5538+
mpl.rcParams['axes.titlepad'] = None
55355539
ax.tick_params(axis="x",
55365540
bottom=True, top=True, labelbottom=True, labeltop=True)
55375541
ax.set_title('xlabel top')
55385542
fig.canvas.draw()
55395543
assert ax.title.get_position()[1] > 1.04
55405544

55415545

5546+
def test_title_noauto_pad():
5547+
# test that if we pad, then the title does not autopos
5548+
5549+
fig, ax = plt.subplots()
5550+
ax.set_title("Title 1", pad=-20)
5551+
ax.tick_params(axis="x",
5552+
bottom=True, top=True, labelbottom=True, labeltop=True)
5553+
fig.canvas.draw()
5554+
assert ax.title.get_position()[1] == 1.0
5555+
5556+
55425557
def test_offset_label_color():
55435558
# Tests issue 6440
55445559
fig = plt.figure()

lib/matplotlib/tests/test_tightlayout.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ def example_plot(ax, fontsize=12):
1919
ax.set_title('Title', fontsize=fontsize)
2020

2121

22-
@image_comparison(['tight_layout1'])
22+
@image_comparison(['tight_layout1'], tol=1.87)
2323
def test_tight_layout1():
2424
"""Test tight_layout for a single subplot."""
2525
fig, ax = plt.subplots()
@@ -115,7 +115,7 @@ def test_tight_layout6():
115115
h_pad=0.45)
116116

117117

118-
@image_comparison(['tight_layout7'])
118+
@image_comparison(['tight_layout7'], tol=1.87)
119119
def test_tight_layout7():
120120
# tight layout with left and right titles
121121
fontsize = 24

matplotlibrc.template

+2-2
Original file line numberDiff line numberDiff line change
@@ -326,7 +326,7 @@
326326
#mathtext.sf: sans
327327
#mathtext.tt: monospace
328328
#mathtext.fallback: cm # Select fallback font from ['cm' (Computer Modern), 'stix'
329-
# 'stixsans'] when a symbol can not be found in one of the
329+
# 'stixsans'] when a symbol can not be found in one of the
330330
# custom math fonts. Select 'None' to not perform fallback
331331
# and replace the missing character by a dummy symbol.
332332
#mathtext.default: it # The default font to use for math.
@@ -352,7 +352,7 @@
352352
#axes.titleweight: normal # font weight of title
353353
#axes.titlecolor: auto # color of the axes title, auto falls back to
354354
# text.color as default value
355-
#axes.titlepad: 6.0 # pad between axes and title in points
355+
#axes.titlepad: None # pad between axes and title in points, None means allow automatic positioning
356356
#axes.labelsize: medium # fontsize of the x any y labels
357357
#axes.labelpad: 4.0 # space between label and axis
358358
#axes.labelweight: normal # weight of the x and y labels

0 commit comments

Comments
 (0)