2
2
Classes to support contour plotting and labelling for the Axes class.
3
3
"""
4
4
5
+ from contextlib import ExitStack
5
6
import functools
6
7
import math
7
8
from numbers import Integral
@@ -937,12 +938,12 @@ def __init__(self, ax, *args,
937
938
", " .join (map (repr , kwargs ))
938
939
)
939
940
940
- allsegs = _api . deprecated ( "3.8" , pending = True )( property (lambda self : [
941
+ allsegs = property (lambda self : [
941
942
[subp .vertices for subp in p ._iter_connected_components ()]
942
- for p in self .get_paths ()]))
943
- allkinds = _api . deprecated ( "3.8" , pending = True )( property (lambda self : [
943
+ for p in self .get_paths ()])
944
+ allkinds = property (lambda self : [
944
945
[subp .codes for subp in p ._iter_connected_components ()]
945
- for p in self .get_paths ()]))
946
+ for p in self .get_paths ()])
946
947
tcolors = _api .deprecated ("3.8" )(property (lambda self : [
947
948
(tuple (rgba ),) for rgba in self .to_rgba (self .cvalues , self .alpha )]))
948
949
tlinewidths = _api .deprecated ("3.8" )(property (lambda self : [
@@ -1396,7 +1397,6 @@ def _find_nearest_contour(self, xy, indices=None):
1396
1397
1397
1398
return idx_level_min , idx_vtx_min , proj_min
1398
1399
1399
- @_api .deprecated ("3.8" )
1400
1400
def find_nearest_contour (self , x , y , indices = None , pixel = True ):
1401
1401
"""
1402
1402
Find the point in the contour plot that is closest to ``(x, y)``.
@@ -1417,64 +1417,39 @@ def find_nearest_contour(self, x, y, indices=None, pixel=True):
1417
1417
1418
1418
Returns
1419
1419
-------
1420
- contour : `.Collection`
1421
- The contour that is closest to ``(x, y)``.
1422
- segment : int
1423
- The index of the `.Path` in *contour* that is closest to
1424
- ``(x, y)``.
1420
+ path : int
1421
+ The index of the path that is closest to ``(x, y)``. Each path corresponds
1422
+ to one contour level.
1423
+ subpath : int
1424
+ The index within that closest path of the subpath that is closest to
1425
+ ``(x, y)``. Each subpath corresponds to one unbroken contour line.
1425
1426
index : int
1426
- The index of the path segment in *segment* that is closest to
1427
+ The index of the vertices within that subpath that are closest to
1427
1428
``(x, y)``.
1428
1429
xmin, ymin : float
1429
1430
The point in the contour plot that is closest to ``(x, y)``.
1430
1431
d2 : float
1431
1432
The squared distance from ``(xmin, ymin)`` to ``(x, y)``.
1432
1433
"""
1434
+ segment = index = d2 = None
1433
1435
1434
- # This function uses a method that is probably quite
1435
- # inefficient based on converting each contour segment to
1436
- # pixel coordinates and then comparing the given point to
1437
- # those coordinates for each contour. This will probably be
1438
- # quite slow for complex contours, but for normal use it works
1439
- # sufficiently well that the time is not noticeable.
1440
- # Nonetheless, improvements could probably be made.
1436
+ with ExitStack () as stack :
1437
+ if not pixel :
1438
+ # _find_nearest_contour works in pixel space. We want axes space, so
1439
+ # effectively disable the transformation here by setting to identity.
1440
+ stack .enter_context (self ._cm_set (
1441
+ transform = mtransforms .IdentityTransform ()))
1441
1442
1442
- if self .filled :
1443
- raise ValueError ("Method does not support filled contours." )
1443
+ i_level , i_vtx , (xmin , ymin ) = self ._find_nearest_contour ((x , y ), indices )
1444
1444
1445
- if indices is None :
1446
- indices = range (len (self .collections ))
1445
+ if i_level is not None :
1446
+ cc_cumlens = np .cumsum (
1447
+ [* map (len , self ._paths [i_level ]._iter_connected_components ())])
1448
+ segment = cc_cumlens .searchsorted (i_vtx , "right" )
1449
+ index = i_vtx if segment == 0 else i_vtx - cc_cumlens [segment - 1 ]
1450
+ d2 = (xmin - x )** 2 + (ymin - y )** 2
1447
1451
1448
- d2min = np .inf
1449
- conmin = None
1450
- segmin = None
1451
- imin = None
1452
- xmin = None
1453
- ymin = None
1454
-
1455
- point = np .array ([x , y ])
1456
-
1457
- for icon in indices :
1458
- con = self .collections [icon ]
1459
- trans = con .get_transform ()
1460
- paths = con .get_paths ()
1461
-
1462
- for segNum , linepath in enumerate (paths ):
1463
- lc = linepath .vertices
1464
- # transfer all data points to screen coordinates if desired
1465
- if pixel :
1466
- lc = trans .transform (lc )
1467
-
1468
- d2 , xc , leg = _find_closest_point_on_path (lc , point )
1469
- if d2 < d2min :
1470
- d2min = d2
1471
- conmin = icon
1472
- segmin = segNum
1473
- imin = leg [1 ]
1474
- xmin = xc [0 ]
1475
- ymin = xc [1 ]
1476
-
1477
- return (conmin , segmin , imin , xmin , ymin , d2min )
1452
+ return (i_level , segment , index , xmin , ymin , d2 )
1478
1453
1479
1454
def draw (self , renderer ):
1480
1455
paths = self ._paths
0 commit comments