FazBrowse GitHub Viewer | Trending |
URL:
| Home
Tools: [Download Repo ZIP]   [Original HTTPS Page]

Make Text._get_layout simpler to follow. by anntzer · Pull Request #12951 · matplotlib/matplotlib · GitHub

Repository navigation

Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension .py  (1) All 1 file type selected
Viewed files
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Unified
Split
Hide whitespace
Diff view
Unified
Split
Hide whitespace
112 changes: 55 additions & 57 deletions lib/matplotlib/text.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Original file line number Diff line number Diff line change
Expand Up @@ -276,86 +276,87 @@ def _get_layout(self, renderer):
if key in self._cached:
return self._cached[key]

horizLayout = []

thisx, thisy = 0.0, 0.0
xmin, ymin = 0.0, 0.0
width, height = 0.0, 0.0
lines = self.get_text().split('\n')
lines = self.get_text().split("\n") # Ensures lines is not empty.

whs = np.zeros((len(lines), 2))
horizLayout = np.zeros((len(lines), 4))
ws = []
hs = []
xs = []
ys = []

# Full vertical extent of font, including ascenders and descenders:
tmp, lp_h, lp_bl = renderer.get_text_width_height_descent('lp',
self._fontproperties,
ismath=False)
offsety = (lp_h - lp_bl) * self._linespacing
_, lp_h, lp_d = renderer.get_text_width_height_descent(
"lp", self._fontproperties, ismath=False)
min_dy = (lp_h - lp_d) * self._linespacing

baseline = 0
for i, line in enumerate(lines):
clean_line, ismath = self.is_math_text(line, self.get_usetex())
if clean_line:
w, h, d = renderer.get_text_width_height_descent(clean_line,
self._fontproperties,
ismath=ismath)
w, h, d = renderer.get_text_width_height_descent(
clean_line, self._fontproperties, ismath=ismath)
else:
w, h, d = 0, 0, 0
w = h = d = 0

# For multiline text, increase the line spacing when the
# text net-height(excluding baseline) is larger than that
# of a "l" (e.g., use of superscripts), which seems
# what TeX does.
# For multiline text, increase the line spacing when the text
# net-height (excluding baseline) is larger than that of a "l"
# (e.g., use of superscripts), which seems what TeX does.
h = max(h, lp_h)
d = max(d, lp_bl)
d = max(d, lp_d)

whs[i] = w, h
ws.append(w)
hs.append(h)

# Metrics of the last line that are needed later:
baseline = (h - d) - thisy

if i == 0:

timhoffm Dec 9, 2018 •
edited
Loading

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality
Suggested change
if i == 0:
if thisy == 0: # first line

gets rid of the need for enumerate().

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

It's not immediately obvious that thisy cannot be zero for the second line too even if the first line is empty (it's true, but only thanks to the h = max(h, lp_h)/d = max(d, lp_d) lines) so I think leaving it as it is is clearer.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

Just by common sense, the vertical position thisy must increase also for empty lines. So it should only be zero before handling the first line.

But ok, if you want to leave it.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

I don't think common sense applies to this function (or to a lot of matplotlib, sadly). (e.g. if you look at the way center_baseline is defined a bit below, it looks weirdly different between anchor and non-anchor rotations...)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

Funnily that got fixed by #13029 :)

# position at baseline
thisy = -(h - d)
else:
# put baseline a good distance from bottom of previous line
thisy -= max(offsety, (h - d) * self._linespacing)
horizLayout[i] = thisx, thisy, w, h
thisy -= max(min_dy, (h - d) * self._linespacing)

xs.append(thisx) # == 0.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

Alterantively

xs = [0.] * len(ys)

outside of the loop.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

I think the symmetry of handling between xs and ys is nicer.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

IMO xs = [0.] * len(ys) is much clearer about xs than secretly constructing a list of zeros in the loop. The loop should only need to bother about the quantities that actually depend on the lines. But not going to argue about this.

ys.append(thisy)

thisy -= d
width = max(width, w)
descent = d

# Metrics of the last line that are needed later:
descent = d

# Bounding box definition:
width = max(ws)
xmin = 0
xmax = width
ymax = 0
# ymin is baseline of previous line minus the descent of this line
ymin = horizLayout[-1][1] - descent
ymin = ys[-1] - descent # baseline of last line minus its descent
height = ymax - ymin
xmax = xmin + width

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

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

# the corners of the unrotated bounding box
cornersHoriz = np.array(
[(xmin, ymin), (xmin, ymax), (xmax, ymax), (xmax, ymin)], float)
corners_horiz = np.array(
[(xmin, ymin), (xmin, ymax), (xmax, ymax), (xmax, ymin)])

# now rotate the bbox
cornersRotated = M.transform(cornersHoriz)

txs = cornersRotated[:, 0]
tys = cornersRotated[:, 1]

corners_rotated = M.transform(corners_horiz)
# compute the bounds of the rotated box
xmin, xmax = txs.min(), txs.max()
ymin, ymax = tys.min(), tys.max()
xmin = corners_rotated[:, 0].min()
xmax = corners_rotated[:, 0].max()
ymin = corners_rotated[:, 1].min()
ymax = corners_rotated[:, 1].max()
width = xmax - xmin
height = ymax - ymin

Expand All @@ -369,25 +370,25 @@ def _get_layout(self, renderer):
# compute the text location in display coords and the offsets
# necessary to align the bbox with that location
if halign == 'center':
offsetx = (xmin + width / 2.0)
offsetx = (xmin + xmax) / 2
elif halign == 'right':
offsetx = (xmin + width)
offsetx = xmax
else:
offsetx = xmin

if valign == 'center':
offsety = (ymin + height / 2.0)
offsety = (ymin + ymax) / 2
elif valign == 'top':
offsety = (ymin + height)
offsety = ymax
elif valign == 'baseline':
offsety = ymin + descent
elif valign == 'center_baseline':
offsety = ymin + height - baseline / 2.0
else:
offsety = ymin
else:
xmin1, ymin1 = cornersHoriz[0]
xmax1, ymax1 = cornersHoriz[2]
xmin1, ymin1 = corners_horiz[0]
xmax1, ymax1 = corners_horiz[2]

if halign == 'center':
offsetx = (xmin1 + xmax1) / 2.0
Expand Down Expand Up @@ -415,12 +416,9 @@ def _get_layout(self, renderer):
bbox = Bbox.from_bounds(xmin, ymin, width, height)

# now rotate the positions around the first x,y position
xys = M.transform(offsetLayout)
xys -= (offsetx, offsety)

xs, ys = xys[:, 0], xys[:, 1]
xys = M.transform(offset_layout) - (offsetx, offsety)

ret = bbox, list(zip(lines, whs, xs, ys)), descent
ret = bbox, list(zip(lines, zip(ws, hs), *xys.T)), descent
self._cached[key] = ret
return ret

Expand Down

Back | FazBrowse Home | New Git URL