2019年10月6日日曜日



https://yolo.love/matplotlib/mplot3d/  を参照


3Dグラフをmatplotlibのmplot3dで作成する方法

今回はmatplotlibで3Dグラフを作成する方法を紹介していきます。matplotlibでは3Dグラフを生成することもできます。mplot3dが用意されており、3Dの散布図や等高線プロットなどを描画できます。
公式のチュートリアルがよくまとまっているので、詳細はこちらでご覧ください。本記事も公式を参考に進めていきます。
参考mplot3d tutorialMatplotlib

mplot3dの下準備

まずはインポート部分から見ていきましょう。一般的なmatplotlibのインポート(import matplotlib.pyplot as plt)に加えて、Axes3Dをインポートします。
空間だけ描画すると以下のようになります。ここにこれから描画していきましょう!
 Python
%matplotlib inline
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D

fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
 注意
Axes3Dを使用していないように見えますが、ここでインポートされていないとKeyError: ‘3D’が出力されるので、要注意です。

Line plotsを描画してみる

先ほどの空間にline plotsを描画してみると、以下のようになります。parametric curveというみたいですね。
 Python
%matplotlib inline
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
import matplotlib as mpl

mpl.rcParams['legend.fontsize'] = 10

fig = plt.figure()
ax = fig.gca(projection='3d')
theta = np.linspace(-4 * np.pi, 4 * np.pi, 100)
z = np.linspace(-2, 2, 100)
r = z**2 + 1
x = r * np.sin(theta)
y = r * np.cos(theta)
ax.plot(x, y, z, label='parametric curve')
ax.legend()

plt.show()

Scatter plotsを描画してみる

散布図を3D上に表示することもできます。
 Python
%matplotlib inline
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D

def randrange(n, vmin, vmax):
return (vmax - vmin)*np.random.rand(n) + vmin

fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')

n = 100
for c, m, zlow, zhigh in [('r', 'o', -50, -25), ('b', '^', -30, -5)]:
xs = randrange(n, 23, 32)
ys = randrange(n, 0, 100)
zs = randrange(n, zlow, zhigh)
ax.scatter(xs, ys, zs, c=c, marker=m)

ax.set_xlabel('X Label')
ax.set_ylabel('Y Label')
ax.set_zlabel('Z Label')

plt.show()

Surface plotsを描画してみる

surface plotsは以下のようなグラフになります。
 Python
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
from matplotlib import cm
from matplotlib.ticker import LinearLocator, FormatStrFormatter

fig = plt.figure()
ax = fig.gca(projection='3d')

X = np.arange(-5, 5, 0.25)
Y = np.arange(-5, 5, 0.25)
X, Y = np.meshgrid(X, Y)
R = np.sqrt(X**2 + Y**2)
Z = np.sin(R)

surf = ax.plot_surface(X, Y, Z, cmap=cm.coolwarm,
                       linewidth=0, antialiased=False)

ax.set_zlim(-1.01, 1.01)
ax.zaxis.set_major_locator(LinearLocator(10))
ax.zaxis.set_major_formatter(FormatStrFormatter('%.02f'))

fig.colorbar(surf, shrink=0.5, aspect=5)

plt.show()

まとめ

様々な3Dプロットを見てきましたが、他にもたくさんの3Dグラフを描画できます。公式のページにはサンプルコード付きですべて載っているので、ぜひ見てみてください!
参考mplot3d tutorialMatplotlib
また、Numpyの知識も必要になると思うので、関連記事をこちらに載せておきます。ぜひチェックしてみてください!
numpyのrandomで生成できる乱数を総まとめ

2D リアルタイムグラフ描画 python その2



matplotlibでリアルタイム描画

この記事は最終更新日から3年以上が経過しています。

モチベーション

センサーとかの値を確認したり,機械学習の学習状況とかそんなんをリアルタイムにグラフにプロットしながら見たいときがある.
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()を使おう!!!

2D グラフ リアルタイム表示



2019年07月10日に更新

PythonでGUI画面とリアルタイムグラフ表示する

前提

急にGUIを作れと言われた。ボタンとかでいろいろ制御できるリアルタイムグラフ描画をしたいが、性能は問われない。
gnuplot触ったことないし、C#もよくわからんが、Pythonは触ったことあるのでmatplotlibを使ってみる。
難しいこととか変な(?)ライブラリへの依存はしたくないのでPython3系のtkinterを使う。
表示したいのは以下。
  • 折れ線グラフ複数
  • カラーマップと対応するカラーバー
  • 制御用のボタンとか
事前にpip install numpy matplotlibしておく必要がある。
(Ubuntuの場合はその前にsudo apt install python3-pip python3-tkしておく)

詳細

最初の一歩

ボタンとグラフを同時に表示する必要があるので、matplotlib.orgの検索窓にでtkinterと入れてみる。
するとEmbedding in Tkが一番上にある。
それから、リアルタイム描画ということでアニメーションする必要があるので、同様にanimationと入れてみる。
すると、今度は少し下のほうにAnimated line plotが見つかる。
今回はボタンなどを配置しつつアニメーションしたいので上記二つを組み合わせる必要がある。

Animated plot in Tk

Embedding in TkAnimated line plotを合体して、少し整理した。
#!/usr/bin/env python3


# https://matplotlib.org/gallery/user_interfaces/embedding_in_tk_sgskip.html
# https://matplotlib.org/gallery/animation/simple_anim.html


import tkinter

from matplotlib.backends.backend_tkagg import (
    FigureCanvasTkAgg, NavigationToolbar2Tk)
from matplotlib.figure import Figure
import matplotlib.animation as animation

import numpy as np


def _quit():
    root.quit()     # stops mainloop
    root.destroy()  # this is necessary on Windows to prevent
                    # Fatal Python Error: PyEval_RestoreThread: NULL tstate


def init():  # only required for blitting to give a clean slate.
    line.set_ydata(np.sin(x))
    return line,


def animate(i):
    line.set_ydata(np.sin(x + i))  # update the data.
    return line,


root = tkinter.Tk()
root.wm_title("Embedding in Tk anim")

fig = Figure()
# FuncAnimationより前に呼ぶ必要がある
canvas = FigureCanvasTkAgg(fig, master=root)  # A tk.DrawingArea.

x = np.arange(0, 3, 0.01)  # x軸(固定の値)
l = np.arange(0, 8, 0.01)  # 表示期間(FuncAnimationで指定する関数の引数になる)
plt = fig.add_subplot(111)
plt.set_ylim([-1.1, 1.1])
line, = plt.plot(x, np.sin(x))

ani = animation.FuncAnimation(fig, animate, l,
    init_func=init, interval=10, blit=True,
    )

toolbar = NavigationToolbar2Tk(canvas, root)
canvas.get_tk_widget().pack()

button = tkinter.Button(master=root, text="Quit", command=_quit)
button.pack()

tkinter.mainloop()
ボタンとかは、普通にtkinterで配置できる。

見た目

Embedding_in_Tk_anim.gif

注意点

  • animation.FuncAnimation()で返ってくるオブジェクト(上記コードではani)の参照がない(?)とグラフが更新されないことがある。
    クラスにした場合は、self.aniとかに格納して大事に持っておく必要がある。
    (上記コードでは、ani = ...がないとだめかもしれない。)
  • set_ydata()とかset_data()では、データ以外の表示は更新されない。
    Y軸範囲を自動追従したい場合とかは、自前でset_ylim()する必要がある。
  • blit=Trueだとグラフが更新されない(軸ラベルだけの更新とかが反映されない)ことがある。
    ボタンでX軸表示モード変えたいのに変わらない時はblit=Falseにしてみるといいかもしれない。

python 3D



https://qiita.com/orange_u/items/8a1e285a45093857aef7  を参照

Python 3:3次元グラフの書き方(matplotlib, pyplot, mplot3d, MPL)

この記事は最終更新日から1年以上が経過しています。

3次元のグラフの書き方

ニューラルネットワークの学習で現れる,偏微分(勾配)の理解のため3次元グラフを描いてみる.(参考:数値微分)
Pythonで,NumPyとmatplotlibを使って3次元グラフを描く

準備

  • 3次元なのでmpl_toolkits.mplot3dなどをインポート
ex1-1.py
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
import numpy as np
  • 引数の2乗和を計算する関数を例として考える
ex1-2.py
def func1(x, y):
    return x**2 + y**2
  • 描写データの作成
    • 3次元で描写するには2次元メッシュが必要
    • 2次元配列をarangeを用いて作る
    • x, y をそれぞれ1次元領域で分割する
ex1-3.py
x = np.arange(-3.0, 3.0, 0.1)
y = np.arange(-3.0, 3.0, 0.1)
  • 2次元メッシュはmeshgridでつくる
    • Xの行にxの行列を,Yは列にyの配列を入れたものになっている
ex1-3.py
X, Y = np.meshgrid(x, y)
Z = func1(X, Y)
  • グラフの作成
    • figureで2次元の図を生成する
    • その後,Axes3D関数で3次元にする
ex1-4.py
fig = plt.figure()
ax = Axes3D(fig)
  • 軸ラベルの設定
ex1-5.py
ax.set_xlabel("x")
ax.set_ylabel("y")
ax.set_zlabel("f(x, y)")
-グラフ描写
ex1-6.py
ax.plot_wireframe(X, Y, Z)
plt.show()

以上をまとめて実装すれば,以下のような3次元のグラフが描画されます.


ex1.png

plotのプロパティとして,color(線の色),linestyle(線の種類),マーカーの種類などが変更できる.