11from collections import OrderedDict
22import itertools
3+ import logging
34import math
45from operator import attrgetter
56import types
3233from matplotlib .rcsetup import cycler
3334from matplotlib .rcsetup import validate_axisbelow
3435
36+ _log = logging .getLogger (__name__ )
37+
3538rcParams = matplotlib .rcParams
3639
3740
@@ -1077,6 +1080,8 @@ def cla(self):
10771080 # refactor this out so it can be called in ax.set_title if
10781081 # pad argument used...
10791082 self ._set_title_offset_trans (title_offset_points )
1083+ # determine if the title position has been set manually:
1084+ self ._autotitlepos = None
10801085
10811086 for _title in (self .title , self ._left_title , self ._right_title ):
10821087 self ._set_artist_props (_title )
@@ -2446,6 +2451,50 @@ def handle_single_axis(scale, autoscaleon, shared_axes, interval,
24462451 def _get_axis_list (self ):
24472452 return (self .xaxis , self .yaxis )
24482453
2454+ def _update_title_position (self , renderer ):
2455+ """
2456+ Update the title position based on the bounding box enclosing
2457+ all the ticklabels and x-axis spine and xlabel...
2458+ """
2459+ _log .debug ('update_title_pos' )
2460+
2461+ if self ._autotitlepos is not None and not self ._autotitlepos :
2462+ _log .debug ('title position was updated manually, not adjusting' )
2463+ return
2464+
2465+ titles = (self .title , self ._left_title , self ._right_title )
2466+
2467+ if self ._autotitlepos is None :
2468+ for title in titles :
2469+ x , y = title .get_position ()
2470+ if not np .isclose (y , 1.0 ):
2471+ self ._autotitlepos = False
2472+ _log .debug ('not adjusting title pos because title was'
2473+ ' already placed manually: %f' , y )
2474+ return
2475+ self ._autotitlepos = True
2476+
2477+ for title in titles :
2478+ x , y0 = title .get_position ()
2479+ y = 1.0
2480+ # need to check all our twins too...
2481+ axs = self ._twinned_axes .get_siblings (self )
2482+
2483+ for ax in axs :
2484+ try :
2485+ if (ax .xaxis .get_label_position () == 'top'
2486+ or ax .xaxis .get_ticks_position () == 'top' ):
2487+ bb = ax .xaxis .get_tightbbox (renderer )
2488+ top = bb .y1
2489+ # we don't need to pad because the padding is already
2490+ # in __init__: titleOffsetTrans
2491+ yn = self .transAxes .inverted ().transform ((0. , top ))[1 ]
2492+ y = max (y , yn )
2493+ except AttributeError :
2494+ pass
2495+
2496+ title .set_position ((x , y ))
2497+
24492498 # Drawing
24502499
24512500 @allow_rasterization
@@ -2459,6 +2508,7 @@ def draw(self, renderer=None, inframe=False):
24592508 if not self .get_visible ():
24602509 return
24612510 renderer .open_group ('axes' )
2511+
24622512 # prevent triggering call backs during the draw process
24632513 self ._stale = True
24642514 locator = self .get_axes_locator ()
@@ -2479,6 +2529,8 @@ def draw(self, renderer=None, inframe=False):
24792529 for spine in self .spines .values ():
24802530 artists .remove (spine )
24812531
2532+ self ._update_title_position (renderer )
2533+
24822534 if self .axison and not inframe :
24832535 if self ._axisbelow is True :
24842536 self .xaxis .set_zorder (0.5 )
@@ -2507,6 +2559,7 @@ def draw(self, renderer=None, inframe=False):
25072559 # rasterize artists with negative zorder
25082560 # if the minimum zorder is negative, start rasterization
25092561 rasterization_zorder = self ._rasterization_zorder
2562+
25102563 if (rasterization_zorder is not None and
25112564 artists and artists [0 ].zorder < rasterization_zorder ):
25122565 renderer .start_rasterizing ()
@@ -4051,6 +4104,12 @@ def get_tightbbox(self, renderer, call_axes_locator=True):
40514104 else :
40524105 self .apply_aspect ()
40534106
4107+ bb_xaxis = self .xaxis .get_tightbbox (renderer )
4108+ if bb_xaxis :
4109+ bb .append (bb_xaxis )
4110+
4111+ self ._update_title_position (renderer )
4112+
40544113 bb .append (self .get_window_extent (renderer ))
40554114
40564115 if self .title .get_visible ():
@@ -4060,10 +4119,6 @@ def get_tightbbox(self, renderer, call_axes_locator=True):
40604119 if self ._right_title .get_visible ():
40614120 bb .append (self ._right_title .get_window_extent (renderer ))
40624121
4063- bb_xaxis = self .xaxis .get_tightbbox (renderer )
4064- if bb_xaxis :
4065- bb .append (bb_xaxis )
4066-
40674122 bb_yaxis = self .yaxis .get_tightbbox (renderer )
40684123 if bb_yaxis :
40694124 bb .append (bb_yaxis )
0 commit comments