SORU
25 EKİM 2010, PAZARTESİ


Çizgi matplotlib kaydırma ile metin kutusu?

Matplotlib ile bir kutuya metin görüntülemek için mümkün olurotomatik Satır sonları? Sadece çok satırlı pencere sınırlarının ötesine akar metin yazdırmayı başardı, sinir bozucu olan, pyplot.text(), kullanarak. Satır boyutunu önceden bilinmiyor... Herhangi bir fikir çok takdir olurdu!

CEVAP
30 EKİM 2010, CUMARTESİ


Bu cevap içeriği https://github.com/matplotlib/matplotlib/pull/4342 mpl usta çatı altında toplandı ve bir sonraki özellik sürüm olacak.


Vay be... Bu dikenli bir sorun... (Ve matplotlib metin işleme sınırlamalar bir yeri gösterir...)

Bu yardımcı olacaktır.m.Ç.) matplotlib-inşa etti, ama yok öyle bir şey. threads about it postada bir kaç liste var, ama bulabildiğim hiçbir çözüm metin kaydırma otomatik.

Böylece ilk olarak, matplotlib çizilmiş olmadan boyutu (piksel olarak) işlenen metin dizesini belirlemek için yolu vardır. Bu sadece çizmek, boyutu ve kaydırılan metin boyutlandırmaya gibi bir sorun, çok büyük değil. (Pahalı, ama çok aşırı kötü

Bir sonraki sorun karakterler piksel cinsinden sabit bir genişlik yok, karakter belirli bir sayıda metin bir dize sarma mutlaka işlenen belirli bir genişlikte yansıtmak istemiyorum. Bu büyük bir sorun değil.

Bunun ötesinde, yapamayız, bu kez... Aksi takdirde olacak sarılmış doğru çizilmiş ilk kez (ekranda, örneğin), ama değilse tekrar çizilir (şekil yeniden boyutlandırıldığında veya kaydedilmiş gibi bir görüntü ile farklı DPİ ekran). Bu sadece matplotlib çizmek olay için bir geri arama işlevini bağlamak gibi büyük bir sorun değil.

Her neyse bu çözüm mükemmel değildir, ama çoğu durumda işe yarayacaktır. Tex-karşılığı hesabı kalkmayın dizeleri, sıradışı En Boy oranı ile gergin tiplerini, yazı tipleri, herhangi bir. Ancak, şimdi doğru döndürülmüş metin işlemek gerekir.

Ancak, otomatik olarak on_draw geri bağlayın hangisi... birçok durumda eksik olacak birden fazla subplots herhangi bir metin nesneleri sarmak denemeniz gerekir, ama iyi bir iş yok.

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()

Figure with wrapped text

Bunu Paylaş:
  • Google+
  • E-Posta
Etiketler:

YORUMLAR

SPONSOR VİDEO

Rastgele Yazarlar

  • Andrey Menshikov

    Andrey Mensh

    28 Ocak 2012
  • Kanaal van Dj0fifty

    Kanaal van D

    28 EKİM 2011
  • macpulenta

    macpulenta

    9 EYLÜL 2006