@@ -417,6 +417,7 @@ def __init__(self, ax, mappable=None, *, cmap=None,
417
417
self ._filled = filled
418
418
self .extendfrac = extendfrac
419
419
self .extendrect = extendrect
420
+ self ._extend_patches = []
420
421
self .solids = None
421
422
self .solids_patches = []
422
423
self .lines = []
@@ -483,6 +484,11 @@ def __init__(self, ax, mappable=None, *, cmap=None,
483
484
setattr (self .ax , x , getattr (self , x ))
484
485
# Set the cla function to the cbar's method to override it
485
486
self .ax .cla = self ._cbar_cla
487
+ # Callbacks for the extend calculations to handle inverting the axis
488
+ self ._extend_cid1 = self .ax .callbacks .connect (
489
+ "xlim_changed" , self ._do_extends )
490
+ self ._extend_cid2 = self .ax .callbacks .connect (
491
+ "ylim_changed" , self ._do_extends )
486
492
487
493
@property
488
494
def locator (self ):
@@ -598,17 +604,20 @@ def _draw_all(self):
598
604
# extensions:
599
605
self .vmin , self .vmax = self ._boundaries [self ._inside ][[0 , - 1 ]]
600
606
# Compute the X/Y mesh.
601
- X , Y , extendlen = self ._mesh ()
607
+ X , Y = self ._mesh ()
602
608
# draw the extend triangles, and shrink the inner axes to accommodate.
603
609
# also adds the outline path to self.outline spine:
604
- self ._do_extends (extendlen )
605
-
610
+ self ._do_extends ()
611
+ lower , upper = self .vmin , self .vmax
612
+ if self ._long_axis ().get_inverted ():
613
+ # If the axis is inverted, we need to swap the vmin/vmax
614
+ lower , upper = upper , lower
606
615
if self .orientation == 'vertical' :
607
616
self .ax .set_xlim (0 , 1 )
608
- self .ax .set_ylim (self . vmin , self . vmax )
617
+ self .ax .set_ylim (lower , upper )
609
618
else :
610
619
self .ax .set_ylim (0 , 1 )
611
- self .ax .set_xlim (self . vmin , self . vmax )
620
+ self .ax .set_xlim (lower , upper )
612
621
613
622
# set up the tick locators and formatters. A bit complicated because
614
623
# boundary norms + uniform spacing requires a manual locator.
@@ -661,12 +670,19 @@ def _add_solids_patches(self, X, Y, C, mappable):
661
670
patches .append (patch )
662
671
self .solids_patches = patches
663
672
664
- def _do_extends (self , extendlen ):
673
+ def _do_extends (self , ax = None ):
665
674
"""
666
675
Add the extend tri/rectangles on the outside of the axes.
676
+
677
+ ax is unused, but required due to the callbacks on xlim/ylim changed
667
678
"""
679
+ # Clean up any previous extend patches
680
+ for patch in self ._extend_patches :
681
+ patch .remove ()
682
+ self ._extend_patches = []
668
683
# extend lengths are fraction of the *inner* part of colorbar,
669
684
# not the total colorbar:
685
+ _ , extendlen = self ._proportional_y ()
670
686
bot = 0 - (extendlen [0 ] if self ._extend_lower () else 0 )
671
687
top = 1 + (extendlen [1 ] if self ._extend_upper () else 0 )
672
688
@@ -708,12 +724,17 @@ def _do_extends(self, extendlen):
708
724
if self .orientation == 'horizontal' :
709
725
xy = xy [:, ::- 1 ]
710
726
# add the patch
711
- color = self .cmap (self .norm (self ._values [0 ]))
727
+ val = - 1 if self ._long_axis ().get_inverted () else 0
728
+ color = self .cmap (self .norm (self ._values [val ]))
712
729
patch = mpatches .PathPatch (
713
730
mpath .Path (xy ), facecolor = color , linewidth = 0 ,
714
731
antialiased = False , transform = self .ax .transAxes ,
715
- hatch = hatches [0 ], clip_on = False )
732
+ hatch = hatches [0 ], clip_on = False ,
733
+ # Place it right behind the standard patches, which is
734
+ # needed if we updated the extends
735
+ zorder = np .nextafter (self .ax .patch .zorder , - np .inf ))
716
736
self .ax .add_patch (patch )
737
+ self ._extend_patches .append (patch )
717
738
if self ._extend_upper ():
718
739
if not self .extendrect :
719
740
# triangle
@@ -724,12 +745,17 @@ def _do_extends(self, extendlen):
724
745
if self .orientation == 'horizontal' :
725
746
xy = xy [:, ::- 1 ]
726
747
# add the patch
727
- color = self .cmap (self .norm (self ._values [- 1 ]))
748
+ val = 0 if self ._long_axis ().get_inverted () else - 1
749
+ color = self .cmap (self .norm (self ._values [val ]))
728
750
patch = mpatches .PathPatch (
729
751
mpath .Path (xy ), facecolor = color ,
730
752
linewidth = 0 , antialiased = False ,
731
- transform = self .ax .transAxes , hatch = hatches [- 1 ], clip_on = False )
753
+ transform = self .ax .transAxes , hatch = hatches [- 1 ], clip_on = False ,
754
+ # Place it right behind the standard patches, which is
755
+ # needed if we updated the extends
756
+ zorder = np .nextafter (self .ax .patch .zorder , - np .inf ))
732
757
self .ax .add_patch (patch )
758
+ self ._extend_patches .append (patch )
733
759
return
734
760
735
761
def add_lines (self , * args , ** kwargs ):
@@ -1049,6 +1075,9 @@ def remove(self):
1049
1075
self .mappable .callbacks .disconnect (self .mappable .colorbar_cid )
1050
1076
self .mappable .colorbar = None
1051
1077
self .mappable .colorbar_cid = None
1078
+ # Remove the extension callbacks
1079
+ self .ax .callbacks .disconnect (self ._extend_cid1 )
1080
+ self .ax .callbacks .disconnect (self ._extend_cid2 )
1052
1081
1053
1082
try :
1054
1083
ax = self .mappable .axes
@@ -1151,7 +1180,7 @@ def _mesh(self):
1151
1180
These are scaled between vmin and vmax, and already handle colorbar
1152
1181
orientation.
1153
1182
"""
1154
- y , extendlen = self ._proportional_y ()
1183
+ y , _ = self ._proportional_y ()
1155
1184
# Use the vmin and vmax of the colorbar, which may not be the same
1156
1185
# as the norm. There are situations where the colormap has a
1157
1186
# narrower range than the colorbar and we want to accommodate the
@@ -1172,9 +1201,9 @@ def _mesh(self):
1172
1201
self ._y = y
1173
1202
X , Y = np .meshgrid ([0. , 1. ], y )
1174
1203
if self .orientation == 'vertical' :
1175
- return (X , Y , extendlen )
1204
+ return (X , Y )
1176
1205
else :
1177
- return (Y , X , extendlen )
1206
+ return (Y , X )
1178
1207
1179
1208
def _forward_boundaries (self , x ):
1180
1209
# map boundaries equally between 0 and 1...
@@ -1322,11 +1351,13 @@ def _get_extension_lengths(self, frac, automin, automax, default=0.05):
1322
1351
1323
1352
def _extend_lower (self ):
1324
1353
"""Return whether the lower limit is open ended."""
1325
- return self .extend in ('both' , 'min' )
1354
+ minmax = "max" if self ._long_axis ().get_inverted () else "min"
1355
+ return self .extend in ('both' , minmax )
1326
1356
1327
1357
def _extend_upper (self ):
1328
1358
"""Return whether the upper limit is open ended."""
1329
- return self .extend in ('both' , 'max' )
1359
+ minmax = "min" if self ._long_axis ().get_inverted () else "max"
1360
+ return self .extend in ('both' , minmax )
1330
1361
1331
1362
def _long_axis (self ):
1332
1363
"""Return the long axis"""
0 commit comments