Skip to content

Commit 185c92c

Browse files
authored
Merge pull request matplotlib#15025 from dstansby/txt-wrap-logic
Re-write text wrapping logic
2 parents 2b31002 + 9704150 commit 185c92c

File tree

2 files changed

+60
-22
lines changed

2 files changed

+60
-22
lines changed

lib/matplotlib/tests/test_text.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -592,3 +592,28 @@ def test_large_subscript_title():
592592
tt.set_position((x, 1.01))
593593
ax.set_title('Old Way', loc='left')
594594
ax.set_xticklabels('')
595+
596+
597+
def test_wrap():
598+
fig = plt.figure(figsize=(6, 4))
599+
s = 'This is a very long text that should be wrapped multiple times.'
600+
text = fig.text(0.7, 0.5, s, wrap=True)
601+
fig.canvas.draw()
602+
assert text._get_wrapped_text() == ('This is a very long\n'
603+
'text that should be\n'
604+
'wrapped multiple\n'
605+
'times.')
606+
607+
608+
def test_long_word_wrap():
609+
fig = plt.figure(figsize=(6, 4))
610+
text = fig.text(9.5, 8, 'Alonglineoftexttowrap', wrap=True)
611+
fig.canvas.draw()
612+
assert text._get_wrapped_text() == 'Alonglineoftexttowrap'
613+
614+
615+
def test_wrap_no_wrap():
616+
fig = plt.figure(figsize=(6, 4))
617+
text = fig.text(0, 0, 'non wrapped text', wrap=True)
618+
fig.canvas.draw()
619+
assert text._get_wrapped_text() == 'non wrapped text'

lib/matplotlib/text.py

Lines changed: 35 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -631,28 +631,41 @@ def _get_wrapped_text(self):
631631

632632
# Build the line incrementally, for a more accurate measure of length
633633
line_width = self._get_wrap_line_width()
634-
wrapped_str = ""
635-
line = ""
636-
637-
for word in self.get_text().split(' '):
638-
# New lines in the user's test need to force a split, so that it's
639-
# not using the longest current line width in the line being built
640-
sub_words = word.split('\n')
641-
for i in range(len(sub_words)):
642-
current_width = self._get_rendered_text_width(
643-
line + ' ' + sub_words[i])
644-
645-
# Split long lines, and each newline found in the current word
646-
if current_width > line_width or i > 0:
647-
wrapped_str += line + '\n'
648-
line = ""
649-
650-
if line == "":
651-
line = sub_words[i]
652-
else:
653-
line += ' ' + sub_words[i]
654-
655-
return wrapped_str + line
634+
wrapped_lines = []
635+
636+
# New lines in the user's text force a split
637+
unwrapped_lines = self.get_text().split('\n')
638+
639+
# Now wrap each individual unwrapped line
640+
for unwrapped_line in unwrapped_lines:
641+
642+
sub_words = unwrapped_line.split(' ')
643+
# Remove items from sub_words as we go, so stop when empty
644+
while len(sub_words) > 0:
645+
if len(sub_words) == 1:
646+
# Only one word, so just add it to the end
647+
wrapped_lines.append(sub_words.pop(0))
648+
continue
649+
650+
for i in range(2, len(sub_words) + 1):
651+
# Get width of all words up to and including here
652+
line = ' '.join(sub_words[:i])
653+
current_width = self._get_rendered_text_width(line)
654+
655+
# If all these words are too wide, append all not including
656+
# last word
657+
if current_width > line_width:
658+
wrapped_lines.append(' '.join(sub_words[:i - 1]))
659+
sub_words = sub_words[i - 1:]
660+
break
661+
662+
# Otherwise if all words fit in the width, append them all
663+
elif i == len(sub_words):
664+
wrapped_lines.append(' '.join(sub_words[:i]))
665+
sub_words = []
666+
break
667+
668+
return '\n'.join(wrapped_lines)
656669

657670
@artist.allow_rasterization
658671
def draw(self, renderer):

0 commit comments

Comments
 (0)