3

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?

zeflex
  • 1,487
  • 1
  • 14
  • 29
Anshul Singhvi
  • 1,692
  • 8
  • 20

1 Answers1

6

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

video

Anshul Singhvi
  • 1,692
  • 8
  • 20