@@ -255,7 +255,7 @@ def __init__(self, ax, cmap=None,
255
255
self .filled = filled
256
256
self .extendfrac = extendfrac
257
257
self .solids = None
258
- self .lines = None
258
+ self .lines = list ()
259
259
self .outline = None
260
260
self .patch = None
261
261
self .dividers = None
@@ -467,14 +467,25 @@ def _add_solids(self, X, Y, C):
467
467
)
468
468
self .ax .add_collection (self .dividers )
469
469
470
- def add_lines (self , levels , colors , linewidths ):
470
+ def add_lines (self , levels , colors , linewidths , erase = True ):
471
471
'''
472
472
Draw lines on the colorbar.
473
+
474
+ *colors* and *linewidths* must be scalars or
475
+ sequences the same length as *levels*.
476
+
477
+ Set *erase* to False to add lines without first
478
+ removing any previously added lines.
473
479
'''
474
- N = len (levels )
475
- dummy , y = self ._locate (levels )
476
- if len (y ) != N :
477
- raise ValueError ("levels are outside colorbar range" )
480
+ y = self ._locate (levels )
481
+ nlevs = len (levels )
482
+ igood = (y < 1.001 ) & (y > - 0.001 )
483
+ y = y [igood ]
484
+ if cbook .iterable (colors ):
485
+ colors = np .asarray (colors )[igood ]
486
+ if cbook .iterable (linewidths ):
487
+ linewidths = np .asarray (linewidths )[igood ]
488
+ N = len (y )
478
489
x = np .array ([0.0 , 1.0 ])
479
490
X , Y = np .meshgrid (x ,y )
480
491
if self .orientation == 'vertical' :
@@ -483,9 +494,10 @@ def add_lines(self, levels, colors, linewidths):
483
494
xy = [zip (Y [i ], X [i ]) for i in xrange (N )]
484
495
col = collections .LineCollection (xy , linewidths = linewidths )
485
496
486
- if self .lines :
487
- self .lines .remove ()
488
- self .lines = col
497
+ if erase and self .lines :
498
+ for lc in self .lines .pop ():
499
+ lc .remove ()
500
+ self .lines .append (col )
489
501
col .set_color (colors )
490
502
self .ax .add_collection (col )
491
503
@@ -528,7 +540,10 @@ def _ticker(self):
528
540
locator .axis .get_minpos = lambda : intv [0 ]
529
541
formatter .axis .get_minpos = lambda : intv [0 ]
530
542
b = np .array (locator ())
531
- b , ticks = self ._locate (b )
543
+ ticks = self ._locate (b )
544
+ inrange = (ticks > - 0.001 ) & (ticks < 1.001 )
545
+ ticks = ticks [inrange ]
546
+ b = b [inrange ]
532
547
formatter .set_locs (b )
533
548
ticklabels = [formatter (t , i ) for i , t in enumerate (b )]
534
549
offset_string = formatter .get_offset ()
@@ -746,37 +761,36 @@ def _mesh(self):
746
761
747
762
def _locate (self , x ):
748
763
'''
749
- Given a possible set of color data values, return the ones
750
- within range, together with their corresponding colorbar
751
- data coordinates.
764
+ Given a set of color data values, return their
765
+ corresponding colorbar data coordinates.
752
766
'''
753
767
if isinstance (self .norm , (colors .NoNorm , colors .BoundaryNorm )):
754
768
b = self ._boundaries
755
769
xn = x
756
- xout = x
757
770
else :
758
771
# Do calculations using normalized coordinates so
759
772
# as to make the interpolation more accurate.
760
773
b = self .norm (self ._boundaries , clip = False ).filled ()
761
- # We do our own clipping so that we can allow a tiny
762
- # bit of slop in the end point ticks to allow for
763
- # floating point errors.
764
774
xn = self .norm (x , clip = False ).filled ()
765
- in_cond = (xn > - 0.001 ) & (xn < 1.001 )
766
- xn = np .compress (in_cond , xn )
767
- xout = np .compress (in_cond , x )
768
- # The rest is linear interpolation with clipping.
775
+ # The rest is linear interpolation with extrapolation at ends.
769
776
y = self ._y
770
777
N = len (b )
771
- ii = np .minimum (np .searchsorted (b , xn ), N - 1 )
772
- i0 = np .maximum (ii - 1 , 0 )
778
+ ii = np .searchsorted (b , xn )
779
+ i0 = ii - 1
780
+ itop = (ii == N )
781
+ ibot = (ii == 0 )
782
+ i0 [itop ] -= 1
783
+ ii [itop ] -= 1
784
+ i0 [ibot ] += 1
785
+ ii [ibot ] += 1
786
+
773
787
#db = b[ii] - b[i0]
774
788
db = np .take (b , ii ) - np .take (b , i0 )
775
- db = np .where (i0 == ii , 1.0 , db )
776
789
#dy = y[ii] - y[i0]
777
790
dy = np .take (y , ii ) - np .take (y , i0 )
778
791
z = np .take (y , i0 ) + (xn - np .take (b ,i0 ))* dy / db
779
- return xout , z
792
+
793
+ return z
780
794
781
795
def set_alpha (self , alpha ):
782
796
self .alpha = alpha
@@ -834,10 +848,13 @@ def on_mappable_changed(self, mappable):
834
848
self .set_clim (mappable .get_clim ())
835
849
self .update_normal (mappable )
836
850
837
- def add_lines (self , CS ):
851
+ def add_lines (self , CS , erase = True ):
838
852
'''
839
853
Add the lines from a non-filled
840
854
:class:`~matplotlib.contour.ContourSet` to the colorbar.
855
+
856
+ Set *erase* to False if these lines should be added to
857
+ any pre-existing lines.
841
858
'''
842
859
if not isinstance (CS , contour .ContourSet ) or CS .filled :
843
860
raise ValueError ('add_lines is only for a ContourSet of lines' )
@@ -851,7 +868,8 @@ def add_lines(self, CS):
851
868
#tcolors = [col.get_colors()[0] for col in CS.collections]
852
869
#tlinewidths = [col.get_linewidth()[0] for lw in CS.collections]
853
870
#print 'tlinewidths:', tlinewidths
854
- ColorbarBase .add_lines (self , CS .levels , tcolors , tlinewidths )
871
+ ColorbarBase .add_lines (self , CS .levels , tcolors , tlinewidths ,
872
+ erase = erase )
855
873
856
874
def update_normal (self , mappable ):
857
875
'''
@@ -884,7 +902,7 @@ def update_bruteforce(self, mappable):
884
902
self .outline = None
885
903
self .patch = None
886
904
self .solids = None
887
- self .lines = None
905
+ self .lines = list ()
888
906
self .dividers = None
889
907
self .set_alpha (mappable .get_alpha ())
890
908
self .cmap = mappable .cmap
0 commit comments