Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit a8560a9

Browse files
committed
Fix text wrap width on figure edges (#31537)
Text with wrap=True at an axis-aligned rotation on the matching figure edge collapsed to zero wrap width. In _get_dist_to_box the trig formula divides by cos(radians(90)) (~6e-17): normally that term's large value loses the min() to the sensible other side, but when the position sits exactly on the edge its numerator is also zero and the returned distance is zero. Short-circuit cardinal rotations. Also normalize rotation to [0, 360) with a small absolute tolerance so near-cardinal angles coming out of transform_angles (e.g. -90.00000000000003 via transform_rotates_text) still take the fast path instead of blowing up in the trig formula. Regression tests cover each cardinal rotation on its broken edge plus a transform_rotates_text case.
1 parent 1068992 commit a8560a9

2 files changed

Lines changed: 56 additions & 0 deletions

File tree

lib/matplotlib/tests/test_text.py

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -753,6 +753,47 @@ def test_wrap_no_wrap():
753753
assert text._get_wrapped_text() == 'non wrapped text'
754754

755755

756+
@pytest.mark.parametrize(
757+
"x, y, rotation",
758+
[(0.0, 1.0, 0),
759+
(1.0, 0.5, 90),
760+
(0.5, 1.0, 180),
761+
(0.0, 0.5, 270)])
762+
def test_wrap_on_figure_edge(x, y, rotation):
763+
# Regression test for #31537 - wrap collapsed to zero on figure edges.
764+
s = 'This is a very long text that should be wrapped multiple times.'
765+
fig = plt.figure(figsize=(6, 4))
766+
t = fig.text(x, y, s, wrap=True, rotation=rotation)
767+
fig.canvas.draw()
768+
769+
# Compare to a nudged-off-the-edge reference that should wrap the same.
770+
nudge = 1e-4
771+
x_ref = x - nudge if x == 1.0 else x + nudge if x == 0.0 else x
772+
y_ref = y - nudge if y == 1.0 else y + nudge if y == 0.0 else y
773+
fig_ref = plt.figure(figsize=(6, 4))
774+
t_ref = fig_ref.text(x_ref, y_ref, s, wrap=True, rotation=rotation)
775+
fig_ref.canvas.draw()
776+
777+
assert t._get_wrapped_text() == t_ref._get_wrapped_text()
778+
779+
780+
def test_wrap_on_figure_edge_transform_rotates_text():
781+
# With transform_rotates_text=True, get_rotation() goes through
782+
# transform_angles() and can return near-cardinal angles with float
783+
# noise (e.g. -90.00000000000003 for a 270 degree rotation), which
784+
# used to skip the cardinal-angle short-circuit in _get_dist_to_box.
785+
from matplotlib.transforms import Affine2D
786+
fig = plt.figure(figsize=(6, 4))
787+
s = 'This is a very long text that should be wrapped multiple times.'
788+
# rotate_deg(90).rotate_deg(-90) is identity geometrically, but carries
789+
# enough numerical slop to perturb transform_angles.
790+
transform = Affine2D().rotate_deg(90).rotate_deg(-90) + fig.transFigure
791+
t = fig.text(0.0, 0.5, s, transform=transform, wrap=True, rotation=270,
792+
transform_rotates_text=True)
793+
fig.canvas.draw()
794+
assert any(' ' in line for line in t._get_wrapped_text().split('\n'))
795+
796+
756797
@check_figures_equal()
757798
def test_buffer_size(fig_test, fig_ref):
758799
# On old versions of the Agg renderer, large non-ascii single-character

lib/matplotlib/text.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -757,6 +757,21 @@ def _get_dist_to_box(self, rotation, x0, y0, figure_box):
757757
Return the distance from the given points to the boundaries of a
758758
rotated box, in pixels.
759759
"""
760+
# Normalize rotation; transform_angles can return values outside
761+
# [0, 360) with tiny float noise.
762+
rotation = rotation % 360
763+
# Short-circuit cardinal angles, otherwise cos(radians(90)) makes
764+
# the trig formula below blow up when the text is on the edge.
765+
tol = 1e-10
766+
if rotation < tol or rotation > 360 - tol:
767+
return figure_box.x1 - x0
768+
if abs(rotation - 90) < tol:
769+
return figure_box.y1 - y0
770+
if abs(rotation - 180) < tol:
771+
return x0 - figure_box.x0
772+
if abs(rotation - 270) < tol:
773+
return y0 - figure_box.y0
774+
760775
if rotation > 270:
761776
quad = rotation - 270
762777
h1 = (y0 - figure_box.y0) / math.cos(math.radians(quad))

0 commit comments

Comments
 (0)