在matplotlib中包装线的文本框?

时间:2023-01-29 22:18:02

Is it possible to display text in a box through Matplotlib, with automatic line breaks? By using pyplot.text(), I was only able to print multi-line text that flows beyond the boundaries of the window, which is annoying. The size of the lines is not known in advance… Any idea would be much appreciated!

是否可以通过Matplotlib在框中显示文本,并自动换行?通过使用pyplot.text(),我只能打印超出窗口边界的多行文本,这很烦人。线条的大小事先不知道...任何想法将不胜感激!

3 个解决方案

#1


106  

The contents of this answer were merged into mpl master in https://github.com/matplotlib/matplotlib/pull/4342 and will be in the next feature release.

这个答案的内容在https://github.com/matplotlib/matplotlib/pull/4342中合并到mpl master中,并将在下一个功能版本中。


Wow... This is a thorny problem... (And it exposes a lot of limitations in matplotlib's text rendering...)

哇...这是一个棘手的问题......(它在matplotlib的文本渲染中暴露了很多限制......)

This should (i.m.o.) be something that matplotlib has built-in, but it doesn't. There have been a few threads about it on the mailing list, but no solution that I could find to automatic text wrapping.

这应该(i.m.o.)是matplotlib内置的东西,但事实并非如此。在邮件列表上有一些关于它的线程,但我找不到自动文本包装的解决方案。

So, first off, there's no way to determine the size (in pixels) of the rendered text string before it's drawn in matplotlib. This isn't too large of a problem, as we can just draw it, get the size, and then redraw the wrapped text. (It's expensive, but not too excessively bad)

因此,首先,在matplotlib中绘制之前,无法确定渲染文本字符串的大小(以像素为单位)。这不是太大的问题,因为我们可以绘制它,获取大小,然后重绘包装的文本。 (这很贵,但不是太糟糕)

The next problem is that characters don't have a fixed width in pixels, so wrapping a text string to a given number of characters won't necessarily reflect a given width when rendered. This isn't a huge problem, though.

下一个问题是字符没有固定的宽度(以像素为单位),因此将文本字符串包装到给定数量的字符时,在渲染时不一定会反映给定的宽度。但这不是一个大问题。

Beyond that, we can't just do this once... Otherwise, it will be wrapped correctly when drawn the first time (on the screen, for example), but not if drawn again (when the figure is resized or saved as an image with a different DPI than the screen). This isn't a huge problem, as we can just connect a callback function to the matplotlib draw event.

除此之外,我们不能只做一次......否则,它会在第一次(例如在屏幕上)时被正确包裹,但如果再次绘制则不会(当图形被调整大小或保存为具有与屏幕不同的DPI的图像)。这不是一个大问题,因为我们可以将回调函数连接到matplotlib绘图事件。

At any rate this solution is imperfect, but it should work in most situations. I don't try to account for tex-rendered strings, any stretched fonts, or fonts with an unusual aspect ratio. However, it should now properly handle rotated text.

无论如何,这种解决方案并不完美,但它应该适用于大多数情况。我不会尝试考虑tex渲染的字符串,任何拉伸的字体或具有不寻常的宽高比的字体。但是,它现在应该正确处理旋转的文本。

However, It should attempt automatically wrap any text objects in multiple subplots in whichever figures you connect the on_draw callback to... It will be imperfect in many cases, but it does a decent job.

但是,它应该尝试自动将多个子图中的任何文本对象包装在你连接on_draw回调的任何数字中......在许多情况下它将是不完美的,但它做得不错。

import matplotlib.pyplot as plt

def main():
    fig = plt.figure()
    plt.axis([0, 10, 0, 10])

    t = "This is a really long string that I'd rather have wrapped so that it"\
    " doesn't go outside of the figure, but if it's long enough it will go"\
    " off the top or bottom!"
    plt.text(4, 1, t, ha='left', rotation=15)
    plt.text(5, 3.5, t, ha='right', rotation=-15)
    plt.text(5, 10, t, fontsize=18, ha='center', va='top')
    plt.text(3, 0, t, family='serif', style='italic', ha='right')
    plt.title("This is a really long title that I want to have wrapped so it"\
             " does not go outside the figure boundaries", ha='center')

    # Now make the text auto-wrap...
    fig.canvas.mpl_connect('draw_event', on_draw)
    plt.show()

def on_draw(event):
    """Auto-wraps all text objects in a figure at draw-time"""
    import matplotlib as mpl
    fig = event.canvas.figure

    # Cycle through all artists in all the axes in the figure
    for ax in fig.axes:
        for artist in ax.get_children():
            # If it's a text artist, wrap it...
            if isinstance(artist, mpl.text.Text):
                autowrap_text(artist, event.renderer)

    # Temporarily disconnect any callbacks to the draw event...
    # (To avoid recursion)
    func_handles = fig.canvas.callbacks.callbacks[event.name]
    fig.canvas.callbacks.callbacks[event.name] = {}
    # Re-draw the figure..
    fig.canvas.draw()
    # Reset the draw event callbacks
    fig.canvas.callbacks.callbacks[event.name] = func_handles

def autowrap_text(textobj, renderer):
    """Wraps the given matplotlib text object so that it exceed the boundaries
    of the axis it is plotted in."""
    import textwrap
    # Get the starting position of the text in pixels...
    x0, y0 = textobj.get_transform().transform(textobj.get_position())
    # Get the extents of the current axis in pixels...
    clip = textobj.get_axes().get_window_extent()
    # Set the text to rotate about the left edge (doesn't make sense otherwise)
    textobj.set_rotation_mode('anchor')

    # Get the amount of space in the direction of rotation to the left and 
    # right of x0, y0 (left and right are relative to the rotation, as well)
    rotation = textobj.get_rotation()
    right_space = min_dist_inside((x0, y0), rotation, clip)
    left_space = min_dist_inside((x0, y0), rotation - 180, clip)

    # Use either the left or right distance depending on the horiz alignment.
    alignment = textobj.get_horizontalalignment()
    if alignment is 'left':
        new_width = right_space 
    elif alignment is 'right':
        new_width = left_space
    else:
        new_width = 2 * min(left_space, right_space)

    # Estimate the width of the new size in characters...
    aspect_ratio = 0.5 # This varies with the font!! 
    fontsize = textobj.get_size()
    pixels_per_char = aspect_ratio * renderer.points_to_pixels(fontsize)

    # If wrap_width is < 1, just make it 1 character
    wrap_width = max(1, new_width // pixels_per_char)
    try:
        wrapped_text = textwrap.fill(textobj.get_text(), wrap_width)
    except TypeError:
        # This appears to be a single word
        wrapped_text = textobj.get_text()
    textobj.set_text(wrapped_text)

def min_dist_inside(point, rotation, box):
    """Gets the space in a given direction from "point" to the boundaries of
    "box" (where box is an object with x0, y0, x1, & y1 attributes, point is a
    tuple of x,y, and rotation is the angle in degrees)"""
    from math import sin, cos, radians
    x0, y0 = point
    rotation = radians(rotation)
    distances = []
    threshold = 0.0001 
    if cos(rotation) > threshold: 
        # Intersects the right axis
        distances.append((box.x1 - x0) / cos(rotation))
    if cos(rotation) < -threshold: 
        # Intersects the left axis
        distances.append((box.x0 - x0) / cos(rotation))
    if sin(rotation) > threshold: 
        # Intersects the top axis
        distances.append((box.y1 - y0) / sin(rotation))
    if sin(rotation) < -threshold: 
        # Intersects the bottom axis
        distances.append((box.y0 - y0) / sin(rotation))
    return min(distances)

if __name__ == '__main__':
    main()

在matplotlib中包装线的文本框?

#2


4  

Its been roughly five years but there still doesn't seem to be a great way to do this. Here is my version of the accepted solution. My goal was to allow pixel-perfect wrapping to be selectively applied to individual text instances. I have also created a simple textBox() function which will convert any axes into a text box with custom margins and alignment.

它已经大概五年了,但似乎仍然没有一个很好的方法来做到这一点。这是我接受的解决方案的版本。我的目标是允许像素完美包装有选择地应用于单个文本实例。我还创建了一个简单的textBox()函数,它将任意轴转换为具有自定义边距和对齐的文本框。

Instead of assuming a particular font aspect ratio or average width, I actually draw the string one word at a time and insert newlines once the threshold is hit. This is horrendously slow compared to the approximations, but still feels quite snappy for strings of <200 words.

我实际上不是假定特定的字体宽高比或平均宽度,而是一次一个字地绘制字符串,并在达到阈值时插入换行符。与近似相比,这是非常缓慢的,但对于<200字的字符串仍然感觉非常活泼。

# Text Wrapping
# Defines wrapText which will attach an event to a given mpl.text object,
# wrapping it within the parent axes object.  Also defines a the convenience
# function textBox() which effectively converts an axes to a text box.
def wrapText(text, margin=4):
    """ Attaches an on-draw event to a given mpl.text object which will
        automatically wrap its string wthin the parent axes object.

        The margin argument controls the gap between the text and axes frame
        in points.
    """
    ax = text.get_axes()
    margin = margin / 72 * ax.figure.get_dpi()

    def _wrap(event):
        """Wraps text within its parent axes."""
        def _width(s):
            """Gets the length of a string in pixels."""
            text.set_text(s)
            return text.get_window_extent().width

        # Find available space
        clip = ax.get_window_extent()
        x0, y0 = text.get_transform().transform(text.get_position())
        if text.get_horizontalalignment() == 'left':
            width = clip.x1 - x0 - margin
        elif text.get_horizontalalignment() == 'right':
            width = x0 - clip.x0 - margin
        else:
            width = (min(clip.x1 - x0, x0 - clip.x0) - margin) * 2

        # Wrap the text string
        words = [''] + _splitText(text.get_text())[::-1]
        wrapped = []

        line = words.pop()
        while words:
            line = line if line else words.pop()
            lastLine = line

            while _width(line) <= width:
                if words:
                    lastLine = line
                    line += words.pop()
                    # Add in any whitespace since it will not affect redraw width
                    while words and (words[-1].strip() == ''):
                        line += words.pop()
                else:
                    lastLine = line
                    break

            wrapped.append(lastLine)
            line = line[len(lastLine):]
            if not words and line:
                wrapped.append(line)

        text.set_text('\n'.join(wrapped))

        # Draw wrapped string after disabling events to prevent recursion
        handles = ax.figure.canvas.callbacks.callbacks[event.name]
        ax.figure.canvas.callbacks.callbacks[event.name] = {}
        ax.figure.canvas.draw()
        ax.figure.canvas.callbacks.callbacks[event.name] = handles

    ax.figure.canvas.mpl_connect('draw_event', _wrap)

def _splitText(text):
    """ Splits a string into its underlying chucks for wordwrapping.  This
        mostly relies on the textwrap library but has some additional logic to
        avoid splitting latex/mathtext segments.
    """
    import textwrap
    import re
    math_re = re.compile(r'(?<!\\)\$')
    textWrapper = textwrap.TextWrapper()

    if len(math_re.findall(text)) <= 1:
        return textWrapper._split(text)
    else:
        chunks = []
        for n, segment in enumerate(math_re.split(text)):
            if segment and (n % 2):
                # Mathtext
                chunks.append('${}$'.format(segment))
            else:
                chunks += textWrapper._split(segment)
        return chunks

def textBox(text, axes, ha='left', fontsize=12, margin=None, frame=True, **kwargs):
    """ Converts an axes to a text box by removing its ticks and creating a
        wrapped annotation.
    """
    if margin is None:
        margin = 6 if frame else 0
    axes.set_xticks([])
    axes.set_yticks([])
    axes.set_frame_on(frame)

    an = axes.annotate(text, fontsize=fontsize, xy=({'left':0, 'right':1, 'center':0.5}[ha], 1), ha=ha, va='top',
                       xytext=(margin, -margin), xycoords='axes fraction', textcoords='offset points', **kwargs)
    wrapText(an, margin=margin)
    return an

Usage:

用法:

在matplotlib中包装线的文本框?

ax = plot.plt.figure(figsize=(6, 6)).add_subplot(111)
an = ax.annotate(t, fontsize=12, xy=(0.5, 1), ha='center', va='top', xytext=(0, -6),
                 xycoords='axes fraction', textcoords='offset points')
wrapText(an)

I dropped a few features which weren't as important to me. Resizing will fail as each call to _wrap() inserts additional newlines into the string but has no way of removing them. This can be solved by either stripping out all \n characters in the _wrap function, or storing the original string somewhere and "resetting" the text instance between wraps.

我放弃了一些对我来说不重要的功能。调整大小将失败,因为每次调用_wrap()都会在字符串中插入其他换行但无法删除它们。这可以通过剥离_wrap函数中的所有\ n字符,或者将原始字符串存储在某处并在包装之间“重置”文本实例来解决。

#3


1  

By setting wrap = True when creating the text box, as in the below example. This may have the desired effect.

通过在创建文本框时设置wrap = True,如下例所示。这可能具有期望的效果。

plt.text(5, 5, t, ha='right', rotation=-15, wrap=True)

#1


106  

The contents of this answer were merged into mpl master in https://github.com/matplotlib/matplotlib/pull/4342 and will be in the next feature release.

这个答案的内容在https://github.com/matplotlib/matplotlib/pull/4342中合并到mpl master中,并将在下一个功能版本中。


Wow... This is a thorny problem... (And it exposes a lot of limitations in matplotlib's text rendering...)

哇...这是一个棘手的问题......(它在matplotlib的文本渲染中暴露了很多限制......)

This should (i.m.o.) be something that matplotlib has built-in, but it doesn't. There have been a few threads about it on the mailing list, but no solution that I could find to automatic text wrapping.

这应该(i.m.o.)是matplotlib内置的东西,但事实并非如此。在邮件列表上有一些关于它的线程,但我找不到自动文本包装的解决方案。

So, first off, there's no way to determine the size (in pixels) of the rendered text string before it's drawn in matplotlib. This isn't too large of a problem, as we can just draw it, get the size, and then redraw the wrapped text. (It's expensive, but not too excessively bad)

因此,首先,在matplotlib中绘制之前,无法确定渲染文本字符串的大小(以像素为单位)。这不是太大的问题,因为我们可以绘制它,获取大小,然后重绘包装的文本。 (这很贵,但不是太糟糕)

The next problem is that characters don't have a fixed width in pixels, so wrapping a text string to a given number of characters won't necessarily reflect a given width when rendered. This isn't a huge problem, though.

下一个问题是字符没有固定的宽度(以像素为单位),因此将文本字符串包装到给定数量的字符时,在渲染时不一定会反映给定的宽度。但这不是一个大问题。

Beyond that, we can't just do this once... Otherwise, it will be wrapped correctly when drawn the first time (on the screen, for example), but not if drawn again (when the figure is resized or saved as an image with a different DPI than the screen). This isn't a huge problem, as we can just connect a callback function to the matplotlib draw event.

除此之外,我们不能只做一次......否则,它会在第一次(例如在屏幕上)时被正确包裹,但如果再次绘制则不会(当图形被调整大小或保存为具有与屏幕不同的DPI的图像)。这不是一个大问题,因为我们可以将回调函数连接到matplotlib绘图事件。

At any rate this solution is imperfect, but it should work in most situations. I don't try to account for tex-rendered strings, any stretched fonts, or fonts with an unusual aspect ratio. However, it should now properly handle rotated text.

无论如何,这种解决方案并不完美,但它应该适用于大多数情况。我不会尝试考虑tex渲染的字符串,任何拉伸的字体或具有不寻常的宽高比的字体。但是,它现在应该正确处理旋转的文本。

However, It should attempt automatically wrap any text objects in multiple subplots in whichever figures you connect the on_draw callback to... It will be imperfect in many cases, but it does a decent job.

但是,它应该尝试自动将多个子图中的任何文本对象包装在你连接on_draw回调的任何数字中......在许多情况下它将是不完美的,但它做得不错。

import matplotlib.pyplot as plt

def main():
    fig = plt.figure()
    plt.axis([0, 10, 0, 10])

    t = "This is a really long string that I'd rather have wrapped so that it"\
    " doesn't go outside of the figure, but if it's long enough it will go"\
    " off the top or bottom!"
    plt.text(4, 1, t, ha='left', rotation=15)
    plt.text(5, 3.5, t, ha='right', rotation=-15)
    plt.text(5, 10, t, fontsize=18, ha='center', va='top')
    plt.text(3, 0, t, family='serif', style='italic', ha='right')
    plt.title("This is a really long title that I want to have wrapped so it"\
             " does not go outside the figure boundaries", ha='center')

    # Now make the text auto-wrap...
    fig.canvas.mpl_connect('draw_event', on_draw)
    plt.show()

def on_draw(event):
    """Auto-wraps all text objects in a figure at draw-time"""
    import matplotlib as mpl
    fig = event.canvas.figure

    # Cycle through all artists in all the axes in the figure
    for ax in fig.axes:
        for artist in ax.get_children():
            # If it's a text artist, wrap it...
            if isinstance(artist, mpl.text.Text):
                autowrap_text(artist, event.renderer)

    # Temporarily disconnect any callbacks to the draw event...
    # (To avoid recursion)
    func_handles = fig.canvas.callbacks.callbacks[event.name]
    fig.canvas.callbacks.callbacks[event.name] = {}
    # Re-draw the figure..
    fig.canvas.draw()
    # Reset the draw event callbacks
    fig.canvas.callbacks.callbacks[event.name] = func_handles

def autowrap_text(textobj, renderer):
    """Wraps the given matplotlib text object so that it exceed the boundaries
    of the axis it is plotted in."""
    import textwrap
    # Get the starting position of the text in pixels...
    x0, y0 = textobj.get_transform().transform(textobj.get_position())
    # Get the extents of the current axis in pixels...
    clip = textobj.get_axes().get_window_extent()
    # Set the text to rotate about the left edge (doesn't make sense otherwise)
    textobj.set_rotation_mode('anchor')

    # Get the amount of space in the direction of rotation to the left and 
    # right of x0, y0 (left and right are relative to the rotation, as well)
    rotation = textobj.get_rotation()
    right_space = min_dist_inside((x0, y0), rotation, clip)
    left_space = min_dist_inside((x0, y0), rotation - 180, clip)

    # Use either the left or right distance depending on the horiz alignment.
    alignment = textobj.get_horizontalalignment()
    if alignment is 'left':
        new_width = right_space 
    elif alignment is 'right':
        new_width = left_space
    else:
        new_width = 2 * min(left_space, right_space)

    # Estimate the width of the new size in characters...
    aspect_ratio = 0.5 # This varies with the font!! 
    fontsize = textobj.get_size()
    pixels_per_char = aspect_ratio * renderer.points_to_pixels(fontsize)

    # If wrap_width is < 1, just make it 1 character
    wrap_width = max(1, new_width // pixels_per_char)
    try:
        wrapped_text = textwrap.fill(textobj.get_text(), wrap_width)
    except TypeError:
        # This appears to be a single word
        wrapped_text = textobj.get_text()
    textobj.set_text(wrapped_text)

def min_dist_inside(point, rotation, box):
    """Gets the space in a given direction from "point" to the boundaries of
    "box" (where box is an object with x0, y0, x1, & y1 attributes, point is a
    tuple of x,y, and rotation is the angle in degrees)"""
    from math import sin, cos, radians
    x0, y0 = point
    rotation = radians(rotation)
    distances = []
    threshold = 0.0001 
    if cos(rotation) > threshold: 
        # Intersects the right axis
        distances.append((box.x1 - x0) / cos(rotation))
    if cos(rotation) < -threshold: 
        # Intersects the left axis
        distances.append((box.x0 - x0) / cos(rotation))
    if sin(rotation) > threshold: 
        # Intersects the top axis
        distances.append((box.y1 - y0) / sin(rotation))
    if sin(rotation) < -threshold: 
        # Intersects the bottom axis
        distances.append((box.y0 - y0) / sin(rotation))
    return min(distances)

if __name__ == '__main__':
    main()

在matplotlib中包装线的文本框?

#2


4  

Its been roughly five years but there still doesn't seem to be a great way to do this. Here is my version of the accepted solution. My goal was to allow pixel-perfect wrapping to be selectively applied to individual text instances. I have also created a simple textBox() function which will convert any axes into a text box with custom margins and alignment.

它已经大概五年了,但似乎仍然没有一个很好的方法来做到这一点。这是我接受的解决方案的版本。我的目标是允许像素完美包装有选择地应用于单个文本实例。我还创建了一个简单的textBox()函数,它将任意轴转换为具有自定义边距和对齐的文本框。

Instead of assuming a particular font aspect ratio or average width, I actually draw the string one word at a time and insert newlines once the threshold is hit. This is horrendously slow compared to the approximations, but still feels quite snappy for strings of <200 words.

我实际上不是假定特定的字体宽高比或平均宽度,而是一次一个字地绘制字符串,并在达到阈值时插入换行符。与近似相比,这是非常缓慢的,但对于<200字的字符串仍然感觉非常活泼。

# Text Wrapping
# Defines wrapText which will attach an event to a given mpl.text object,
# wrapping it within the parent axes object.  Also defines a the convenience
# function textBox() which effectively converts an axes to a text box.
def wrapText(text, margin=4):
    """ Attaches an on-draw event to a given mpl.text object which will
        automatically wrap its string wthin the parent axes object.

        The margin argument controls the gap between the text and axes frame
        in points.
    """
    ax = text.get_axes()
    margin = margin / 72 * ax.figure.get_dpi()

    def _wrap(event):
        """Wraps text within its parent axes."""
        def _width(s):
            """Gets the length of a string in pixels."""
            text.set_text(s)
            return text.get_window_extent().width

        # Find available space
        clip = ax.get_window_extent()
        x0, y0 = text.get_transform().transform(text.get_position())
        if text.get_horizontalalignment() == 'left':
            width = clip.x1 - x0 - margin
        elif text.get_horizontalalignment() == 'right':
            width = x0 - clip.x0 - margin
        else:
            width = (min(clip.x1 - x0, x0 - clip.x0) - margin) * 2

        # Wrap the text string
        words = [''] + _splitText(text.get_text())[::-1]
        wrapped = []

        line = words.pop()
        while words:
            line = line if line else words.pop()
            lastLine = line

            while _width(line) <= width:
                if words:
                    lastLine = line
                    line += words.pop()
                    # Add in any whitespace since it will not affect redraw width
                    while words and (words[-1].strip() == ''):
                        line += words.pop()
                else:
                    lastLine = line
                    break

            wrapped.append(lastLine)
            line = line[len(lastLine):]
            if not words and line:
                wrapped.append(line)

        text.set_text('\n'.join(wrapped))

        # Draw wrapped string after disabling events to prevent recursion
        handles = ax.figure.canvas.callbacks.callbacks[event.name]
        ax.figure.canvas.callbacks.callbacks[event.name] = {}
        ax.figure.canvas.draw()
        ax.figure.canvas.callbacks.callbacks[event.name] = handles

    ax.figure.canvas.mpl_connect('draw_event', _wrap)

def _splitText(text):
    """ Splits a string into its underlying chucks for wordwrapping.  This
        mostly relies on the textwrap library but has some additional logic to
        avoid splitting latex/mathtext segments.
    """
    import textwrap
    import re
    math_re = re.compile(r'(?<!\\)\$')
    textWrapper = textwrap.TextWrapper()

    if len(math_re.findall(text)) <= 1:
        return textWrapper._split(text)
    else:
        chunks = []
        for n, segment in enumerate(math_re.split(text)):
            if segment and (n % 2):
                # Mathtext
                chunks.append('${}$'.format(segment))
            else:
                chunks += textWrapper._split(segment)
        return chunks

def textBox(text, axes, ha='left', fontsize=12, margin=None, frame=True, **kwargs):
    """ Converts an axes to a text box by removing its ticks and creating a
        wrapped annotation.
    """
    if margin is None:
        margin = 6 if frame else 0
    axes.set_xticks([])
    axes.set_yticks([])
    axes.set_frame_on(frame)

    an = axes.annotate(text, fontsize=fontsize, xy=({'left':0, 'right':1, 'center':0.5}[ha], 1), ha=ha, va='top',
                       xytext=(margin, -margin), xycoords='axes fraction', textcoords='offset points', **kwargs)
    wrapText(an, margin=margin)
    return an

Usage:

用法:

在matplotlib中包装线的文本框?

ax = plot.plt.figure(figsize=(6, 6)).add_subplot(111)
an = ax.annotate(t, fontsize=12, xy=(0.5, 1), ha='center', va='top', xytext=(0, -6),
                 xycoords='axes fraction', textcoords='offset points')
wrapText(an)

I dropped a few features which weren't as important to me. Resizing will fail as each call to _wrap() inserts additional newlines into the string but has no way of removing them. This can be solved by either stripping out all \n characters in the _wrap function, or storing the original string somewhere and "resetting" the text instance between wraps.

我放弃了一些对我来说不重要的功能。调整大小将失败,因为每次调用_wrap()都会在字符串中插入其他换行但无法删除它们。这可以通过剥离_wrap函数中的所有\ n字符,或者将原始字符串存储在某处并在包装之间“重置”文本实例来解决。

#3


1  

By setting wrap = True when creating the text box, as in the below example. This may have the desired effect.

通过在创建文本框时设置wrap = True,如下例所示。这可能具有期望的效果。

plt.text(5, 5, t, ha='right', rotation=-15, wrap=True)