How do dynamic text content with Makie and record?

I’d want to create a animation of a plot that show the changing in the values in the time. Changing the plot charts, ok. But, I want to chance a text content and the scale of x and y axes per i. How I do it? I cannot indexing this code part:

    # Graf 2 - Values
    ii = @lift Int128.($i)
    ii = ii[]
    areaMC = df.Fx[ii]
    error  = dfIntegral.erro[ii]
    Δ = dfIntegral.n[ii]
    GLMakie.Label(fig[1, 3], "Area: " * string(integralCorreta) * "\nArea MC: " * string(areaMC) * "\nError: " * string(error)* "\nΔA: " * string(Δ))

The result is a static value. How I do it?
Is there another better method to print a text content than “GLMakie.Label()” function?

test

My code:

using LaTeXStrings
using GLMakie
using DataFrames

# Building dataframe with values

function simulation_data(nSimul, AreaSquare)
    df = DataFrame(
        x = rand(nSimul) * 10,
        y = rand(nSimul) * 100,
        Fx = 0.00,
        Δy = 0.00,
        up_x = -1.00,
        up_y = -1.00,
        dw_x = -1.00,
        dw_y = -1.00,
    )
    # df.x .- df.y

    #Up or Down of the function y?
    df.Fx = df.x .^ 2
    df.Δy = df.y .- df.Fx
    for i = 1:nSimul
        if df.Δy[i] .> 0
            df.up_x[i] = df.x[i]
            df.up_y[i] = df.y[i]
        else
            df.dw_x[i] = df.x[i]
            df.dw_y[i] = df.y[i]
        end
    end
    contXYdw = nrow(df[df.Δy .<= 0, :])

    #Calc integral
    integral = (contXYdw / nSimul) * AreaSquare #final
    integralCorreta = (10^3) / 3 #by integer equation

    #loop for i to generate the steps in a dataframe
    dfIntegral = DataFrame(n = 1:nSimul, cont = 0, valor = 0.00, erro = 0.00, Δ = 0.00)
    cont = 0
    area = 0
    for i = 1:nSimul
        if df[i, "Δy"] <= 0
            cont = cont + 1
        end
        area = (cont / i) * AreaSquare
        dfIntegral.cont[i] = cont
        dfIntegral.valor[i] = area
        dfIntegral.erro[i] = area - integralCorreta
        if i > 1
            dfIntegral.Δ[i] = dfIntegral.valor[i] - dfIntegral.valor[i - 1]
        end
    end
    return df, dfIntegral, integralCorreta
end

# Now, plotting the dataframe per i

function geraPlot(df, dfIntegral, AreaSquare, integralCorreta) #function that update the chart to each i points

    #nSimul = 1000; AreaSquare = 10 * 10^2
    #df, dfIntegral, integralCorreta = simulation_data(nSimul, AreaSquare)

    nSimul = size(df, 1)
    #i=10


    i = Observable(1)  #Recorder make_animation

    fig = Figure()
    # Graf 1
    ax1 =
        fig[1:4, 1] = Axis(
            fig,
            xlabel = L"x",
            ylabel = L"f (x)",
            xgridstyle = :dash,
            ygridstyle = :dash,
            title = L"Integral (area) of the function: $f(x)=x^{2}$"
        )

    x = 0:10
    y = x .^ 2
    lines!(x, y; label = L"x^{2}")
    #save("im1.png", fig)
    band!(
        x,
        fill(0, length(x)),
        y;
        color = (:blue, 0.4),
        label = L"A (x) = \int_0^{10} x^{2}dx",
    )
    #save("im2.png", fig)

    #choosing points to exibition
    up_pts = @lift Point2f.(df.up_x[1:($i)], df.up_y[1:($i)])
    dw_pts = @lift Point2f.(df.dw_x[1:($i)], df.dw_y[1:($i)])
    scatter!(up_pts, rasterize = true, markersize = 4.0, color = (:gray, 1.0), label = "∉A")
    scatter!(dw_pts, rasterize = true, markersize = 4.0, color = (:red, 1.0), label = "∈A")

    xlims!(0, 10)
    ylims!(0, 100)
    #axislegend("Legend"; position = :rt, bgcolor = (:grey90, 0.25))

    fig[1, 2] = Legend(fig, ax1, "Legend", bgcolor = (:grey90, 0.25), framevisible = false)
    #display(fig)

    # Graf 2 - Values
    ii = @lift Int128.($i)
    ii = ii[]
    areaMC = df.Fx[ii]
    error  = dfIntegral.erro[ii]
    Δ = dfIntegral.n[ii]
    GLMakie.Label(fig[1, 3], "Area: " * string(integralCorreta) * "\nArea MC: " * string(areaMC) * "\nError: " * string(error)* "\nΔA: " * string(Δ))
    
    #display(fig)
    # Graf 3 - Integral Result x nSimulation
    valor_pts = @lift Point2f.(dfIntegral.n[1:($i)], dfIntegral.valor[1:($i)])
    ax3 = fig[2, 2:3] = Axis(fig, title = "Integral value (A)" )
    lines!(valor_pts)
    xlims!(0, nSimul + 10)
    A_yMax = AreaSquare
    A_yMin = 0
    ylims!(A_yMin, A_yMax)

    # Graf 4 - Erro x nSimulation
    erro_pts = @lift Point2f.(dfIntegral.n[1:($i)], dfIntegral.erro[1:($i)])
    ax4 = Axis(fig[3, 2:3], title = "Erro")
    lines!(erro_pts)
    xlims!(0, nSimul + 10)
    er_yMax = maximum(dfIntegral.erro)
    er_yMin = minimum(dfIntegral.erro)
    ylims!(er_yMin, er_yMax)

    # Graf - Δ Resultado x nSimulation
    Δ_pts = @lift Point2f.(dfIntegral.n[1:($i)], dfIntegral.Δ[1:($i)])
    ax5 = Axis(fig[4, 2:3], title = "Δ = A(i) - A(i-1)", xlabel = "n points")
    lines!(Δ_pts)
    xlims!(0, nSimul + 10)
    Δ_yMax = maximum(dfIntegral.Δ)
    Δ_yMin = minimum(dfIntegral.Δ)
    ylims!(Δ_yMin, Δ_yMax)
    #display(fig)
    return fig, i
end

function make_animation(output_filename, nSimul = 100, AreaSquare = 10 * 10^2)
    df, dfIntegral, integralCorreta = simulation_data(nSimul, AreaSquare)
    figure, index = geraPlot(df, dfIntegral, AreaSquare, integralCorreta)

    record(figure, output_filename, 1:nSimul; framerate = 50) do i
        index[] = i
    end
end

make_animation("test.gif", 100)
1 Like

Instead of

ii = @lift Int128.($i)
ii = ii[]
areaMC = df.Fx[ii]
error  = dfIntegral.erro[ii]
Δ = dfIntegral.n[ii]
GLMakie.Label(fig[1, 3], "Area: " * string(integralCorreta) * "\nArea MC: " * string(areaMC) * "\nError: " * string(error)* "\nΔA: " * string(Δ))

I think you need something like:

str = lift(ii -> "Area: " * string(integralCorreta) * "\nArea MC: " * string(df.Fx[ii]) * "\nError: " * string(dfIntegral.erro[ii])* "\nΔA: " * string(dfIntegral.n[ii]), i )
Label(fig[1, 3], str)

So using lift to create another observable that depends on the one you already had (i).

or in my opinion a little better looking:

str = lift(ii -> string("Area: " , integralCorreta , "\nArea MC: " , df.Fx[ii] , "\nError: " ,dfIntegral.erro[ii], "\nΔA: " , dfIntegral.n[ii]), i )
Label(fig[1, 3], str)

What you are doing does not work in part because when you do ii = ii[], ii is no longer an observable but just an integer, therefore you are creating the label with a static value.

1 Like

@aramirezreyes, it’s work. Thank you!