I am generating a set of Datashader images used as layers and I would like to make an animation out of it. The data are stored in a xarray.Dataset, I generate a density map for each timestep and I would like to play it. I have tried to follow the different examples online but none seem to produce a result. here part of the code
from datetime import timedelta, datetime
import numpy as np
import xarray as xr
import datashader as DS
import plotly.graph_objects as go
from colorcet import fire
from datashader import transfer_functions as tf
from pyproj import Proj
## Control the resolution of the images in degrees for Scattermapbox
p=Proj("epsg:27700", preserve_units=False)
resolution=[0.0001*3,0.0001*10,0.0001*50,0.0001*100]#30,100,500,1000m
resolution_M=[20,30,50,100]
center_lat,center_lon=55.8,-5.38
x,y=p(center_lon,center_lat)
res_h,res_v=[],[]
for res in resolution_M:
lon,lat=(p(x+res,y+res, inverse=True))
res_h.append(lon-center_lon)
res_v.append(lat-center_lat)
def mk_frame(subds,res_h,res_v,resolution_M,r=-1):
'''
compute each frame with datashader
'''
subds=subds.where(np.logical_and(subds.lat<90,subds.lon<180), drop=True) #filter netcdf NaN
V_arc,H_arc=subds.lat.max()-subds.lat.values.min(),subds.lon.values.max()-subds.lon.values.min()
#compute the canvas
cvs = DS.Canvas(plot_width=int(H_arc//res_h[r]), \
plot_height=int(V_arc//res_v[r]))
agg = cvs.points(subds, x='lon',
y='lat',
agg=DS.count('mass'))
coords_lat, coords_lon = agg.coords['lat'].values, agg.coords['lon'].values
coordinates=[[coords_lon[0], coords_lat[0]],
[coords_lon[-1], coords_lat[0]],
[coords_lon[-1], coords_lat[-1]],
[coords_lon[0], coords_lat[-1]]]
return tf.shade(agg, cmap=fire, span=[0,1],how='linear').to_pil(), agg.values.max(), agg.values.min(), coordinates
## make a fake dataset
T=25
start_time,end_time=datetime(year=2022, month=1,day=1),datetime(year=2022, month=1,day=T)
pts=5000
ds= xr.Dataset({
'time': ('time', np.arange(start_time,end_time, timedelta(days=1)),
'trajectory': ('trajectory', np.arange(pts)),
'lat': (('time','trajectory'), center_lat +(2*np.random.rand(T,5000)-1)),
'lon': (('time','trajectory'), center_lon +(2*np.random.rand(T,5000)-1)),
'mass': (('time','trajectory'), np.random.rand(T,5000))),
})
# init fig dictionary
fig_dic={
'data':[{'type':'scattermapbox'},{'type':'scatter',
'x':[None], 'y':[None],'marker':go.scatter.Marker(
colorscale=fire,
cmax=1,
cmin=0,
showscale=True,
),
'showlegend':False},],
'layout':dict(
height=800,
width=640,
hovermode='closest',
showlegend=False,
coloraxis_colorbar=dict(title='ng/L'),
mapbox=dict(
bearing=0,
center=dict(
lat=center_lat,
lon=center_lon,
),
pitch=0,
zoom=8.5,
style="carto-darkmatter",
)),
'frame':[]
}
#buttons
fig_dic["layout"]["updatemenus"] = [
{
"buttons": [
{
"args": [None, {"frame": {"duration": 500, "redraw": False},
"fromcurrent": True, "transition": {"duration": 300,
"easing": "quadratic-in-out"}}],
"label": "Play",
"method": "animate"
},
{
"args": [[None], {"frame": {"duration": 0, "redraw": False},
"mode": "immediate",
"transition": {"duration": 0}}],
"label": "Pause",
"method": "animate"
}
],
"direction": "left",
"pad": {"r": 10, "t": 87},
"showactive": False,
"type": "buttons",
"x": 0.1,
"xanchor": "right",
"y": 0,
"yanchor": "top"
}
]
#slider
sliders_dict = {
"active": 0,
"yanchor": "top",
"xanchor": "left",
"currentvalue": {
"font": {"size": 20},
"prefix": "date:",
"visible": True,
"xanchor": "right"
},
"transition": {"duration": 300, "easing": "cubic-in-out"},
"pad": {"b": 10, "t": 50},
"len": 0.9,
"x": 0.1,
"y": 0,
"steps": []
}
# make frames
for time in ds.time.values:
img,cmax,cmin, coordinates=mk_frame(ds.loc[dict(time=time)].drop('time'),res_h,res_v,resolution_M,r=-1)
frame={'layout':{'mapbox':
dict(layers=[
{
"below": 'traces',
"sourcetype": "image",
"source": img,
"coordinates": coordinates
}])
}
}
# slider steps
slider_step = {"args": [
[time],
{"frame": {"duration": 300, "redraw": False},
"mode": "immediate",
"transition": {"duration": 300}}],
"label": datetime.utcfromtimestamp(time.astype(int)*1e-9).strftime('%H:%M-%d/%m/%y'),
"method": "animate"}
sliders_dict["steps"].append(slider_step)
fig_dic["layout"]["sliders"] = [sliders_dict]
fig2=go.Figure(fig_dic)
Thanks