グラフアニメーション表示をやってみました。
表示領域を確保
最初に、Kino.render()で、グラフを描画する領域を確保しておきます。
Kino.render()が返した値を保存(wl_wiget)しておいきます。
グラフの描画
Kino.VegaLite.push_manyを使ってグラフのデータを更新してアニメーション表示します。
ポイントは、この更新方法です。
push_manyは、データを追加するためのもので、グラフ全体を書き直す機能はもっていません。
どうやらグラフ全体を書き換える手段がありません。
Kino.VegaLite.clear()でクリアして再描画するという力業を使ってます。
push_manyにclearオプションがあってもいいかも。
描画と描画の間が短かすぎるとちらついたりします。適当に時間をあけます。
Process.sleep(20)
で20msec停止させてみました。
Kino.VegaLite.clear(vl_widget)
Kino.VegaLite.push_many(vl_widget, points)
sin波が移動しているデモを作ってみました。
動画は、https://github.com/masahiro-999/kino-animation
を見てください
livemd全体
以下の通りです。
kino-animation
Mix.install([
{:kino_vega_lite, "~> 0.1.3"}
])
Section
alias VegaLite, as: Vl
vl_widget =
Vl.new(width: 800, height: 400)
|> VegaLite.mark(:point, tooltip: true)
|> VegaLite.encode_field(:x, "x", type: :quantitative)
|> VegaLite.encode_field(:y, "y", type: :quantitative)
|> Kino.VegaLite.new()
|> Kino.render()
plot = fn x, y ->
points =
[x, y]
|> Enum.zip()
|> Enum.map(fn {x, y} -> %{x: x, y: y} end)
Kino.VegaLite.clear(vl_widget)
Kino.VegaLite.push_many(vl_widget, points)
end
target_func = fn x, t -> :math.sin((x - t) * :math.pi() * 2) end
x = for i <- 0..100, do: i / 100
for i <- 0..1000 do
t = i / 100
y = for x1 <- x, do: target_func.(x1, t)
plot.(x, y)
Process.sleep(20)
end
nil