Pulse Animation in Plolty Express on ScatterMapbox

Hi together,
As described in the title, I am trying to animate the points on a ScatterMapbox with a Pulse effect. This seems to be possible with Mapbox in general, but I canโ€™t find a way to do it with Dash and Plotly Express.

The goal of the app is the following: New data sets are read in sequentially and visualised on a ScatterMapbox. The new data records are fetched every X minutes from a web service. Each data record is then added to the previous data within a callback function for X minutes / Y entries * 1000 seconds. This already works very well. My problem now is that I would like to animate each new data point as soon as it is set on the map. The whole thing should be done without buttons and user interaction. As mentioned above, there is exactly this possibility of animation in Javascript, but unfortunately I cannot adapt this for Python. I hope you can help me!

Here is the link to the animation in Javascript with Mapbox GL: Add an animated icon to the map | Mapbox GL JS | Mapbox

Many thanks in advance

1 Like

No luck, Iโ€™m assuming? That would be a great addition to any map plot in plotly dash ecosystem.

Plotly can generate the pulse animation, but it can be trigerred only by a button:

import plotly.graph_objects as go

fig=go.Figure()
fig.update_layout(width=400, height=400, xaxis_range=[-1,2], yaxis_range=[-1,2],
                 yaxis_scaleratio=1, yaxis_scaleanchor='x', 
                 xaxis_visible=False, yaxis_visible=False)
fig.add_shape(type="circle",
              xref="paper", yref="paper",
              x0=0.33, y0=0.33, x1=0.67, y1=0.67,
              fillcolor="rgba(255, 0, 0, 0.35)",          
              line_width=0)
fig.add_shape(type="circle",
                          xref="paper", yref="paper",
                         x0=0.35, y0=0.35, x1=0.65, y1=0.65,
                         fillcolor="rgba(255, 0, 0, 1)",          
                         line_color="white")

frames=[]
for k in range(36):
    opacity=round(0.35-round(k*0.01,2),2)
    X0=round(0.33-round(k*0.01,2), 2)
    X1=round(0.67+round(k*0.01,2), 2)
    frames.append(go.Frame(layout=dict(shapes=[dict(type="circle",
                                                    xref="paper", yref="paper",
                                                    x0=X0, y0=X0, x1=X1, y1=X1,
    
                                                    fillcolor=f"rgba(255, 0, 0, {opacity})",          
                                                    line_width=0,
                                                    )])))
fig.update_layout(updatemenus = [
                      dict(type="buttons",
                           buttons=[dict(label="Play",
                                         method="animate",
                                         args=[None,
                                               dict(frame=dict(duration=10, redraw=True),
                                                    fromcurrent=True,
                                                    transition_duration=0)
                            
                                              ])
                                   ])
                                 ])   
fig.update(frames=frames)

Similarly can be created a pulse as a mapbox layer.
pulse150

3 Likes

Nice, thank you! Will be using this in the future for sure!

Iโ€™m using this exact setup in a dcc.Graph() component. The animation will only run when pressing play. And only once. The dcc.Graph() component is updated every second through a callback with a dcc.Interval component. Any suggestions on how to get this up and running and looking the same as in the example?

@vestland
I donโ€™t use Dash, so I donโ€™t know how to suggest something that works for sure, but I explain below how I created the posted gif file.
First I created 36 frames saved as png files, from a Jupyter notebook. Then I changed the Python kernel to Julia kernel, because julia has a very simple and fast method to generate animations. You may upload
the png files to [Animated GIF Maker](Animated GIF Maker to get a gif file.

import plotly.graph_objects as go

fig=go.Figure()
fig.update_layout(template="plotly_white", width=400, height=400, xaxis_range=[-1,2], yaxis_range=[-1,2],
                 yaxis_scaleratio=1, yaxis_scaleanchor='x', 
                 xaxis_visible=False, yaxis_visible=False, margin=dict(t=2, r=2, b=2, l=2))

nframes=36
for k in range(nframes):
    opacity=round(0.35-round(k*0.01,2),  2)
    X0=round(0.33-k*0.01, 2)
    X1=round(0.67+k*0.01,2)
    fig.update_layout(shapes=[dict(type="circle",
                             xref="paper", yref="paper",     
                             x0=X0, y0=X0, x1=X1, y1=X1,
                             fillcolor=f"rgba(255, 0, 0, {opacity})",          
                                                    line_width=0,
                                                    ),
                             dict(type="circle",
                                    xref="paper", yref="paper",
                                    x0=0.35, y0=0.35, x1=0.65, y1=0.65,
                                   fillcolor="rgba(255, 0, 0, 1)",          
                                   line_color="white")])
                                   fig.write_image(f"images/{k+1:06d}.png", 
                                   width=100, height=100, scale=1)

Here I changed the Jupyter kernel from Python to Julia, to create the gif from pngs:

import Plots: Animation, buildanimation
nframes=36
fnames = String[]
for k in 1:nframes
    filename=lpad(k, 6, "0")*".png"
    push!(fnames, filename)
end
anim = Animation("images", fnames);
buildanimation(anim, "pulse.gif", fps = 18, show_msg=false)

If you upload the gif file somewhere on the web, there should be a way, in Dash, to display the gif from url.
In Jupyter notebook a gif file can be displayed as follows:

%%html 
<img src="https://github.com/empet/Datasets/blob/master/Images/pulse.gif?raw=true">
1 Like