7
7
from six .moves import xrange
8
8
9
9
import itertools
10
+ import logging
10
11
import warnings
11
12
import math
12
13
from operator import attrgetter
@@ -508,6 +509,9 @@ def __init__(self, fig, rect,
508
509
# warnings.warn(
509
510
# 'shared axes: "adjustable" is being changed to "datalim"')
510
511
self ._adjustable = 'datalim'
512
+ # list of possible twinned axes...
513
+ self ._twinx_axes = []
514
+ self ._twiny_axes = []
511
515
self .set_label (label )
512
516
self .set_figure (fig )
513
517
@@ -1063,6 +1067,8 @@ def cla(self):
1063
1067
verticalalignment = 'baseline' ,
1064
1068
horizontalalignment = 'right' ,
1065
1069
)
1070
+ # determine if the title position has been set manually:
1071
+ self ._autotitlepos = None
1066
1072
1067
1073
for _title in (self .title , self ._left_title , self ._right_title ):
1068
1074
_title .set_transform (self .transAxes + self .titleOffsetTrans )
@@ -2315,11 +2321,59 @@ def handle_single_axis(scale, autoscaleon, shared_axes, interval,
2315
2321
def _get_axis_list (self ):
2316
2322
return (self .xaxis , self .yaxis )
2317
2323
2324
+ def _update_title_position (self , renderer ):
2325
+ """
2326
+ Update the title position based on the bounding box enclosing
2327
+ all the ticklabels and x-axis spine and xlabel...
2328
+ """
2329
+ log = logging .getLogger (__name__ )
2330
+ log .debug ('update_title_pos' )
2331
+
2332
+ if self ._autotitlepos is not None and not self ._autotitlepos :
2333
+ log .info ('title position was updated manually, not adjusting' )
2334
+ return
2335
+
2336
+ titles = (self .title , self ._left_title , self ._right_title )
2337
+
2338
+ if self ._autotitlepos is None :
2339
+ for title in titles :
2340
+ x , y = title .get_position ()
2341
+ if not np .isclose (y , 1.0 ):
2342
+ self ._autotitlepos = False
2343
+ log .info ('not adjusting title pos because title was'
2344
+ ' already placed manually: %f' , y )
2345
+ return
2346
+ self ._autotitlepos = True
2347
+
2348
+ for title in titles :
2349
+ x , y0 = title .get_position ()
2350
+ y = 1.0
2351
+ # need to check all our twins too...
2352
+ axs = [self ] + self ._twinx_axes + self ._twiny_axes
2353
+
2354
+ for ax in axs :
2355
+ try :
2356
+ if (ax .xaxis .get_label_position () == 'top'
2357
+ or ax .xaxis .get_tick_position () == 'top' ):
2358
+ # this may not work?
2359
+ bb = ax .xaxis .get_tightbbox (renderer )
2360
+ top = bb .y1
2361
+ # we don't need to pad because the padding is already
2362
+ # in __init__: titleOffsetTrans
2363
+ yn = self .transAxes .inverted ().transform ((0. , top ))[1 ]
2364
+ if yn > y :
2365
+ y = yn
2366
+ except AttributeError :
2367
+ pass
2368
+
2369
+ title .set_position ((x , y ))
2370
+
2318
2371
# Drawing
2319
2372
2320
2373
@allow_rasterization
2321
2374
def draw (self , renderer = None , inframe = False ):
2322
2375
"""Draw everything (plot lines, axes, labels)"""
2376
+ log = logging .getLogger (__name__ )
2323
2377
if renderer is None :
2324
2378
renderer = self ._cachedRenderer
2325
2379
@@ -2328,6 +2382,7 @@ def draw(self, renderer=None, inframe=False):
2328
2382
if not self .get_visible ():
2329
2383
return
2330
2384
renderer .open_group ('axes' )
2385
+
2331
2386
# prevent triggering call backs during the draw process
2332
2387
self ._stale = True
2333
2388
locator = self .get_axes_locator ()
@@ -2348,6 +2403,8 @@ def draw(self, renderer=None, inframe=False):
2348
2403
for spine in six .itervalues (self .spines ):
2349
2404
artists .remove (spine )
2350
2405
2406
+ self ._update_title_position (renderer )
2407
+
2351
2408
if self .axison and not inframe :
2352
2409
if self ._axisbelow is True :
2353
2410
self .xaxis .set_zorder (0.5 )
@@ -2376,6 +2433,8 @@ def draw(self, renderer=None, inframe=False):
2376
2433
# rasterize artists with negative zorder
2377
2434
# if the minimum zorder is negative, start rasterization
2378
2435
rasterization_zorder = self ._rasterization_zorder
2436
+ log .debug ('rasterization_zorder %s' , rasterization_zorder )
2437
+
2379
2438
if (rasterization_zorder is not None and
2380
2439
artists and artists [0 ].zorder < rasterization_zorder ):
2381
2440
renderer .start_rasterizing ()
@@ -2396,7 +2455,10 @@ def draw(self, renderer=None, inframe=False):
2396
2455
a .draw (renderer )
2397
2456
renderer .stop_rasterizing ()
2398
2457
2458
+ for a in artists :
2459
+ log .debug ('draw: artist %s' , a )
2399
2460
mimage ._draw_list_compositing_images (renderer , self , artists )
2461
+ self ._update_title_position (renderer )
2400
2462
2401
2463
renderer .close_group ('axes' )
2402
2464
self ._cachedRenderer = renderer
@@ -3949,6 +4011,12 @@ def get_tightbbox(self, renderer, call_axes_locator=True):
3949
4011
else :
3950
4012
self .apply_aspect ()
3951
4013
4014
+ bb_xaxis = self .xaxis .get_tightbbox (renderer )
4015
+ if bb_xaxis :
4016
+ bb .append (bb_xaxis )
4017
+
4018
+ self ._update_title_position (renderer )
4019
+
3952
4020
bb .append (self .get_window_extent (renderer ))
3953
4021
3954
4022
if self .title .get_visible ():
@@ -3958,10 +4026,6 @@ def get_tightbbox(self, renderer, call_axes_locator=True):
3958
4026
if self ._right_title .get_visible ():
3959
4027
bb .append (self ._right_title .get_window_extent (renderer ))
3960
4028
3961
- bb_xaxis = self .xaxis .get_tightbbox (renderer )
3962
- if bb_xaxis :
3963
- bb .append (bb_xaxis )
3964
-
3965
4029
bb_yaxis = self .yaxis .get_tightbbox (renderer )
3966
4030
if bb_yaxis :
3967
4031
bb .append (bb_yaxis )
@@ -4010,6 +4074,7 @@ def twinx(self):
4010
4074
self .yaxis .tick_left ()
4011
4075
ax2 .xaxis .set_visible (False )
4012
4076
ax2 .patch .set_visible (False )
4077
+ self ._twinx_axes .append (ax2 )
4013
4078
return ax2
4014
4079
4015
4080
def twiny (self ):
@@ -4039,6 +4104,7 @@ def twiny(self):
4039
4104
self .xaxis .tick_bottom ()
4040
4105
ax2 .yaxis .set_visible (False )
4041
4106
ax2 .patch .set_visible (False )
4107
+ self ._twiny_axes .append (ax2 )
4042
4108
return ax2
4043
4109
4044
4110
def get_shared_x_axes (self ):
0 commit comments