web-dev-qa-db-ja.com

Jupyter Notebookでmatplotlibを使用して動的に変化するグラフをプロットする

M x N 2D配列があります:i番目の行は、時間iでのNポイントの値を表します。

ポイント[配列の1行]をグラフの形式で視覚化し、小さな間隔の後に値が更新されるようにします。したがって、グラフには一度に1つの行が表示され、その後、値が次の行に更新され、以下同様に続きます。

これをjupyterノートブックで行いたいです。参照コードを探しています。

私は次のことを試みましたが、成功しませんでした:

23
Anuj Gupta
6
Anuj Gupta

代替の、おそらくより簡単なソリューションを次に示します。

%matplotlib notebook
import numpy as np
import matplotlib.pyplot as plt

m = 100
n = 100
matrix = np.random.normal(0,1,m*n).reshape(m,n)

fig = plt.figure()
ax = fig.add_subplot(111)
plt.ion()

fig.show()
fig.canvas.draw()

for i in range(0,100):
    ax.clear()
    ax.plot(matrix[i,:])
    fig.canvas.draw()
44
Graham S

1つのスレッドがデータをポンピングし、Jupyterノートブックが何もブロックせずにグラフを更新し続けるシナリオの良い答えを特に探していました。約12個ほどの関連する回答を調べた結果、次のような結果が得られました。

注意

ライブグラフが必要な場合は、以下のマジックを使用しないでください。ノートブックが以下を使用している場合、グラフの更新は機能しません。

%load_ext autoreload
%autoreload 2

Matplotlibをインポートする前に、ノートブックで以下の魔法が必要です:

%matplotlib notebook

方法1:FuncAnimationの使用

これには、データがまだ更新されていない場合でもグラフが更新されるという欠点があります。以下の例は、JupyterノートブックがFuncAnimationを介してグラフを更新している間にデータを更新する別のスレッドを示しています。

%matplotlib notebook

from matplotlib import pyplot as plt
from matplotlib.animation import FuncAnimation
from random import randrange
from threading import Thread
import time

class LiveGraph:
    def __init__(self):
        self.x_data, self.y_data = [], []
        self.figure = plt.figure()
        self.line, = plt.plot(self.x_data, self.y_data)
        self.animation = FuncAnimation(self.figure, self.update, interval=1000)
        self.th = Thread(target=self.thread_f, daemon=True)
        self.th.start()

    def update(self, frame):
        self.line.set_data(self.x_data, self.y_data)
        self.figure.gca().relim()
        self.figure.gca().autoscale_view()
        return self.line,

    def show(self):
        plt.show()

    def thread_f(self):
        x = 0
        while True:
            self.x_data.append(x)
            x += 1
            self.y_data.append(randrange(0, 100))   
            time.sleep(1)  

g = LiveGraph()
g.show()

方法2:直接更新

2番目の方法は、データが別のスレッドから到着したときにグラフを更新することです。 matplotlibはスレッドセーフではありませんが、更新を行うスレッドが1つしかない限り機能するように見えるため、これは危険です。

%matplotlib notebook

from matplotlib import pyplot as plt
from matplotlib.animation import FuncAnimation
from random import randrange
from threading import Thread
import time

class LiveGraph:
    def __init__(self):
        self.x_data, self.y_data = [], []
        self.figure = plt.figure()
        self.line, = plt.plot(self.x_data, self.y_data)

        self.th = Thread(target=self.thread_f, daemon=True)
        self.th.start()

    def update_graph(self):
        self.line.set_data(self.x_data, self.y_data)
        self.figure.gca().relim()
        self.figure.gca().autoscale_view()

    def show(self):
        plt.show()

    def thread_f(self):
        x = 0
        while True:
            self.x_data.append(x)
            x += 1
            self.y_data.append(randrange(0, 100))  

            self.update_graph()

            time.sleep(1)  


from live_graph import LiveGraph

g = LiveGraph()
g.show()
3
Shital Shah

私はこれを調査し、主に自己文書化された以下を作成しました。

import matplotlib.pyplot as plt
%matplotlib notebook

print('This text appears above the figures')
fig1 = plt.figure(num='DORMANT')
print('This text appears betweeen the figures')
fig2 = plt.figure()
print('This text appears below the figures')

fig1.canvas.set_window_title('Canvas active title')
fig1.suptitle('Figure title', fontsize=20)

# Create plots inside the figures
ax1 = fig1.add_subplot(111)
ax1.set_xlabel('x label')
ax2 = fig2.add_subplot(111)

# Loop to update figures
end = 40
for i in range(end):
    ax2.cla()  # Clear only 2nd figure's axes, figure 1 is ADDITIVE
    ax1.set_title('Axes title')  # Reset as removed by cla()

    ax1.plot(range(i,end), (i,)*(end-i))
    ax2.plot(range(i,end), range(i,end), 'rx')
    fig1.canvas.draw()
    fig2.canvas.draw()
1
Tom Hale

@ 0aslam0に加えて、 here のコードを使用しました。私は、次のたびに次の行を取得するようにアニメーション関数を変更しました。 N個すべてのポイントのアニメーション化された進化(Mステップ)を描画します。

from IPython.display import HTML
import numpy as np
from matplotlib import animation
N = 5
M = 100
points_evo_array = np.random.Rand(M,N)

# First set up the figure, the axis, and the plot element we want to animate
fig = plt.figure()
ax = plt.axes(xlim=(0, M), ylim=(0, np.max(points_evo_array)))
lines = []

lines = [ax.plot([], [])[0] for _ in range(N)]

def init():    
    for line in lines:
        line.set_data([], [])
    return lines

def animate(i):
    for j,line in enumerate(lines):
        line.set_data(range(i), [points_evo_array[:i,j]])
    return lines

# call the animator.  blit=True means only re-draw the parts that have changed.
anim = animation.FuncAnimation(fig, animate,np.arange(1, M), init_func=init, interval=10, blit=True)

HTML(anim.to_html5_video())

それが役立つことを願っています

1
segevara

リアルタイムプロット/ロギングデータ( joystick )を扱うライブラリを次に示しますが、jupyterで動作するかどうかはわかりません。通常の_pip install joystick_を使用してインストールできます。

データの詳細なしに実用的なソリューションを作成するのは困難です。オプションは次のとおりです。

_import joystick as jk
import numpy as np

class test(jk.Joystick):
   # initialize the infinite loop decorator
    _infinite_loop = jk.deco_infinite_loop()

    def _init(self, *args, **kwargs):
        """
        Function called at initialization, see the docs
        """
        # INIT DATA HERE
        self.shape = (10, 4) # M, N
        self.data = np.random.random(self.shape)
        self.xaxis = range(self.shape[1])
        ############
        # create a graph frame
        self.mygraph = self.add_frame(
                   jk.Graph(name="TheName", size=(500, 500), pos=(50, 50),
                            fmt="go-", xnpts=self.shape[1], freq_up=5, bgcol="w",
                            xylim=(0, self.shape[1]-1, None, None)))

    @_infinite_loop(wait_time=0.5)
    def _generate_fake_data(self):  # function looped every 0.5 second
        """
        Loop starting with the simulation start, getting data and
        pushing it to the graph every 0.5 seconds
        """
        # NEW (RANDOM) DATA
        new_data = np.random.random(self.shape[1])
        # concatenate data
        self.data = np.vstack((self.data, new_data))
        # Push new data to the graph
        self.mygraph.set_xydata(self.xaxis, self.data[-1])

t = test()
t.start()

t.stop()
t.exit()
_

このコードは、1秒に5回自動更新されるグラフ(freq_up = 5)を作成し、新しいデータは(ランダムに)0.5秒ごとに生成され(wait_time = 0.5)、表示のためにグラフにプッシュされます。

Y軸を小刻みに動かしたくない場合は、t.mygraph.xylim = (0, t.shape[1]-1, 0, 1)と入力します。

0
Guillaume S