Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 3ecb148

Browse files
authored
Merge pull request #27088 from rcomer/nearest-contour
Update `find_nearest_contour` and revert contour deprecations
2 parents 775fbc0 + e9a102f commit 3ecb148

File tree

4 files changed

+45
-73
lines changed

4 files changed

+45
-73
lines changed
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
Deprecations removed in ``contour``
2+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3+
4+
``contour.allsegs``, ``contour.allkinds``, and ``contour.find_nearest_contour`` are no
5+
longer marked for deprecation.

lib/matplotlib/contour.py

Lines changed: 27 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
Classes to support contour plotting and labelling for the Axes class.
33
"""
44

5+
from contextlib import ExitStack
56
import functools
67
import math
78
from numbers import Integral
@@ -937,12 +938,12 @@ def __init__(self, ax, *args,
937938
", ".join(map(repr, kwargs))
938939
)
939940

940-
allsegs = _api.deprecated("3.8", pending=True)(property(lambda self: [
941+
allsegs = property(lambda self: [
941942
[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: [
944945
[subp.codes for subp in p._iter_connected_components()]
945-
for p in self.get_paths()]))
946+
for p in self.get_paths()])
946947
tcolors = _api.deprecated("3.8")(property(lambda self: [
947948
(tuple(rgba),) for rgba in self.to_rgba(self.cvalues, self.alpha)]))
948949
tlinewidths = _api.deprecated("3.8")(property(lambda self: [
@@ -1396,7 +1397,6 @@ def _find_nearest_contour(self, xy, indices=None):
13961397

13971398
return idx_level_min, idx_vtx_min, proj_min
13981399

1399-
@_api.deprecated("3.8")
14001400
def find_nearest_contour(self, x, y, indices=None, pixel=True):
14011401
"""
14021402
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):
14171417
14181418
Returns
14191419
-------
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.
14251426
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
14271428
``(x, y)``.
14281429
xmin, ymin : float
14291430
The point in the contour plot that is closest to ``(x, y)``.
14301431
d2 : float
14311432
The squared distance from ``(xmin, ymin)`` to ``(x, y)``.
14321433
"""
1434+
segment = index = d2 = None
14331435

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()))
14411442

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)
14441444

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
14471451

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)
14781453

14791454
def draw(self, renderer):
14801455
paths = self._paths

lib/matplotlib/contour.pyi

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,6 @@ class ContourSet(ContourLabeler, Collection):
159159
) -> tuple[list[Artist], list[str]]: ...
160160
def find_nearest_contour(
161161
self, x: float, y: float, indices: Iterable[int] | None = ..., pixel: bool = ...
162-
) -> tuple[Collection, int, int, float, float, float]: ...
162+
) -> tuple[int, int, int, float, float, float]: ...
163163

164164
class QuadContourSet(ContourSet): ...

lib/matplotlib/tests/test_contour.py

Lines changed: 12 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -569,23 +569,19 @@ def test_find_nearest_contour():
569569
img = np.exp(-np.pi * (np.sum((xy - 5)**2, 0)/5.**2))
570570
cs = plt.contour(img, 10)
571571

572-
with pytest.warns(mpl._api.MatplotlibDeprecationWarning):
573-
nearest_contour = cs.find_nearest_contour(1, 1, pixel=False)
572+
nearest_contour = cs.find_nearest_contour(1, 1, pixel=False)
574573
expected_nearest = (1, 0, 33, 1.965966, 1.965966, 1.866183)
575574
assert_array_almost_equal(nearest_contour, expected_nearest)
576575

577-
with pytest.warns(mpl._api.MatplotlibDeprecationWarning):
578-
nearest_contour = cs.find_nearest_contour(8, 1, pixel=False)
576+
nearest_contour = cs.find_nearest_contour(8, 1, pixel=False)
579577
expected_nearest = (1, 0, 5, 7.550173, 1.587542, 0.547550)
580578
assert_array_almost_equal(nearest_contour, expected_nearest)
581579

582-
with pytest.warns(mpl._api.MatplotlibDeprecationWarning):
583-
nearest_contour = cs.find_nearest_contour(2, 5, pixel=False)
580+
nearest_contour = cs.find_nearest_contour(2, 5, pixel=False)
584581
expected_nearest = (3, 0, 21, 1.884384, 5.023335, 0.013911)
585582
assert_array_almost_equal(nearest_contour, expected_nearest)
586583

587-
with pytest.warns(mpl._api.MatplotlibDeprecationWarning):
588-
nearest_contour = cs.find_nearest_contour(2, 5, indices=(5, 7), pixel=False)
584+
nearest_contour = cs.find_nearest_contour(2, 5, indices=(5, 7), pixel=False)
589585
expected_nearest = (5, 0, 16, 2.628202, 5.0, 0.394638)
590586
assert_array_almost_equal(nearest_contour, expected_nearest)
591587

@@ -595,16 +591,13 @@ def test_find_nearest_contour_no_filled():
595591
img = np.exp(-np.pi * (np.sum((xy - 5)**2, 0)/5.**2))
596592
cs = plt.contourf(img, 10)
597593

598-
with pytest.warns(mpl._api.MatplotlibDeprecationWarning), \
599-
pytest.raises(ValueError, match="Method does not support filled contours."):
594+
with pytest.raises(ValueError, match="Method does not support filled contours"):
600595
cs.find_nearest_contour(1, 1, pixel=False)
601596

602-
with pytest.warns(mpl._api.MatplotlibDeprecationWarning), \
603-
pytest.raises(ValueError, match="Method does not support filled contours."):
597+
with pytest.raises(ValueError, match="Method does not support filled contours"):
604598
cs.find_nearest_contour(1, 10, indices=(5, 7), pixel=False)
605599

606-
with pytest.warns(mpl._api.MatplotlibDeprecationWarning), \
607-
pytest.raises(ValueError, match="Method does not support filled contours."):
600+
with pytest.raises(ValueError, match="Method does not support filled contours"):
608601
cs.find_nearest_contour(2, 5, indices=(2, 7), pixel=True)
609602

610603

@@ -864,12 +857,11 @@ def test_allsegs_allkinds():
864857

865858
cs = plt.contour(x, y, z, levels=[0, 0.5])
866859

867-
# Expect two levels, first with 5 segments and the second with 4.
868-
with pytest.warns(PendingDeprecationWarning, match="all"):
869-
for result in [cs.allsegs, cs.allkinds]:
870-
assert len(result) == 2
871-
assert len(result[0]) == 5
872-
assert len(result[1]) == 4
860+
# Expect two levels, the first with 5 segments and the second with 4.
861+
for result in [cs.allsegs, cs.allkinds]:
862+
assert len(result) == 2
863+
assert len(result[0]) == 5
864+
assert len(result[1]) == 4
873865

874866

875867
def test_deprecated_apis():

0 commit comments

Comments
 (0)