Skip to content

Commit ab50f6b

Browse files
committed
Move title if x-axis is on the top of the figure
1 parent 85e124a commit ab50f6b

File tree

6 files changed

+838
-4
lines changed

6 files changed

+838
-4
lines changed

lib/matplotlib/axes/_base.py

+70-4
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
from six.moves import xrange
88

99
import itertools
10+
import logging
1011
import warnings
1112
import math
1213
from operator import attrgetter
@@ -512,6 +513,9 @@ def __init__(self, fig, rect,
512513
# warnings.warn(
513514
# 'shared axes: "adjustable" is being changed to "datalim"')
514515
self._adjustable = 'datalim'
516+
# list of possible twinned axes...
517+
self._twinx_axes = []
518+
self._twiny_axes = []
515519
self.set_label(label)
516520
self.set_figure(fig)
517521

@@ -1077,6 +1081,8 @@ def cla(self):
10771081
# refactor this out so it can be called in ax.set_title if
10781082
# pad argument used...
10791083
self._set_title_offset_trans(title_offset_points)
1084+
# determine if the title position has been set manually:
1085+
self._autotitlepos = None
10801086

10811087
for _title in (self.title, self._left_title, self._right_title):
10821088
self._set_artist_props(_title)
@@ -2377,11 +2383,59 @@ def handle_single_axis(scale, autoscaleon, shared_axes, interval,
23772383
def _get_axis_list(self):
23782384
return (self.xaxis, self.yaxis)
23792385

2386+
def _update_title_position(self, renderer):
2387+
"""
2388+
Update the title position based on the bounding box enclosing
2389+
all the ticklabels and x-axis spine and xlabel...
2390+
"""
2391+
log = logging.getLogger(__name__)
2392+
log.debug('update_title_pos')
2393+
2394+
if self._autotitlepos is not None and not self._autotitlepos:
2395+
log.info('title position was updated manually, not adjusting')
2396+
return
2397+
2398+
titles = (self.title, self._left_title, self._right_title)
2399+
2400+
if self._autotitlepos is None:
2401+
for title in titles:
2402+
x, y = title.get_position()
2403+
if not np.isclose(y, 1.0):
2404+
self._autotitlepos = False
2405+
log.info('not adjusting title pos because title was'
2406+
' already placed manually: %f', y)
2407+
return
2408+
self._autotitlepos = True
2409+
2410+
for title in titles:
2411+
x, y0 = title.get_position()
2412+
y = 1.0
2413+
# need to check all our twins too...
2414+
axs = [self] + self._twinx_axes + self._twiny_axes
2415+
2416+
for ax in axs:
2417+
try:
2418+
if (ax.xaxis.get_label_position() == 'top'
2419+
or ax.xaxis.get_tick_position() == 'top'):
2420+
# this may not work?
2421+
bb = ax.xaxis.get_tightbbox(renderer)
2422+
top = bb.y1
2423+
# we don't need to pad because the padding is already
2424+
# in __init__: titleOffsetTrans
2425+
yn = self.transAxes.inverted().transform((0., top))[1]
2426+
if yn > y:
2427+
y = yn
2428+
except AttributeError:
2429+
pass
2430+
2431+
title.set_position((x, y))
2432+
23802433
# Drawing
23812434

23822435
@allow_rasterization
23832436
def draw(self, renderer=None, inframe=False):
23842437
"""Draw everything (plot lines, axes, labels)"""
2438+
log = logging.getLogger(__name__)
23852439
if renderer is None:
23862440
renderer = self._cachedRenderer
23872441

@@ -2390,6 +2444,7 @@ def draw(self, renderer=None, inframe=False):
23902444
if not self.get_visible():
23912445
return
23922446
renderer.open_group('axes')
2447+
23932448
# prevent triggering call backs during the draw process
23942449
self._stale = True
23952450
locator = self.get_axes_locator()
@@ -2410,6 +2465,8 @@ def draw(self, renderer=None, inframe=False):
24102465
for spine in six.itervalues(self.spines):
24112466
artists.remove(spine)
24122467

2468+
self._update_title_position(renderer)
2469+
24132470
if self.axison and not inframe:
24142471
if self._axisbelow is True:
24152472
self.xaxis.set_zorder(0.5)
@@ -2438,6 +2495,8 @@ def draw(self, renderer=None, inframe=False):
24382495
# rasterize artists with negative zorder
24392496
# if the minimum zorder is negative, start rasterization
24402497
rasterization_zorder = self._rasterization_zorder
2498+
log.debug('rasterization_zorder %s', rasterization_zorder)
2499+
24412500
if (rasterization_zorder is not None and
24422501
artists and artists[0].zorder < rasterization_zorder):
24432502
renderer.start_rasterizing()
@@ -2458,7 +2517,10 @@ def draw(self, renderer=None, inframe=False):
24582517
a.draw(renderer)
24592518
renderer.stop_rasterizing()
24602519

2520+
for a in artists:
2521+
log.debug('draw: artist %s', a)
24612522
mimage._draw_list_compositing_images(renderer, self, artists)
2523+
self._update_title_position(renderer)
24622524

24632525
renderer.close_group('axes')
24642526
self._cachedRenderer = renderer
@@ -4028,6 +4090,12 @@ def get_tightbbox(self, renderer, call_axes_locator=True):
40284090
else:
40294091
self.apply_aspect()
40304092

4093+
bb_xaxis = self.xaxis.get_tightbbox(renderer)
4094+
if bb_xaxis:
4095+
bb.append(bb_xaxis)
4096+
4097+
self._update_title_position(renderer)
4098+
40314099
bb.append(self.get_window_extent(renderer))
40324100

40334101
if self.title.get_visible():
@@ -4037,10 +4105,6 @@ def get_tightbbox(self, renderer, call_axes_locator=True):
40374105
if self._right_title.get_visible():
40384106
bb.append(self._right_title.get_window_extent(renderer))
40394107

4040-
bb_xaxis = self.xaxis.get_tightbbox(renderer)
4041-
if bb_xaxis:
4042-
bb.append(bb_xaxis)
4043-
40444108
bb_yaxis = self.yaxis.get_tightbbox(renderer)
40454109
if bb_yaxis:
40464110
bb.append(bb_yaxis)
@@ -4091,6 +4155,7 @@ def twinx(self):
40914155
self.yaxis.tick_left()
40924156
ax2.xaxis.set_visible(False)
40934157
ax2.patch.set_visible(False)
4158+
self._twinx_axes.append(ax2)
40944159
return ax2
40954160

40964161
def twiny(self):
@@ -4120,6 +4185,7 @@ def twiny(self):
41204185
self.xaxis.tick_bottom()
41214186
ax2.yaxis.set_visible(False)
41224187
ax2.patch.set_visible(False)
4188+
self._twiny_axes.append(ax2)
41234189
return ax2
41244190

41254191
def get_shared_x_axes(self):

lib/matplotlib/axis.py

+2
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66

77
import six
88

9+
import logging
10+
911
from matplotlib import rcParams
1012
import matplotlib.artist as artist
1113
from matplotlib.artist import allow_rasterization
Binary file not shown.

0 commit comments

Comments
 (0)