Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 7 additions & 6 deletions lib/matplotlib/offsetbox.py
Original file line number Diff line number Diff line change
Expand Up @@ -799,23 +799,24 @@ def get_bbox(self, renderer):
ismath="TeX" if self._text.get_usetex() else False,
dpi=self.get_figure(root=True).dpi)

bbox, info, yd = self._text._get_layout(renderer)
bbox, info = self._text._get_layout(renderer)
_last_line, (_last_width, _last_ascent, last_descent), _last_xy = info[-1]
w, h = bbox.size

self._baseline_transform.clear()

if len(info) > 1 and self._multilinebaseline:
yd_new = 0.5 * h - 0.5 * (h_ - d_)
self._baseline_transform.translate(0, yd - yd_new)
yd = yd_new
self._baseline_transform.translate(0, last_descent - yd_new)
last_descent = yd_new
else: # single line
h_d = max(h_ - d_, h - yd)
h = h_d + yd
h_d = max(h_ - d_, h - last_descent)
h = h_d + last_descent

ha = self._text.get_horizontalalignment()
x0 = {"left": 0, "center": -w / 2, "right": -w}[ha]

return Bbox.from_bounds(x0, -yd, w, h)
return Bbox.from_bounds(x0, -last_descent, w, h)

def draw(self, renderer):
# docstring inherited
Expand Down
72 changes: 36 additions & 36 deletions lib/matplotlib/text.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,23 +37,22 @@ def _get_textbox(text, renderer):
# called within the _get_textbox. So, it would be better to move this
# function as a method with some refactoring of _get_layout method.

projected_xs = []
projected_ys = []
projected_xys = []

theta = np.deg2rad(text.get_rotation())
tr = Affine2D().rotate(-theta)

_, parts, d = text._get_layout(renderer)
_, parts = text._get_layout(renderer)

for t, wh, x, y in parts:
w, h = wh

xt1, yt1 = tr.transform((x, y))
yt1 -= d
xt2, yt2 = xt1 + w, yt1 + h

projected_xs.extend([xt1, xt2])
projected_ys.extend([yt1, yt2])
for t, (w, a, d), xy in parts:
xt, yt = tr.transform(xy)
projected_xys.extend([
(xt, yt + a),
(xt, yt - d),
(xt + w, yt + a),
(xt + w, yt - d),
])
projected_xs, projected_ys = zip(*projected_xys)

xt_box, yt_box = min(projected_xs), min(projected_ys)
w_box, h_box = max(projected_xs) - xt_box, max(projected_ys) - yt_box
Expand Down Expand Up @@ -434,15 +433,18 @@ def update_from(self, other):

def _get_layout(self, renderer):
"""
Return the extent (bbox) of the text together with
multiple-alignment information. Note that it returns an extent
of a rotated text when necessary.
Return

- the (rotated) text bbox, and
- a list of ``(line, (width, ascent, descent), xy)`` tuples for each line.
"""
thisx, thisy = 0.0, 0.0
lines = self._get_wrapped_text().split("\n") # Ensures lines is not empty.

ws = []
hs = []
# Reminder: The ascent (a) goes from the baseline to the top and the
# descent (d) from the baseline to the bottom; both are (typically)
# nonnegative. The height h is the sum, h = a + d.
wads = [] # (width, ascents, descents)
xs = []
ys = []

Expand All @@ -451,7 +453,8 @@ def _get_layout(self, renderer):
renderer, "lp", self._fontproperties,
ismath="TeX" if self.get_usetex() else False,
dpi=self.get_figure(root=True).dpi)
min_dy = (lp_h - lp_d) * self._linespacing
lp_a = lp_h - lp_d
min_dy = lp_a * self._linespacing

for i, line in enumerate(lines):
clean_line, ismath = self._preprocess_math(line)
Expand All @@ -462,25 +465,21 @@ def _get_layout(self, renderer):
else:
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.
h = max(h, lp_h)
a = h - d
# To ensure good linespacing, pretend that the ascent (resp.
# descent) of all lines is at least as large as "l" (resp. "p").
a = max(a, lp_a)
d = max(d, lp_d)

ws.append(w)
hs.append(h)

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

if i == 0:
# position at baseline
thisy = -(h - d)
else:
# put baseline a good distance from bottom of previous line
thisy -= max(min_dy, (h - d) * self._linespacing)
if i == 0: # position at baseline
thisy = -a
else: # put baseline a good distance from bottom of previous line
thisy -= max(min_dy, a * self._linespacing)

wads.append((w, a, d))
xs.append(thisx) # == 0.
ys.append(thisy)

Expand All @@ -490,6 +489,7 @@ def _get_layout(self, renderer):
descent = d

# Bounding box definition:
ws = [w for w, a, d in wads]
width = max(ws)
xmin = 0
xmax = width
Expand Down Expand Up @@ -587,7 +587,7 @@ def _get_layout(self, renderer):
# now rotate the positions around the first (x, y) position
xys = M.transform(offset_layout) - (offsetx, offsety)

return bbox, list(zip(lines, zip(ws, hs), *xys.T)), descent
return bbox, list(zip(lines, wads, xys))

def set_bbox(self, rectprops):
"""
Expand Down Expand Up @@ -840,7 +840,7 @@ def draw(self, renderer):
renderer.open_group('text', self.get_gid())

with self._cm_set(text=self._get_wrapped_text()):
bbox, info, descent = self._get_layout(renderer)
bbox, info = self._get_layout(renderer)
trans = self.get_transform()

# don't use self.get_position here, which refers to text
Expand Down Expand Up @@ -876,7 +876,7 @@ def draw(self, renderer):

angle = self.get_rotation()

for line, wh, x, y in info:
for line, wad, (x, y) in info:

mtext = self if len(info) == 1 else None
x = x + posx
Expand Down Expand Up @@ -1064,7 +1064,7 @@ def get_window_extent(self, renderer=None, dpi=None):
"want to call 'figure.draw_without_rendering()' first.")

with cbook._setattr_cm(fig, dpi=dpi):
bbox, info, descent = self._get_layout(self._renderer)
bbox, _ = self._get_layout(self._renderer)
x, y = self.get_unitless_position()
x, y = self.get_transform().transform((x, y))
bbox = bbox.translated(x, y)
Expand Down
Loading