[Package] Interact.jlを動作させる + GraphPlot.jlと併用する
背景
今回はインタラクティブなグラフ操作を実装する Interact.jl の動作環境を作成しつつ,これまで LightGraphs.jl を用いて操作してきたグラフを描画するために利用していた GraphPlot.jl と併用できる環境を作成します.
環境設定
大まかな流れとしては次のように作成しました.
- Python環境の用意 (ここではpyenvを利用してpython 3.9.1をインストールしました)
- Jupyter labのインストール (最新の3.0.xでは Interact.jl に必要な WebIO.jl の問題が解消出来なかったため,ここでは 2.3.0 をインストールしました)
- IJulia.jl, Interact.jl のインストール (ここでは WebIO.jl のドキュメントに従い,しばらく待機しました)
Interact.jl の動作確認
描画環境としては普段からよく使っている Plots.jl + gr とします.
サイクロイド曲線
例として高校生が習うサイクロイド曲線の媒介変数表示を使います.パラメータ
となるような点
a に対する,サイクロイド曲線の Interact.jl + Plots.jl を用いたインタラクティブな描画
様々なパラメータ 媒介変数
using WebIO, Interact, Plots
gr()
θ = 0:π/180:2*π;
@manipulate for a in 1:1:10
x = a .* (θ .- sin.(θ))
y = a .* (1 .- cos.(θ))
plot(x, y, xlim=(0, 2π * 10), ylim=(0, 23), lw=3, color=:tomato, label="curve (a=$a)")
end
これを Jupyter lab 上で動作させたものが以下の通りです.うまく動作しましたね.
GraphPlot.jlとの併用と注意点
GraphPlot.jl は Compose.jl を利用した LigtGraphs.jl の可視化ライブラリの一つです.これまでの記事でも利用しています.例えば以下の記事で出力したグラフ構造は,GraphPlot.jl によるものでした.
ここで Plot.jl と同じように GraphPlot.jl を利用したいのですが,これを単純に次のように描くと失敗します.ここでは Barabási–Albert model で作成した適当なサイズのグラフ構造を circular layout によって配置したグラフを描画させてみます.ここでは次のような操作を Interact.jl で描画しようとしています.
- グラフを作成する (頂点集合
)V=\{1,\dots, n\} -
として,s=1 と変化させたとき,変化したt\in V の値に応じた最短経路を GraphPlot.jl でインタラクティブに描画するt
using Plots, Interact, WebIO
using GraphPlot, LightGraphs, Colors, Cairo
# グラフとノードの座標を作成
g = barabasi_albert(20, 3);
pos = circular_layout(g);
s = 1
# tを変化させる
ui = @manipulate for t in 2:nv(g)
states = dijkstra_shortest_paths(g, s) # 最短経路状態
pt = enumerate_paths(states)[t] # 状態 -> 経路
path = Edge[]
for i in 1:length(pt)-1 # ここの処理はゴミ(雑)
push!(path, Edge(pt[i], pt[i + 1]))
push!(path, Edge(pt[i + 1], pt[i]))
end
# 頂点と最短経路を塗る
nc = [v in pt ? colorant"blue" : colorant"turquoise" for v in vertices(g)]
ec = [e in path ? colorant"tomato" : colorant"lightgray" for e in edges(g)]
gplot(g, pos[1], pos[2], edgestrokec=ec, nodelabel=1:nv(g), nodefillc=nc)
end
display(ui)
動作させてみましょう.
動きました!だいたいいい感じですが,円形上のグラフのアスペクト比が GraphPlot.jl のデフォルトになって横に伸びてしまっているので,これを直したいですね.きれいな比にするには,ドキュメントなどには書いていないのですが,Compose.jl の方のデフォルトの画像サイズを修正すると良いことが分かります.この設定ですが,分からなすぎて泣きながら調べていたら,こちらの Qiita の記事に教えてもらいました.
さてこの一行を追加して,(7cm, 7cm) ぐらいの1:1比で画像を作成しましょう.上のスクリプトの冒頭にこちらを追加します.
using Compose
set_default_graphic_size(7cm, 7cm)
うまく行った気持ちになるのですが,これで実行すると怒られます.というか次のような出力になってしまいます.
実はこの設定は微妙に曲者で,雑に利用するとこのようなことになることがあります.つまり Jupyter lab に画像を書き出しているところが壊れてしまい,うまく確認ができません.こうなると kernel を再起動するなどしないとうまく回復できません (できる方法を知っている人は教えていただけると助かります).
これの原因ですが,正直よく分かっていません (?????).おそらく using Compose と using Interact が何らかの不具合を起こすことがある,ような気がしています (ここまで調べたならちゃんと調べろという説もあるのですが,Interact.jl + Compose.jl(GraphPlot.jl) をhard useしている人が世の中にあまりいなくて…).
もう少し詳しい理由が分かったらどこかに書いておきたいと思います
memo: Juliaの端末で試すと分かりますが,Interact.jlからimportしてくると1.0cm,Compose.jlからimportしてくると10.0mmと出るので,このあたりに何か多重ディスパッチの齟齬がありそうな気がしています.
今の所,次の書き方で using の影響を薄めにしておくと,正しく動作することを確認しています
import Compose: set_default_graphic_size, cm
set_default_graphic_size(7cm, 7cm)
いずれにしても,この設定によってアスペクト比を直せるようになったので,再度動作確認した結果が次の図です.
動きました!今日はここで終わりです.
Discussion