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
_hold_msg = """axes.hold is deprecated.
@@ -1082,6 +1085,8 @@ def cla(self):
1082
1085
# refactor this out so it can be called in ax.set_title if
1083
1086
# pad argument used...
1084
1087
self ._set_title_offset_trans (title_offset_points )
1088
+ # determine if the title position has been set manually:
1089
+ self ._autotitlepos = None
1085
1090
1086
1091
for _title in (self .title , self ._left_title , self ._right_title ):
1087
1092
self ._set_artist_props (_title )
@@ -2512,6 +2517,50 @@ def handle_single_axis(scale, autoscaleon, shared_axes, interval,
2512
2517
def _get_axis_list (self ):
2513
2518
return (self .xaxis , self .yaxis )
2514
2519
2520
+ def _update_title_position (self , renderer ):
2521
+ """
2522
+ Update the title position based on the bounding box enclosing
2523
+ all the ticklabels and x-axis spine and xlabel...
2524
+ """
2525
+ _log .debug ('update_title_pos' )
2526
+
2527
+ if self ._autotitlepos is not None and not self ._autotitlepos :
2528
+ _log .debug ('title position was updated manually, not adjusting' )
2529
+ return
2530
+
2531
+ titles = (self .title , self ._left_title , self ._right_title )
2532
+
2533
+ if self ._autotitlepos is None :
2534
+ for title in titles :
2535
+ x , y = title .get_position ()
2536
+ if not np .isclose (y , 1.0 ):
2537
+ self ._autotitlepos = False
2538
+ _log .debug ('not adjusting title pos because title was'
2539
+ ' already placed manually: %f' , y )
2540
+ return
2541
+ self ._autotitlepos = True
2542
+
2543
+ for title in titles :
2544
+ x , y0 = title .get_position ()
2545
+ y = 1.0
2546
+ # need to check all our twins too...
2547
+ axs = self ._twinned_axes .get_siblings (self )
2548
+
2549
+ for ax in axs :
2550
+ try :
2551
+ if (ax .xaxis .get_label_position () == 'top'
2552
+ or ax .xaxis .get_ticks_position () == 'top' ):
2553
+ bb = ax .xaxis .get_tightbbox (renderer )
2554
+ top = bb .y1
2555
+ # we don't need to pad because the padding is already
2556
+ # in __init__: titleOffsetTrans
2557
+ yn = self .transAxes .inverted ().transform ((0. , top ))[1 ]
2558
+ y = max (y , yn )
2559
+ except AttributeError :
2560
+ pass
2561
+
2562
+ title .set_position ((x , y ))
2563
+
2515
2564
# Drawing
2516
2565
2517
2566
@allow_rasterization
@@ -2525,6 +2574,7 @@ def draw(self, renderer=None, inframe=False):
2525
2574
if not self .get_visible ():
2526
2575
return
2527
2576
renderer .open_group ('axes' )
2577
+
2528
2578
# prevent triggering call backs during the draw process
2529
2579
self ._stale = True
2530
2580
locator = self .get_axes_locator ()
@@ -2545,6 +2595,8 @@ def draw(self, renderer=None, inframe=False):
2545
2595
for spine in self .spines .values ():
2546
2596
artists .remove (spine )
2547
2597
2598
+ self ._update_title_position (renderer )
2599
+
2548
2600
if self .axison and not inframe :
2549
2601
if self ._axisbelow is True :
2550
2602
self .xaxis .set_zorder (0.5 )
@@ -2573,6 +2625,7 @@ def draw(self, renderer=None, inframe=False):
2573
2625
# rasterize artists with negative zorder
2574
2626
# if the minimum zorder is negative, start rasterization
2575
2627
rasterization_zorder = self ._rasterization_zorder
2628
+
2576
2629
if (rasterization_zorder is not None and
2577
2630
artists and artists [0 ].zorder < rasterization_zorder ):
2578
2631
renderer .start_rasterizing ()
@@ -2594,6 +2647,7 @@ def draw(self, renderer=None, inframe=False):
2594
2647
renderer .stop_rasterizing ()
2595
2648
2596
2649
mimage ._draw_list_compositing_images (renderer , self , artists )
2650
+ self ._update_title_position (renderer )
2597
2651
2598
2652
renderer .close_group ('axes' )
2599
2653
self ._cachedRenderer = renderer
@@ -4117,6 +4171,12 @@ def get_tightbbox(self, renderer, call_axes_locator=True):
4117
4171
else :
4118
4172
self .apply_aspect ()
4119
4173
4174
+ bb_xaxis = self .xaxis .get_tightbbox (renderer )
4175
+ if bb_xaxis :
4176
+ bb .append (bb_xaxis )
4177
+
4178
+ self ._update_title_position (renderer )
4179
+
4120
4180
bb .append (self .get_window_extent (renderer ))
4121
4181
4122
4182
if self .title .get_visible ():
@@ -4126,10 +4186,6 @@ def get_tightbbox(self, renderer, call_axes_locator=True):
4126
4186
if self ._right_title .get_visible ():
4127
4187
bb .append (self ._right_title .get_window_extent (renderer ))
4128
4188
4129
- bb_xaxis = self .xaxis .get_tightbbox (renderer )
4130
- if bb_xaxis :
4131
- bb .append (bb_xaxis )
4132
-
4133
4189
bb_yaxis = self .yaxis .get_tightbbox (renderer )
4134
4190
if bb_yaxis :
4135
4191
bb .append (bb_yaxis )
0 commit comments