334
317

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

matplotlibでリアルタイム描画

Last updated at Posted at 2015-08-04

モチベーション

センサーとかの値を確認したり,機械学習の学習状況とかそんなんをリアルタイムにグラフにプロットしながら見たいときがある.
pythonにはmatplotlibっていう便利なグラフ作成ライブラリがあるのでこれを使いたい.

既知の問題とか

普通matplotlibでグラフを作るときは

import matplotlib.pyplot as plt

"""
plotしたいデータを計算する処理
...
"""
plt.plot(data)
plt.show()

とかやる.
だけど,show()を呼ぶとプログラムがそこでブロックされてリアルタイムな描画ができない.
調べてみるとshow()ではなくてdraw()を使おう!みたいな記事とか,Tkinter(tkinter)とかQtとかのGUIライブラリと組み合わせた方法とかがでてくるんだけど,Windows環境だとグラフに一度でも触るとGUIが固まったりしてとてもじゃないけど使えなかったりした.
(たしかMacとかのUnix環境だったら使えたような気がする.)

pause()を使おう!!!

例の如くstackoverflowにそれ関係のやりとりがあった.
参考: real-time plotting in while loop with matplotlib

結論はplt.show()の代わりにplt.pause(interval)を使うということ.
下に簡単なsin関数を永遠にplotする例を載っける.

注意点などはコメントに書いたので,読んでください.

matplotlib_realtime_plot_example.py
# -*- coding: utf-8 -*-
"""
matplotlibでリアルタイムプロットする例

無限にsin関数をplotし続ける
"""
from __future__ import unicode_literals, print_function

import numpy as np
import matplotlib.pyplot as plt


def pause_plot():
    fig, ax = plt.subplots(1, 1)
    x = np.arange(-np.pi, np.pi, 0.1)
    y = np.sin(x)
    # 初期化的に一度plotしなければならない
    # そのときplotしたオブジェクトを受け取る受け取る必要がある.
    # listが返ってくるので,注意
    lines, = ax.plot(x, y)

    # ここから無限にplotする
    while True:
        # plotデータの更新
        x += 0.1
        y = np.sin(x)

        # 描画データを更新するときにplot関数を使うと
        # lineオブジェクトが都度増えてしまうので,注意.
        #
        # 一番楽なのは上記で受け取ったlinesに対して
        # set_data()メソッドで描画データを更新する方法.
        lines.set_data(x, y)

        # set_data()を使うと軸とかは自動設定されないっぽいので,
        # 今回の例だとあっという間にsinカーブが描画範囲からいなくなる.
        # そのためx軸の範囲は適宜修正してやる必要がある.
        ax.set_xlim((x.min(), x.max()))

        # 一番のポイント
        # - plt.show() ブロッキングされてリアルタイムに描写できない
        # - plt.ion() + plt.draw() グラフウインドウが固まってプログラムが止まるから使えない
        # ----> plt.pause(interval) これを使う!!! 引数はsleep時間
        plt.pause(.01)

if __name__ == "__main__":
    pause_plot()

これで色々捗る!!!

おまけ

上で載っけたstackoverflowにdrawnowというパッケージを使った方法も載っているので紹介する.
drawnowpipで入るので

$ pip install drawnow

でOK.

使い方

matplotlib_drawnow_realtime_plot_example.py
# -*- coding: utf-8 -*-
"""
matplotlibでリアルタイムプロットする例

無限にsin関数をplotし続ける
"""
from __future__ import unicode_literals, print_function

import numpy as np
import matplotlib.pyplot as plt
from drawnow import drawnow, figure

def drawnow_plot():
    # drawnowパッケージに含まれているfigure関数を使って
    # figureオブジェクトを作る
    fig = figure()
    x = np.arange(-np.pi, np.pi, .1)
    y = np.sin(x)

    def draw():
        """
        drawnow関数に渡すplotに必要な処理を記述
        plotに必要な変数はこの関数がアクセスできるスコープの変数にしておく
        """
        plt.plot(x, y)

    while True:
        x += .1
        y = np.sin(x)
        drawnow(draw)

...書いてからソースコード見てみたが,drawnowは結局中でdraw()を呼んでるみたいで,Windowsでやると上手く行かなかった(GUIが固まる現象)...

結論

リアルタイムにプロットしたいときはplt.pause()を使おう!!!

334
317
5

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
334
317

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?