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

Skip to content

Commit 65d03b7

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 e964783 commit 65d03b7

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
@@ -759,6 +759,47 @@ def test_wrap_no_wrap():
759759
assert text._get_wrapped_text() == 'non wrapped text'
760760

761761

762+
@pytest.mark.parametrize(
763+
"x, y, rotation",
764+
[(0.0, 1.0, 0),
765+
(1.0, 0.5, 90),
766+
(0.5, 1.0, 180),
767+
(0.0, 0.5, 270)])
768+
def test_wrap_on_figure_edge(x, y, rotation):
769+
# Regression test for #31537 - wrap collapsed to zero on figure edges.
770+
s = 'This is a very long text that should be wrapped multiple times.'
771+
fig = plt.figure(figsize=(6, 4))
772+
t = fig.text(x, y, s, wrap=True, rotation=rotation)
773+
fig.canvas.draw()
774+
775+
# Compare to a nudged-off-the-edge reference that should wrap the same.
776+
nudge = 1e-4
777+
x_ref = x - nudge if x == 1.0 else x + nudge if x == 0.0 else x
778+
y_ref = y - nudge if y == 1.0 else y + nudge if y == 0.0 else y
779+
fig_ref = plt.figure(figsize=(6, 4))
780+
t_ref = fig_ref.text(x_ref, y_ref, s, wrap=True, rotation=rotation)
781+
fig_ref.canvas.draw()
782+
783+
assert t._get_wrapped_text() == t_ref._get_wrapped_text()
784+
785+
786+
def test_wrap_on_figure_edge_transform_rotates_text():
787+
# With transform_rotates_text=True, get_rotation() goes through
788+
# transform_angles() and can return near-cardinal angles with float
789+
# noise (e.g. -90.00000000000003 for a 270 degree rotation), which
790+
# used to skip the cardinal-angle short-circuit in _get_dist_to_box.
791+
from matplotlib.transforms import Affine2D
792+
fig = plt.figure(figsize=(6, 4))
793+
s = 'This is a very long text that should be wrapped multiple times.'
794+
# rotate_deg(90).rotate_deg(-90) is identity geometrically, but carries
795+
# enough numerical slop to perturb transform_angles.
796+
transform = Affine2D().rotate_deg(90).rotate_deg(-90) + fig.transFigure
797+
t = fig.text(0.0, 0.5, s, transform=transform, wrap=True, rotation=270,
798+
transform_rotates_text=True)
799+
fig.canvas.draw()
800+
assert any(' ' in line for line in t._get_wrapped_text().split('\n'))
801+
802+
762803
@check_figures_equal()
763804
def test_buffer_size(fig_test, fig_ref):
764805
# 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
@@ -743,6 +743,21 @@ def _get_dist_to_box(self, rotation, x0, y0, figure_box):
743743
Return the distance from the given points to the boundaries of a
744744
rotated box, in pixels.
745745
"""
746+
# Normalize rotation; transform_angles can return values outside
747+
# [0, 360) with tiny float noise.
748+
rotation = rotation % 360
749+
# Short-circuit cardinal angles, otherwise cos(radians(90)) makes
750+
# the trig formula below blow up when the text is on the edge.
751+
tol = 1e-10
752+
if rotation < tol or rotation > 360 - tol:
753+
return figure_box.x1 - x0
754+
if abs(rotation - 90) < tol:
755+
return figure_box.y1 - y0
756+
if abs(rotation - 180) < tol:
757+
return x0 - figure_box.x0
758+
if abs(rotation - 270) < tol:
759+
return y0 - figure_box.y0
760+
746761
if rotation > 270:
747762
quad = rotation - 270
748763
h1 = (y0 - figure_box.y0) / math.cos(math.radians(quad))

0 commit comments

Comments
 (0)