I've been trying to plot a simple function:
v(x, y) = (y*t, 2*x*t)
(actual implementation: v(x::Point2{T}, t) where T = Point2{T}(one(T) * x[2] * t, 4 * x[1])
)
using Makie's 2D streamplot function.
While I can plot each timestep individually, by creating an anonymous function f = x -> v(x, 5e0)
(for example) and plotting f
, when I try to wrap it in an Observable (using Node(f)
), then I can no longer update that Observable to point to another function, so my record loop fails.
I've tried forcing the type of the Node to be more abstract (Node{Function}
). Unfortunately, this abstract type seems to get lost somewhere in the internals of Makie, and is thus lost.
Is there any way I could wrap my type, so as to not run into type conflicts, but still be a Function?
So it turns out that there's this lovely Base method Fix2(function, argument)
, which basically fixes my problem (since it returns a wrapped type).
Consider this example function:
v(x::Point2{T}, t) where T = Point2{T}(one(T) * x[2] * t, 4 * x[1])
One can create a callable function with the time set to 1.0 by:
fixedfunc = Base.Fix2(v, 1.0)
which can then be loaded into an Observable, and updated to have a new time value without issue.
Here's the final code, for reference:
v(x::Point2{T}, t) where T = Point2{T}(one(T) * x[2] * t, 4 * x[1])
sf = Node(Base.Fix2(v, 0e0))
title_str = Node("t = 0.00")
sp = streamplot(
sf,
-2..2, -2..2;
linewidth = 2,
padding = (0, 0),
arrow_size = 0.09,
colormap =:magma
)
sc = title(sp, title_str)
record(sc, "test.mp4", LinRange(0, 20, 5*30)) do i
sf[] = Base.Fix2(v, i)
title_str[] = "t = $(round(i; sigdigits = 2))"
end