Skip to content

Commit d050b21

Browse files
authored
Merge pull request #19018 from anntzer/glc
Inline and optimize ContourLabeler.get_label_coords.
2 parents 5960b5a + 1800cd6 commit d050b21

File tree

2 files changed

+31
-29
lines changed

2 files changed

+31
-29
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
``ContourLabeler.get_label_coords`` is deprecated
2+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3+
It is considered an internal helper.

lib/matplotlib/contour.py

+28-29
Original file line numberDiff line numberDiff line change
@@ -217,6 +217,7 @@ def too_close(self, x, y, lw):
217217
return any((x - loc[0]) ** 2 + (y - loc[1]) ** 2 < thresh
218218
for loc in self.labelXYs)
219219

220+
@_api.deprecated("3.4")
220221
def get_label_coords(self, distances, XX, YY, ysize, lw):
221222
"""
222223
Return x, y, and the index of a label location.
@@ -278,37 +279,35 @@ def locate_label(self, linecontour, labelwidth):
278279
"""
279280
Find good place to draw a label (relatively flat part of the contour).
280281
"""
281-
282-
# Number of contour points
283-
nsize = len(linecontour)
284-
if labelwidth > 1:
285-
xsize = int(np.ceil(nsize / labelwidth))
286-
else:
287-
xsize = 1
288-
if xsize == 1:
289-
ysize = nsize
290-
else:
291-
ysize = int(labelwidth)
292-
293-
XX = np.resize(linecontour[:, 0], (xsize, ysize))
294-
YY = np.resize(linecontour[:, 1], (xsize, ysize))
295-
# I might have fouled up the following:
296-
yfirst = YY[:, :1]
297-
ylast = YY[:, -1:]
298-
xfirst = XX[:, :1]
299-
xlast = XX[:, -1:]
300-
s = (yfirst - YY) * (xlast - xfirst) - (xfirst - XX) * (ylast - yfirst)
301-
L = np.hypot(xlast - xfirst, ylast - yfirst)
282+
ctr_size = len(linecontour)
283+
n_blocks = int(np.ceil(ctr_size / labelwidth)) if labelwidth > 1 else 1
284+
block_size = ctr_size if n_blocks == 1 else int(labelwidth)
285+
# Split contour into blocks of length ``block_size``, filling the last
286+
# block by cycling the contour start (per `np.resize` semantics). (Due
287+
# to cycling, the index returned is taken modulo ctr_size.)
288+
xx = np.resize(linecontour[:, 0], (n_blocks, block_size))
289+
yy = np.resize(linecontour[:, 1], (n_blocks, block_size))
290+
yfirst = yy[:, :1]
291+
ylast = yy[:, -1:]
292+
xfirst = xx[:, :1]
293+
xlast = xx[:, -1:]
294+
s = (yfirst - yy) * (xlast - xfirst) - (xfirst - xx) * (ylast - yfirst)
295+
l = np.hypot(xlast - xfirst, ylast - yfirst)
302296
# Ignore warning that divide by zero throws, as this is a valid option
303297
with np.errstate(divide='ignore', invalid='ignore'):
304-
dist = np.sum(np.abs(s) / L, axis=-1)
305-
x, y, ind = self.get_label_coords(dist, XX, YY, ysize, labelwidth)
306-
307-
# There must be a more efficient way...
308-
lc = [tuple(l) for l in linecontour]
309-
dind = lc.index((x, y))
310-
311-
return x, y, dind
298+
distances = (abs(s) / l).sum(axis=-1)
299+
# Labels are drawn in the middle of the block (``hbsize``) where the
300+
# contour is the closest (per ``distances``) to a straight line, but
301+
# not `too_close()` to a preexisting label.
302+
hbsize = block_size // 2
303+
adist = np.argsort(distances)
304+
# If all candidates are `too_close()`, go back to the straightest part
305+
# (``adist[0]``).
306+
for idx in np.append(adist, adist[0]):
307+
x, y = xx[idx, hbsize], yy[idx, hbsize]
308+
if not self.too_close(x, y, labelwidth):
309+
break
310+
return x, y, (idx * block_size + hbsize) % ctr_size
312311

313312
def calc_label_rot_and_inline(self, slc, ind, lw, lc=None, spacing=5):
314313
"""

0 commit comments

Comments
 (0)