@@ -217,6 +217,7 @@ def too_close(self, x, y, lw):
217
217
return any ((x - loc [0 ]) ** 2 + (y - loc [1 ]) ** 2 < thresh
218
218
for loc in self .labelXYs )
219
219
220
+ @_api .deprecated ("3.4" )
220
221
def get_label_coords (self , distances , XX , YY , ysize , lw ):
221
222
"""
222
223
Return x, y, and the index of a label location.
@@ -278,37 +279,35 @@ def locate_label(self, linecontour, labelwidth):
278
279
"""
279
280
Find good place to draw a label (relatively flat part of the contour).
280
281
"""
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 )
302
296
# Ignore warning that divide by zero throws, as this is a valid option
303
297
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
312
311
313
312
def calc_label_rot_and_inline (self , slc , ind , lw , lc = None , spacing = 5 ):
314
313
"""
0 commit comments