PlotlyJS.jl animation

Are there any examples of animating plots in PlotlyJS.jl, in particular using multiple frames such as this Python example?

I noticed a mention of using react!, but that has downsides (e.g. it resets the viewer orientation: I want to be able to animate a mesh3d plot and look at it from different angles).

I use react!, and you are right, it is somewhat limited. However, it should be possible to change the camera
after each react! to achieve programmatic control of things like the up vector, the target of the camera, and so on.

1 Like

This is an example of animation with button and slider. Each frame updates some attributes of the basic trace, as well as the layout (this example is more general than that in the link you posted). Even more general would be an example with two basic traces, each one updated by the animation frames.

using PlotlyJS

N=300
X = LinRange(0, 10, N)
Y = -3 .+ 7*rand(N)

trace = scatter(x = [X[1]],  
                y = [Y[1]],
                mode="lines",
                line_width=1.5,
                line_color="RoyalBlue")

n_frames = length(X)
frames  = Vector{PlotlyFrame}(undef, n_frames)
for k in 1:n_frames
    frames[k] = frame(data=[attr(x=X[1:k], #update x and y
                                 y=Y[1:k],
                                 )],
                      layout=attr(title_text="Test frame $k"), #update title
                      name="fr$k", #frame name; it is passed to slider 
                      traces=[0] # this means that the above data update the first trace (here the unique one) 
                        ) 
end    


updatemenus = [attr(type="buttons", 
                    active=0,
                    y=1,  #(x,y) button position 
                    x=1.1,
                    buttons=[attr(label="Play",
                                  method="animate",
                                  args=[nothing,
                                        attr(frame=attr(duration=5, 
                                                        redraw=true),
                                             transition=attr(duration=0),
                                             fromcurrent=true,
                                             mode="immediate"
                                                        )])])];


sliders = [attr(active=0, 
                minorticklen=0,
                
                steps=[attr(label="f$k",
                            method="animate",
                            args=[["fr$k"], # match the frame[:name]
                                  attr(mode="immediate",
                                       transition=attr(duration=0),
                                       frame=attr(duration=5, 
                                                  redraw=true))
                                 ]) for k in 1:n_frames ]
             )];    

ym, yM = extrema(Y)
layout = Layout(title_text="Test", title_x=0.5,
    width=700, height=450,
              xaxis_range=[-0.1, 10.1], 
              yaxis_range=[ym-1, yM+1],
              updatemenus=updatemenus,
              sliders=sliders
    )
pl = Plot(trace, layout, frames)
4 Likes

This is the animation for head scanning:

using FileIO, Images, HTTP
using PlotlyJS

url = "https://s3.amazonaws.com/assets.datacamp.com/blog_assets/attention-mri.tif"

download(url, "attention-mri.tif")
img = load("attention-mri.tif");
GRAY = permutedims(channelview(img), (2,1,3));

r, c = size(GRAY[1, :, :])
n_slices = size(GRAY, 1)
height = (n_slices-1) / 10
grid = LinRange(0, height, n_slices)
slice_step = grid[2] - grid[1]


pl_bone=[[0.0, "rgb(0, 0, 0)"],
         [0.1, "rgb(21, 21, 30)"],
         [0.2, "rgb(44, 44, 62)"],
         [0.3, "rgb(66, 66, 92)"],
         [0.4, "rgb(89, 92, 121)"],
         [0.5, "rgb(112, 123, 143)"],
         [0.6, "rgb(133, 153, 165)"],
         [0.7, "rgb(156, 184, 188)"],
         [0.8, "rgb(185, 210, 210)"],
         [0.9, "rgb(220, 233, 233)"],
         [1.0, "rgb(255, 255, 255)"]];

initial_slice = surface(
                     z=height*ones(r,c),
                     surfacecolor=GRAY[end, end:-1:1, :],
                     colorscale=pl_bone,
                     reversescale=true, #commenting out this line we get  darker slices
                     showscale=false)


frames  = Vector{PlotlyFrame}(undef, n_slices)
for k in 1:n_slices
    frames[k] = frame(data=[attr(
                                 z=(height-(k-1)*slice_step)*ones(r,c),
                                 surfacecolor=GRAY[end-(k-1), end:-1:1, :])],
                                 name="fr$k",
                                 traces=[0])
end    

sliders = [attr(steps = [attr(method= "animate",
                              args= [["fr$k"],                           
                              attr(mode= "immediate",
                                   frame= attr(duration=40, redraw= true),
                                   transition=attr(duration= 0))
                                 ],
                              label="$k"
                             ) for k in 1:n_slices], 
                active=17,
                transition= attr(duration= 0 ),
                x=0, # slider starting position  
                y=0, 
                currentvalue=attr(font=attr(size=12), 
                                  prefix="slice: ", 
                                  visible=true, 
                                  xanchor= "center"
                                 ),  
               len=1.0) #slider length
           ];
layout = Layout(title_text="Head Scanning", title_x=0.5,
                width=600,
                height=600,
                scene_zaxis_range= [-0.1, 6.8],
                sliders=sliders,
            )
pl= Plot(initial_slice, layout, frames)

Moving the slider with the mouse you can visualize each slice.

3 Likes

Thanks, I really appreciate it. It would be a great example to add to the docs.

Fantastic! One note: I installed to a fresh environment, and I needed to add AstroIO in the first line.

I 'm running Julia 1.6.1 and PlotlyJS, version 0.18.7, and the last one is 0.18.8.

This code is not working in my machine. I am getting an empty plot. Can anybody check why this is happening? For more details, please check the stackoverflow question: plotly.js - animation of scatter plot using PlotlyJS.jl Julia - Stack Overflow

@lokitkhemka

For animations use Plot, not plot.
Hence, replace the last line with:

fig =Plot(trace, layout, frames)
display(fig)

Thank you for the answer. But, it is only displaying first plot for all the frames.


Please refer to the attached screenshot

I’ve just copied the code posted here and it works. I’m running Julia 1.7.0 and PlotlyJS 0.18.8.

1 Like

I get the same result as you when I run the code in vscode. But you can disable Use Plot Pane in the julia extension setting so you can see the animation in the browser

1 Like