1919
2020import matplotlib as mpl
2121from matplotlib import _api , collections , cm , colors , contour , ticker
22- from matplotlib .axes ._base import _TransformedBoundsLocator
23- from matplotlib .axes ._axes import Axes
2422import matplotlib .artist as martist
2523import matplotlib .patches as mpatches
2624import matplotlib .path as mpath
@@ -206,76 +204,12 @@ def _set_ticks_on_axis_warn(*args, **kw):
206204 _api .warn_external ("Use the colorbar set_ticks() method instead." )
207205
208206
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-
273207class _ColorbarSpine (mspines .Spine ):
274208 def __init__ (self , axes ):
275209 self ._ax = axes
276210 super ().__init__ (axes , 'colorbar' ,
277211 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 )
279213
280214 def get_window_extent (self , renderer = None ):
281215 # This Spine has no Axis associated with it, and doesn't need to adjust
@@ -294,6 +228,66 @@ def draw(self, renderer):
294228 return ret
295229
296230
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+
297291class Colorbar :
298292 r"""
299293 Draw a colorbar in an existing axes.
@@ -393,7 +387,7 @@ def __init__(self, ax, mappable=None, *, cmap=None,
393387 extendfrac = None ,
394388 extendrect = False ,
395389 label = '' ,
396- userax = False ,
390+ userax = True ,
397391 ):
398392
399393 if mappable is None :
@@ -432,9 +426,9 @@ def __init__(self, ax, mappable=None, *, cmap=None,
432426 _api .check_in_list (
433427 ['uniform' , 'proportional' ], spacing = spacing )
434428
435- # wrap the axes so that it can be positioned as an inset axes:
436- ax = ColorbarAxes (ax , userax = userax )
437429 self .ax = ax
430+ self ._userax = userax
431+ self .ax ._axes_locator = _ColorbarAxesLocator (self )
438432 ax .set (navigate = False )
439433
440434 if extend is None :
@@ -467,10 +461,8 @@ def __init__(self, ax, mappable=None, *, cmap=None,
467461
468462 for spine in self .ax .spines .values ():
469463 spine .set_visible (False )
470- for spine in self .ax .outer_ax .spines .values ():
471- spine .set_visible (False )
472464 self .outline = self .ax .spines ['outline' ] = _ColorbarSpine (self .ax )
473-
465+ self . _short_axis (). set_visible ( False )
474466 self .patch = mpatches .Polygon (
475467 np .empty ((0 , 2 )),
476468 color = mpl .rcParams ['axes.facecolor' ], linewidth = 0.01 , zorder = - 1 )
@@ -621,37 +613,27 @@ def _add_solids_patches(self, X, Y, C, mappable):
621613
622614 def _do_extends (self , extendlen ):
623615 """
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.
626617 """
627618 # extend lengths are fraction of the *inner* part of colorbar,
628619 # not the total colorbar:
629620 elower = extendlen [0 ] if self ._extend_lower () else 0
630621 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
638623
639624 # xyout is the outline of the colorbar including the extend patches:
640625 if not self .extendrect :
641626 # 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 ]])
644629 else :
645630 # 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 ]])
649634
650- bounds = np .array ([0.0 , elower , 1.0 , inner_length ])
651635 if self .orientation == 'horizontal' :
652- bounds = bounds [[1 , 0 , 3 , 2 ]]
653636 xyout = xyout [:, ::- 1 ]
654- self .ax ._set_inner_bounds (bounds )
655637
656638 # xyout is the path for the spine:
657639 self .outline .set_xy (xyout )
@@ -670,35 +652,35 @@ def _do_extends(self, extendlen):
670652 if self ._extend_lower ():
671653 if not self .extendrect :
672654 # triangle
673- xy = np .array ([[0.5 , 0 ], [1 , elower ], [0 , elower ]])
655+ xy = np .array ([[0.5 , - elower ], [1 , 0 ], [0 , 0 ]])
674656 else :
675657 # 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 ]])
677659 if self .orientation == 'horizontal' :
678660 xy = xy [:, ::- 1 ]
679661 # add the patch
680662 color = self .cmap (self .norm (self ._values [0 ]))
681663 patch = mpatches .PathPatch (
682664 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 )
686668 if self ._extend_upper ():
687669 if not self .extendrect :
688670 # 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 ]])
690672 else :
691673 # 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 ]])
693675 if self .orientation == 'horizontal' :
694676 xy = xy [:, ::- 1 ]
695677 # add the patch
696678 color = self .cmap (self .norm (self ._values [- 1 ]))
697679 patch = mpatches .PathPatch (
698680 mpath .Path (xy ), facecolor = color ,
699681 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 )
702684 return
703685
704686 def add_lines (self , * args , ** kwargs ):
@@ -949,8 +931,7 @@ def remove(self):
949931 If the colorbar was created with ``use_gridspec=True`` the previous
950932 gridspec is restored.
951933 """
952- self .ax .inner_ax .remove ()
953- self .ax .outer_ax .remove ()
934+ self .ax .remove ()
954935
955936 self .mappable .callbacksSM .disconnect (self .mappable .colorbar_cid )
956937 self .mappable .colorbar = None
0 commit comments