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
@@ -512,6 +513,9 @@ def __init__(self, fig, rect,
512
513
# warnings.warn(
513
514
# 'shared axes: "adjustable" is being changed to "datalim"')
514
515
self ._adjustable = 'datalim'
516
+ # list of possible twinned axes...
517
+ self ._twinx_axes = []
518
+ self ._twiny_axes = []
515
519
self .set_label (label )
516
520
self .set_figure (fig )
517
521
@@ -1077,6 +1081,8 @@ def cla(self):
1077
1081
# refactor this out so it can be called in ax.set_title if
1078
1082
# pad argument used...
1079
1083
self ._set_title_offset_trans (title_offset_points )
1084
+ # determine if the title position has been set manually:
1085
+ self ._autotitlepos = None
1080
1086
1081
1087
for _title in (self .title , self ._left_title , self ._right_title ):
1082
1088
self ._set_artist_props (_title )
@@ -2377,11 +2383,59 @@ def handle_single_axis(scale, autoscaleon, shared_axes, interval,
2377
2383
def _get_axis_list (self ):
2378
2384
return (self .xaxis , self .yaxis )
2379
2385
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
+
2380
2433
# Drawing
2381
2434
2382
2435
@allow_rasterization
2383
2436
def draw (self , renderer = None , inframe = False ):
2384
2437
"""Draw everything (plot lines, axes, labels)"""
2438
+ log = logging .getLogger (__name__ )
2385
2439
if renderer is None :
2386
2440
renderer = self ._cachedRenderer
2387
2441
@@ -2390,6 +2444,7 @@ def draw(self, renderer=None, inframe=False):
2390
2444
if not self .get_visible ():
2391
2445
return
2392
2446
renderer .open_group ('axes' )
2447
+
2393
2448
# prevent triggering call backs during the draw process
2394
2449
self ._stale = True
2395
2450
locator = self .get_axes_locator ()
@@ -2410,6 +2465,8 @@ def draw(self, renderer=None, inframe=False):
2410
2465
for spine in six .itervalues (self .spines ):
2411
2466
artists .remove (spine )
2412
2467
2468
+ self ._update_title_position (renderer )
2469
+
2413
2470
if self .axison and not inframe :
2414
2471
if self ._axisbelow is True :
2415
2472
self .xaxis .set_zorder (0.5 )
@@ -2438,6 +2495,8 @@ def draw(self, renderer=None, inframe=False):
2438
2495
# rasterize artists with negative zorder
2439
2496
# if the minimum zorder is negative, start rasterization
2440
2497
rasterization_zorder = self ._rasterization_zorder
2498
+ log .debug ('rasterization_zorder %s' , rasterization_zorder )
2499
+
2441
2500
if (rasterization_zorder is not None and
2442
2501
artists and artists [0 ].zorder < rasterization_zorder ):
2443
2502
renderer .start_rasterizing ()
@@ -2458,7 +2517,10 @@ def draw(self, renderer=None, inframe=False):
2458
2517
a .draw (renderer )
2459
2518
renderer .stop_rasterizing ()
2460
2519
2520
+ for a in artists :
2521
+ log .debug ('draw: artist %s' , a )
2461
2522
mimage ._draw_list_compositing_images (renderer , self , artists )
2523
+ self ._update_title_position (renderer )
2462
2524
2463
2525
renderer .close_group ('axes' )
2464
2526
self ._cachedRenderer = renderer
@@ -4028,6 +4090,12 @@ def get_tightbbox(self, renderer, call_axes_locator=True):
4028
4090
else :
4029
4091
self .apply_aspect ()
4030
4092
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
+
4031
4099
bb .append (self .get_window_extent (renderer ))
4032
4100
4033
4101
if self .title .get_visible ():
@@ -4037,10 +4105,6 @@ def get_tightbbox(self, renderer, call_axes_locator=True):
4037
4105
if self ._right_title .get_visible ():
4038
4106
bb .append (self ._right_title .get_window_extent (renderer ))
4039
4107
4040
- bb_xaxis = self .xaxis .get_tightbbox (renderer )
4041
- if bb_xaxis :
4042
- bb .append (bb_xaxis )
4043
-
4044
4108
bb_yaxis = self .yaxis .get_tightbbox (renderer )
4045
4109
if bb_yaxis :
4046
4110
bb .append (bb_yaxis )
@@ -4091,6 +4155,7 @@ def twinx(self):
4091
4155
self .yaxis .tick_left ()
4092
4156
ax2 .xaxis .set_visible (False )
4093
4157
ax2 .patch .set_visible (False )
4158
+ self ._twinx_axes .append (ax2 )
4094
4159
return ax2
4095
4160
4096
4161
def twiny (self ):
@@ -4120,6 +4185,7 @@ def twiny(self):
4120
4185
self .xaxis .tick_bottom ()
4121
4186
ax2 .yaxis .set_visible (False )
4122
4187
ax2 .patch .set_visible (False )
4188
+ self ._twiny_axes .append (ax2 )
4123
4189
return ax2
4124
4190
4125
4191
def get_shared_x_axes (self ):
0 commit comments