Revision: 5830
http://matplotlib.svn.sourceforge.net/matplotlib/?rev=5830&view=rev
Author: dmkaplan
Date: 2008-07-24 08:50:43 +0000 (Thu, 24 Jul 2008)
Log Message:
-----------
Committing rewrite of clabel inlining and label rotation code. Also, renaming
ContourLabeler attributes to something like .labelAttribute. A few of the old
attribute names have been maintained (in addition to new versions) for
backward compatibility, but these should be remove in +1 releases.
Added appropriate comments to CHANGELOG and API_CHANGES.
Modified Paths:
--------------
trunk/matplotlib/API_CHANGES
trunk/matplotlib/CHANGELOG
trunk/matplotlib/lib/matplotlib/blocking_input.py
trunk/matplotlib/lib/matplotlib/contour.py
Modified: trunk/matplotlib/API_CHANGES
===================================================================
--- trunk/matplotlib/API_CHANGES 2008-07-24 08:06:45 UTC (rev 5829)
+++ trunk/matplotlib/API_CHANGES 2008-07-24 08:50:43 UTC (rev 5830)
@@ -8,6 +8,12 @@
Axes.patch, Axes.axesFrame renamed Axes.frame, Axes.get_frame, which
returns Axes.patch, is deprecated. Examples and users guide updated
+* Changes in the ContourLabeler attributes (clabel function) so that they
+ all have a form like .labelAttribute. The three attributes that are most
+ likely to be used by end users, .cl, .cl_xy and .cl_cvalues have been
+ maintained for the moment (in addition to their renamed versions), but they
+ are depricated and will eventually be removed.
+
Changes for 0.98.1
==================
Modified: trunk/matplotlib/CHANGELOG
===================================================================
--- trunk/matplotlib/CHANGELOG 2008-07-24 08:06:45 UTC (rev 5829)
+++ trunk/matplotlib/CHANGELOG 2008-07-24 08:50:43 UTC (rev 5830)
@@ -1,3 +1,6 @@
+2008-07-24 Rewrite of a significant portion of the clabel code (class
+ ContourLabeler) to improve inlining. - DMK
+
2008-07-22 Added Barbs polygon collection (similar to Quiver) for plotting
wind barbs. Added corresponding helpers to Axes and pyplot as
well. (examples/pylab_examples/barb_demo.py shows it off.) - RMM
@@ -4,7 +7,7 @@
2008-07-21 Added scikits.delaunay as matplotlib.delaunay. Added griddata
function in matplotlib.mlab, with example (griddata_demo.py) in
- pylab_examples. griddata function will use mpl_toolkits._natgrid
+ pylab_examples. griddata function will use mpl_toolkits._natgrid
if installed (haven't yet created the toolkit). - JSW
2008-07-21 Re-introduced offset_copy that works in the context of the
Modified: trunk/matplotlib/lib/matplotlib/blocking_input.py
===================================================================
--- trunk/matplotlib/lib/matplotlib/blocking_input.py 2008-07-24 08:06:45 UTC
(rev 5829)
+++ trunk/matplotlib/lib/matplotlib/blocking_input.py 2008-07-24 08:50:43 UTC
(rev 5830)
@@ -19,8 +19,9 @@
import time
import numpy as np
+
from matplotlib import path, verbose
-from cbook import is_sequence_of_strings
+from matplotlib.cbook import is_sequence_of_strings
class BlockingInput(object):
"""
@@ -267,47 +268,39 @@
if event.inaxes == cs.ax:
conmin,segmin,imin,xmin,ymin = cs.find_nearest_contour(
- event.x, event.y, cs.label_indices)[:5]
+ event.x, event.y, cs.labelIndiceList)[:5]
# Get index of nearest level in subset of levels used for labeling
- lmin = cs.label_indices.index(conmin)
+ lmin = cs.labelIndiceList.index(conmin)
+ # Coordinates of contour
paths = cs.collections[conmin].get_paths()
lc = paths[segmin].vertices
- # Figure out label rotation. This is very cludgy.
- # Ideally, there would be one method in ContourLabeler
- # that would figure out the best rotation for a label at a
- # point, but the way automatic label rotation is done is
- # quite mysterious to me and doesn't seem easy to
- # generalize to non-automatic label placement. The method
- # used below is not very robust! It basically looks one
- # point before and one point after label location on
- # contour and takes mean of angles of two vectors formed.
- # This produces "acceptable" results, but not nearly as
- # nice as automatic method.
- ll = lc[max(0,imin-1):imin+2] # Get points around point
- dd = np.diff(ll,axis=0)
- rotation = np.mean( np.arctan2(dd[:,1], dd[:,0]) ) * 180 / np.pi
- if rotation > 90:
- rotation = rotation -180
- if rotation < -90:
- rotation = 180 + rotation
+ # In pixel/screen space
+ slc = cs.ax.transData.transform(lc)
- cs.add_label(xmin,ymin,rotation,cs.label_levels[lmin],
- cs.label_cvalues[lmin])
+ # Get label width for rotating labels and breaking contours
+ lw = cs.get_label_width(cs.labelLevelList[lmin],
+ cs.labelFmt, cs.labelFontSizeList[lmin])
+ # Figure out label rotation.
+ rotation,nlc = cs.calc_label_rot_and_inline(
+ slc, imin, lw, lc if self.inline else [],
+ self.inline_spacing )
+
+ cs.add_label(xmin,ymin,rotation,cs.labelLevelList[lmin],
+ cs.labelCValueList[lmin])
+
if self.inline:
- # Get label width for breaking contours
- lw = cs.get_label_width(cs.label_levels[lmin],
- cs.fmt, cs.fslist[lmin])
- # Break contour
- new=cs.break_linecontour(lc,rotation,lw,imin)
- if len(new[0]):
- paths[segmin] = path.Path(new[0])
- if len(new[1]):
- paths.extend([path.Path(new[1])])
+ # Remove old, not looping over paths so we can do this up front
+ paths.pop(segmin)
+ # Add paths if not empty or single point
+ for n in nlc:
+ if len(n)>1:
+ paths.append( path.Path(n) )
+
self.fig.canvas.draw()
else: # Remove event if not valid
BlockingInput.pop(self)
@@ -320,14 +313,21 @@
broken contour - once humpty-dumpty is broken, he can't be put
back together. In inline mode, this does nothing.
"""
+ # Remove this last event - not too important for clabel use
+ # since clabel normally doesn't have a maximum number of
+ # events, but best for cleanliness sake.
+ BlockingInput.pop(self)
+
if self.inline:
pass
else:
self.cs.pop_label()
self.cs.ax.figure.canvas.draw()
- def __call__(self,inline,n=-1,timeout=-1):
+ def __call__(self,inline,inline_spacing=5,n=-1,timeout=-1):
self.inline=inline
+ self.inline_spacing=inline_spacing
+
BlockingMouseInput.__call__(self,n=n,timeout=timeout,
show_clicks=False)
Modified: trunk/matplotlib/lib/matplotlib/contour.py
===================================================================
--- trunk/matplotlib/lib/matplotlib/contour.py 2008-07-24 08:06:45 UTC (rev
5829)
+++ trunk/matplotlib/lib/matplotlib/contour.py 2008-07-24 08:50:43 UTC (rev
5830)
@@ -69,6 +69,12 @@
controls whether the underlying contour is removed or
not. Default is *True*.
+ *inline_spacing*:
+ space in pixels to leave on each side of label when
+ placing inline. Defaults to 5. This spacing will be
+ exact for labels at locations where the contour is
+ straight, less so for labels on curved contours.
+
*fmt*:
a format string for the label. Default is '%1.3f'
Alternatively, this can be a dictionary matching contour
@@ -108,11 +114,12 @@
fontsize = kwargs.get('fontsize', None)
inline = kwargs.get('inline', 1)
- self.fmt = kwargs.get('fmt', '%1.3f')
+ inline_spacing = kwargs.get('inline_spacing', 5)
+ self.labelFmt = kwargs.get('fmt', '%1.3f')
_colors = kwargs.get('colors', None)
# Detect if manual selection is desired and remove from argument list
- self.manual_select=kwargs.get('manual',False)
+ self.labelManual=kwargs.get('manual',False)
if len(args) == 0:
levels = self.levels
@@ -131,52 +138,59 @@
raise ValueError(msg)
else:
raise TypeError("Illegal arguments to clabel, see help(clabel)")
- self.label_levels = levels
- self.label_indices = indices
+ self.labelLevelList = levels
+ self.labelIndiceList = indices
- self.fp = font_manager.FontProperties()
+ self.labelFontProps = font_manager.FontProperties()
if fontsize == None:
- font_size = int(self.fp.get_size_in_points())
+ font_size = int(self.labelFontProps.get_size_in_points())
else:
if type(fontsize) not in [int, float, str]:
raise TypeError("Font size must be an integer number.")
# Can't it be floating point, as indicated in line above?
else:
if type(fontsize) == str:
- font_size = int(self.fp.get_size_in_points())
+ font_size = int(self.labelFontProps.get_size_in_points())
else:
- self.fp.set_size(fontsize)
+ self.labelFontProps.set_size(fontsize)
font_size = fontsize
- self.fslist = [font_size] * len(levels)
+ self.labelFontSizeList = [font_size] * len(levels)
if _colors == None:
- self.label_mappable = self
- self.label_cvalues = np.take(self.cvalues, self.label_indices)
+ self.labelMappable = self
+ self.labelCValueList = np.take(self.cvalues, self.labelIndiceList)
else:
- cmap = colors.ListedColormap(_colors, N=len(self.label_levels))
- self.label_cvalues = range(len(self.label_levels))
- self.label_mappable = cm.ScalarMappable(cmap = cmap,
- norm = colors.NoNorm())
+ cmap = colors.ListedColormap(_colors, N=len(self.labelLevelList))
+ self.labelCValueList = range(len(self.labelLevelList))
+ self.labelMappable = cm.ScalarMappable(cmap = cmap,
+ norm = colors.NoNorm())
- #self.cl = [] # Initialized in ContourSet.__init__
- #self.cl_cvalues = [] # same
- self.cl_xy = []
+ #self.labelTexts = [] # Initialized in ContourSet.__init__
+ #self.labelCValues = [] # same
+ self.labelXYs = []
- if self.manual_select:
+ if self.labelManual:
print 'Select label locations manually using first mouse button.'
print 'End manual selection with second mouse button.'
if not inline:
print 'Remove last label by clicking third mouse button.'
blocking_contour_labeler = BlockingContourLabeler(self)
- blocking_contour_labeler(inline)
+ blocking_contour_labeler(inline,inline_spacing)
else:
- self.labels(inline)
+ self.labels(inline,inline_spacing)
- self.label_list = cbook.silent_list('text.Text', self.cl)
- return self.label_list
+ # Hold on to some old attribute names. These are depricated and will
+ # be moved in the near future (sometime after 2008-08-01), but keeping
+ # for now for backwards compatibility
+ self.cl = self.labelTexts
+ self.cl_xy = self.labelXYs
+ self.cl_cvalues = self.labelCValues
+ self.labelTextsList = cbook.silent_list('text.Text', self.labelTexts)
+ return self.labelTextsList
+
def print_label(self, linecontour,labelwidth):
"if contours are too short, don't plot a label"
lcsize = len(linecontour)
@@ -196,9 +210,9 @@
def too_close(self, x,y, lw):
"if there's a label already nearby, find a better place"
- if self.cl_xy != []:
+ if self.labelXYs != []:
dist = [np.sqrt((x-loc[0]) ** 2 + (y-loc[1]) ** 2)
- for loc in self.cl_xy]
+ for loc in self.labelXYs]
for d in dist:
if d < 1.2*lw:
return 1
@@ -237,12 +251,35 @@
return lw
+ def get_real_label_width( self, lev, fmt, fsize ):
+ """
+ This computes actual onscreen label width.
+ This uses some black magic to determine onscreen extent of non-drawn
+ label. This magic may not be very robust.
+ """
+ # Find middle of axes
+ xx = np.mean( np.asarray(self.ax.axis()).reshape(2,2), axis=1 )
+ # Temporarily create text object
+ t = text.Text( xx[0], xx[1] )
+ self.set_label_props( t, self.get_text(lev,fmt), 'k' )
+
+ # Some black magic to get onscreen extent
+ # NOTE: This will only work for already drawn figures, as the canvas
+ # does not have a renderer otherwise. This is the reason this function
+ # can't be integrated into the rest of the code.
+ bbox = t.get_window_extent(renderer=self.ax.figure.canvas.renderer)
+
+ # difference in pixel extent of image
+ lw = np.diff(bbox.corners()[0::2,0])[0]
+
+ return lw
+
def set_label_props(self, label, text, color):
"set the label properties - color, fontsize, text"
label.set_text(text)
label.set_color(color)
- label.set_fontproperties(self.fp)
+ label.set_fontproperties(self.labelFontProps)
label.set_clip_box(self.ax.bbox)
def get_text(self, lev, fmt):
@@ -255,85 +292,6 @@
else:
return fmt%lev
- def break_linecontour(self, linecontour, rot, labelwidth, ind):
- "break a contour in two contours at the location of the label"
- lcsize = len(linecontour)
- hlw = int(labelwidth/2)
-
- #length of label in screen coords
- ylabel = abs(hlw * np.sin(rot*np.pi/180))
- xlabel = abs(hlw * np.cos(rot*np.pi/180))
-
- trans = self.ax.transData
-
- slc = trans.transform(linecontour)
- x,y = slc[ind]
- xx=slc[:,0].copy()
- yy=slc[:,1].copy()
-
- #indices which are under the label
- inds, = np.nonzero(((xx < x+xlabel) & (xx > x-xlabel)) &
- ((yy < y+ylabel) & (yy > y-ylabel)))
-
- if len(inds) >0:
- #if the label happens to be over the beginning of the
- #contour, the entire contour is removed, i.e.
- #indices to be removed are
- #inds= [0,1,2,3,305,306,307]
- #should rewrite this in a better way
- linds, = np.nonzero(inds[1:]- inds[:-1] != 1)
- if inds[0] == 0 and len(linds) != 0:
- ii = inds[linds[0]]
- lc1 =linecontour[ii+1:inds[ii+1]]
- lc2 = []
-
- else:
- lc1=linecontour[:inds[0]]
- lc2= linecontour[inds[-1]+1:]
-
- else:
- lc1=linecontour[:ind]
- lc2 = linecontour[ind+1:]
-
-
- if rot <0:
- new_x1, new_y1 = x-xlabel, y+ylabel
- new_x2, new_y2 = x+xlabel, y-ylabel
- else:
- new_x1, new_y1 = x-xlabel, y-ylabel
- new_x2, new_y2 = x+xlabel, y+ylabel
-
- inverse = trans.inverted()
- new_x1d, new_y1d = inverse.transform_point((new_x1, new_y1))
- new_x2d, new_y2d = inverse.transform_point((new_x2, new_y2))
- new_xy1 = np.array(((new_x1d, new_y1d),))
- new_xy2 = np.array(((new_x2d, new_y2d),))
-
-
- if rot > 0:
- if (len(lc1) > 0 and (lc1[-1][0] <= new_x1d)
- and (lc1[-1][1] <= new_y1d)):
- lc1 = np.concatenate((lc1, new_xy1))
- #lc1.append((new_x1d, new_y1d))
-
- if (len(lc2) > 0 and (lc2[0][0] >= new_x2d)
- and (lc2[0][1] >= new_y2d)):
- lc2 = np.concatenate((new_xy2, lc2))
- #lc2.insert(0, (new_x2d, new_y2d))
- else:
- if (len(lc1) > 0 and ((lc1[-1][0] <= new_x1d)
- and (lc1[-1][1] >= new_y1d))):
- lc1 = np.concatenate((lc1, new_xy1))
- #lc1.append((new_x1d, new_y1d))
-
- if (len(lc2) > 0 and ((lc2[0][0] >= new_x2d)
- and (lc2[0][1] <= new_y2d))):
- lc2 = np.concatenate((new_xy2, lc2))
- #lc2.insert(0, (new_x2d, new_y2d))
-
- return [lc1,lc2]
-
-
def locate_label(self, linecontour, labelwidth):
"""find a good place to plot a label (relatively flat
part of the contour) and the angle of rotation for the
@@ -362,12 +320,6 @@
dist = np.add.reduce(([(abs(s)[i]/L[i]) for i in range(xsize)]),-1)
x,y,ind = self.get_label_coords(dist, XX, YY, ysize, labelwidth)
#print 'ind, x, y', ind, x, y
- angle = np.arctan2(ylast - yfirst, xlast - xfirst).ravel()
- rotation = angle[ind]*180/np.pi
- if rotation > 90:
- rotation = rotation -180
- if rotation < -90:
- rotation = 180 + rotation
# There must be a more efficient way...
lc = [tuple(l) for l in linecontour]
@@ -375,72 +327,181 @@
#print 'dind', dind
#dind = list(linecontour).index((x,y))
- return x,y, rotation, dind
+ return x, y, dind
+ def calc_label_rot_and_inline( self, slc, ind, lw, lc=[], spacing=5 ):
+ """
+ This function calculates the appropriate label rotation given
+ the linecontour coordinates in screen units, the index of the
+ label location and the label width.
+
+ It will also break contour and calculate inlining if *lc* is
+ not empty. *spacing* is the space around the label in pixels
+ to leave empty.
+
+ Do both of these tasks at once to avoid calling cbook.path_length
+ multiple times, which is relatively costly.
+
+ The method used here involves calculating the path length
+ along the contour in pixel coordinates and then looking
+ approximately label width / 2 away from central point to
+ determine rotation and then to break contour if desired.
+ """
+
+ # Half the label width
+ hlw = lw/2.0
+
+ # Check if closed and, if so, rotate contour so label is at edge
+ closed = cbook.is_closed_polygon(slc)
+ if closed:
+ slc = np.r_[ slc[ind:-1], slc[:ind+1] ]
+
+ if len(lc): # Rotate lc also if not empty
+ lc = np.r_[ lc[ind:-1], lc[:ind+1] ]
+
+ ind = 0
+
+ # Path length in pixel space
+ pl = cbook.path_length(slc)
+ pl = pl-pl[ind]
+
+ # Use linear interpolation to get points around label
+ xi = np.array( [ -hlw, hlw ] )
+ if closed: # Look at end also for closed contours
+ dp = np.array([pl[-1],0])
+ else:
+ dp = np.zeros_like(xi)
+
+ ll = cbook.less_simple_linear_interpolation( pl, slc, dp+xi,
+ extrap=True )
+
+ # get vector in pixel space coordinates from one point to other
+ dd = np.diff( ll, axis=0 ).ravel()
+
+ # Get angle of vector - must be calculated in pixel space for
+ # text rotation to work correctly
+ if np.all(dd==0): # Must deal with case of zero length label
+ rotation = 0.0
+ else:
+ rotation = np.arctan2(dd[1], dd[0]) * 180.0 / np.pi
+
+ # Fix angle so text is never upside-down
+ if rotation > 90:
+ rotation = rotation - 180.0
+ if rotation < -90:
+ rotation = 180.0 + rotation
+
+ # Break contour if desired
+ nlc = []
+ if len(lc):
+ # Expand range by spacing
+ xi = dp + xi + np.array([-spacing,spacing])
+
+ # Get indices near points of interest
+ I = cbook.less_simple_linear_interpolation(
+ pl, np.arange(len(pl)), xi, extrap=False )
+
+ # If those indices aren't beyond contour edge, find x,y
+ if (not np.isnan(I[0])) and int(I[0])<>I[0]:
+ xy1 = cbook.less_simple_linear_interpolation(
+ pl, lc, [ xi[0] ] )
+
+ if (not np.isnan(I[1])) and int(I[1])<>I[1]:
+ xy2 = cbook.less_simple_linear_interpolation(
+ pl, lc, [ xi[1] ] )
+
+ # Make integer
+ I = [ np.floor(I[0]), np.ceil(I[1]) ]
+
+ # Actually break contours
+ if closed:
+ # This will remove contour if shorter than label
+ if np.all(~np.isnan(I)):
+ nlc.append( np.r_[ xy2, lc[I[1]:I[0]+1], xy1 ] )
+ else:
+ # These will remove pieces of contour if they have length zero
+ if not np.isnan(I[0]):
+ nlc.append( np.r_[ lc[:I[0]+1], xy1 ] )
+ if not np.isnan(I[1]):
+ nlc.append( np.r_[ xy2, lc[I[1]:] ] )
+
+ # The current implementation removes contours completely
+ # covered by labels. Uncomment line below to keep
+ # original contour if this is the preferred behavoir.
+ #if not len(nlc): nlc = [ lc ]
+
+ return (rotation,nlc)
+
+
def add_label(self,x,y,rotation,lev,cvalue):
dx,dy = self.ax.transData.inverted().transform_point((x,y))
t = text.Text(dx, dy, rotation = rotation,
horizontalalignment='center',
verticalalignment='center')
- color = self.label_mappable.to_rgba(cvalue,alpha=self.alpha)
+ color = self.labelMappable.to_rgba(cvalue,alpha=self.alpha)
- _text = self.get_text(lev,self.fmt)
+ _text = self.get_text(lev,self.labelFmt)
self.set_label_props(t, _text, color)
- self.cl.append(t)
- self.cl_cvalues.append(cvalue)
- self.cl_xy.append((x,y))
+ self.labelTexts.append(t)
+ self.labelCValues.append(cvalue)
+ self.labelXYs.append((x,y))
# Add label to plot here - useful for manual mode label selection
self.ax.add_artist(t)
def pop_label(self,index=-1):
'''Defaults to removing last label, but any index can be supplied'''
- self.cl_cvalues.pop(index)
- t = self.cl.pop(index)
+ self.labelCValues.pop(index)
+ t = self.labelTexts.pop(index)
t.remove()
- def labels(self, inline):
+ def labels(self, inline, inline_spacing):
trans = self.ax.transData # A bit of shorthand
for icon, lev, fsize, cvalue in zip(
- self.label_indices, self.label_levels, self.fslist,
- self.label_cvalues ):
+ self.labelIndiceList, self.labelLevelList, self.labelFontSizeList,
+ self.labelCValueList ):
con = self.collections[icon]
- lw = self.get_label_width(lev, self.fmt, fsize)
+ lw = self.get_label_width(lev, self.labelFmt, fsize)
additions = []
paths = con.get_paths()
for segNum, linepath in enumerate(paths):
- linecontour = linepath.vertices
- # for closed contours add one more point to
- # avoid division by zero
- if np.all(linecontour[0] == linecontour[-1]):
- linecontour = np.concatenate((linecontour,
-
linecontour[1][np.newaxis,:]))
- #linecontour.append(linecontour[1])
- # transfer all data points to screen coordinates
- slc = trans.transform(linecontour)
+ lc = linepath.vertices # Line contour
+ slc0 = trans.transform(lc) # Line contour in screen coords
+
+ # For closed polygons, add extra point to avoid division by
+ # zero in print_label and locate_label. Other than these
+ # functions, this is not necessary and should probably be
+ # eventually removed.
+ if cbook.is_closed_polygon( lc ):
+ slc = np.r_[ slc0, slc0[1:2,:] ]
+ else:
+ slc = slc0
+
if self.print_label(slc,lw):
- x,y, rotation, ind = self.locate_label(slc, lw)
+ x,y,ind = self.locate_label(slc, lw)
+ rotation,new=self.calc_label_rot_and_inline(
+ slc0, ind, lw, lc if inline else [],
+ inline_spacing )
+
# Actually add the label
self.add_label(x,y,rotation,lev,cvalue)
- # Use break_linecontour to split contours for inlining
+ # If inline, add new contours
if inline:
- new = self.break_linecontour(linecontour, rotation,
- lw, ind)
- if len(new[0]):
- paths[segNum] = path.Path(new[0])
- if len(new[1]):
- additions.append(path.Path(new[1]))
+ for n in new:
+ # Add path if not empty or single point
+ if len(n)>1: additions.append( path.Path(n) )
- # After looping over all segments on a contour, append
- # new paths to existing
- paths.extend(additions)
+ # After looping over all segments on a contour, remove old
+ # paths and add new ones if inlining
+ if inline:
+ del paths[:]
+ paths.extend(additions)
-
class ContourSet(cm.ScalarMappable, ContourLabeler):
"""
Create and store a set of contour lines or filled regions.
@@ -512,8 +573,8 @@
else:
self.collections = cbook.silent_list('collections.LineCollection')
# label lists must be initialized here
- self.cl = []
- self.cl_cvalues = []
+ self.labelTexts = []
+ self.labelCValues = []
kw = {'cmap': cmap}
if norm is not None:
@@ -574,9 +635,9 @@
for color, collection in zip(tcolors, self.collections):
collection.set_alpha(self.alpha)
collection.set_color(color)
- for label, cv in zip(self.cl, self.cl_cvalues):
+ for label, cv in zip(self.labelTexts, self.labelCValues):
label.set_alpha(self.alpha)
- label.set_color(self.label_mappable.to_rgba(cv))
+ label.set_color(self.labelMappable.to_rgba(cv))
# add label colors
cm.ScalarMappable.changed(self)
This was sent by the SourceForge.net collaborative development platform, the
world's largest Open Source development site.
-------------------------------------------------------------------------
This SF.Net email is sponsored by the Moblin Your Move Developer's challenge
Build the coolest Linux based applications with Moblin SDK & win great prizes
Grand prize is a trip for two to an Open Source event anywhere in the world
http://moblin-contest.org/redirect.php?banner_id=100&url=/
_______________________________________________
Matplotlib-checkins mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/matplotlib-checkins