2013-07-09 43 views
6

Tôi không thể tìm ra cách để có được một tiêu đề hoạt hình hoạt động trên một ô FuncAnimation (sử dụng blit). Dựa trên http://jakevdp.github.io/blog/2012/08/18/matplotlib-animation-tutorial/Python/Matplotlib - Quickly Updating Text on Axes, tôi đã tạo một hoạt ảnh nhưng các phần văn bản sẽ không hoạt ảnh. Ví dụ đơn giản:Tiêu đề hoạt ảnh trong matplotlib

import matplotlib.pyplot as plt 
import matplotlib.animation as animation 
import numpy as np 

vls = np.linspace(0,2*2*np.pi,100) 

fig=plt.figure() 
img, = plt.plot(np.sin(vls)) 
ax = plt.axes() 
ax.set_xlim([0,2*2*np.pi]) 
#ttl = ax.set_title('',animated=True) 
ttl = ax.text(.5, 1.005, '', transform = ax.transAxes) 

def init(): 
    ttl.set_text('') 
    img.set_data([0],[0]) 
    return img, ttl 
def func(n): 
    ttl.set_text(str(n)) 
    img.set_data(vls,np.sin(vls+.02*n*2*np.pi)) 
    return img, ttl 

ani = animation.FuncAnimation(fig,func,init_func=init,frames=50,interval=30,blit=True) 

plt.show() 

Nếu blit=True bị xóa, văn bản hiển thị, nhưng nó chậm lại. Có vẻ như không thành công với plt.title, ax.set_titleax.text.

Chỉnh sửa: Tôi đã tìm hiểu lý do tại sao ví dụ thứ hai trong liên kết đầu tiên hoạt động; văn bản nằm trong phần img. Nếu bạn thực hiện trên 1.005 một .99, bạn sẽ thấy ý của tôi. Có lẽ là một cách để làm điều này với một hộp bounding, bằng cách nào đó ...

Trả lời

14

Xem Animating matplotlib axes/tickspython matplotlib blit to axes or sides of the figure?

Vì vậy, vấn đề là trong ruột của animation nơi nền blit đang thực sự lưu (dòng 792 của animation.py), nó lấy những gì có trong trục bounding cái hộp. Điều này có ý nghĩa khi bạn có nhiều trục được hoạt ảnh độc lập. Trong trường hợp của bạn, bạn chỉ có một số axes để lo lắng và chúng tôi muốn tạo nội dung động bên ngoài của hộp giới hạn trục. Với một chút vá khỉ, một mức độ khoan dung đối với việc thâm nhập vào ruột của mpl và chọc xung quanh một chút, và sự chấp nhận của giải pháp nhanh nhất và dirtyest chúng ta có thể giải quyết vấn đề của bạn như vậy:

import matplotlib 
import matplotlib.pyplot as plt 
import matplotlib.animation as animation 
import numpy as np 

def _blit_draw(self, artists, bg_cache): 
    # Handles blitted drawing, which renders only the artists given instead 
    # of the entire figure. 
    updated_ax = [] 
    for a in artists: 
     # If we haven't cached the background for this axes object, do 
     # so now. This might not always be reliable, but it's an attempt 
     # to automate the process. 
     if a.axes not in bg_cache: 
      # bg_cache[a.axes] = a.figure.canvas.copy_from_bbox(a.axes.bbox) 
      # change here 
      bg_cache[a.axes] = a.figure.canvas.copy_from_bbox(a.axes.figure.bbox) 
     a.axes.draw_artist(a) 
     updated_ax.append(a.axes) 

    # After rendering all the needed artists, blit each axes individually. 
    for ax in set(updated_ax): 
     # and here 
     # ax.figure.canvas.blit(ax.bbox) 
     ax.figure.canvas.blit(ax.figure.bbox) 

# MONKEY PATCH!! 
matplotlib.animation.Animation._blit_draw = _blit_draw 

vls = np.linspace(0,2*2*np.pi,100) 

fig=plt.figure() 
img, = plt.plot(np.sin(vls)) 
ax = plt.axes() 
ax.set_xlim([0,2*2*np.pi]) 
#ttl = ax.set_title('',animated=True) 
ttl = ax.text(.5, 1.05, '', transform = ax.transAxes, va='center') 

def init(): 
    ttl.set_text('') 
    img.set_data([0],[0]) 
    return img, ttl 

def func(n): 
    ttl.set_text(str(n)) 
    img.set_data(vls,np.sin(vls+.02*n*2*np.pi)) 
    return img, ttl 

ani = animation.FuncAnimation(fig,func,init_func=init,frames=50,interval=30,blit=True) 

plt.show() 

Lưu ý rằng điều này có thể không hoạt động như mong đợi nếu bạn có nhiều hơn một trục trong hình. Một giải pháp tốt hơn là mở rộng axes.bboxchỉ đủ để nắm bắt nhãn dấu + trục tiêu đề của bạn. Tôi nghi ngờ có mã nơi nào đó trong mpl để làm điều đó, nhưng tôi không biết nó ở đâu trên đầu của tôi.

+0

Điều này hoạt động ở tốc độ tối đa! Chúc nó được bao gồm trong matplotlib, so với khỉ vá, nhưng hoạt động tốt! –

+0

@HenrySchreiner Chỉnh sửa của bạn đã được chấp nhận. (Tôi vừa làm lại). Nếu điều này giải quyết được vấn đề của bạn, bạn có thể chấp nhận câu trả lời (hộp kiểm lớn màu xám ở bên trái). – tacaswell

+0

Lý tưởng nhất, hộp giới hạn văn bản nên được sử dụng (vì nó được chuyển từ chức năng hoạt hình), nhưng vì một số lý do nó không được sử dụng (mặc dù tôi nghĩ nó nằm trong các nghệ sĩ). Đây là một hack hợp lý để sửa chữa nó ngay bây giờ. :) Cảm ơn! –

1

Bạn phải gọi

plt.draw() 

Sau

ttl.set_text(str(n)) 

Ở đây có một ví dụ rất đơn giản một văn bản hoạt hình bên trong một hình "không có FuncAnimation()". Hãy thử nó, bạn sẽ thấy nếu nó là hữu ích cho bạn.

import matplotlib.pyplot as plt 
import numpy as np 
titles = np.arange(100) 
plt.ion() 
fig = plt.figure() 
for text in titles: 
    plt.clf() 
    fig.text(0.5,0.5,str(text)) 
    plt.draw() 
+1

Điều đó vẽ nó, nhưng nó làm chậm nó xuống cùng một lượng 'blit = False'. Tôi đã hy vọng sẽ vẽ lại văn bản. –

+0

Tại sao bạn không chỉ đơn giản là tránh hoạt ảnh và tạo hoạt ảnh của riêng bạn với plt.ion()?Với nó, bạn có rất nhiều kiểm soát, và bạn chắc chắn bạn đang làm gì mỗi khung ... Hãy xem http://stackoverflow.com/questions/17444655/dynamically-updating-a-graphed-line-in- python/17480397 # 17480397 – Pablo

+0

fig = plt.figure() img, = plt.plot (np.sin (vls)) ax = plt.axes() ax.set_xlim ([0,2 * 2 * np. pi]) tiêu đề = ax.text (.5, 1.005, '', transform = ax.transAxes) plt.ion() cho i trong phạm vi (100): img.set_data (vls, np.sin (vls + .02 * (i% 50) * 2 * np.pi)) title.set_text (str (i% 50)) plt.draw() –

2

Để thêm vào giải pháp "vá khỉ" của tcaswell, dưới đây là cách bạn có thể thêm hoạt ảnh vào nhãn đánh dấu trục. Cụ thể, để tạo hiệu ứng trục x, hãy đặt ax.xaxis.set_animated(True) và trả lại ax.xaxis từ các chức năng hoạt ảnh.

import matplotlib 
import matplotlib.pyplot as plt 
import matplotlib.animation as animation 
import numpy as np 

def _blit_draw(self, artists, bg_cache): 
    # Handles blitted drawing, which renders only the artists given instead 
    # of the entire figure. 
    updated_ax = [] 
    for a in artists: 
     # If we haven't cached the background for this axes object, do 
     # so now. This might not always be reliable, but it's an attempt 
     # to automate the process. 
     if a.axes not in bg_cache: 
      # bg_cache[a.axes] = a.figure.canvas.copy_from_bbox(a.axes.bbox) 
      # change here 
      bg_cache[a.axes] = a.figure.canvas.copy_from_bbox(a.axes.figure.bbox) 
     a.axes.draw_artist(a) 
     updated_ax.append(a.axes) 

    # After rendering all the needed artists, blit each axes individually. 
    for ax in set(updated_ax): 
     # and here 
     # ax.figure.canvas.blit(ax.bbox) 
     ax.figure.canvas.blit(ax.figure.bbox) 

# MONKEY PATCH!! 
matplotlib.animation.Animation._blit_draw = _blit_draw 

vls = np.linspace(0,2*2*np.pi,100) 

fig=plt.figure() 
img, = plt.plot(np.sin(vls)) 
ax = plt.axes() 
ax.set_xlim([0,2*2*np.pi]) 
#ttl = ax.set_title('',animated=True) 
ttl = ax.text(.5, 1.05, '', transform = ax.transAxes, va='center') 

ax.xaxis.set_animated(True) 

def init(): 
    ttl.set_text('') 
    img.set_data([0],[0]) 
    return img, ttl, ax.xaxis 

def func(n): 
    ttl.set_text(str(n)) 
    vls = np.linspace(0.2*n,0.2*n+2*2*np.pi,100) 
    img.set_data(vls,np.sin(vls)) 
    ax.set_xlim(vls[0],vls[-1]) 
    return img, ttl, ax.xaxis 

ani = animation.FuncAnimation(fig,func,init_func=init,frames=60,interval=200,blit=True) 

plt.show() 
1

Nếu bạn cần phải sửa chữa các tiêu đề, bạn chỉ có thể cập nhật các tiêu đề với:

fig.suptitle() 

Xem hình API document.

+0

Tính năng này có hoạt động nếu bạn đã bật chức năng bật không? – bretcj7

+0

@ bretcj7 Tôi nghĩ bạn có thể thử. – shane

Các vấn đề liên quan