@@ -1338,18 +1338,22 @@ def _process_linestyles(self, linestyles):
13381338 raise ValueError ("Unrecognized type for linestyles kwarg" )
13391339 return tlinestyles
13401340
1341- def _find_nearest_contour (self , xy , indices = None ):
1341+ def _find_nearest_contour (self , xy , indices = None , pixel = True ):
13421342 """
1343- Find the point in the unfilled contour plot that is closest (in screen
1343+ Find the point in the unfilled contour plot that is closest (in axes or screen
13441344 space) to point *xy*.
13451345
13461346 Parameters
13471347 ----------
13481348 xy : tuple[float, float]
1349- The reference point (in screen space) .
1349+ The reference point.
13501350 indices : list of int or None, default: None
13511351 Indices of contour levels to consider. If None (the default), all levels
13521352 are considered.
1353+ pixel : bool, default: True
1354+ If *True*, measure distance in pixel (screen) space, which is
1355+ useful for manual contour labeling; else, measure distance in axes
1356+ space.
13531357
13541358 Returns
13551359 -------
@@ -1378,7 +1382,9 @@ def _find_nearest_contour(self, xy, indices=None):
13781382 path = self ._paths [idx_level ]
13791383 if not len (path .vertices ):
13801384 continue
1381- lc = self .get_transform ().transform (path .vertices )
1385+ lc = path .vertices
1386+ if pixel :
1387+ lc = self .get_transform ().transform (lc )
13821388 d2 , proj , leg = _find_closest_point_on_path (lc , xy )
13831389 if d2 < d2min :
13841390 d2min = d2
@@ -1422,53 +1428,19 @@ def find_nearest_contour(self, x, y, indices=None, pixel=True):
14221428 d2 : float
14231429 The squared distance from ``(xmin, ymin)`` to ``(x, y)``.
14241430 """
1431+ segment = index = d2 = None
14251432
1426- # This function uses a method that is probably quite
1427- # inefficient based on converting each contour segment to
1428- # pixel coordinates and then comparing the given point to
1429- # those coordinates for each contour. This will probably be
1430- # quite slow for complex contours, but for normal use it works
1431- # sufficiently well that the time is not noticeable.
1432- # Nonetheless, improvements could probably be made.
1433+ i_level , i_vtx , (xmin , ymin ) = self ._find_nearest_contour (
1434+ (x , y ), indices , pixel )
14331435
1434- if self . filled :
1435- raise ValueError ( "Method does not support filled contours." )
1436-
1437- paths = self . get_paths ( )
1438- if indices is None :
1439- indices = range ( len ( paths ))
1436+ if i_level is not None :
1437+ cc_cumlens = np . cumsum (
1438+ [ * map ( len , self . _paths [ i_level ]. _iter_connected_components ())])
1439+ segment = cc_cumlens . searchsorted ( i_vtx , "right" )
1440+ index = i_vtx if segment == 0 else i_vtx - cc_cumlens [ segment - 1 ]
1441+ d2 = ( xmin - x ) ** 2 + ( ymin - y ) ** 2
14401442
1441- d2min = np .inf
1442- conmin = None
1443- segmin = None
1444- imin = None
1445- xmin = None
1446- ymin = None
1447-
1448- point = np .array ([x , y ])
1449- trans = self .get_transform ()
1450-
1451- for icon in indices :
1452- path = paths [icon ]
1453-
1454- for segNum , linepath in enumerate (path ._iter_connected_components ()):
1455- lc = linepath .vertices
1456- if lc .size == 0 :
1457- continue
1458- # transfer all data points to screen coordinates if desired
1459- if pixel :
1460- lc = trans .transform (lc )
1461-
1462- d2 , xc , leg = _find_closest_point_on_path (lc , point )
1463- if d2 < d2min :
1464- d2min = d2
1465- conmin = icon
1466- segmin = segNum
1467- imin = leg [1 ]
1468- xmin = xc [0 ]
1469- ymin = xc [1 ]
1470-
1471- return (conmin , segmin , imin , xmin , ymin , d2min )
1443+ return (i_level , segment , index , xmin , ymin , d2 )
14721444
14731445 def draw (self , renderer ):
14741446 paths = self ._paths
0 commit comments