Help us understand the problem. What is going on with this article?

Interact.jl を用いて Julia で使う対話機能を持つ可視化ソフトを作ろう

本日は

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)

実行結果は次のようになります

image.png

グラフの描画の上にスライダーが見えます.これをマウスで掴んでグリグリ動かすとそれに応じて三角関数が左右に動くことがわかります.グリグリ動かすことは 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 が出ていると思います.

image.png

コードを書く

普段 Python で notebook を触っている方は Python の代わりに Julia を使うの違いしかありません Shift+Enter でどんどん実行させることができます.冒頭で述べた Python とだいたい同じようなことができるコードを書いてみましょう.

ここでは, 描画には Plots.jl を用います PyPlot.jlMakie.jl でも良いですがグリグリ動かす場合はレスポンスが素早い方がいいので Plots.jl を選ぶことにします. Makie.jl の場合はそれ自身が対話機能を保持しているのでそちらを用いた方がヌルヌル動きます.
 

静的なコードを書く

ヌルヌル動かすための対象を書きましょう.例えばこんな感じ

using Plots.jl
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 が見えることがわかります.

image.png

グリグリさせたら何をさせるか

それではスライダーを動かしたらそれに応じて何かをする動作を結びつけましょう.

p=map(a->f(a), observe(a_slider))

map の第一引数にはスライダーを動かした時にする動作を書きます.その右隣には部品を observe させるようにします.

これで a_slider を動かすとその時の value に応じて f が動くようになります.

これらを可視化しよう

map(display,[a_slider, p])

各々のオブジェクトを部品とみて display させます

image.png

そうすると上の図のような結果が得られると思います.

稀にうまくいかない場合がありますがその場合は標準の WebIO ライブラリをパッケージモードで build WebIO させたり IJuliaInteract.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

実行結果は下図の通りです.
image.png

グリグリ動かしてみましょう.
今日はこんな感じで終わります.

さらに興味のある読者へ

JuliaCon 2019 | Julia + JavaScript = ❤️

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away