1
1
from collections import OrderedDict
2
2
import itertools
3
+ import logging
3
4
import math
4
5
from operator import attrgetter
5
6
import types
32
33
from matplotlib .rcsetup import cycler
33
34
from matplotlib .rcsetup import validate_axisbelow
34
35
36
+ _log = logging .getLogger (__name__ )
37
+
35
38
rcParams = matplotlib .rcParams
36
39
37
40
@@ -1077,6 +1080,8 @@ def cla(self):
1077
1080
# refactor this out so it can be called in ax.set_title if
1078
1081
# pad argument used...
1079
1082
self ._set_title_offset_trans (title_offset_points )
1083
+ # determine if the title position has been set manually:
1084
+ self ._autotitlepos = None
1080
1085
1081
1086
for _title in (self .title , self ._left_title , self ._right_title ):
1082
1087
self ._set_artist_props (_title )
@@ -2446,6 +2451,50 @@ def handle_single_axis(scale, autoscaleon, shared_axes, interval,
2446
2451
def _get_axis_list (self ):
2447
2452
return (self .xaxis , self .yaxis )
2448
2453
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
+
2449
2498
# Drawing
2450
2499
2451
2500
@allow_rasterization
@@ -2459,6 +2508,7 @@ def draw(self, renderer=None, inframe=False):
2459
2508
if not self .get_visible ():
2460
2509
return
2461
2510
renderer .open_group ('axes' )
2511
+
2462
2512
# prevent triggering call backs during the draw process
2463
2513
self ._stale = True
2464
2514
locator = self .get_axes_locator ()
@@ -2479,6 +2529,8 @@ def draw(self, renderer=None, inframe=False):
2479
2529
for spine in self .spines .values ():
2480
2530
artists .remove (spine )
2481
2531
2532
+ self ._update_title_position (renderer )
2533
+
2482
2534
if self .axison and not inframe :
2483
2535
if self ._axisbelow is True :
2484
2536
self .xaxis .set_zorder (0.5 )
@@ -2507,6 +2559,7 @@ def draw(self, renderer=None, inframe=False):
2507
2559
# rasterize artists with negative zorder
2508
2560
# if the minimum zorder is negative, start rasterization
2509
2561
rasterization_zorder = self ._rasterization_zorder
2562
+
2510
2563
if (rasterization_zorder is not None and
2511
2564
artists and artists [0 ].zorder < rasterization_zorder ):
2512
2565
renderer .start_rasterizing ()
@@ -2528,7 +2581,7 @@ def draw(self, renderer=None, inframe=False):
2528
2581
renderer .stop_rasterizing ()
2529
2582
2530
2583
mimage ._draw_list_compositing_images (renderer , self , artists )
2531
-
2584
+
2532
2585
renderer .close_group ('axes' )
2533
2586
self ._cachedRenderer = renderer
2534
2587
self .stale = False
@@ -4051,6 +4104,12 @@ def get_tightbbox(self, renderer, call_axes_locator=True):
4051
4104
else :
4052
4105
self .apply_aspect ()
4053
4106
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
+
4054
4113
bb .append (self .get_window_extent (renderer ))
4055
4114
4056
4115
if self .title .get_visible ():
@@ -4060,10 +4119,6 @@ def get_tightbbox(self, renderer, call_axes_locator=True):
4060
4119
if self ._right_title .get_visible ():
4061
4120
bb .append (self ._right_title .get_window_extent (renderer ))
4062
4121
4063
- bb_xaxis = self .xaxis .get_tightbbox (renderer )
4064
- if bb_xaxis :
4065
- bb .append (bb_xaxis )
4066
-
4067
4122
bb_yaxis = self .yaxis .get_tightbbox (renderer )
4068
4123
if bb_yaxis :
4069
4124
bb .append (bb_yaxis )
0 commit comments