cách cập nhật động một âm mưu trong một vòng lặp trong sổ ghi chép ipython (trong một ô)


91

Môi trường: Python 2.7, matplotlib 1.3, IPython notebook 1.1, linux, chrome. Mã nằm trong một ô đầu vào duy nhất, sử dụng--pylab=inline

Tôi muốn sử dụng máy tính xách tay và gấu trúc IPython để sử dụng luồng và cập nhật động một âm mưu sau mỗi 5 giây.

Khi tôi chỉ sử dụng câu lệnh print để in dữ liệu ở định dạng văn bản, nó hoạt động hoàn toàn tốt: ô đầu ra chỉ tiếp tục in dữ liệu và thêm các hàng mới. Nhưng khi tôi cố gắng vẽ biểu đồ dữ liệu (và sau đó cập nhật nó trong một vòng lặp), biểu đồ không bao giờ hiển thị trong ô đầu ra. Nhưng nếu tôi loại bỏ vòng lặp, chỉ cần vẽ sơ đồ một lần. Nó hoạt động tốt.

Sau đó, tôi đã thực hiện một số thử nghiệm đơn giản:

i = pd.date_range('2013-1-1',periods=100,freq='s')
while True:
    plot(pd.Series(data=np.random.randn(100), index=i))
    #pd.Series(data=np.random.randn(100), index=i).plot() also tried this one
    time.sleep(5)

Đầu ra sẽ không hiển thị bất cứ điều gì cho đến khi tôi ngắt quá trình theo cách thủ công (ctrl + m + i). Và sau khi tôi ngắt lời, cốt truyện hiển thị chính xác dưới dạng nhiều dòng chồng lên nhau. Nhưng những gì tôi thực sự muốn là một âm mưu hiển thị và được cập nhật sau mỗi 5 giây (hoặc bất cứ khi nào plot()hàm được gọi, giống như kết quả của câu lệnh in mà tôi đã đề cập ở trên, hoạt động tốt). Chỉ hiển thị biểu đồ cuối cùng sau khi ô hoàn thành KHÔNG phải là điều tôi muốn.

Tôi thậm chí đã cố gắng thêm một cách rõ ràng hàm draw () sau mỗi hàm plot(), v.v. Không có hàm nào hoạt động. Tự hỏi làm thế nào để cập nhật động một âm mưu bằng vòng lặp for / while trong một ô trong sổ ghi chép IPython.

Câu trả lời:


118

sử dụng IPython.displaymô-đun:

%matplotlib inline
import time
import pylab as pl
from IPython import display
for i in range(10):
    pl.plot(pl.randn(100))
    display.clear_output(wait=True)
    display.display(pl.gcf())
    time.sleep(1.0)

4
đây không phải là mịn tùy chọn, cốt truyện được tái tạo từ đầu với di động đi lên và xuống ở giữa
denfromufa

3
Thêm clear_output(wait=True)giải quyết vấn đề này. Xem câu trả lời của wabu bên dưới.
Alex Williams

3
Bạn có thể làm tốt hơn trong những ngày %matplotlib nbaggnày, nhờ đó mà bạn có một con số trực tiếp để chơi cùng.
tacaswell

@tcaswell Tôi đã thêm một câu hỏi mới hỏi cách một người sử dụng nbaggđể đạt được điều này. (Pinging bạn trong trường hợp bạn đang quan tâm trong việc trả lời nó.) Stackoverflow.com/questions/34486642/...
Nathaniel

3
điều này hoạt động nhưng cũng phá hủy bất kỳ thứ gì khác trong ô như các biện pháp được in. Có cách nào thực sự chỉ cập nhật cốt truyện và giữ nguyên mọi thứ khác không?
KIC

30

Bạn có thể cải thiện thêm điều này bằng cách thêm wait=Truevào clear_output:

display.clear_output(wait=True)
display.display(pl.gcf())

1
+1. Cái này rất quan trọng. Tôi nghĩ câu trả lời của HYRY nên được cập nhật với thông tin này.
Alex Williams

5
Điều này là tốt, nhưng cũng có tác dụng phụ khó chịu là xóa đầu ra in.
Peter

29

Một số cải tiến trong câu trả lời của HYRY :

  • gọi displaytrước clear_outputđể bạn kết thúc với một âm mưu, thay vì hai, khi ô bị ngắt.
  • bắt KeyboardInterrupt, để kết quả đầu ra của ô không bị rải rác với dấu vết.
import matplotlib.pylab as plt
import pandas as pd
import numpy as np
import time
from IPython import display
%matplotlib inline

i = pd.date_range('2013-1-1',periods=100,freq='s')

while True:
    try:
        plt.plot(pd.Series(data=np.random.randn(100), index=i))
        display.display(plt.gcf())
        display.clear_output(wait=True)
        time.sleep(1)
    except KeyboardInterrupt:
        break

7
Thật vậy, display.display(gcf())nên đi TRƯỚC display.clear_output(wait=True)
herrlich 10

Cảm ơn, @csta. Đã thêm nó.
Tom Phillips

@ herrlich10 Tại sao nên displayđược gọi là trước clear_output? Trước tiên, bạn không nên xóa đầu ra và sau đó hiển thị dữ liệu mới, thay vì làm theo cách khác?
Jakub Arnold

1
Tôi vẫn nhận được màn hình nhấp nháy khi cập nhật biểu đồ, tuy nhiên không phải lúc nào cũng vậy. Có giải pháp nào cho điều này không?
MasayoMusic

2

Cố gắng thêm show()hoặc gcf().show()sau plot()chức năng. Những điều này sẽ buộc hình hiện tại cập nhật (gcf () trả về một tham chiếu cho hình hiện tại).


2
cảm ơn. gcf (). show () cũng hoạt động. Cần thêm clear_output () được đề xuất bởi HYRY để hiển thị nội dung trên các vả cùng
user3236895

Điều này có bổ sung cho "display.display (pl.gcf ())" không?
MasayoMusic

2

Thêm nhãn cho các giải pháp khác được đăng ở đây sẽ tiếp tục thêm nhãn mới trong mỗi vòng lặp. Để đối phó với điều đó, hãy xóa cốt truyện bằng cách sử dụngclf

for t in range(100)
   if t % refresh_rate == 0:

     plt.clf()
     plt.plot(history['val_loss'], 'r-', lw=2, label='val')
     plt.plot(history['training_loss'], 'b-', lw=1, label='training')
     plt.legend()
     display.clear_output(wait=True)
     display.display(plt.gcf())

4
Cảm ơn plt.clf()hoạt động. Tuy nhiên, vẫn có cách nào để loại bỏ hiện tượng nhấp nháy từ các bản cập nhật?
MasayoMusic

0

Bạn có thể làm điều đó như thế này. Nó chấp nhận x, y làm danh sách và xuất ra một biểu đồ phân tán cộng với xu hướng tuyến tính trên cùng một biểu đồ.

from IPython.display import clear_output
from matplotlib import pyplot as plt
%matplotlib inline
    
def live_plot(x, y, figsize=(7,5), title=''):
    clear_output(wait=True)
    plt.figure(figsize=figsize)
    plt.xlim(0, training_steps)
    plt.ylim(0, 100)
    x= [float(i) for i in x]
    y= [float(i) for i in y]
    
    if len(x) > 1:
        plt.scatter(x,y, label='axis y', color='k') 
        m, b = np.polyfit(x, y, 1)
        plt.plot(x, [x * m for x in x] + b)

    plt.title(title)
    plt.grid(True)
    plt.xlabel('axis x')
    plt.ylabel('axis y')
    plt.show();

bạn chỉ cần gọi live_plot(x, y)bên trong một vòng lặp. Đây là cách nó trông: nhập mô tả hình ảnh ở đây

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.