วิธีที่ถูกต้องในปัจจุบันในการอัปเดตพล็อตแบบไดนามิกใน Jupyter / iPython คืออะไร


93

ในคำตอบของวิธีอัปเดตพล็อตแบบไดนามิกในลูปในโน้ตบุ๊ก ipython (ภายในเซลล์เดียว) จะมีตัวอย่างวิธีการอัปเดตพล็อตแบบไดนามิกภายในสมุดบันทึก Jupyter ภายในลูป Python อย่างไรก็ตามการทำงานนี้ทำได้โดยการทำลายและสร้างพล็อตใหม่ในการทำซ้ำทุกครั้งและความคิดเห็นในหนึ่งในเธรดตั้งข้อสังเกตว่าสถานการณ์นี้สามารถปรับปรุงได้โดยใช้%matplotlib nbaggเวทมนตร์ใหม่ซึ่งให้รูปแบบโต้ตอบที่ฝังอยู่ในสมุดบันทึก มากกว่าภาพนิ่ง

อย่างไรก็ตามnbaggฟีเจอร์ใหม่ที่ยอดเยี่ยมนี้ดูเหมือนจะไม่มีเอกสารโดยสมบูรณ์เท่าที่ฉันสามารถบอกได้และฉันไม่พบตัวอย่างวิธีใช้เพื่ออัปเดตพล็อตแบบไดนามิก ดังนั้นคำถามของฉันคือวิธีหนึ่งจะอัปเดตพล็อตที่มีอยู่ในสมุดบันทึก Jupyter / Python อย่างมีประสิทธิภาพโดยใช้แบ็กเอนด์ nbagg ได้อย่างไร เนื่องจากการอัปเดตพล็อตแบบไดนามิกใน matplotlib เป็นปัญหาที่ยุ่งยากโดยทั่วไปตัวอย่างการทำงานที่เรียบง่ายจึงเป็นตัวช่วยอย่างมาก ตัวชี้ไปยังเอกสารใด ๆ ในหัวข้อก็มีประโยชน์อย่างยิ่งเช่นกัน

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

ต่อไปนี้เป็นโค้ดที่แก้ไขเล็กน้อยจากคำตอบของคำถามที่เชื่อมโยงด้านบนซึ่งทำได้โดยการวาดรูปใหม่ทุกครั้ง ฉันต้องการบรรลุผลลัพธ์เดียวกัน แต่มีประสิทธิภาพมากขึ้นโดยใช้nbaggไฟล์.

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

คำตอบ:


62

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

%matplotlib notebook

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

def pltsin(ax, colors=['b']):
    x = np.linspace(0,1,100)
    if ax.lines:
        for line in ax.lines:
            line.set_xdata(x)
            y = np.random.random(size=(100,1))
            line.set_ydata(y)
    else:
        for color in colors:
            y = np.random.random(size=(100,1))
            ax.plot(x, y, color)
    fig.canvas.draw()

fig,ax = plt.subplots(1,1)
ax.set_xlabel('X')
ax.set_ylabel('Y')
ax.set_xlim(0,1)
ax.set_ylim(0,1)
for f in range(5):
    pltsin(ax, ['b', 'r'])
    time.sleep(1)

ฉันใส่สิ่งนี้ไว้ใน nbviewer ที่นี่

มีรุ่น IPython Widget ของnbaggว่าขณะนี้เป็นงานในความคืบหน้าในพื้นที่เก็บข้อมูล Matplotlib nbaggเมื่อที่มีอยู่ว่าอาจจะเป็นวิธีที่ดีที่สุดในการใช้งาน

แก้ไข: อัปเดตเพื่อแสดงหลายแปลง


1
เยี่ยมมากที่ดูเหมือนจะใช้งานได้ดี การขาดการโต้ตอบในขณะที่กำลังทำงานอยู่ไม่ใช่ปัญหาใหญ่สำหรับฉัน สิ่งหนึ่งที่แปลกเล็กน้อย: ถ้าฉันเปลี่ยนwhile True:เป็น for loop เมื่อลูปสิ้นสุดลงฉันจะได้ภาพคงที่สองภาพของพล็อตสุดท้ายแทนที่จะเป็น nbagg แบบโต้ตอบ มีความคิดว่าทำไม?
Nathaniel

ฉันเปลี่ยน while เป็น for loop และลองใช้บน tmpnb.org แต่ฉันไม่เห็นภาพที่สองหรือการสูญเสียการโต้ตอบ ถ่ายในที่มืด แต่คุณสามารถลองเลื่อนวงรอบการเรียกไปที่ฟังก์ชันแทนที่จะให้ลูปอยู่ในฟังก์ชัน สำหรับ f ในช่วง (10): เวลา pltsin (ax) การนอนหลับ (1)
นิวเมติกส์

3
@pneumatics น่าเสียดายที่มีปัญหาบางอย่างกับ Matplotlib 2.0 บนจอแสดงผล Retina: ในลูปพล็อตจะเล็กกว่าปกติสองเท่า
Alexander Rodin

1
ดูเหมือนว่าตัวเลขจะไม่ได้รับเวลาในการปรับขนาดตัวเองอย่างถูกต้อง ดังนั้นฉันจึงมีประสบการณ์ที่ดีขึ้นมากเมื่อใส่plt.show()และย้าย for-loop ไปยังเซลล์ถัดไป
ImportanceOfBeingErnest

2
ตรวจสอบให้แน่ใจว่าคุณมีสมุดบันทึก% matplotlib ในเซลล์สมุดบันทึก jupyter เดียวกันกับพล็อตของคุณ - ฉันใช้เวลามากกว่า 2 ชั่วโมงในวันนี้ในการแก้ไขปัญหานี้เพราะฉันมีสมุดบันทึก% matplotlib ในเซลล์แรกพร้อม
สถิติ

12

ฉันใช้ jupyter-lab และมันใช้ได้สำหรับฉัน (ปรับให้เข้ากับกรณีของคุณ):

from IPython.display import clear_output
from matplotlib import pyplot as plt
import collections
%matplotlib inline

def live_plot(data_dict, figsize=(7,5), title=''):
    clear_output(wait=True)
    plt.figure(figsize=figsize)
    for label,data in data_dict.items():
        plt.plot(data, label=label)
    plt.title(title)
    plt.grid(True)
    plt.xlabel('epoch')
    plt.legend(loc='center left') # the plot evolves to the right
    plt.show();

จากนั้นในการวนซ้ำคุณจะเติมพจนานุกรมและส่งไปที่live_plot():

data = collections.defaultdict(list)
for i in range(100):
    data['foo'].append(np.random.random())
    data['bar'].append(np.random.random())
    data['baz'].append(np.random.random())
    live_plot(data)

ตรวจสอบให้แน่ใจว่าคุณมีเซลล์สองสามเซลล์ด้านล่างพล็อตมิฉะนั้นมุมมองจะเข้าที่ทุกครั้งที่วาดพล็อตใหม่


1
สิ่งนี้จะสร้างพล็อตใหม่ทุกครั้งแทนที่จะอัปเดตพล็อตที่มีอยู่
pneumatics

2
แก้ไข. ฉันไม่พบวิธีที่ดีกว่าในการมีพล็อตแบบไดนามิกใน jupyter-lab
Ziofil

1
มีวิธีกำหนดระยะเวลารอระหว่างการทำซ้ำหรือไม่? แทนที่จะมีแค่ 'wait = True'
Ahmad Moussa

1
ทุกครั้งที่วาดพล็อตใหม่กราฟจะกะพริบ มีวิธีแก้ไขปัญหานี้หรือไม่? ฉันมีเซลล์ว่างสองสามเซลล์ใต้โครงเรื่อง แต่ดูเหมือนจะไม่ช่วยอะไร
MasayoMusic

@MasayoMusic ดู "การกะพริบและการกระโดด" ในbuildmedia.readthedocs.org/media/pdf/ipywidgets/latest/…
สิงห์

0

ฉันได้ปรับคำตอบ @Ziofil และแก้ไขให้ยอมรับ 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.