วิธีอัปเดตพล็อตแบบไดนามิกในลูปในสมุดบันทึก Ipython (ภายในเซลล์เดียว)


93

สภาพแวดล้อม: Python 2.7, matplotlib 1.3, IPython notebook 1.1, linux, chrome รหัสอยู่ในเซลล์อินพุตเดียวโดยใช้--pylab=inline

ฉันต้องการใช้สมุดบันทึก IPython และแพนด้าเพื่อใช้สตรีมและอัปเดตพล็อตแบบไดนามิกทุกๆ 5 วินาที

เมื่อฉันใช้คำสั่งพิมพ์เพื่อพิมพ์ข้อมูลในรูปแบบข้อความมันทำงานได้ดีอย่างสมบูรณ์: เซลล์ผลลัพธ์จะเก็บข้อมูลการพิมพ์และเพิ่มแถวใหม่ แต่เมื่อฉันพยายามลงจุดข้อมูล (แล้วอัปเดตแบบวนซ้ำ) พล็อตจะไม่ปรากฏในเซลล์ผลลัพธ์ แต่ถ้าฉันลบลูปออกก็แค่ลงจุดครั้ง มันทำงานได้ดี

จากนั้นฉันก็ทำการทดสอบง่ายๆ:

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)

ผลลัพธ์จะไม่แสดงอะไรเลยจนกว่าฉันจะขัดจังหวะกระบวนการด้วยตนเอง (ctrl + m + i) และหลังจากที่ฉันขัดจังหวะพล็อตจะแสดงเป็นเส้นที่ทับซ้อนกันหลายบรรทัดอย่างถูกต้อง แต่สิ่งที่ฉันต้องการจริงๆคือพล็อตที่แสดงและได้รับการอัปเดตทุก ๆ 5 วินาที (หรือเมื่อใดก็ตามที่มีplot()การเรียกใช้ฟังก์ชันเช่นเดียวกับผลลัพธ์ของคำสั่งพิมพ์ที่ฉันกล่าวถึงข้างต้นซึ่งทำงานได้ดี) การแสดงแผนภูมิสุดท้ายหลังจากเซลล์เสร็จสมบูรณ์เท่านั้นไม่ใช่สิ่งที่ฉันต้องการ

ฉันพยายามที่จะเพิ่มฟังก์ชัน draw () อย่างชัดเจนหลังจากแต่ละฟังก์ชันplot()ฯลฯ ไม่ได้ผลเลย สงสัยว่าจะอัปเดตพล็อตแบบไดนามิกโดยการวนรอบ for / while ภายในเซลล์เดียวในโน้ตบุ๊ก IPython

คำตอบ:


123

ใช้IPython.displayโมดูล:

%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
นี่ไม่ใช่ตัวเลือกที่ราบรื่นพล็อตถูกสร้างขึ้นใหม่ตั้งแต่เริ่มต้นโดยมีเซลล์ขึ้นและลงระหว่าง
denfromufa

3
การเพิ่มclear_output(wait=True)จะช่วยแก้ปัญหานี้ได้ ดูคำตอบของ wabu ด้านล่าง
ahwillia

3
คุณสามารถทำได้ดีขึ้นในทุกวันนี้%matplotlib nbaggซึ่งจะทำให้คุณมีหุ่นที่เล่นได้
tacaswell

@tcaswell ฉันได้เพิ่มคำถามใหม่เพื่อถามว่าจะใช้nbaggเพื่อบรรลุเป้าหมายนี้ได้อย่างไร (ถามคุณในกรณีที่คุณสนใจที่จะตอบ) stackoverflow.com/questions/34486642/…
นาธาเนียล

3
วิธีนี้ใช้ได้ผล แต่ยังทำลายสิ่งอื่นในเซลล์เช่นมาตรการที่พิมพ์ออกมา มีวิธีเพียงแค่อัปเดตพล็อตและทำให้ทุกอย่างอยู่ในสถานที่หรือไม่?
KIC

31

คุณสามารถปรับปรุงเพิ่มเติมได้โดยเพิ่มwait=Trueไปที่clear_output:

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

1
+1. สิ่งนี้สำคัญมาก ฉันคิดว่าคำตอบของ HYRY ควรได้รับการอัปเดตด้วยข้อมูลนี้
ahwillia

5
นี่เป็นสิ่งที่ดี แต่มีผลข้างเคียงที่น่ารำคาญในการล้างผลงานพิมพ์เช่นกัน
Peter

31

การปรับปรุงสองประการเกี่ยวกับคำตอบของ HYRY :

  • โทรdisplayมาก่อนclear_outputเพื่อให้คุณจบลงด้วยพล็อตเดียวแทนที่จะเป็นสองเมื่อเซลล์ถูกขัดจังหวะ
  • จับKeyboardInterruptเพื่อไม่ให้เอาต์พุตของเซลล์ทิ้งขยะไปกับการย้อนกลับ
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
อันที่จริงdisplay.display(gcf())ควรไปก่อน display.clear_output(wait=True)
herrlich10

ขอบคุณ @csta เพิ่มแล้ว
Tom Phillips

@ herrlich10 ทำไมdisplayต้องโทรมาก่อนclear_output? คุณไม่ควรล้างผลลัพธ์ก่อนแล้วจึงแสดงข้อมูลใหม่แทนที่จะทำแบบอื่นหรือไม่?
Jakub Arnold

1
ฉันยังคงได้รับการสั่นไหวของหน้าจอด้วยการอัปเดตกราฟ แต่ก็ไม่ได้เป็นตลอด มีวิธีแก้ปัญหานี้หรือไม่?
MasayoMusic

3

การเพิ่มป้ายกำกับในโซลูชันอื่น ๆ ที่โพสต์ไว้ที่นี่จะเพิ่มป้ายกำกับใหม่ในทุกๆลูป ในการจัดการกับสิ่งนั้นให้ล้างพล็อตโดยใช้clf

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
ขอบคุณplt.clf()ผลงาน อย่างไรก็ตามจะมีการกำจัดการสั่นไหวจากการอัปเดตหรือไม่?
MasayoMusic

2

พยายามเพิ่มshow()หรือgcf().show()หลังplot()ฟังก์ชัน สิ่งเหล่านี้จะบังคับให้ตัวเลขปัจจุบันอัปเดต (gcf () ส่งคืนการอ้างอิงสำหรับรูปปัจจุบัน)


2
ขอบคุณ. gcf (). show () ยังใช้งานได้ ต้องเพิ่ม clear_output () ที่ HYRY แนะนำเพื่อแสดงสิ่งต่างๆในรูปเดียวกัน
user3236895

สิ่งนี้นอกเหนือจาก "display.display (pl.gcf ())" หรือไม่
MasayoMusic

0

คุณสามารถทำมันได้เช่นนี้ ยอมรับ x, y เป็นรายการและส่งออกพล็อตกระจายบวกแนวโน้มเชิงเส้นในพล็อตเดียวกัน

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

คุณเพียงแค่ต้องโทรlive_plot(x, y)ภายในวง นี่คือลักษณะ: ป้อนคำอธิบายภาพที่นี่

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.