@@ -1338,18 +1338,22 @@ def _process_linestyles(self, linestyles):
1338
1338
raise ValueError ("Unrecognized type for linestyles kwarg" )
1339
1339
return tlinestyles
1340
1340
1341
- def _find_nearest_contour (self , xy , indices = None ):
1341
+ def _find_nearest_contour (self , xy , indices = None , pixel = True ):
1342
1342
"""
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
1344
1344
space) to point *xy*.
1345
1345
1346
1346
Parameters
1347
1347
----------
1348
1348
xy : tuple[float, float]
1349
- The reference point (in screen space) .
1349
+ The reference point.
1350
1350
indices : list of int or None, default: None
1351
1351
Indices of contour levels to consider. If None (the default), all levels
1352
1352
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.
1353
1357
1354
1358
Returns
1355
1359
-------
@@ -1378,7 +1382,9 @@ def _find_nearest_contour(self, xy, indices=None):
1378
1382
path = self ._paths [idx_level ]
1379
1383
if not len (path .vertices ):
1380
1384
continue
1381
- lc = self .get_transform ().transform (path .vertices )
1385
+ lc = path .vertices
1386
+ if pixel :
1387
+ lc = self .get_transform ().transform (lc )
1382
1388
d2 , proj , leg = _find_closest_point_on_path (lc , xy )
1383
1389
if d2 < d2min :
1384
1390
d2min = d2
@@ -1422,53 +1428,19 @@ def find_nearest_contour(self, x, y, indices=None, pixel=True):
1422
1428
d2 : float
1423
1429
The squared distance from ``(xmin, ymin)`` to ``(x, y)``.
1424
1430
"""
1431
+ segment = index = d2 = None
1425
1432
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 )
1433
1435
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
1440
1442
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 )
1472
1444
1473
1445
def draw (self , renderer ):
1474
1446
paths = self ._paths
0 commit comments