|
From: <ef...@us...> - 2010-04-15 07:30:50
|
Revision: 8232
http://matplotlib.svn.sourceforge.net/matplotlib/?rev=8232&view=rev
Author: efiring
Date: 2010-04-15 07:30:44 +0000 (Thu, 15 Apr 2010)
Log Message:
-----------
contour: refactoring by Ian Thomas to facilitate new tricontour functionality
Modified Paths:
--------------
trunk/matplotlib/lib/matplotlib/axes.py
trunk/matplotlib/lib/matplotlib/contour.py
Modified: trunk/matplotlib/lib/matplotlib/axes.py
===================================================================
--- trunk/matplotlib/lib/matplotlib/axes.py 2010-04-15 07:17:42 UTC (rev 8231)
+++ trunk/matplotlib/lib/matplotlib/axes.py 2010-04-15 07:30:44 UTC (rev 8232)
@@ -6896,14 +6896,14 @@
def contour(self, *args, **kwargs):
if not self._hold: self.cla()
kwargs['filled'] = False
- return mcontour.ContourSet(self, *args, **kwargs)
- contour.__doc__ = mcontour.ContourSet.contour_doc
+ return mcontour.QuadContourSet(self, *args, **kwargs)
+ contour.__doc__ = mcontour.QuadContourSet.contour_doc
def contourf(self, *args, **kwargs):
if not self._hold: self.cla()
kwargs['filled'] = True
- return mcontour.ContourSet(self, *args, **kwargs)
- contourf.__doc__ = mcontour.ContourSet.contour_doc
+ return mcontour.QuadContourSet(self, *args, **kwargs)
+ contourf.__doc__ = mcontour.QuadContourSet.contour_doc
def clabel(self, CS, *args, **kwargs):
return CS.clabel(*args, **kwargs)
Modified: trunk/matplotlib/lib/matplotlib/contour.py
===================================================================
--- trunk/matplotlib/lib/matplotlib/contour.py 2010-04-15 07:17:42 UTC (rev 8231)
+++ trunk/matplotlib/lib/matplotlib/contour.py 2010-04-15 07:30:44 UTC (rev 8232)
@@ -577,7 +577,7 @@
class ContourSet(cm.ScalarMappable, ContourLabeler):
"""
- Create and store a set of contour lines or filled regions.
+ Store a set of contour lines or filled regions.
User-callable method: clabel
@@ -592,17 +592,49 @@
same as levels for line contours; half-way between
levels for filled contours. See _process_colors method.
"""
-
-
def __init__(self, ax, *args, **kwargs):
"""
Draw contour lines or filled regions, depending on
whether keyword arg 'filled' is False (default) or True.
- The first argument of the initializer must be an axes
- object. The remaining arguments and keyword arguments
- are described in ContourSet.contour_doc.
+ The first three arguments must be:
+ *ax*: axes object.
+
+ *levels*: [level0, level1, ..., leveln]
+ A list of floating point numbers indicating the contour
+ levels.
+
+ *allsegs*: [level0segs, level1segs, ...]
+ List of all the polygon segments for all the *levels*.
+ For contour lines len(allsegs) == len(levels), and for
+ filled contour regions len(allsegs) = len(levels)-1.
+
+ level0segs = [polygon0, polygon1, ...]
+
+ polygon0 = array_like [[x0,y0], [x1,y1], ...]
+
+ *allkinds*: None or [level0kinds, level1kinds, ...]
+ Optional list of all the polygon vertex kinds (code types), as
+ described and used in Path. This is used to allow multiply-
+ connected paths such as holes within filled polygons.
+ If not None, len(allkinds) == len(allsegs).
+
+ level0kinds = [polygon0kinds, ...]
+
+ polygon0kinds = [vertexcode0, vertexcode1, ...]
+
+ If allkinds is not None, usually all polygons for a particular
+ contour level are grouped together so that
+
+ level0segs = [polygon0] and level0kinds = [polygon0kinds].
+
+ Keyword arguments are as described in
+ :class:`~matplotlib.contour.QuadContourSet` object.
+
+ **Examples:**
+
+ .. plot:: mpl_examples/misc/contour_manual.py
"""
self.ax = ax
self.levels = kwargs.get('levels', None)
@@ -638,24 +670,7 @@
raise ValueError('Either colors or cmap must be None')
if self.origin == 'image': self.origin = mpl.rcParams['image.origin']
- if isinstance(args[0], ContourSet):
- C = args[0].Cntr
- if self.levels is None:
- self.levels = args[0].levels
- else:
- x, y, z = self._contour_args(args, kwargs)
-
- x0 = ma.minimum(x)
- x1 = ma.maximum(x)
- y0 = ma.minimum(y)
- y1 = ma.maximum(y)
- self.ax.update_datalim([(x0,y0), (x1,y1)])
- self.ax.autoscale_view()
- _mask = ma.getmask(z)
- if _mask is ma.nomask:
- _mask = None
- C = _cntr.Cntr(x, y, z.filled(), _mask)
- self.Cntr = C
+ self._process_args(*args, **kwargs)
self._process_levels()
if self.colors is not None:
@@ -673,28 +688,23 @@
kw['norm'] = norm
cm.ScalarMappable.__init__(self, **kw) # sets self.cmap;
self._process_colors()
+
+ self.allsegs, self.allkinds = self._get_allsegs_and_allkinds()
+
if self.filled:
if self.linewidths is not None:
warnings.warn('linewidths is ignored by contourf')
- lowers = self._levels[:-1]
- if self.zmin == lowers[0]:
- # Include minimum values in lowest interval
- lowers = lowers.copy() # so we don't change self._levels
- if self.logscale:
- lowers[0] = 0.99 * self.zmin
- else:
- lowers[0] -= 1
- uppers = self._levels[1:]
+ # Lower and upper contour levels.
+ lowers, uppers = self._get_lowers_and_uppers()
- for level, level_upper in zip(lowers, uppers):
- nlist = C.trace(level, level_upper, nchunk = self.nchunk)
- nseg = len(nlist)//2
- segs = nlist[:nseg]
- kinds = nlist[nseg:]
+ # Ensure allkinds can be zipped below.
+ if self.allkinds is None:
+ self.allkinds = [None]*len(self.allsegs)
+ for level, level_upper, segs, kinds in \
+ zip(lowers, uppers, self.allsegs, self.allkinds):
paths = self._make_paths(segs, kinds)
-
# Default zorder taken from Collection
zorder = kwargs.get('zorder', 1)
col = collections.PathCollection(paths,
@@ -708,12 +718,8 @@
tlinewidths = self._process_linewidths()
self.tlinewidths = tlinewidths
tlinestyles = self._process_linestyles()
- for level, width, lstyle in zip(self.levels, tlinewidths, tlinestyles):
- nlist = C.trace(level)
- nseg = len(nlist)//2
- segs = nlist[:nseg]
- #kinds = nlist[nseg:]
-
+ for level, width, lstyle, segs in \
+ zip(self.levels, tlinewidths, tlinestyles, self.allsegs):
# Default zorder taken from LineCollection
zorder = kwargs.get('zorder', 2)
col = collections.LineCollection(segs,
@@ -721,20 +727,81 @@
linestyle = lstyle,
alpha=self.alpha,
zorder=zorder)
-
col.set_label('_nolegend_')
self.ax.add_collection(col, False)
self.collections.append(col)
self.changed() # set the colors
- def _make_paths(self, segs, kinds):
- paths = []
- for seg, kind in zip(segs, kinds):
- paths.append(mpath.Path(seg, codes=kind))
- return paths
+ def _process_args(self, *args, **kwargs):
+ """
+ Process args and kwargs; override in derived classes.
+ Must set self.levels, self.zmin and self.zmax, and update axes
+ limits.
+ """
+ self.levels = args[0]
+ self.allsegs = args[1]
+ self.allkinds = len(args) > 2 and args[2] or None
+ self.zmax = np.amax(self.levels)
+ self.zmin = np.amin(self.levels)
+ self._auto = False
+ # Check lengths of levels and allsegs.
+ if self.filled:
+ if len(self.allsegs) != len(self.levels)-1:
+ raise ValueError('must be one less number of segments as levels')
+ else:
+ if len(self.allsegs) != len(self.levels):
+ raise ValueError('must be same number of segments as levels')
+ # Check length of allkinds.
+ if self.allkinds is not None and len(self.allkinds) != len(self.allsegs):
+ raise ValueError('allkinds has different length to allsegs')
+
+ # Determine x,y bounds and update axes data limits.
+ havelimits = False
+ for segs in self.allsegs:
+ for seg in segs:
+ seg = np.asarray(seg)
+ if havelimits:
+ min = np.minimum(min, seg.min(axis=0))
+ max = np.maximum(max, seg.max(axis=0))
+ else:
+ min = seg.min(axis=0)
+ max = seg.max(axis=0)
+ havelimits = True
+ if havelimits:
+ self.ax.update_datalim([min, max])
+ self.ax.autoscale_view()
+
+ def _get_allsegs_and_allkinds(self):
+ """
+ Override in derived classes to create and return allsegs and allkinds.
+ allkinds can be None.
+ """
+ return self.allsegs, self.allkinds
+
+ def _get_lowers_and_uppers(self):
+ """
+ Return (lowers,uppers) for filled contours.
+ """
+ lowers = self._levels[:-1]
+ if self.zmin == lowers[0]:
+ # Include minimum values in lowest interval
+ lowers = lowers.copy() # so we don't change self._levels
+ if self.logscale:
+ lowers[0] = 0.99 * self.zmin
+ else:
+ lowers[0] -= 1
+ uppers = self._levels[1:]
+ return (lowers, uppers)
+
+ def _make_paths(self, segs, kinds):
+ if kinds is not None:
+ return [mpath.Path(seg,codes=kind) for seg,kind in zip(segs,kinds)]
+ else:
+ return [mpath.Path(seg) for seg in segs]
+
def changed(self):
tcolors = [ (tuple(rgba),) for rgba in
self.to_rgba(self.cvalues, alpha=self.alpha)]
@@ -750,7 +817,6 @@
# add label colors
cm.ScalarMappable.changed(self)
-
def _autolev(self, z, N):
'''
Select contour levels to span the data.
@@ -778,101 +844,18 @@
# For line contours, drop levels outside the data range.
return lev[(lev > zmin) & (lev < zmax)]
- def _initialize_x_y(self, z):
- '''
- Return X, Y arrays such that contour(Z) will match imshow(Z)
- if origin is not None.
- The center of pixel Z[i,j] depends on origin:
- if origin is None, x = j, y = i;
- if origin is 'lower', x = j + 0.5, y = i + 0.5;
- if origin is 'upper', x = j + 0.5, y = Nrows - i - 0.5
- If extent is not None, x and y will be scaled to match,
- as in imshow.
- If origin is None and extent is not None, then extent
- will give the minimum and maximum values of x and y.
- '''
- if z.ndim != 2:
- raise TypeError("Input must be a 2D array.")
- else:
- Ny, Nx = z.shape
- if self.origin is None: # Not for image-matching.
- if self.extent is None:
- return np.meshgrid(np.arange(Nx), np.arange(Ny))
- else:
- x0,x1,y0,y1 = self.extent
- x = np.linspace(x0, x1, Nx)
- y = np.linspace(y0, y1, Ny)
- return np.meshgrid(x, y)
- # Match image behavior:
- if self.extent is None:
- x0,x1,y0,y1 = (0, Nx, 0, Ny)
- else:
- x0,x1,y0,y1 = self.extent
- dx = float(x1 - x0)/Nx
- dy = float(y1 - y0)/Ny
- x = x0 + (np.arange(Nx) + 0.5) * dx
- y = y0 + (np.arange(Ny) + 0.5) * dy
- if self.origin == 'upper':
- y = y[::-1]
- return np.meshgrid(x,y)
-
- def _check_xyz(self, args, kwargs):
- '''
- For functions like contour, check that the dimensions
- of the input arrays match; if x and y are 1D, convert
- them to 2D using meshgrid.
-
- Possible change: I think we should make and use an ArgumentError
- Exception class (here and elsewhere).
- '''
- x, y = args[:2]
- self.ax._process_unit_info(xdata=x, ydata=y, kwargs=kwargs)
- x = self.ax.convert_xunits(x)
- y = self.ax.convert_yunits(y)
-
- x = np.asarray(x, dtype=np.float64)
- y = np.asarray(y, dtype=np.float64)
- z = ma.asarray(args[2], dtype=np.float64)
- if z.ndim != 2:
- raise TypeError("Input z must be a 2D array.")
- else: Ny, Nx = z.shape
- if x.shape == z.shape and y.shape == z.shape:
- return x,y,z
- if x.ndim != 1 or y.ndim != 1:
- raise TypeError("Inputs x and y must be 1D or 2D.")
- nx, = x.shape
- ny, = y.shape
- if nx != Nx or ny != Ny:
- raise TypeError("Length of x must be number of columns in z,\n" +
- "and length of y must be number of rows.")
- x,y = np.meshgrid(x,y)
- return x,y,z
-
-
- def _contour_args(self, args, kwargs):
+ def _contour_level_args(self, z, args):
+ """
+ Determine the contour levels and store in self.levels.
+ """
if self.filled: fn = 'contourf'
else: fn = 'contour'
- Nargs = len(args)
- if Nargs <= 2:
- z = ma.asarray(args[0], dtype=np.float64)
- x, y = self._initialize_x_y(z)
- elif Nargs <=4:
- x,y,z = self._check_xyz(args[:3], kwargs)
- else:
- raise TypeError("Too many arguments to %s; see help(%s)" % (fn,fn))
- z = ma.masked_invalid(z, copy=False)
- self.zmax = ma.maximum(z)
- self.zmin = ma.minimum(z)
- if self.logscale and self.zmin <= 0:
- z = ma.masked_where(z <= 0, z)
- warnings.warn('Log scale: values of z <=0 have been masked')
- self.zmin = z.min()
self._auto = False
if self.levels is None:
- if Nargs == 1 or Nargs == 3:
+ if len(args) == 0:
lev = self._autolev(z, 7)
- else: # 2 or 4 args
- level_arg = args[-1]
+ else:
+ level_arg = args[0]
try:
if type(level_arg) == int:
lev = self._autolev(z, level_arg)
@@ -884,7 +867,6 @@
if self.filled and len(lev) < 2:
raise ValueError("Filled contours require at least 2 levels.")
self.levels = lev
- return (x, y, z)
def _process_levels(self):
self._levels = list(self.levels)
@@ -907,7 +889,6 @@
if self.extend in ('both', 'max'):
self.layers[-1] = 0.5 * (self.vmax + self._levels[-2])
-
def _process_colors(self):
"""
Color argument processing for contouring.
@@ -989,6 +970,241 @@
self.alpha = alpha
self.changed()
+ def find_nearest_contour( self, x, y, indices=None, pixel=True ):
+ """
+ Finds contour that is closest to a point. Defaults to
+ measuring distance in pixels (screen space - useful for manual
+ contour labeling), but this can be controlled via a keyword
+ argument.
+
+ Returns a tuple containing the contour, segment, index of
+ segment, x & y of segment point and distance to minimum point.
+
+ Call signature::
+
+ conmin,segmin,imin,xmin,ymin,dmin = find_nearest_contour(
+ self, x, y, indices=None, pixel=True )
+
+ Optional keyword arguments::
+
+ *indices*:
+ Indexes of contour levels to consider when looking for
+ nearest point. Defaults to using all levels.
+
+ *pixel*:
+ If *True*, measure distance in pixel space, if not, measure
+ distance in axes space. Defaults to *True*.
+
+ """
+
+ # This function uses a method that is probably quite
+ # inefficient based on converting each contour segment to
+ # pixel coordinates and then comparing the given point to
+ # those coordinates for each contour. This will probably be
+ # quite slow for complex contours, but for normal use it works
+ # sufficiently well that the time is not noticeable.
+ # Nonetheless, improvements could probably be made.
+
+ if indices==None:
+ indices = range(len(self.levels))
+
+ dmin = 1e10
+ conmin = None
+ segmin = None
+ xmin = None
+ ymin = None
+
+ for icon in indices:
+ con = self.collections[icon]
+ paths = con.get_paths()
+ for segNum, linepath in enumerate(paths):
+ lc = linepath.vertices
+
+ # transfer all data points to screen coordinates if desired
+ if pixel:
+ lc = self.ax.transData.transform(lc)
+
+ ds = (lc[:,0]-x)**2 + (lc[:,1]-y)**2
+ d = min( ds )
+ if d < dmin:
+ dmin = d
+ conmin = icon
+ segmin = segNum
+ imin = mpl.mlab.find( ds == d )[0]
+ xmin = lc[imin,0]
+ ymin = lc[imin,1]
+
+ return (conmin,segmin,imin,xmin,ymin,dmin)
+
+
+class QuadContourSet(ContourSet):
+ """
+ Create and store a set of contour lines or filled regions.
+
+ User-callable method: clabel
+
+ Useful attributes:
+ ax:
+ the axes object in which the contours are drawn
+ collections:
+ a silent_list of LineCollections or PolyCollections
+ levels:
+ contour levels
+ layers:
+ same as levels for line contours; half-way between
+ levels for filled contours. See _process_colors method.
+ """
+ def __init__(self, ax, *args, **kwargs):
+ """
+ Calculate and draw contour lines or filled regions, depending
+ on whether keyword arg 'filled' is False (default) or True.
+
+ The first argument of the initializer must be an axes
+ object. The remaining arguments and keyword arguments
+ are described in QuadContourSet.contour_doc.
+ """
+ ContourSet.__init__(self, ax, *args, **kwargs)
+
+ def _process_args(self, *args, **kwargs):
+ """
+ Process args and kwargs.
+ """
+ if isinstance(args[0], QuadContourSet):
+ C = args[0].Cntr
+ if self.levels is None:
+ self.levels = args[0].levels
+ else:
+ x, y, z = self._contour_args(args, kwargs)
+
+ x0 = ma.minimum(x)
+ x1 = ma.maximum(x)
+ y0 = ma.minimum(y)
+ y1 = ma.maximum(y)
+ self.ax.update_datalim([(x0,y0), (x1,y1)])
+ self.ax.autoscale_view()
+ _mask = ma.getmask(z)
+ if _mask is ma.nomask:
+ _mask = None
+ C = _cntr.Cntr(x, y, z.filled(), _mask)
+ self.Cntr = C
+
+ def _get_allsegs_and_allkinds(self):
+ """
+ Create and return allsegs and allkinds by calling underlying C code.
+ """
+ allsegs = []
+ if self.filled:
+ lowers, uppers = self._get_lowers_and_uppers()
+ allkinds = []
+ for level, level_upper in zip(lowers, uppers):
+ nlist = self.Cntr.trace(level, level_upper, nchunk = self.nchunk)
+ nseg = len(nlist)//2
+ segs = nlist[:nseg]
+ kinds = nlist[nseg:]
+ allsegs.append(segs)
+ allkinds.append(kinds)
+ else:
+ allkinds = None
+ for level in self.levels:
+ nlist = self.Cntr.trace(level)
+ nseg = len(nlist)//2
+ segs = nlist[:nseg]
+ allsegs.append(segs)
+ return allsegs, allkinds
+
+ def _contour_args(self, args, kwargs):
+ if self.filled: fn = 'contourf'
+ else: fn = 'contour'
+ Nargs = len(args)
+ if Nargs <= 2:
+ z = ma.asarray(args[0], dtype=np.float64)
+ x, y = self._initialize_x_y(z)
+ args = args[1:]
+ elif Nargs <=4:
+ x,y,z = self._check_xyz(args[:3], kwargs)
+ args = args[3:]
+ else:
+ raise TypeError("Too many arguments to %s; see help(%s)" % (fn,fn))
+ z = ma.masked_invalid(z, copy=False)
+ self.zmax = ma.maximum(z)
+ self.zmin = ma.minimum(z)
+ if self.logscale and self.zmin <= 0:
+ z = ma.masked_where(z <= 0, z)
+ warnings.warn('Log scale: values of z <= 0 have been masked')
+ self.zmin = z.min()
+ self._contour_level_args(z, args)
+ return (x, y, z)
+
+ def _check_xyz(self, args, kwargs):
+ '''
+ For functions like contour, check that the dimensions
+ of the input arrays match; if x and y are 1D, convert
+ them to 2D using meshgrid.
+
+ Possible change: I think we should make and use an ArgumentError
+ Exception class (here and elsewhere).
+ '''
+ x, y = args[:2]
+ self.ax._process_unit_info(xdata=x, ydata=y, kwargs=kwargs)
+ x = self.ax.convert_xunits(x)
+ y = self.ax.convert_yunits(y)
+
+ x = np.asarray(x, dtype=np.float64)
+ y = np.asarray(y, dtype=np.float64)
+ z = ma.asarray(args[2], dtype=np.float64)
+ if z.ndim != 2:
+ raise TypeError("Input z must be a 2D array.")
+ else: Ny, Nx = z.shape
+ if x.shape == z.shape and y.shape == z.shape:
+ return x,y,z
+ if x.ndim != 1 or y.ndim != 1:
+ raise TypeError("Inputs x and y must be 1D or 2D.")
+ nx, = x.shape
+ ny, = y.shape
+ if nx != Nx or ny != Ny:
+ raise TypeError("Length of x must be number of columns in z,\n" +
+ "and length of y must be number of rows.")
+ x,y = np.meshgrid(x,y)
+ return x,y,z
+
+ def _initialize_x_y(self, z):
+ '''
+ Return X, Y arrays such that contour(Z) will match imshow(Z)
+ if origin is not None.
+ The center of pixel Z[i,j] depends on origin:
+ if origin is None, x = j, y = i;
+ if origin is 'lower', x = j + 0.5, y = i + 0.5;
+ if origin is 'upper', x = j + 0.5, y = Nrows - i - 0.5
+ If extent is not None, x and y will be scaled to match,
+ as in imshow.
+ If origin is None and extent is not None, then extent
+ will give the minimum and maximum values of x and y.
+ '''
+ if z.ndim != 2:
+ raise TypeError("Input must be a 2D array.")
+ else:
+ Ny, Nx = z.shape
+ if self.origin is None: # Not for image-matching.
+ if self.extent is None:
+ return np.meshgrid(np.arange(Nx), np.arange(Ny))
+ else:
+ x0,x1,y0,y1 = self.extent
+ x = np.linspace(x0, x1, Nx)
+ y = np.linspace(y0, y1, Ny)
+ return np.meshgrid(x, y)
+ # Match image behavior:
+ if self.extent is None:
+ x0,x1,y0,y1 = (0, Nx, 0, Ny)
+ else:
+ x0,x1,y0,y1 = self.extent
+ dx = float(x1 - x0)/Nx
+ dy = float(y1 - y0)/Ny
+ x = x0 + (np.arange(Nx) + 0.5) * dx
+ y = y0 + (np.arange(Ny) + 0.5) * dy
+ if self.origin == 'upper':
+ y = y[::-1]
+ return np.meshgrid(x,y)
+
contour_doc = """
:func:`~matplotlib.pyplot.contour` and
:func:`~matplotlib.pyplot.contourf` draw contour lines and
@@ -1047,7 +1263,7 @@
handle internal masked regions correctly.
``C = contour(...)`` returns a
- :class:`~matplotlib.contour.ContourSet` object.
+ :class:`~matplotlib.contour.QuadContourSet` object.
Optional keyword arguments:
@@ -1170,69 +1386,3 @@
.. plot:: mpl_examples/pylab_examples/contourf_demo.py
"""
-
- def find_nearest_contour( self, x, y, indices=None, pixel=True ):
- """
- Finds contour that is closest to a point. Defaults to
- measuring distance in pixels (screen space - useful for manual
- contour labeling), but this can be controlled via a keyword
- argument.
-
- Returns a tuple containing the contour, segment, index of
- segment, x & y of segment point and distance to minimum point.
-
- Call signature::
-
- conmin,segmin,imin,xmin,ymin,dmin = find_nearest_contour(
- self, x, y, indices=None, pixel=True )
-
- Optional keyword arguments::
-
- *indices*:
- Indexes of contour levels to consider when looking for
- nearest point. Defaults to using all levels.
-
- *pixel*:
- If *True*, measure distance in pixel space, if not, measure
- distance in axes space. Defaults to *True*.
-
- """
-
- # This function uses a method that is probably quite
- # inefficient based on converting each contour segment to
- # pixel coordinates and then comparing the given point to
- # those coordinates for each contour. This will probably be
- # quite slow for complex contours, but for normal use it works
- # sufficiently well that the time is not noticeable.
- # Nonetheless, improvements could probably be made.
-
- if indices==None:
- indices = range(len(self.levels))
-
- dmin = 1e10
- conmin = None
- segmin = None
- xmin = None
- ymin = None
-
- for icon in indices:
- con = self.collections[icon]
- paths = con.get_paths()
- for segNum, linepath in enumerate(paths):
- lc = linepath.vertices
-
- # transfer all data points to screen coordinates if desired
- if pixel:
- lc = self.ax.transData.transform(lc)
-
- ds = (lc[:,0]-x)**2 + (lc[:,1]-y)**2
- d = min( ds )
- if d < dmin:
- dmin = d
- conmin = icon
- segmin = segNum
- imin = mpl.mlab.find( ds == d )[0]
- xmin = lc[imin,0]
- ymin = lc[imin,1]
-
- return (conmin,segmin,imin,xmin,ymin,dmin)
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|