19
19
20
20
import matplotlib as mpl
21
21
from matplotlib import _api , collections , cm , colors , contour , ticker
22
- from matplotlib .axes ._base import _TransformedBoundsLocator
23
- from matplotlib .axes ._axes import Axes
24
22
import matplotlib .artist as martist
25
23
import matplotlib .patches as mpatches
26
24
import matplotlib .path as mpath
@@ -206,76 +204,12 @@ def _set_ticks_on_axis_warn(*args, **kw):
206
204
_api .warn_external ("Use the colorbar set_ticks() method instead." )
207
205
208
206
209
- class ColorbarAxes (Axes ):
210
- """
211
- ColorbarAxes packages two axes, a parent axes that takes care of
212
- positioning the axes, and an inset_axes that takes care of the drawing,
213
- labels, ticks, etc. The inset axes is used as a way to properly
214
- position the extensions (triangles or rectangles) that are used to indicate
215
- over/under colors.
216
-
217
- Users should not normally instantiate this class, but it is the class
218
- returned by ``cbar = fig.colorbar(im); cax = cbar.ax``.
219
- """
220
- def __init__ (self , parent , userax = True ):
221
- """
222
- Parameters
223
- ----------
224
- parent : Axes
225
- Axes that specifies the position of the colorbar.
226
- userax : boolean
227
- True if the user passed `.Figure.colorbar` the axes manually.
228
- """
229
-
230
- if userax :
231
- # copy position:
232
- fig = parent .figure
233
- outer_ax = fig .add_axes (parent .get_position ())
234
- # copy the locator if one exists:
235
- outer_ax ._axes_locator = parent ._axes_locator
236
- # if the parent is a child of another axes, swap these...
237
- if (parent ._axes is not None and
238
- parent in parent ._axes .child_axes ):
239
- parent ._axes .add_child_axes (outer_ax )
240
- outer_ax ._axes .child_axes .remove (parent )
241
- else :
242
- parent .remove ()
243
- else :
244
- outer_ax = parent
245
-
246
- inner_ax = outer_ax .inset_axes ([0 , 0 , 1 , 1 ])
247
- self .__dict__ .update (inner_ax .__dict__ )
248
-
249
- self .outer_ax = outer_ax
250
- self .inner_ax = inner_ax
251
- self .outer_ax .xaxis .set_visible (False )
252
- self .outer_ax .yaxis .set_visible (False )
253
- self .outer_ax .set_facecolor ('none' )
254
- self .outer_ax .tick_params = self .inner_ax .tick_params
255
- self .outer_ax .set_xticks = self .inner_ax .set_xticks
256
- self .outer_ax .set_yticks = self .inner_ax .set_yticks
257
- for attr in ["get_position" , "set_position" , "set_aspect" ]:
258
- setattr (self , attr , getattr (self .outer_ax , attr ))
259
- self ._colorbar_info = None # used for mpl-created axes
260
- if userax :
261
- self ._colorbar_info = 'user'
262
- # point the parent's methods all at this axes...
263
- parent .__dict__ = self .__dict__
264
-
265
- def _set_inner_bounds (self , bounds ):
266
- """
267
- Change the inset_axes location...
268
- """
269
- self .inner_ax ._axes_locator = _TransformedBoundsLocator (
270
- bounds , self .outer_ax .transAxes )
271
-
272
-
273
207
class _ColorbarSpine (mspines .Spine ):
274
208
def __init__ (self , axes ):
275
209
self ._ax = axes
276
210
super ().__init__ (axes , 'colorbar' ,
277
211
mpath .Path (np .empty ((0 , 2 )), closed = True ))
278
- mpatches .Patch .set_transform (self , axes .outer_ax . transAxes )
212
+ mpatches .Patch .set_transform (self , axes .transAxes )
279
213
280
214
def get_window_extent (self , renderer = None ):
281
215
# This Spine has no Axis associated with it, and doesn't need to adjust
@@ -294,6 +228,66 @@ def draw(self, renderer):
294
228
return ret
295
229
296
230
231
+ class _ColorbarAxesLocator :
232
+ """
233
+ Wrap any locator on the axes, or its position, to shrink the
234
+ inner axes if there are extend triangles at either min or max.
235
+ """
236
+ def __init__ (self , cbar ):
237
+ """
238
+ *bounds* (a ``[l, b, w, h]`` rectangle) and *transform* together
239
+ specify the position of the inset axes.
240
+ """
241
+ self ._cbar = cbar
242
+ self ._orig_locator = cbar .ax ._axes_locator
243
+
244
+ def __call__ (self , ax , renderer ):
245
+
246
+ # make sure that lims and scales are the same
247
+ scale = self ._cbar ._long_axis ().get_scale ()
248
+ try :
249
+ self ._cbar ._short_axis ()._set_scale (scale )
250
+ except TypeError :
251
+ pass
252
+ lim = self ._cbar ._long_axis ().get_view_interval ()
253
+ self ._cbar ._short_axis ().set_view_interval (* lim )
254
+
255
+ if self ._orig_locator is not None :
256
+ pos = self ._orig_locator (ax , renderer )
257
+ else :
258
+ pos = ax .get_position (original = True )
259
+ if self ._cbar .extend == 'neither' :
260
+ return pos
261
+
262
+ y , extendlen = self ._cbar ._proportional_y ()
263
+ if not self ._cbar ._extend_lower ():
264
+ extendlen [0 ] = 0
265
+ if not self ._cbar ._extend_upper ():
266
+ extendlen [1 ] = 0
267
+ len = sum (extendlen ) + 1
268
+ shrink = 1 / len
269
+ offset = extendlen [0 ] / len
270
+ # we need to reset the aspect ratio of the axes to account
271
+ # of the extends...
272
+ if not self ._cbar ._userax :
273
+ aspect = ax ._colorbar_info ['aspect' ]
274
+ else :
275
+ aspect = False
276
+ # now shrink and/or offset to take into account the
277
+ # extend tri/rectangles.
278
+ if self ._cbar .orientation == 'vertical' :
279
+ if aspect :
280
+ ax .set_aspect (aspect * shrink )
281
+ offset = offset * pos .height
282
+ pos = pos .shrunk (1 , shrink ).translated (0 , offset )
283
+ else :
284
+ if aspect :
285
+ ax .set_aspect (aspect / shrink )
286
+ offset = offset * pos .width
287
+ pos = pos .shrunk (shrink , 1 ).translated (offset , 0 )
288
+ return pos
289
+
290
+
297
291
class Colorbar :
298
292
r"""
299
293
Draw a colorbar in an existing axes.
@@ -393,7 +387,7 @@ def __init__(self, ax, mappable=None, *, cmap=None,
393
387
extendfrac = None ,
394
388
extendrect = False ,
395
389
label = '' ,
396
- userax = False ,
390
+ userax = True ,
397
391
):
398
392
399
393
if mappable is None :
@@ -432,9 +426,9 @@ def __init__(self, ax, mappable=None, *, cmap=None,
432
426
_api .check_in_list (
433
427
['uniform' , 'proportional' ], spacing = spacing )
434
428
435
- # wrap the axes so that it can be positioned as an inset axes:
436
- ax = ColorbarAxes (ax , userax = userax )
437
429
self .ax = ax
430
+ self ._userax = userax
431
+ self .ax ._axes_locator = _ColorbarAxesLocator (self )
438
432
ax .set (navigate = False )
439
433
440
434
if extend is None :
@@ -467,10 +461,8 @@ def __init__(self, ax, mappable=None, *, cmap=None,
467
461
468
462
for spine in self .ax .spines .values ():
469
463
spine .set_visible (False )
470
- for spine in self .ax .outer_ax .spines .values ():
471
- spine .set_visible (False )
472
464
self .outline = self .ax .spines ['outline' ] = _ColorbarSpine (self .ax )
473
-
465
+ self . _short_axis (). set_visible ( False )
474
466
self .patch = mpatches .Polygon (
475
467
np .empty ((0 , 2 )),
476
468
color = mpl .rcParams ['axes.facecolor' ], linewidth = 0.01 , zorder = - 1 )
@@ -621,37 +613,27 @@ def _add_solids_patches(self, X, Y, C, mappable):
621
613
622
614
def _do_extends (self , extendlen ):
623
615
"""
624
- Make adjustments of the inner axes for the extend triangles (or
625
- rectanges) and add them as patches.
616
+ Add the extend tri/rectangles on the outside of the axes.
626
617
"""
627
618
# extend lengths are fraction of the *inner* part of colorbar,
628
619
# not the total colorbar:
629
620
elower = extendlen [0 ] if self ._extend_lower () else 0
630
621
eupper = extendlen [1 ] if self ._extend_upper () else 0
631
- total_len = eupper + elower + 1
632
- elower = elower / total_len
633
- eupper = eupper / total_len
634
- inner_length = 1 / total_len
635
-
636
- # make the inner axes smaller to make room for the extend rectangle
637
- top = elower + inner_length
622
+ top = eupper + 1
638
623
639
624
# xyout is the outline of the colorbar including the extend patches:
640
625
if not self .extendrect :
641
626
# triangle:
642
- xyout = np .array ([[0 , elower ], [0.5 , 0 ], [1 , elower ],
643
- [1 , top ], [0.5 , 1 ], [0 , top ], [0 , elower ]])
627
+ xyout = np .array ([[0 , 0 ], [0.5 , - elower ], [1 , 0 ],
628
+ [1 , 1 ], [0.5 , top ], [0 , 1 ], [0 , 0 ]])
644
629
else :
645
630
# rectangle:
646
- xyout = np .array ([[0 , elower ], [0 , 0 ], [1 , 0 ], [1 , elower ],
647
- [1 , top ], [1 , 1 ], [0 , 1 ], [0 , top ],
648
- [0 , elower ]])
631
+ xyout = np .array ([[0 , 0 ], [0 , - elower ], [1 , - elower ], [1 , 0 ],
632
+ [1 , 1 ], [1 , top ], [0 , top ], [0 , 1 ],
633
+ [0 , - elower ]])
649
634
650
- bounds = np .array ([0.0 , elower , 1.0 , inner_length ])
651
635
if self .orientation == 'horizontal' :
652
- bounds = bounds [[1 , 0 , 3 , 2 ]]
653
636
xyout = xyout [:, ::- 1 ]
654
- self .ax ._set_inner_bounds (bounds )
655
637
656
638
# xyout is the path for the spine:
657
639
self .outline .set_xy (xyout )
@@ -670,35 +652,35 @@ def _do_extends(self, extendlen):
670
652
if self ._extend_lower ():
671
653
if not self .extendrect :
672
654
# triangle
673
- xy = np .array ([[0.5 , 0 ], [1 , elower ], [0 , elower ]])
655
+ xy = np .array ([[0.5 , - elower ], [1 , 0 ], [0 , 0 ]])
674
656
else :
675
657
# rectangle
676
- xy = np .array ([[0 , 0 ], [1. , 0 ], [1 , elower ], [0 , elower ]])
658
+ xy = np .array ([[0 , - elower ], [1. , - elower ], [1 , 0 ], [0 , 0 ]])
677
659
if self .orientation == 'horizontal' :
678
660
xy = xy [:, ::- 1 ]
679
661
# add the patch
680
662
color = self .cmap (self .norm (self ._values [0 ]))
681
663
patch = mpatches .PathPatch (
682
664
mpath .Path (xy ), facecolor = color , linewidth = 0 ,
683
- antialiased = False , transform = self .ax .outer_ax . transAxes ,
684
- hatch = hatches [0 ])
685
- self .ax .outer_ax . add_patch (patch )
665
+ antialiased = False , transform = self .ax .transAxes ,
666
+ hatch = hatches [0 ], clip_on = False )
667
+ self .ax .add_patch (patch )
686
668
if self ._extend_upper ():
687
669
if not self .extendrect :
688
670
# triangle
689
- xy = np .array ([[0.5 , 1 ], [1 , 1 - eupper ], [0 , 1 - eupper ]])
671
+ xy = np .array ([[0.5 , top ], [1 , 1 ], [0 , 1 ]])
690
672
else :
691
673
# rectangle
692
- xy = np .array ([[0 , 1 ], [1 , 1 ], [1 , 1 - eupper ], [0 , 1 - eupper ]])
674
+ xy = np .array ([[0 , top ], [1 , top ], [1 , 1 ], [0 , 1 ]])
693
675
if self .orientation == 'horizontal' :
694
676
xy = xy [:, ::- 1 ]
695
677
# add the patch
696
678
color = self .cmap (self .norm (self ._values [- 1 ]))
697
679
patch = mpatches .PathPatch (
698
680
mpath .Path (xy ), facecolor = color ,
699
681
linewidth = 0 , antialiased = False ,
700
- transform = self .ax .outer_ax . transAxes , hatch = hatches [- 1 ])
701
- self .ax .outer_ax . add_patch (patch )
682
+ transform = self .ax .transAxes , hatch = hatches [- 1 ], clip_on = False )
683
+ self .ax .add_patch (patch )
702
684
return
703
685
704
686
def add_lines (self , * args , ** kwargs ):
@@ -949,8 +931,7 @@ def remove(self):
949
931
If the colorbar was created with ``use_gridspec=True`` the previous
950
932
gridspec is restored.
951
933
"""
952
- self .ax .inner_ax .remove ()
953
- self .ax .outer_ax .remove ()
934
+ self .ax .remove ()
954
935
955
936
self .mappable .callbacksSM .disconnect (self .mappable .colorbar_cid )
956
937
self .mappable .colorbar = None
0 commit comments