EurekaMoments

ロボットや自動車の自律移動に関する知識や技術、プログラミング、ソフトウェア開発について勉強したことをメモするブログ

JuliaとMatplotlibでグラフを作る際のハマりポイントとサンプルプログラム集

目次

目的

  • プログラミング言語Juliaと、Pythonのグラフ描画ライブラリであるMatplotlibを組み合わせたグラフ作成の方法についてまとめる。
  • グラフを作成するための準備の中でハマったポイント、その対処方法についてメモしておく。
  • 基本的な各種グラフを作るためのサンプルプログラムをまとめておく。

f:id:sy4310:20200905155935p:plain

JuliaのPlotsではなくMatplotlibを使う理由

  • Matplotlibでグラフを表示させた時のGUIが便利
  • Plotsだとグラフをスタンドアローンのウィンドウで表示させる際の挙動が不安定
  • Matplotlibなら設定やコードの書き方が少し面倒になるが、確実に動いてくれる

JuliaからMatplotlibを使えるようにするための設定手順

1. Pythonのインストール

  • Matplotlibを使えるようにするためにPythonをインストールする
  • 自分はPythonもメインで使うので、各種ライブラリがほぼ揃っているAnacondaでインストールした
  • Anacondaのインストール手順は下記を参照

sukkiri.jp

www.anaconda.com

2. JuliaにPyCallとMatplotlibをインストール

  • JuliaからPythonを呼び出すためのパッケージ
  • JuliaにはデフォルトでPython2環境が導入されているが、これをPython3に切り替えておく
  • 下記の記事を参考に、PyCallのインストール前にJuliaのREPLからENV["CONDA_JL_VERSION"]=3を実行しておく

qiita.com

  • 上記の設定が済んだら、下記の記事を参考にJuliaのREPLからPyCallとMatplotlibをインストールする

qiita.com

3. エラー "could not find or load the Qt platform plugin windows"が出た時の対処法

  • 1~2の手順まで完了すれば基本的にはグラフが作成できるようになるが、人によっては上記のエラーメッセージが出てグラフが作れないことがある
  • この場合は、下記を参考にグラフのGUIを形成するのに使われるQtプラグインを正しく読み込むように環境変数を設定する必要がある

qiita.com

stackoverflow.com

サンプルプログラム集

JuliaプログラムからのMatplotlib呼び出し

  • PyCallが持つマクロの@pyimportを使う
  • 下記のようにPythonライクな書き方でMatplotlibをインポートできる
  • ただし、"from hoge import fuga"のような書き方は出来ない
  • この場合は、"@pyimport hoge.fuga as fuga"のように書く
using PyCall
@pyimport matplotlib.pyplot as plt

2次元線グラフ

x = range(0, 2pi, length=100)
fig = plt.figure()
ax = fig.add_subplot(1, 1, 1)
ax.plot(x, sin.(x), "-", c="b", ms=10)
ax.set_xlabel("X")
ax.set_ylabel("Y")
ax.set_title("2D Line Plot Sample")
ax.grid(true)
plt.show()

f:id:sy4310:20200905213217p:plain

2次元点グラフ

x = range(0, 2pi, length=100)
fig = plt.figure()
ax = fig.add_subplot(1, 1, 1)
ax.plot(x, cos.(x), ".", c="b", ms=10)
ax.set_xlabel("X")
ax.set_ylabel("Y")
ax.set_title("2D Point Plot Sample")
ax.grid(true)
plt.show()

f:id:sy4310:20200905213626p:plain

2次元アニメーション

# data
x = range(0, 2pi, length=100)
y = sin.(x)

# figure
fig = plt.figure()
ax = fig.add_subplot(1, 1, 1)
pxy, = ax.plot([], [], ".", c="b", ms=10)
ax.set_xlabel("X")
ax.set_ylabel("Y")
ax.set_xlim([0.0, 7.0])
ax.set_ylim([-1.0, 1.0])
ax.grid(true)

# animation
for i in 1:length(x)
    if show_plot == true
        pxy.set_data(x[1:i], y[1:i])
        plt.pause(0.001)
    end
end

plt.show()

f:id:sy4310:20200906094108g:plain

アニメーションのGIFファイル作成

  • まずは上記のアニメーションを1フレームずつPNGファイルで保存していく
  • 各ファイル名は、1始まりの連番.pngとなるようにする
# data
x = range(0, 2pi, length=100)
y = sin.(x)

# image number
im_num = 0

# figure
fig = plt.figure()
ax = fig.add_subplot(1, 1, 1)
pxy, = ax.plot([], [], ".", c="b", ms=10)
ax.set_xlabel("X")
ax.set_ylabel("Y")
ax.set_xlim([0.0, 7.0])
ax.set_ylim([-1.0, 1.0])
ax.grid(true)

# animation
for i in 1:length(x)
    if show_plot == true
        pxy.set_data(x[1:i], y[1:i])
        i_num += 1 # update image number
        plt.savefig(string(im_num, ".png")) # save each frame as png file
        plt.pause(0.001)
    end
end

plt.show()
  • 画像ファイルを扱うためのPythonライブラリであるPillowをインストールする
  • インストール方法は、先述したMatplotlibと同様
  • インストールしたら、Pillowライブラリの一つであるImageモジュールをインポートする
using PyCall
@pyimport matplotlib.pyplot as plt
@pyimport PIL.Image as Image
  • Imageモジュールで保存したPNGファイルを一枚ずつ読み込み配列に格納する
  • 画像配列をまとめてGIFファイルに変換する関数
function create_gif(im_num)
    images = []
    if im_num > 0
        for num in 1:im_num
            im_name = string(num, ".png")
            im = Image.open(im_name)
            push!(images, im)
        end
        images[1].save("animation_2d_sample.gif",
                            save_all=true,
                            append_images=images[1:end],
                            loop=0,
                            duration=60)
    end
end
  • 保存したPNGファイルが必要なければ、こちらの関数でまとめて削除する
function delete_png(im_num)
    if im_num > 0
        for num in 1:im_num
            im_name = string(num, ".png")
            rm(im_name)
        end
    end
end

複数グラフの重ね合わせ

x = range(0, 2pi, length=100)
fig = plt.figure()
ax = fig.add_subplot(1, 1, 1)
ax.plot(x, sin.(x), "-", c="b", ms=10, label="sin")
ax.plot(x, cos.(x), ".", c="r", ms=10, label="cos")
ax.set_xlabel("X")
ax.set_ylabel("Y")
ax.set_title("2D Over Plot Sample")
ax.grid(true)
ax.legend()
plt.show()

f:id:sy4310:20200905213756p:plain

複数グラフを1つのFigureに並べて表示

x = range(-2, 2, length=100)
fig = plt.figure()
for i in 1:6
    ax = fig.add_subplot(2, 3, i)
    ax.plot(x, x.^i, "-", c="c", ms=10)
    ax.set_xlabel("X")
    ax.set_ylabel("Y")
    ax.set_title("\$y = x^$(i)\$")
    ax.grid(true)
end
fig.tight_layout()

f:id:sy4310:20200906102123p:plain

2次元散布図

x = rand(100)
y = x.^2 + randn(100).* abs.(x) * 0.5
fig = plt.figure()
ax = fig.add_subplot(1, 1, 1)
ax.scatter(x, y, marker="*", s=13)
ax.set_xlabel("X")
ax.set_ylabel("Y")
ax.set_title("2D Scatter Sample")
ax.grid(true)
plt.show()

f:id:sy4310:20200905224926p:plain

ヒストグラム

x = vcat(randn(100), 2 * randn(100).+ 4)
fig = plt.figure()
ax = fig.add_subplot(1, 1, 1)
ax.hist(x, bins=30, color="g")
ax.set_title("Histgram Sample")
ax.grid(true)
plt.show()

f:id:sy4310:20200905231250p:plain

円グラフ

x = 10:10:40
labels = ["A", "B", "C", "D"]
colors = ["r", "g", "b", "m"]
fig = plt.figure()
ax = fig.add_subplot(1, 1, 1)
ax.pie(x, labels=labels, colors=colors, autopct="%1.1f%%", counterclock=true, startangle=90)
ax.legend(labels, fontsize=12, loc=1)
ax.set_title("Pie Chart Sample")
plt.show()

f:id:sy4310:20200905231352p:plain

3次元グラフのためのpyimport

using PyCall
@pyimport matplotlib.pyplot as plt
@pyimport mpl_toolkits.mplot3d as mpl3

3次元点グラフ

x = randn(100)
y = randn(100)
z = randn(100)
fig = plt.figure()
ax = fig.add_subplot(1, 1, 1, projection="3d")
ax.plot(x, y, z, "o", color="r", ms=8)
ax.set_xlabel("X")
ax.set_ylabel("Y")
ax.set_zlabel("Z")
ax.set_title("3D Point Plot Sample")
ax.grid(true)
plt.show()

f:id:sy4310:20200905233817p:plain

3次元線グラフ

x = 1:5
y = 1:5
z = 1:5
fig = plt.figure()
ax = fig.add_subplot(1, 1, 1, projection="3d")
ax.plot(x, y, z, "o-", color="r", ms=5)
ax.set_xlabel("X")
ax.set_ylabel("Y")
ax.set_zlabel("Z")
ax.set_title("3D Line Plot Sample")
ax.grid(true)
plt.show()

f:id:sy4310:20200905233911p:plain

GitHub

各サンプルプルプログラムは全て下記のGitHubリポジトリで公開済み。

github.com