Plots.jl入門
はじめに
juliapackages.comによると, Juliaの最もポピュラーな可視化パッケージはPlots.jlです. しかし, 公式のチュートリアルやサンプルがあまり分かりやすいとは感じられませんでした. そこで, さらにシンプルに, できるだけ簡単な例を通して, Plots.jlの最初の一歩を踏み出すためのノートを作成しました.
インストール
Juliaのパッケージモードでadd Plots
を実行し, 事前にPlots.jlをインストールしておく必要がある. また, ノート上ではusing Plots
を宣言する.
# using Pkg
# Pkg.add("Plots")
using Plots
Hello World!
plot()
に関数名を渡すことで描写できる. 特に指定しなければ(かなり滑らかな)折れ線グラフになる.
plot(sin)
自作関数を渡すこともできる. 関数の宣言方法はこちらを参考にするとよい.
f(x) = x^2
plot(f)
1行で書きたい時は無名関数(Anonymous Function)を渡す.
plot(x->x^2)
2つの配列を渡して, それぞれx軸とy軸の値として折れ線グラフや散布図を描くこともできる.
X = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
Y = [0, 1, 0, 2, 0, 4, 0, 8, 0, 4, 4]
plot(X, Y)
追加オプション
タイトルや軸ラベル, マーカーや線の色などを変更したい場合は以下のオプションを書き加えればよい. 以下の紹介するものはごく一部で, こちらに全て載っている.
文字列
説明 | 省略形 | オプション | 引数例 |
---|---|---|---|
タイトル | title | "", "hello" | |
凡例 | label | "", "hello" | |
x軸ラベル | xlabel | "", "hello" | |
y軸ラベル | ylabel | "", "hello" | |
タイトルのフォントサイズ | titlefontsize | 12, 18 | |
凡例のフォントサイズ | legendfontsize | 12, 18 | |
軸の数字のフォントサイズ | tickfontsize | 12, 18 | |
軸ラベルのフォントサイズ | guidefont | 12, 18 | |
x軸ラベルのフォントサイズ | xguidefont | 12, 18 | |
y軸ラベルのフォントサイズ | yguidefont | 12, 18 |
軸
説明 | 省略形 | オプション | 引数例 |
---|---|---|---|
枠線と軸 | framestyle | :box, :semi, :origin, :zerolines, :grid :none | |
x軸の表示 | xshowaxis | true, false | |
y軸の表示 | yshowaxis | true, false | |
x軸の描写範囲 | xlims | (-1,1), (0,2π) | |
y軸の描写範囲 | ylims | (-1,1), (0,2π) | |
x軸のスケール | xscale | :log10, :ln, :log2 | |
y軸のスケール | yscale | :log10, :ln, :log2 | |
x軸の目盛り位置 | xticks | 0:0.1:2, [1,3,4] | |
y軸の目盛り位置 | yticks | 0:0.1:2, [1,3,4] | |
x軸のグリッド線 | xgrid | true, false | |
y軸のグリッド線 | ygrid | true, false | |
x軸のマイナーグリッド線 | xminorgrid | true, false | |
y軸のマイナーグリッド線 | yminorgrid | true, false |
デザイン
説明 | 省略形 | オプション | 引数例 |
---|---|---|---|
グラフの種類 | st | seriestype | :line, :scatter, :steppre, etc. |
線の種類(実線, 破線等) | ls | linestyle | :solid, :dash, :dot, etc. |
線の透明度 | la | linealpha | 0.0, 0.2, 0.5, 1.0 |
線の太さ | lw | linewidth | 1, 2, 4 |
線の色 | lc | linecolor | :red, :green, :blue, "#FF0000" |
塗潰しの透明度 | fa | fillalpha | 0.0, 0.2, 0.5, 1.0 |
塗潰しの色 | fc | fillcolor | :red, :green, :blue, "#FF0000" |
マーカーの形 | markershape | :circle, :square, :hexagon, etc. | |
マーカーの大きさ | ms | markersize | 20 |
マーカーの透明度 | markeralpha | 0.0, 0.2, 0.5, 1.0 | |
マーカーの色 | mc | markercolor | :red, :green, :blue, "#FF0000" |
マーカーの囲み線の太さ | msw | markerstrokewidth | 1, 2, 4 |
マーカーの囲み線の透明度 | markerstrokealpha | 0.0, 0.2, 0.5, 1.0 | |
マーカーの囲み線の色 | msc | markerstrokecolor | :red, :green, :blue, "#FF0000" |
マーカーの囲み線の種類(実線, 破線等) | markerstrokestyle | :solid, :dot | |
凡例の位置 | legend | :bottomleft, :topright, ect. | |
凡例の背景の色 | background_color_legend | :red, "#FF0000", nothing | |
凡例の枠線の色 | foreground_color_legend | :red, "#FF0000", nothing |
基本的な文字列の指定と, 配色の指定について例を示す.
plot(sin, title="title", label="label", xlabel="x", ylabel="y", lw=10, lc="#00C8AF", foreground_color_legend=:red)
定義域と描写範囲
関数を描写する場合 の定義域とサンプル間隔は-1:0.01:1
のように指定する. 描写範囲についてはxlims=(min,max)
とylims=(min,max)
をそれぞれ指定する. 片方だけ指定してもよい. 配列を描写する場合, サンプル数の指定は不要なのでplot(X, Y, xlims=(-2*pi,2*pi), ylims=(-0.5,1))
のように指定すればよい.
plot(-5:0.01:5, sin, xlims=(-2*pi,2*pi), ylims=(-0.5,1))
散布図
散布図はplot()
にst=:scatter
というオプションを追加するか, scatter()
を用いる. 基本的な使い方はplot()
と同じである.
plot(sin, st=:scatter)
scatter(sin)
ヒストグラム
配列を渡すことで要素についてのヒストグラムを描くことができる. 下記ではnormed=true
のオプションによって正規化された(総面積が1の)ヒストグラムを描いている.
X = [1, 2, 3, 3, 4, 5, 5]
histogram(X, bins=range(0, 6, step=0.2), normed=true)
一様分布の例:
X = rand(10000)
histogram(X, bins=range(0, 1, step=0.02), normed=true)
正規分布の例:
X = randn(10000)
histogram(X, bins=range(-5, 5, step=0.2), normed=true)
2つの配列を渡して, 2次元ヒストグラムを描写することもできる. c=:heat
のように配色を指定できる. 配色についてはこちらを参照されたい.
X = randn(1000)
Y = randn(1000)
histogram2d(X, Y, nbins=20, c=:heat)
ヒートマップ
x軸とy軸それぞれの定義域と, 2変数関数f
を渡せばよい. c=:thermal
のように配色を指定できる. 配色についてはこちらを参照されたい.
f(x,y) = x^2 + y^2
heatmap(-3:0.01:3, -2:0.01:2, f, c=:thermal)
2次元配列を渡すこともでてきる.
Z = randn(20,20)
heatmap(Z)
X軸とY軸に相当する1次元配列を渡すこともできる.
X = [0.1*i for i in 0:20]
Y = [0.1*i for i in 0:20]
Z = randn(21,21)
heatmap(X, Y, Z)
3Dグラフ
基本的な使い方は上記のheatmap
をsurface
に置き換えるだけである.
f(x,y) = x^2 + y^2
surface(-3:0.01:3, -2:0.01:2, f, c=:thermal)
Z = randn(21,21)
surface(Z)
多変数関数
多変数関数のプロットでエラーが出て躓くことは多々あると思います. 2変数関数ならヒートマップや3Dで描写すればよいですが, それ以上となると難しくなります. 以下のように射影し, 1変数関数を作ってプロットしましょう.
f(x,y,z) = x^2 + y^2 + z^2
plot(x->f(x,0,0))
f(x,y,z) = x^2 + y^2 + z^2
g(x) = f(x,0,0)
plot(g)
グラフを並べる
等価な書き方を4通り列挙する. それぞれ一長一短があるので, 適宜使い分けてほしい.
plt1 = plot(sin, label="")
plt2 = plot(cos, label="")
plt3 = plot(exp, label="")
plt4 = plot(abs, label="")
plot(plt1, plt2, plt3, plt4, layout = (2, 2))
次の記法ではループが使いやすい.
plt = []
push!(plt, plot(sin, label=""))
push!(plt, plot(cos, label=""))
push!(plt, plot(exp, label=""))
push!(plt, plot(abs, label=""))
plot(plt..., layout = (2, 2))
plot(
plot(sin, label=""),
plot(cos, label=""),
plot(exp, label=""),
plot(abs, label=""),
layout = (2, 2)
)
plot(
plot(x->sin(x), label=""),
plot(x->cos(x), label=""),
plot(x->exp(x), label=""),
plot(x->abs(x), label=""),
layout = (2, 2)
)
無名関数も同様
plot(
plot(x->x^1, label=""),
plot(x->x^2, label=""),
plot(x->x^3, label=""),
plot(x->x^4, label=""),
layout = (2, 2)
)
グラフを重ねる
重ねる場合は, plot!()
を使う.
plt = plot(sin, label="sin")
plot!(plt, cos, label="cos")
折れ線グラフと散布図を重ねることもできる.
X = [i for i in 0:10]
Y = sin.(X)
plt = plot(0:0.1:10, sin, label="function")
scatter!(plt, X, Y, label="array")
文字列
title
, label
, xlabel
, ylabel
などとは別に, 座標を指定して文字列を描写したい場合がある. グラフを重ねるのと同じ要領で, plot!(annotations=(x座標, y座標, ("文字列", フォントサイズ(整数), 角度(浮動小数点数), 位置)))
として文字列を描写することができる. フォントの色の指定はうまくいかないことが多いので, 推奨しない(おそらくバックエンドに依存している). また, xticks!([0,1,3], ["A", "B", "C"])
のようにして目盛りの数値に好きな文字列を与えることもできる.
plot(-3:0.1:3, sin, title="example", label="label", xlabel="xlabel", ylabel="ylabel")
# 1つずつ指定する例:
plot!(annotations=(-pi/2, -1, ("min", 8, 0.0, :bottom)))
plot!(annotations=(0, 0, ("origin", 8, 0.0, :center)))
plot!(annotations=(pi/2, 1, ("max", 8, 0.0, :top)))
# 1つずつ指定する例:
annotate!(-1, 0.5, "aaaaa")
# 配列として渡す例:
plot!(annotations=[
(pi/2, 0.0, ("a", 8, 0.0, :center)),
(pi/2, 0.1, ("b", 8, 45.0, :center)),
(pi/2, 0.2, ("c", 8, 90.0, :center)),
])
# 軸の文字を変更する例:
xticks!([0,1,3], ["A", "B", "C"])
保存
ファイルに保存する場合は以下のようにサイズと拡張子を指定する. SVGはベクタ画像の中でも扱いやすく, PowerPointでもドラッグ&ドロップすれば貼り付けられる. Zennにアップロードする場合はGIFに変換すると劣化しにくい.
plt = plot(sin, size=(420,300), fmt=:svg)
savefig(plt, "plot.svg")
display(plt)
アニメーション
GIFアニメーションを出力することもできる.(FFmpegが必要なのでこちらに従ってインストールし, binフォルダを環境変数のパスに追加する必要がある. なお, Juliaのバージョンを上げたときにUndefVarError: ffmpeg not defined
というエラーが出たが, パッケージモードで再度add Plots
とbuild Plots
を実行すれば動くようになった(参考).)
anim = Animation()
for i in 1:10
plt = plot(x->sin(i*x), title="i = "*string(i), label="")
frame(anim, plt)
end
gif(anim, "plot.gif", fps = 2)
CSVファイル
CSVファイル等の外部ファイルを読み込んでプロットしたい場合, まずCSV.jlやDataFrames.jlを使って. データを配列として格納しましょう. 配列として得られてしまえば, あとは先ほど解説した通りにプロットできる.
Tips
plot(sin, label="")
plot(x->x*sin(x^2), label="")
plot(0.1:0.1:10, x->x, yscale=:log10, label="")
plt = plot()
for i in 1:10
plot!(plt, x->exp(-x^(2*i)), label=string(i), legend=:topleft, xlim=(-2,2))
end
plot(plt)
plt = []
for i in 1:9
push!(plt, plot(x->sin(x)^i, title=string(i), label=""))
end
plot(plt...)
ここで利用した"splat"について補足する. 以下を実行した結果からprintln(A[1],A[2],A[3],A[4])
とprintln(A...)
が等価な記法だとわかる.
A = [3,4,5,6]
println(A[1],A[2],A[3],A[4])
println(A...)
println(A)
3456
3456
[3, 4, 5, 6]
f(x) = exp(-x^2/2) / sqrt(2*pi)
X = randn(1000)
Y = [-0.01-0.0001*i for i in 1:1000]
plt = histogram(X, bins=range(-5,5,step=0.2), ylims=(-0.14,), normed=true, label="Histogram", fa=0.3, fc=1, lc="#FFFFFF")
plot!(plt, f, lw=2, lc="#393e46", label="Exact PDF")
f(x) = exp(-x^2/2) / sqrt(2*pi)
X = randn(1000)
Y = [-0.01-0.00005*i for i in 1:1000]
plt = histogram(X, bins=range(-5,5,step=0.2), ylims=(-0.7,), normed=true, label="Histogram", fa=0.3, fc=1, lc="#FFFFFF")
scatter!(plt, X, Y, xlims=(-5,5), ms=1, msw=0, mc="#3261AB", label="Sample")
plot!(plt, f, lw=2, lc="#393e46", label="Exact PDF")
X = randn(1000)
Y = randn(1000)
histogram2d(X, Y, nbins=20, c=:heat)
scatter!(X, Y, mc="#000000", msw=0, ms=1, label="")
# using Pkg
# Pkg.add("LaTeXStrings")
using LaTeXStrings
plot(sin, xlabel=L"x", ylabel=L"\sin(x)")
E(Z,n) = -Z^2/(2*n^2)
plot(xlims=(0,3), xshowaxis=false, xgrid=false, ylabel="\$\\mathrm{Energy~Level~/~}E_\\mathrm{h}\$")
annotate!(0.5, E(3,1)-0.4, "\$\\mathrm{H}\$", 12)
annotate!(1.5, E(3,1)-0.4, "\$\\mathrm{He}^+\$", 12)
annotate!(2.5, E(3,1)-0.4, "\$\\mathrm{Li}^{2+}\$", 12)
for i in 1:30
plot!([0.1,0.9], fill(E(1,i),2), label="", lc=:darkblue)
plot!([1.1,1.9], fill(E(2,i),2), label="", lc=:darkblue)
plot!([2.1,2.9], fill(E(3,i),2), label="", lc=:darkblue)
end
plot!()
plot(sin, left_margin=Plots.Measures.Length(:mm, 50.0))
画質:
dpiを変更することもできるらしい.
動作環境
versioninfo()
Julia Version 1.6.2
Commit 1b93d53fc4 (2021-07-14 15:36 UTC)
Platform Info:
OS: Windows (x86_64-w64-mingw32)
CPU: Intel(R) Core(TM) i7-4650U CPU @ 1.70GHz
WORD_SIZE: 64
LIBM: libopenlibm
LLVM: libLLVM-11.0.1 (ORCJIT, haswell)
参考文献
この記事の元になったJupyter Notebookのデータは下記のリンクにある.
SVGからGIF画像への変換には次のサービスを利用した.
Discussion
日本語を使いたい場合はこちらで対応できました.