Skip to content

Commit 806923d

Browse files
committed
Make Text._get_layout simpler to follow.
- Instead of constructing and accessing multidimensional arrays whs and horizLayout by (opaque) index, construct separate lists with more meaningful names. - Define xmin/xmax/ymin/ymax/width/height closer to their place of use. - Make computation of offsetx and offsety more symmetric between rotation_mode == "anchor" and == "default".
1 parent d72f069 commit 806923d

File tree

1 file changed

+54
-58
lines changed

1 file changed

+54
-58
lines changed

lib/matplotlib/text.py

Lines changed: 54 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -276,86 +276,85 @@ def _get_layout(self, renderer):
276276
if key in self._cached:
277277
return self._cached[key]
278278

279-
horizLayout = []
280-
281279
thisx, thisy = 0.0, 0.0
282-
xmin, ymin = 0.0, 0.0
283-
width, height = 0.0, 0.0
284-
lines = self.get_text().split('\n')
280+
lines = self.get_text().split('\n') # Ensures lines is not empty.
285281

286-
whs = np.zeros((len(lines), 2))
287-
horizLayout = np.zeros((len(lines), 4))
282+
ws = []
283+
hs = []
284+
xs = []
285+
ys = []
288286

289287
# Full vertical extent of font, including ascenders and descenders:
290-
tmp, lp_h, lp_bl = renderer.get_text_width_height_descent('lp',
291-
self._fontproperties,
292-
ismath=False)
293-
offsety = (lp_h - lp_bl) * self._linespacing
288+
_, lp_h, lp_d = renderer.get_text_width_height_descent(
289+
'lp', self._fontproperties, ismath=False)
290+
min_dy = (lp_h - lp_d) * self._linespacing
294291

295-
baseline = 0
296292
for i, line in enumerate(lines):
297293
clean_line, ismath = self.is_math_text(line, self.get_usetex())
298294
if clean_line:
299-
w, h, d = renderer.get_text_width_height_descent(clean_line,
300-
self._fontproperties,
301-
ismath=ismath)
295+
w, h, d = renderer.get_text_width_height_descent(
296+
clean_line, self._fontproperties, ismath=ismath)
302297
else:
303-
w, h, d = 0, 0, 0
298+
w = h = d = 0
304299

305-
# For multiline text, increase the line spacing when the
306-
# text net-height(excluding baseline) is larger than that
307-
# of a "l" (e.g., use of superscripts), which seems
308-
# what TeX does.
300+
# For multiline text, increase the line spacing when the text
301+
# net-height (excluding baseline) is larger than that of a "l"
302+
# (e.g., use of superscripts), which seems what TeX does.
309303
h = max(h, lp_h)
310-
d = max(d, lp_bl)
304+
d = max(d, lp_d)
311305

312-
whs[i] = w, h
306+
ws.append(w)
307+
hs.append(h)
313308

314-
baseline = (h - d) - thisy
315309
if i == 0:
316310
# position at baseline
317311
thisy = -(h - d)
318312
else:
319313
# put baseline a good distance from bottom of previous line
320-
thisy -= max(offsety, (h - d) * self._linespacing)
321-
horizLayout[i] = thisx, thisy, w, h
314+
thisy -= max(min_dy, (h - d) * self._linespacing)
315+
316+
xs.append(thisx) # == 0.
317+
ys.append(thisy)
318+
322319
thisy -= d
323-
width = max(width, w)
324-
descent = d
320+
321+
# Metrics of the last line that are needed later:
322+
descent = d
323+
baseline = (h - d) - thisy
325324

326325
# Bounding box definition:
326+
width = max(ws)
327+
xmin = 0
328+
xmax = width
327329
ymax = 0
328-
# ymin is baseline of previous line minus the descent of this line
329-
ymin = horizLayout[-1][1] - descent
330+
ymin = ys[-1] - descent # baseline of last line minus its descent
330331
height = ymax - ymin
331-
xmax = xmin + width
332332

333333
# get the rotation matrix
334334
M = Affine2D().rotate_deg(self.get_rotation())
335335

336-
offsetLayout = np.zeros((len(lines), 2))
337-
offsetLayout[:] = horizLayout[:, 0:2]
338336
# now offset the individual text lines within the box
339-
if len(lines) > 1: # do the multiline aligment
340-
malign = self._get_multialignment()
341-
if malign == 'center':
342-
offsetLayout[:, 0] += width / 2.0 - horizLayout[:, 2] / 2.0
343-
elif malign == 'right':
344-
offsetLayout[:, 0] += width - horizLayout[:, 2]
337+
malign = self._get_multialignment()
338+
if malign == 'left':
339+
offset_layout = [(x, y) for x, y in zip(xs, ys)]
340+
elif malign == 'center':
341+
offset_layout = [(x + width / 2 - w / 2, y)
342+
for x, y, w in zip(xs, ys, ws)]
343+
elif malign == 'right':
344+
offset_layout = [(x + width - w, y)
345+
for x, y, w in zip(xs, ys, ws)]
345346

346347
# the corners of the unrotated bounding box
347-
cornersHoriz = np.array(
348-
[(xmin, ymin), (xmin, ymax), (xmax, ymax), (xmax, ymin)], float)
348+
corners_horiz = np.array(
349+
[(xmin, ymin), (xmin, ymax), (xmax, ymax), (xmax, ymin)])
349350

350351
# now rotate the bbox
351-
cornersRotated = M.transform(cornersHoriz)
352-
353-
txs = cornersRotated[:, 0]
354-
tys = cornersRotated[:, 1]
355-
352+
corners_rotated = M.transform(corners_horiz)
356353
# compute the bounds of the rotated box
357-
xmin, xmax = txs.min(), txs.max()
358-
ymin, ymax = tys.min(), tys.max()
354+
xmin = corners_rotated[:, 0].min()
355+
xmax = corners_rotated[:, 0].max()
356+
ymin = corners_rotated[:, 1].min()
357+
ymax = corners_rotated[:, 1].max()
359358
width = xmax - xmin
360359
height = ymax - ymin
361360

@@ -369,25 +368,25 @@ def _get_layout(self, renderer):
369368
# compute the text location in display coords and the offsets
370369
# necessary to align the bbox with that location
371370
if halign == 'center':
372-
offsetx = (xmin + width / 2.0)
371+
offsetx = (xmin + xmax) / 2
373372
elif halign == 'right':
374-
offsetx = (xmin + width)
373+
offsetx = xmax
375374
else:
376375
offsetx = xmin
377376

378377
if valign == 'center':
379-
offsety = (ymin + height / 2.0)
378+
offsety = (ymin + ymax) / 2
380379
elif valign == 'top':
381-
offsety = (ymin + height)
380+
offsety = ymax
382381
elif valign == 'baseline':
383382
offsety = ymin + descent
384383
elif valign == 'center_baseline':
385384
offsety = ymin + height - baseline / 2.0
386385
else:
387386
offsety = ymin
388387
else:
389-
xmin1, ymin1 = cornersHoriz[0]
390-
xmax1, ymax1 = cornersHoriz[2]
388+
xmin1, ymin1 = corners_horiz[0]
389+
xmax1, ymax1 = corners_horiz[2]
391390

392391
if halign == 'center':
393392
offsetx = (xmin1 + xmax1) / 2.0
@@ -415,12 +414,9 @@ def _get_layout(self, renderer):
415414
bbox = Bbox.from_bounds(xmin, ymin, width, height)
416415

417416
# now rotate the positions around the first x,y position
418-
xys = M.transform(offsetLayout)
419-
xys -= (offsetx, offsety)
420-
421-
xs, ys = xys[:, 0], xys[:, 1]
417+
xys = M.transform(offset_layout) - (offsetx, offsety)
422418

423-
ret = bbox, list(zip(lines, whs, xs, ys)), descent
419+
ret = bbox, list(zip(lines, zip(ws, hs), *xys.T)), descent
424420
self._cached[key] = ret
425421
return ret
426422

0 commit comments

Comments
 (0)