[Python] matplotlib에 줄 바꿈이 포함 된 텍스트 상자?



Answers

그것의 대략 5 년 그러나 아직도 이것을하는 중대한 방법 인 것처럼 보이지 않는다. 여기에 허용 된 솔루션의 제 버전이 있습니다. 내 목표는 개별 텍스트 인스턴스에 선택적으로 픽셀 완전 포장을 적용하는 것이 었습니다. 또한 모든 축을 사용자 정의 여백과 정렬이있는 텍스트 상자로 변환하는 간단한 textBox () 함수를 만들었습니다.

특정 글꼴 종횡비 또는 평균 너비를 가정하는 대신 실제로 한 번에 한 단어 씩 그려보고 임계 값에 도달하면 줄 바꿈을 삽입합니다. 이것은 근사값에 비해 끔찍하게 느리지 만 문자열이 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

용법:

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)

나에게별로 중요하지 않은 몇 가지 기능을 떨어 뜨 렸습니다. _wrap ()을 호출 할 때마다 줄 바꿈을 추가하지만 제거 할 방법이 없으므로 크기 조정이 실패합니다. 이것은 _wrap 함수의 모든 \ n 문자를 제거하거나 원래 문자열을 어딘가에 저장하고 랩간에 텍스트 인스턴스를 "재설정"하여 해결할 수 있습니다.

Question

Matplotlib을 통해 자동 줄 바꿈으로 텍스트를 상자에 표시 할 수 있습니까? pyplot.text() 를 사용하여 창 테두리를 넘는 여러 줄의 텍스트 만 인쇄 할 수있었습니다. 이는 성가신 일입니다. 선의 크기는 미리 알려지지 않았습니다 ... 어떤 아이디어라도 높이 평가할 것입니다!




Links