本日は
ipywidgets
という Python のライブラリで Jupyter notebook 上で動作させる対話ツールの構築をサポートするパッケージがあります.
例えば,Jupyter Notebookを開いて,次のようなコードを書いてみましょう
from matplotlib import pyplot as plt
import numpy as np
from ipywidgets import interact
import ipywidgets as widgets
def plot_something(a):
xs = np.linspace(-np.pi, np.pi, 100)
ys = np.sin(xs-a)
plt.plot(xs, ys)
plt.xlim(-np.pi, np.pi)
a_slider = widgets.FloatSlider(min=0.0, max=10.0, step=0.05)
interact(plot_something, a=a_slider)
実行結果は次のようになります
グラフの描画の上にスライダーが見えます.これをマウスで掴んでグリグリ動かすとそれに応じて三角関数が左右に動くことがわかります.グリグリ動かすことは plot_something
関数の引数にある a
を変化させることと等価です.グリグリさせる対象とグリグリするパラメータを interact
に投げればお手軽に対話的ツールが作成できるわけです.
Julia ではどうでしょう?
結論から言うとできます.本日は Interact.jl を用いて同じようなことをやってみましょう.数ヶ月前は Jupyter で動かない,インストールできないとか色々不満がありましたが,今はとても快適です.
Install
Interact.jl
は Julia の公式パッケージとして登録されているのでパッケージモードで add
するだけです
_
_ _ _(_)_ | Documentation: https://docs.julialang.org
(_) | (_) (_) |
_ _ _| |_ __ _ | Type "?" for help, "]?" for Pkg help.
| | | | | | |/ _` | |
| | |_| | | | (_| | | Version 1.3.0-alpha.unknown (2019-07-24)
_/ |\__'_|_|_|\__'_| | Commit a8a567e (0 days old master)
|__/ |
(v1.3) pkg> add Interact.jl
基本これだけです.Python で jupyter 入れたけれど IJulia 入れていない場合は下記の手順で Julia のカーネルを登録することができます.
julia> ENV["JUPYTER"]=Sys.which("jupyter")
(v1.3) pkg> add IJulia
julia> using IJulia
julia> notebook()
# いつも見慣れたjupyter notebook が起動する
New
notebook を作成するボタンに Julia バージョン番号 と言う形で出現すれば成功です.写真では 1.3.0-alpha と Julia 1.1.1が混ざっていますが,読者はおそらく Julia 1.1.1 が出ていると思います.
コードを書く
普段 Python で notebook を触っている方は Python の代わりに Julia を使うの違いしかありません Shift+Enter でどんどん実行させることができます.冒頭で述べた Python とだいたい同じようなことができるコードを書いてみましょう.
ここでは, 描画には Plots.jl
を用います PyPlot.jl
や Makie.jl
でも良いですがグリグリ動かす場合はレスポンスが素早い方がいいので Plots.jl
を選ぶことにします. Makie.jl
の場合はそれ自身が対話機能を保持しているのでそちらを用いた方がヌルヌル動きます.
静的なコードを書く
ヌルヌル動かすための対象を書きましょう.例えばこんな感じ
using Plots
function f(a)
xs = -pi:0.01:pi
ys = sin.(xs .- a)
plot(xs, ys)
end
パーツ作り
a
をパラメータとして動かしたいのでこれを動かすように実装します.
まずは Widget という我々が作りたいGUIのパーツを作ります.ここでは slider を作りましょう
using Interact
a_slider=slider(-3:0.1:3,value=0.2, label="a_slider")
上記のコードを書くと次のような部品が出るでしょう.
左には label
で指定した文字が, 右側には value
で指定した 0.2 が見えることがわかります.
グリグリさせたら何をさせるか
それではスライダーを動かしたらそれに応じて何かをする動作を結びつけましょう.
p=map(a->f(a), observe(a_slider))
map
の第一引数にはスライダーを動かした時にする動作を書きます.その右隣には部品を observe
させるようにします.
これで a_slider
を動かすとその時の value に応じて f
が動くようになります.
これらを可視化しよう
map(display,[a_slider, p])
各々のオブジェクトを部品とみて display
させます
そうすると上の図のような結果が得られると思います.
稀にうまくいかない場合がありますがその場合は標準の WebIO
ライブラリをパッケージモードで build WebIO
させたり IJulia
や Interact.jl
なども build
させた方が良いでしょう.
もう少し複雑な例
using Interact
using Plots
using Rotations
p=ones(3)/sqrt(3)
scatter3d(
[p[1]],[p[2]],[p[3]],
xlabel="x",ylabel="y",zlabel="z",
color=:blue
)
function plot_rotated_pts(x_angle,y_angle,z_angle)
xyz_rad = deg2rad.([x_angle,y_angle,z_angle])
r=RotXYZ(xyz_rad...)
q=r*p
scatter3d!([q[1]],[q[2]],[q[3]],color=:green,legend=false)
xlims!((-1.0,1.0)); ylims!((-1.0,1.0)); zlims!((-1.0,1.0))
end
x_axis=slider(-180:180, label="x_axis")
y_axis=slider(-180:180, label="y_axis")
z_axis=slider(-180:180, label="z_axis")
angle_plot=map(
(x_deg,y_deg,z_deg)->plot_rotated_pts(x_deg,y_deg,z_deg),
map(observe, [x_axis,y_axis,z_axis])...,
)
#observe(x_axis),observe(y_axis),observe(z_axis)
map(display,[x_axis, y_axis, z_axis, angle_plot]);
パラメータが複数ある場合も同様にできます.パラメータを動かした時に何をさせるかを決める map
に複数の引数を入力とする関数を設定すれば良いです.observe
も各々のスライダーに作用させればOKです
observe(x_axis),observe(y_axis),observe(z_axis)
繰り返しがイヤな場合は map でそして ...
splat させます.
map(observe, [x_axis,y_axis,z_axis])...
...
も Julia の機能ですヘルプモードですので,Juliaさんに訪ねてみましょう.
help?> ...
search:
...
The "splat" operator, ..., represents a sequence of arguments. ... can be
used in function definitions, to indicate that the function accepts an
arbitrary number of arguments. ... can also be used to apply a function to a
sequence of arguments.
Examples
≡≡≡≡≡≡≡≡≡≡
julia> add(xs...) = reduce(+, xs)
add (generic function with 1 method)
julia> add(1, 2, 3, 4, 5)
15
julia> add([1, 2, 3]...)
6
julia> add(7, 1:100..., 1000:1100...)
111107
グリグリ動かしてみましょう.
今日はこんな感じで終わります.