Engee 文档

动画

该页面正在翻译中。

使用Makie可以轻松创建动画情节。 动画通过对数据或绘图属性Observables进行更改并逐帧记录变化的图形来工作。 您可以在 可观察页。

一个简单的例子

要创建动画,您需要使用 记录功能。

首先你创建一个 . 接下来,您传递一个函数,该函数将此图逐帧修改为 记录. 您对图形或其绘图所做的任何更改都将显示在最终动画中。 您还需要传递一个iterable,它具有任意多的元素,只要您希望动画中的帧。 作为第一个参数传递的函数在动画过程中与此迭代器中的每个元素一起调用。

首先,以下是如何更改线条图的颜色:

using GLMakie
using Makie.Colors

fig, ax, lineplot = lines(0..10, sin; linewidth=10)

# animation settings
nframes = 30
framerate = 30
hue_iterator = range(0, 360, length=nframes)

record(fig, "color_animation.mp4", hue_iterator;
        framerate = framerate) do hue
    lineplot.color = HSV(hue, 1, 0.75)
end

传递一个函数作为第一个参数通常是用Julia的 -符号,你可能不熟悉。 而不是上面的,我们也可以写:

function change_function(hue)
    lineplot.color = HSV(hue, 1, 0.75)
end

record(change_function, fig, "color_animation.mp4", hue_iterator; framerate = framerate)

档案格式

视频文件与创建https://github.com/JuliaBinaryWrappers/FFMPEG_jll.jl[脧锚脧赂`FFMPEG_jll。jl`]. 您可以从以下文件格式中进行选择:

  • .mkv (默认,不需要转换)

  • .mp4 (适用于web,广泛支持)

  • .webm (最小档案大小)

  • .gif (最低质量和最大文件大小)

使用动画 可观察的

通常,您希望随着时间的推移对复杂绘图进行动画处理,并且显示的所有数据都应由当前时间戳确定。 这样的依赖关系真的很容易表达 可观察的.

如果我们创建我们的数据取决于一个单一的时间,我们可以节省大量的工作 可观察的,因此我们不必在动画进行时手动更改每个情节的数据。

下面是一个绘制两个不同函数的示例。 每个图的y值都取决于时间,因此我们只需更改两个图的时间即可更改。 我们使用方便 @升降机 宏,表示 升降机ed表达式取决于每个Observable标有 $ 签名。

using GLMakie

time = Observable(0.0)

xs = range(0, 7, length=40)

ys_1 = @lift(sin.(xs .- $time))
ys_2 = @lift(cos.(xs .- $time) .+ 3)

fig = lines(xs, ys_1, color = :blue, linewidth = 4,
    axis = (title = @lift("t = $(round($time, digits = 1))"),))
scatter!(xs, ys_2, color = :red, markersize = 15)

framerate = 30
timestamps = range(0, 2, step=1/framerate)

record(fig, "time_animation.mp4", timestamps;
        framerate = framerate) do t
    time[] = t
end

您可以将大多数绘图属性设置为等于 可观察的s,因此您只需要在动画循环期间更新单个变量(如时间)。

例如,要使一条线的颜色依赖于时间,你可以写:

using GLMakie

time = Observable(0.0)
color_observable = @lift(RGBf($time, 0, 0))

fig = lines(0..10, sin, color = color_observable)

framerate = 30
timestamps = range(0, 2, step=1/framerate)

record(fig, "color_animation_2.mp4", timestamps; framerate = framerate) do t
    time[] = t
end

用Observable追加数据

您还可以在动画期间将数据附加到绘图。 而不是通过 xy (或 z)值分开,最好做一个 可观察的 与向量 s,使数 xy 值不能不同步。

using GLMakie

points = Observable(Point2f[(0, 0)])

fig, ax = scatter(points)
limits!(ax, 0, 30, 0, 30)

frames = 1:30

record(fig, "append_animation.mp4", frames;
        framerate = 30) do frame
    new_point = Point2f(frame, frame)
    points[] = push!(points[], new_point)
end

动画情节"活"

您可以使用循环轻松地为实时情节制作动画。 全部更新 可观察的 你需要,然后添加一个短的睡眠间隔,以便显示可以刷新:

points = Observable(Point2f[randn(2)])

fig, ax = scatter(points)
limits!(ax, -4, 4, -4, 4)

fps = 60
nframes = 120

for i = 1:nframes
    new_point = Point2f(randn(2))
    points[] = push!(points[], new_point)
    sleep(1/fps) # refreshes the display!
end

更新热图内容的另一个例子:

using GLMakie

function mandelbrot(x, y)
    z = c = x + y*im
    for i in 1:30.0; abs(z) > 2 && return i; z = z^2 + c; end; 0
end

x = LinRange(-2, 1, 200)
y = LinRange(-1.1, 1.1, 200)
matrix = mandelbrot.(x, y')
fig, ax, hm = heatmap(x, y, matrix)

N = 50
xmin = LinRange(-2.0, -0.72, N)
xmax = LinRange(1, -0.6, N)
ymin = LinRange(-1.1, -0.51, N)
ymax = LinRange(1, -0.42, N)

# we use `record` to show the resulting video in the docs.
# If one doesn't need to record a video, a normal loop works as well.
# Just don't forget to call `display(fig)` before the loop
# and without record, one needs to insert a yield to yield to the render task
record(fig, "heatmap_mandelbrot.mp4", 1:7:N) do i
    _x = LinRange(xmin[i], xmax[i], 200)
    _y = LinRange(ymin[i], ymax[i], 200)
    hm[1] = _x # update x coordinates
    hm[2] = _y # update y coordinates
    hm[3] = mandelbrot.(_x, _y') # update data
    autolimits!(ax) # update limits
    # yield() -> not required with record
end

"heatmap_mandelbrot.mp4"