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