Thank you! I managed to package my code into a class, and the refresh button now works as intended! Here is the full code.
from datetime import datetime, date
import glob
import geoviews as gv
import holoviews as hv
from holoviews.operation.datashader import rasterize
import numpy as np
import panel as pn
import param
from shapely.geometry import Point
import xarray as xr
## LOAD AND PREPARING DATA
#ds = xr.open_dataset('/usr/src/app/test_raytheon.nc')
# ns = 1e-9 # number of seconds in a nanosecond
# delta = timedelta(days=1, minutes=15)
# latest = datetime.utcfromtimestamp(ds['time'].values[0].astype(int) * ns)
# start = latest - delta
# date_slider = pn.widgets.DateSlider(name='Timestamp', start=start, end=latest, value=latest)
today = date.today().strftime("%Y%m%d")
files = sorted(glob.glob(f'/data/{today}*.nc'))
#files = sorted(glob.glob(f'2021*.nc'))
ds = xr.open_mfdataset(files)
var_list = ["Reflectivity", "SpecificDifferentialPhase", 'CorrectedReflectivity','DifferentialReflectivity', 'CorrectedDifferentialReflectivity', 'CrossPolCorrelation', 'Velocity']
angle_list = list(ds['scan_angle'].values)
# Package things into class:
class SkylerApp(param.Parameterized):
# param depends on
var_selected = param.ObjectSelector(default='Reflectivity', objects=var_list)
scan_angle = param.ObjectSelector(default=2.0, objects=angle_list)
timestep = param.ObjectSelector(default = -1, objects=list(np.arange(-70, 0))) #last 30min
def __init__(self, ds, **params):
super().__init__(**params)
self._ds = ds
# Refresh data using a button
self.refresh = pn.widgets.Button(name='Refresh Data', button_type='primary')
def update_data(event):
today = date.today().strftime("%Y%m%d")
files = sorted(glob.glob(f'/data/{today}.nc')) # 500 second
self._ds = xr.open_mfdataset(files)
print(f'File list refreshed {files[-5:]}')
self.refresh.on_click(update_data)
self.base_map() # create basemap
def base_map(self):
tiles = gv.tile_sources.StamenTonerBackground().apply.opts()
# site
ntc = gv.Text(-73.82, 40.7, 'National Tennis Center').opts(text_font_style='bold')
site = gv.Points([(-73.8492017,40.7498823)]).opts(color='red', line_color='black', line_width=0.5, size=5)
site_shapely = Point(-73.8492017,40.7498823)
first_circle = gv.Shape(site_shapely.buffer(0.0573)).opts(line_color='red', line_dash='dashed', fill_alpha=0,line_width=2, alpha=0.5) #3mi
second_circle = gv.Shape(site_shapely.buffer(0.0955)).opts(line_color='blue', line_dash='dashed', fill_alpha=0, line_width=2, alpha=0.5) #5mi
third_circle = gv.Shape(site_shapely.buffer(0.191)).opts(line_color='green', line_dash='dashed', fill_alpha=0, line_width=2, alpha=0.5) #10mi
cirle_anno1 = gv.Text(-73.8492017, 40.807, '3mi').opts(text_alpha=0.6, text_font_size='12px')
cirle_anno2 = gv.Text(-73.8492017, 40.846, '5mi').opts(text_alpha=0.6, text_font_size='12px')
cirle_anno3 = gv.Text(-73.8492017, 40.941, '10mi').opts(text_alpha=0.6, text_font_size='12px')
out = tiles * site * ntc * first_circle * second_circle * third_circle * cirle_anno1 * cirle_anno2 * cirle_anno3
self._base = out
@param.depends('var_selected', 'scan_angle', 'timestep')
def make_map(self):
### TODO how to handle the dependency
### https://panel.holoviz.org/user_guide/Param.html
timestamp = self._ds['time'][self.timestep].astype(int)
ns = 1e-9
dt = datetime.utcfromtimestamp(timestamp * ns)
ts = dt.strftime("%Y/%m/%d %H:%M:%S")
# Need to solve this part
data = self._ds[self.var_selected].sel(scan_angle=self.scan_angle).isel(time=self.timestep).load()
NWSVelocity = [
'#90009F',
'#00FF00',
'#00E800',
'#00C800',
'#00B000',
'#009000',
'#007000',
'#779777',
'#977777',
'#800000',
'#A00000',
'#B80000',
'#D80000',
'#EE0000',
'#FF0000']
NWSReflectivity = [
'#00ECEC',
'#01A0F6',
'#0000F6',
'#00FF00',
'#00C800',
'#009000',
'#FFFF00',
'#E7C000',
'#FF9000',
'#FF0000',
'#D60000',
'#C00000',
'#FF00FF',
'#9955C9',
'#000000']
if self.var_selected in ['Reflectivity', 'CorrectedReflectivity','DifferentialReflectivity', 'CorrectedDifferentialReflectivity']:
color_map = NWSReflectivity
elif self.var_selected in ['Velocity']:
color_map = NWSVelocity
else:
color_map = 'gist_ncar'
data = hv.Dataset(data, vdims=self.var_selected)
graph = data.to(gv.Image, ["lon", "lat"])
graph = (
rasterize(graph).opts(title=ts, height=550, width=800, colorbar=True, cnorm='eq_hist', cmap=color_map, alpha=0.5, tools=['hover'])
)
return graph * self._base
skyler = SkylerApp(ds)
## Create Dashboard from template
dark_material = pn.template.MaterialTemplate(title='US Open Skyler', theme='dark')
# dark_material.sidebar.append(skyler.var_selected)
# dark_material.sidebar.append(skyler.angle)
dark_material.sidebar.append(skyler.param['var_selected'])
dark_material.sidebar.append(skyler.param['scan_angle'])
dark_material.sidebar.append(skyler.refresh)
dark_material.main.append(
pn.Row(
pn.Card(skyler.make_map)
)
)
dark_material.main.append(
pn.Row(pn.widgets.DiscretePlayer.from_param(skyler.param['timestep'], loop_policy='loop', interval=2000))
)
dark_material.servable()