Julia でグラフを描画するとき、よく使われるパッケージには以下のものがあります。
この中で、最も広く利用されているパッケージが Plots.jl (Plots) です。特定の描画エンジンに依存せず、共通の構文で多様なグラフを作成できるのが最大の特徴です。 本ページでは Plots の基本的な使い方を簡単に説明します。
Julia のパッケージモード (REPL で ] キーを押す) で次のコマンドを実行します。
(@v1.12) pkg> add Plots
Plots はけっこう大きなパッケージなので、インストールするのにちょっと時間がかかります。st で状態を表示すると、M.Hiroi の環境では次のように表示されます。
(@v1.12) pkg> st Status `~/.julia/environments/v1.12/Project.toml` [91a5bcdd] Plots v1.41.6
インストールが終了したら、Backspace または Ctrl + C を押してください。通常の julia> プロンプトに戻ります
Julia の場合、パッケージを読み込むには、主に 2 つの方法があります。
たとえば、REPL で以下のコマンドを実行すると Plots を読み込みことができます。
julia> using Plots
なお、Google Colab で Julia を実行する場合、Plots.jl はプリインストールされているので、インストールする必要はありません。using Plots だけで Plots を利用することができます。
パッケージを読み込んだあと、関数 plot() にデータを渡すだけでグラフが表示されます。
plot(x, y) plot(f)
x, y はベクトル (配列) を渡します。関数 f を直接渡すと、デフォルトの範囲で描画されます。このとき、引数に範囲 [min, max] を指定することもできます。plot() はグラフを表すオブジェクト (グラフオブジェクト) を返します。簡単な実行例を示します。
julia> using Plots
julia> x = 1 : 10
1:10
julia> y = rand(10)
10-element Vector{Float64}:
0.16116243864223467
0.5895124216904838
0.39221713442678796
0.34981689970996377
0.4389798743195866
0.20122255767832964
0.9227604875746361
0.8479738347646548
0.3197783494102423
0.8989425549639676
julia> plot(x, y)
折れ線グラフ
julia> plot(sin)
サインカーブ
既存のグラフにデータを追加する場合は、関数名に ! をつけた plot!() を使用します。簡単な例として多項式のグラフを描画してみましょう。
julia> f1(x) = x * x - 4 f1 (generic function with 1 method) julia> f2(x) = x ^ 3 - 9 * x f2 (generic function with 1 method) julia> f3(x) = x ^ 4 - 10 * x ^ 2 + 9 f3 (generic function with 1 method) julia> f4(x) = x ^ 5 - 5 * x ^ 3 + 4 * x f4 (generic function with 1 method) julia> plot(f1, -2.5, 2.5) julia> plot!(f2, -2.5, 2.5) julia> plot!(f3, -2.5, 2.5) julia> plot!(f4, -2.5, 2.5)
多項式のグラフ
なお、複数の関数を配列に格納して plot() に渡すこともできます。上図は次のコードでも描画することができます。
julia> plot([f1, f2, f3, f4], -2.5, 2.5)
今までのグラフはウィンドウをキャプチャしたものですが、関数 savefig() で画像を保存することもできます。
savefig(ファイル名)
拡張子に応じた形式 (PNG, PDF, SVG など) で保存することができます。
julia> savefig("myplot.png")
"/home/mhiro/julia/myplot.png"
多項式のグラフ
Plots.jl は、それ自体が描画するのではなく、他のライブラリを「バックエンド」として利用します。コードを書き換えずに、一行のコマンドで見た目や機能を切り替えることができます。
バックエンド 特徴 切り替えコマンド ---------------------------------------------------------------------------------------- GR デフォルト。高速で、PDFやSVGなどの静止画出力に強い gr() PlotlyJS インタラクティブ性が高く、3Dグラフをマウスで動かせる plotlyjs() PythonPlot Pythonの matplotlib をベースとしており、安定性が高い pythonplot() UnicodePlots REPL 上にテキストベースでグラフを表示する unicodeplots()
なお、特定のバックエンド (PythonPlot や PlotlyJS など) を使用するには、事前にパッケージのインストールが必要です。本ページではデフォルトのバックエンド GR を使用することにします。
Plots では、グラフの見た目や挙動をカスタマイズするために、多くのオプショナル引数が用意されています。Plots ではこれを「属性 (Attributes)」と呼んでいます。よく使われる属性を以下に示します。
グラフの種類は st で指定するだけではなく、専用の関数も用意されています。
このほかにも、Plots にはたくさんの属性やグラフが用意されています。詳細は本家のドキュメントをお読みくださいませ。
折れ線グラフの簡単な例題として、東京都の 2024 年度月平均気温 を Plots で表示してみましょう。
リスト : 折れ線グラフ
using Plots
# 月平均気温
ys1 = [7.1, 8.0, 9.6, 17.1, 20.0, 23.1, 28.7, 29.0, 26.6, 20.6, 13.7, 8.1]
# 月平均最高気温
ys2 = [11.8, 12.5, 14.8, 21.8, 24.8, 27.7, 33.5, 33.6, 30.9, 24.5, 17.8, 13.2]
# 月平均最低気温
ys3 = [2.9, 4.1, 5.1, 13.1, 15.6, 19.3, 25.0, 25.7, 23.5, 17.4, 10.2, 3.8]
# 描画
plot(1 : 12,
[ys1, ys2, ys3],
size=(600, 400),
xticks=1:1:12, ylims=(0, 40),
lw=2, markershape=:circle,
title="Average temperature in 2024", xlabel="Month", ylabel="Celsius",
label=["avg" "max" "min"])
折れ線グラフ
ある学年の生徒 100 人の身長を計測したとしましょう。ここでは、現実のデータではなく、乱数で作成した仮想的なデータを用います。
リスト : 身長のデータ
height = [
148.7, 149.5, 133.7, 157.9, 154.2, 147.8, 154.6, 159.1, 148.2, 153.1,
138.2, 138.7, 143.5, 153.2, 150.2, 157.3, 145.1, 157.2, 152.3, 148.3,
152.0, 146.0, 151.5, 139.4, 158.8, 147.6, 144.0, 145.8, 155.4, 155.5,
153.6, 138.5, 147.1, 149.6, 160.9, 148.9, 157.5, 155.1, 138.9, 153.0,
153.9, 150.9, 144.4, 160.3, 153.4, 163.0, 150.9, 153.3, 146.6, 153.3,
152.3, 153.3, 142.8, 149.0, 149.4, 156.5, 141.7, 146.2, 151.0, 156.5,
150.8, 141.0, 149.0, 163.2, 144.1, 147.1, 167.9, 155.3, 142.9, 148.7,
164.8, 154.1, 150.4, 154.2, 161.4, 155.0, 146.8, 154.2, 152.7, 149.7,
151.5, 154.5, 156.8, 150.3, 143.2, 149.5, 145.6, 140.4, 136.5, 146.9,
158.9, 144.4, 148.1, 155.5, 152.4, 153.3, 142.3, 155.3, 153.1, 152.3
];
数値を並べただけではデータの特徴を把握することは難しいので、これを表にまとめます。たとえば、130 cm から 5 cm 間隔でデータの個数を求めると、次のようになります。
| 階級 | 階級値 | 度数 | 累積度数 |
|---|---|---|---|
| 130 - 135 | 132.5 | 1 | 1 |
| 135 - 140 | 137.5 | 6 | 7 |
| 140 - 145 | 142.5 | 12 | 19 |
| 145 - 150 | 147.5 | 25 | 44 |
| 150 - 155 | 152.5 | 32 | 76 |
| 155 - 160 | 157.5 | 17 | 93 |
| 160 - 165 | 162.5 | 6 | 99 |
| 165 - 170 | 167.5 | 1 | 100 |
階級はデータの範囲を表します。この表では x cm 以上 y cm 未満を x - y で表しています。階級値は階級 x - y の中央値 (x + y) / 2 のことです。度数はその階級に出現したデータの個数です。度数を示してある表のことを「度数分布表」といいます。累積度数はその階級までの度数を全部加えたものです。累積度数を示してある表を「累積度数分布表」といいます。
そして、度数分布表を棒グラフで表したものを「ヒストグラム」といいます。Plots を使って棒グラフを作成すると、次のようになります。
リスト : ヒストグラム (1) using Plots bins = ["130-135", "135-140", "140-145", "145-150", "150-155", "155-160", "160-165", "165-170"] count = [1, 6, 12, 25, 32, 17, 6, 1] bar(bins, count, title="Frequency", label="Frequency")
ヒストグラム (1)
関数 histogram() を使うと、もっと簡単にヒストグラムを作成することができます。
julia> height = [ ... 略 ... ] ... 略 ... julia> histogram(height, title="Frequency", label="Frequency")
ヒストグラム (2)
累積度数を表示することもできます。
リスト : 度数分布と累積度数
using Plots
bins = ["130-135", "135-140", "140-145", "145-150", "150-155", "155-160", "160-165", "165-170"]
count = [1, 6, 12, 25, 32, 17, 6, 1]
cum_count = cumsum(count)
p1 = bar(bins, count, title="Frequency", label="Frequency")
p2 = plot(bins, cum_count, title="Cumulative Frequency",
marker=:circle, label="Cumulative", color=:red)
plot(p1, p2, layout=(2, 1), size=(600, 800))
度数分布と累積度数
Plots で横棒グラフを描くには、関数 bar() に属性 orientation=:horizontal を指定します。ただし、M.Hiroi が使用している Plots (バックエンド GR) では、x 軸と y 軸の目盛りが変更されません。バックエンドを変更する、または他のバージョンでは正常に動作するかもしれませんが未確認です。ここでは xticks, yticks, ylims を使って x / y 軸の目盛りを手動で設定しています。
リスト : 横棒グラフ
using Plots
bins = ["130-135", "135-140", "140-145", "145-150", "150-155", "155-160", "160-165", "165-170"]
count = [1, 6, 12, 25, 32, 17, 6, 1]
bar(bins, count, orientation = :horizontal,
xticks=0:10:40, yticks=(0.5 : 7.5, bins), ylims=(0, 8), title="Frequency", label="Frequency")
横棒グラフ
一方が増加するときに他方も増加傾向が見られる場合を「正の相関」があるといい、他方に減少傾向が見られる場合を「負の相関」があるといいます。また、相関関係が明瞭な場合を「強い相関」といい、不明瞭な場合を「弱い相関」といいます。文章で説明してもわかりにくいのて、図に示すことにしましょう。
たとえば、次の配列に示す対のデータ [x, y] が 30 個あります。
リスト : 対のデータ (1)
# 強い正の相関
data1 = [
[4.6, 5.5], [0.0, 1.7], [6.4, 7.2], [6.5, 8.3],
[4.4, 5.7], [1.1, 1.1], [2.8, 4.1], [5.1, 6.7],
[3.4, 5.0], [5.8, 6.6], [5.7, 6.3], [5.5, 5.6],
[7.9, 8.7], [3.0, 3.6], [6.8, 8.2], [6.2, 6.2],
[4.0, 5.0], [8.6, 9.5], [7.5, 8.9], [1.3, 2.6],
[6.3, 7.4], [3.1, 5.0], [6.1, 8.2], [5.3, 6.6],
[3.9, 5.1], [5.8, 7.0], [2.6, 3.5], [4.8, 6.3],
[2.2, 2.9], [5.3, 6.9]
];
これを平面上にプロットしたものを「相関図 (correlation diagram)」とか「散布図」といいます。散布図は関数 scatter() で簡単に作成することができます。
リスト : 散布図 (1)
using Plots
# 強い正の相関
data1 = [
[4.6, 5.5], [0.0, 1.7], [6.4, 7.2], [6.5, 8.3],
[4.4, 5.7], [1.1, 1.1], [2.8, 4.1], [5.1, 6.7],
[3.4, 5.0], [5.8, 6.6], [5.7, 6.3], [5.5, 5.6],
[7.9, 8.7], [3.0, 3.6], [6.8, 8.2], [6.2, 6.2],
[4.0, 5.0], [8.6, 9.5], [7.5, 8.9], [1.3, 2.6],
[6.3, 7.4], [3.1, 5.0], [6.1, 8.2], [5.3, 6.6],
[3.9, 5.1], [5.8, 7.0], [2.6, 3.5], [4.8, 6.3],
[2.2, 2.9], [5.3, 6.9]
]
xs = [x[1] for x = data1]
ys = [x[2] for x = data1]
scatter(xs, ys, title="Simple Scatter Plot", label="Data1")
散布図 (1)
横軸を x, 縦軸を y とすると、x が増加すると y も増加していることが一目でわかります。これが正の相関です。そして、点がある直線上に並んでいることもわかるでしょう。強い相関性を示しています。
もちろん、複数のデータを表示することもできます。
リスト : 対のデータ (2)
using Plots
# 強い正の相関
data1 = [
[4.6, 5.5], [0.0, 1.7], [6.4, 7.2], [6.5, 8.3],
[4.4, 5.7], [1.1, 1.1], [2.8, 4.1], [5.1, 6.7],
[3.4, 5.0], [5.8, 6.6], [5.7, 6.3], [5.5, 5.6],
[7.9, 8.7], [3.0, 3.6], [6.8, 8.2], [6.2, 6.2],
[4.0, 5.0], [8.6, 9.5], [7.5, 8.9], [1.3, 2.6],
[6.3, 7.4], [3.1, 5.0], [6.1, 8.2], [5.3, 6.6],
[3.9, 5.1], [5.8, 7.0], [2.6, 3.5], [4.8, 6.3],
[2.2, 2.9], [5.3, 6.9]
]
# 強い負の相関
const data2 = [
[6.1, 3.7], [3.9, 7.5], [8.6, 1.7], [5.9, 3.9],
[3.5, 5.5], [7.0, 2.4], [0.9, 9.8], [0.0, 10.2],
[5.2, 4.2], [3.5, 6.5], [6.9, 3.2], [4.3, 5.9],
[5.0, 5.9], [7.4, 3.3], [3.1, 6.6], [4.0, 6.2],
[6.9, 2.9], [4.8, 5.0], [10.6, 0.0], [4.7, 4.3],
[2.9, 7.6], [7.2, 2.2], [3.6, 6.0], [5.5, 4.3],
[5.5, 4.5], [6.9, 3.2], [5.8, 3.6], [4.8, 4.6],
[7.3, 2.5], [4.7, 5.4]
]
xs1 = [x[1] for x = data1]
ys1 = [x[2] for x = data1]
xs2 = [x[1] for x = data2]
ys2 = [x[2] for x = data2]
scatter([xs1, xs2], [ys1, ys2], title="Simple Scatter Plot", label=["Data1" "Data2"])
散布図 (2)
バブルチャートは、対となるデータに加えて、それに関係するもう一つのデータの量を円の大きさで表したグラフです。Plots の場合、関数 scatter() を使用し、属性 markersize にデータのサイズを渡すことで、プロットする点の大きさが変化するグラフになります。
リスト : バブルチャート (1)
using Plots
x = [128, 139.4, 129.7, 129.7, 127.9, 127.2, 144.1, 130.4, 140.4]
y = [26.2, 37, 29.6, 29.6, 26.3, 26.9, 42.5, 28.7, 39.5]
z = [14, 11, 8, 9, 17.5, 19, 22, 26, 12.5]
scatter(x, y, markersize = z, alpha = 0.5, label = "data1",
xlims=(126, 146), ylims=(24, 44), title = "Bubble Chart")
バブルチャート (1)
リスト : バブルチャート (2) using Plots x = [10, 20, 30, 40, 50, 60] y1 = [15.6, 15.0, 15.8, 16.1, 16.9, 16.9] z1 = [4, 8, 16, 12, 10, 20] y2 = [16.9, 16,5, 16.3, 17.1, 16.6, 16.4] z2 = [20, 10, 12, 16, 8, 4] scatter(x, y1, markersize=z1, ylims=(14, 18), alpha=0.5, label="data1", title="Bubble Chart") scatter!(x, y2, markersize=z2, alpha=0.5, label="data2")
バブルチャート (2)
Plots を使用した時系列チャートの作成は、標準ライブラリ Dates を組み合わせて時間を定義するのが一般的です。基本的には、グラフを描画する関数に Dates のデータを渡すだけで簡単に行えます。それでは簡単な例題として、東京の年平均気温を散布図で表してみましょう。データは「気象庁: 年ごとの値 (東京)」の 1975 年から 2021 年までの年平均気温を用いました。
| 1975 | 1976 | 1977 | 1978 | 1979 | 1980 | 1981 | 1982 |
|---|---|---|---|---|---|---|---|
| 15.6 | 15.0 | 15.8 | 16.1 | 16.9 | 15.4 | 15.0 | 16.0 |
| 1983 | 1984 | 1985 | 1986 | 1987 | 1988 | 1989 | 1990 |
| 15.7 | 14.9 | 15.7 | 15.2 | 16.3 | 15.4 | 16.4 | 17.0 |
| 1991 | 1992 | 1993 | 1994 | 1995 | 1996 | 1997 | 1998 |
| 16.4 | 16.0 | 15.5 | 15.9 | 16.3 | 15.8 | 16.7 | 16.7 |
| 1999 | 2000 | 2001 | 2002 | 2003 | 2004 | 2005 | 2006 |
| 17.0 | 16.9 | 16.5 | 16.7 | 16.0 | 17.3 | 16.2 | 16.4 |
| 2007 | 2008 | 2009 | 2010 | 2011 | 2012 | 2013 | 2014 |
| 17.0 | 16.4 | 16.7 | 16.9 | 16.5 | 16.3 | 17.1 | 16.6 |
| 2015 | 2016 | 2017 | 2018 | 2019 | 2020 | 2021 | |
| 16.4 | 16.4 | 15.8 | 16.8 | 16.5 | 16.5 | 16.6 |
このように、一定の時間経過によって計測されたデータ列のことを「時系列 (time series)」といいます。
リスト : 時系列チャート
using Dates
using Plots
x = [Date(n) for n in range(1975, 2021)]
y = [
15.6, 15.0, 15.8, 16.1, 16.9, 15.4, 15.0, 16.0, 15.7, 14.9,
15.7, 15.2, 16.3, 15.4, 16.4, 17.0, 16.4, 16.0, 15.5, 16.9,
16.3, 15.8, 16.7, 16.7, 17.0, 16.9, 16.5, 16.7, 16.0, 17.3,
16.2, 16.4, 17.0, 16.4, 16.7, 16.9, 16.5, 16.3, 17.1, 16.6,
16.4, 16.4, 15.8, 16.8, 16.5, 16.5, 16.6
]
scatter(x, y, ylims=(14, 18), label="Celsius",
title="Annual Average Temperature in Tokyo")
時系列チャート (1)
リスト : 時系列チャート (2)
using Dates
using Plots
# 平均気温
ys1 = [7.1, 8.0, 9.6, 17.1, 20.0, 23.1, 28.7, 29.0, 26.6, 20.6, 13.7, 8.1]
# 最高気温
ys2 = [11.8, 12.5, 14.8, 21.8, 24.8, 27.7, 33.5, 33.6, 30.9, 24.5, 17.8, 13.2]
# 最低気温
ys3 = [2.9, 4.1, 5.1, 13.1, 15.6, 19.3, 25.0, 25.7, 23.5, 17.4, 10.2, 3.8]
plot([Date(2024, m) for m in 1 : 12],
[ys1, ys2, ys3],
ylims=(0, 40),
lw=2, markershape=:circle,
title="Average temperature in 2024", xlabel="Month", ylabel="Celsius",
label=["avg" "max" "min"])
時系列チャート (2)
2 つの確率変数の間に相関が認められるとき、その関係を曲線や曲面で代表することを「回帰 (regression)」といいます。相関に線形傾向が見られる場合、その関係を一本の直線で表すことができます。これを「直線回帰」とか「線形回帰」といい、その直線を「回帰直線」といいます。詳しい説明は拙作のページをお読みください。
簡単な例題として、東京の年平均気温が今後どの程度上昇するか、回帰を用いて推定してみましょう。上記ページの方法で計算したところ、回帰直線は y = 0.025 * (x - 1975) + 15.69 になりました。散布図に回帰直線を描画するのは簡単です。1975 年と 2030 年の y の値を求めると (1975, 15.69), (2030, 17.065) になります。あとは plot() で散布図上に回帰直線を引くだけです。
リスト : 回帰直線
using Dates
using Plots
x = [Date(n) for n in range(1975, 2021)]
y = [
15.6, 15.0, 15.8, 16.1, 16.9, 15.4, 15.0, 16.0, 15.7, 14.9,
15.7, 15.2, 16.3, 15.4, 16.4, 17.0, 16.4, 16.0, 15.5, 16.9,
16.3, 15.8, 16.7, 16.7, 17.0, 16.9, 16.5, 16.7, 16.0, 17.3,
16.2, 16.4, 17.0, 16.4, 16.7, 16.9, 16.5, 16.3, 17.1, 16.6,
16.4, 16.4, 15.8, 16.8, 16.5, 16.5, 16.6
]
scatter(x, y, ylims=(14, 18), label="Celsius",
title="Annual Average Temperature in Tokyo")
plot!([Date(1975), Date(2030)], [15.69, 17.065], label="regression", lw=2)
回帰直線
グラフの一方の軸が対数スケールになっているグラフを「片対数グラフ (Semi-log graph)」といい、両方の軸が対数スケールになっているグラフを「両対数グラフ (Log-log graph)」といいます。Plots で対数グラフを描画する方法は簡単です。x, y 軸のスケールを設定する属性 xscale, yscale に以下の値を指定するだけです。
リスト : 片対数グラフ (1) using Plots x = 0:4 y = [10 ^ n for n = x] # y軸を対数スケールにする plot(x, y, yscale=:log10, title="Semi-log Plot (y-axis)", label="10 ^ x")
片対数グラフ (1)
リスト : 片対数グラフ (2) using Plots x = 0:4 y = [exp(n) for n = x] # y 軸を対数スケールにする plot(x, y, yscale=:log10, minorgrid=true, title="Semi-log Plot (y-axis)", label="exp(x)")
片対数グラフ (2)
次は度数分布表を円グラフで描画してみましょう。
リスト : 円グラフ using Plots ls = ["130-135", "135-140", "140-145", "145-150", "150-155", "155-160", "160-165", "165-170"] vs = [1, 6, 12, 25, 32, 17, 6, 1] pie(ls, vs, lc=:white, title="Pie Chart")
円グラフ