Skip to content

Commit 27cec21

Browse files
authored
Merge pull request #27212 from meeseeksmachine/auto-backport-of-pr-27088-on-v3.8.x
Backport PR #27088 on branch v3.8.x (Update `find_nearest_contour` and revert contour deprecations)
2 parents f3a1084 + ad92457 commit 27cec21

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
@@ -944,12 +945,12 @@ def __init__(self, ax, *args,
944945
", ".join(map(repr, kwargs))
945946
)
946947

947-
allsegs = _api.deprecated("3.8", pending=True)(property(lambda self: [
948+
allsegs = property(lambda self: [
948949
[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: [
951952
[subp.codes for subp in p._iter_connected_components()]
952-
for p in self.get_paths()]))
953+
for p in self.get_paths()])
953954
tcolors = _api.deprecated("3.8")(property(lambda self: [
954955
(tuple(rgba),) for rgba in self.to_rgba(self.cvalues, self.alpha)]))
955956
tlinewidths = _api.deprecated("3.8")(property(lambda self: [
@@ -1403,7 +1404,6 @@ def _find_nearest_contour(self, xy, indices=None):
14031404

14041405
return idx_level_min, idx_vtx_min, proj_min
14051406

1406-
@_api.deprecated("3.8")
14071407
def find_nearest_contour(self, x, y, indices=None, pixel=True):
14081408
"""
14091409
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):
14241424
14251425
Returns
14261426
-------
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.
14321433
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
14341435
``(x, y)``.
14351436
xmin, ymin : float
14361437
The point in the contour plot that is closest to ``(x, y)``.
14371438
d2 : float
14381439
The squared distance from ``(xmin, ymin)`` to ``(x, y)``.
14391440
"""
1441+
segment = index = d2 = None
14401442

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

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

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
14541458

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

14861461
def draw(self, renderer):
14871462
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)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy