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

Skip to content

Commit 521c4d9

Browse files
rcomeranntzer
andcommitted
use _find_nearest_contour
Co-authored-by: Antony Lee <[email protected]>
1 parent d5c0c15 commit 521c4d9

File tree

2 files changed

+23
-51
lines changed

2 files changed

+23
-51
lines changed

lib/matplotlib/contour.py

Lines changed: 20 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -1338,18 +1338,22 @@ def _process_linestyles(self, linestyles):
13381338
raise ValueError("Unrecognized type for linestyles kwarg")
13391339
return tlinestyles
13401340

1341-
def _find_nearest_contour(self, xy, indices=None):
1341+
def _find_nearest_contour(self, xy, indices=None, pixel=True):
13421342
"""
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
13441344
space) to point *xy*.
13451345
13461346
Parameters
13471347
----------
13481348
xy : tuple[float, float]
1349-
The reference point (in screen space).
1349+
The reference point.
13501350
indices : list of int or None, default: None
13511351
Indices of contour levels to consider. If None (the default), all levels
13521352
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.
13531357
13541358
Returns
13551359
-------
@@ -1378,7 +1382,9 @@ def _find_nearest_contour(self, xy, indices=None):
13781382
path = self._paths[idx_level]
13791383
if not len(path.vertices):
13801384
continue
1381-
lc = self.get_transform().transform(path.vertices)
1385+
lc = path.vertices
1386+
if pixel:
1387+
lc = self.get_transform().transform(lc)
13821388
d2, proj, leg = _find_closest_point_on_path(lc, xy)
13831389
if d2 < d2min:
13841390
d2min = d2
@@ -1422,53 +1428,19 @@ def find_nearest_contour(self, x, y, indices=None, pixel=True):
14221428
d2 : float
14231429
The squared distance from ``(xmin, ymin)`` to ``(x, y)``.
14241430
"""
1431+
segment = index = d2 = None
14251432

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

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
14401442

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

14731445
def draw(self, renderer):
14741446
paths = self._paths

lib/matplotlib/tests/test_contour.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -557,15 +557,15 @@ def test_find_nearest_contour_no_filled():
557557
cs = plt.contourf(img, 10)
558558

559559
with pytest.warns(mpl._api.MatplotlibDeprecationWarning), \
560-
pytest.raises(ValueError, match="Method does not support filled contours."):
560+
pytest.raises(ValueError, match="Method does not support filled contours"):
561561
cs.find_nearest_contour(1, 1, pixel=False)
562562

563563
with pytest.warns(mpl._api.MatplotlibDeprecationWarning), \
564-
pytest.raises(ValueError, match="Method does not support filled contours."):
564+
pytest.raises(ValueError, match="Method does not support filled contours"):
565565
cs.find_nearest_contour(1, 10, indices=(5, 7), pixel=False)
566566

567567
with pytest.warns(mpl._api.MatplotlibDeprecationWarning), \
568-
pytest.raises(ValueError, match="Method does not support filled contours."):
568+
pytest.raises(ValueError, match="Method does not support filled contours"):
569569
cs.find_nearest_contour(2, 5, indices=(2, 7), pixel=True)
570570

571571

0 commit comments

Comments
 (0)