@@ -255,7 +255,7 @@ def __init__(self, ax, cmap=None,
255255 self .filled = filled
256256 self .extendfrac = extendfrac
257257 self .solids = None
258- self .lines = None
258+ self .lines = list ()
259259 self .outline = None
260260 self .patch = None
261261 self .dividers = None
@@ -467,14 +467,25 @@ def _add_solids(self, X, Y, C):
467467 )
468468 self .ax .add_collection (self .dividers )
469469
470- def add_lines (self , levels , colors , linewidths ):
470+ def add_lines (self , levels , colors , linewidths , erase = True ):
471471 '''
472472 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.
473479 '''
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 )
478489 x = np .array ([0.0 , 1.0 ])
479490 X , Y = np .meshgrid (x ,y )
480491 if self .orientation == 'vertical' :
@@ -483,9 +494,10 @@ def add_lines(self, levels, colors, linewidths):
483494 xy = [zip (Y [i ], X [i ]) for i in xrange (N )]
484495 col = collections .LineCollection (xy , linewidths = linewidths )
485496
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 )
489501 col .set_color (colors )
490502 self .ax .add_collection (col )
491503
@@ -528,7 +540,10 @@ def _ticker(self):
528540 locator .axis .get_minpos = lambda : intv [0 ]
529541 formatter .axis .get_minpos = lambda : intv [0 ]
530542 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 ]
532547 formatter .set_locs (b )
533548 ticklabels = [formatter (t , i ) for i , t in enumerate (b )]
534549 offset_string = formatter .get_offset ()
@@ -746,37 +761,36 @@ def _mesh(self):
746761
747762 def _locate (self , x ):
748763 '''
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.
752766 '''
753767 if isinstance (self .norm , (colors .NoNorm , colors .BoundaryNorm )):
754768 b = self ._boundaries
755769 xn = x
756- xout = x
757770 else :
758771 # Do calculations using normalized coordinates so
759772 # as to make the interpolation more accurate.
760773 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.
764774 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.
769776 y = self ._y
770777 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+
773787 #db = b[ii] - b[i0]
774788 db = np .take (b , ii ) - np .take (b , i0 )
775- db = np .where (i0 == ii , 1.0 , db )
776789 #dy = y[ii] - y[i0]
777790 dy = np .take (y , ii ) - np .take (y , i0 )
778791 z = np .take (y , i0 ) + (xn - np .take (b ,i0 ))* dy / db
779- return xout , z
792+
793+ return z
780794
781795 def set_alpha (self , alpha ):
782796 self .alpha = alpha
@@ -834,10 +848,13 @@ def on_mappable_changed(self, mappable):
834848 self .set_clim (mappable .get_clim ())
835849 self .update_normal (mappable )
836850
837- def add_lines (self , CS ):
851+ def add_lines (self , CS , erase = True ):
838852 '''
839853 Add the lines from a non-filled
840854 :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.
841858 '''
842859 if not isinstance (CS , contour .ContourSet ) or CS .filled :
843860 raise ValueError ('add_lines is only for a ContourSet of lines' )
@@ -851,7 +868,8 @@ def add_lines(self, CS):
851868 #tcolors = [col.get_colors()[0] for col in CS.collections]
852869 #tlinewidths = [col.get_linewidth()[0] for lw in CS.collections]
853870 #print 'tlinewidths:', tlinewidths
854- ColorbarBase .add_lines (self , CS .levels , tcolors , tlinewidths )
871+ ColorbarBase .add_lines (self , CS .levels , tcolors , tlinewidths ,
872+ erase = erase )
855873
856874 def update_normal (self , mappable ):
857875 '''
@@ -884,7 +902,7 @@ def update_bruteforce(self, mappable):
884902 self .outline = None
885903 self .patch = None
886904 self .solids = None
887- self .lines = None
905+ self .lines = list ()
888906 self .dividers = None
889907 self .set_alpha (mappable .get_alpha ())
890908 self .cmap = mappable .cmap
0 commit comments