Dynamic Timeseries Image Analysis#
Download this notebook from GitHub (right-click to download).
Timeseries Image Analysis with HoloViews and Panel#
The purpose of this notebook is to illustrate how you can make an interactive and responsive tool for timeseries analysis of images by combining a Panel IntSlider
, some @pn.depends
annotated plotting functions and a few HoloViews DynamicMap
.
Dependencies#
import numpy as np
import pandas as pd
import holoviews as hv
import hvplot.pandas
import panel as pn
hv.extension('bokeh')
pn.extension(sizing_mode="stretch_width")
Data#
def make_ts_data(n_timesteps):
data = pd.DataFrame(
{
"a": np.random.normal(size=(n_timesteps,)),
"b": np.random.normal(size=(n_timesteps,)),
"c": np.random.normal(size=(n_timesteps,)),
},
index=pd.Index(np.arange(n_timesteps), name="time", )
)
return data
ts_data = make_ts_data(1000)
ts_data.head()
Plots#
HEIGHT=300
plot_a = ts_data.hvplot(y="a", responsive=True, height=HEIGHT)
plot_b = ts_data.hvplot(y="b", responsive=True, height=HEIGHT)
plot_c = ts_data.hvplot(y="c", responsive=True, height=HEIGHT)
plot_a + plot_b + plot_c
def get_image(frame):
return hv.Image(np.random.normal(size=(100, 100))).opts(height=HEIGHT, responsive=True)
get_image(100)
def get_vline(frame):
return hv.VLine(frame).opts(color="red")
get_vline(0.5)
App#
Bar#
app_bar = pn.Row(
pn.pane.Markdown("## TimeSeries Image Analysis - POC", style={"color": "white"}, width=500, sizing_mode="fixed", margin=(10,5,10,15)),
pn.Spacer(),
pn.pane.PNG("http://holoviews.org/_static/logo.png", height=50, sizing_mode="fixed", align="center"),
pn.pane.PNG("https://panel.holoviz.org/_static/logo_horizontal.png", height=50, sizing_mode="fixed", align="center"),
background="black",
)
app_bar
Dynamic Plots#
frame_slider = pn.widgets.IntSlider(name="Time", value=25, start=0, end=999)
@pn.depends(frame=frame_slider)
def image(frame):
return get_image(frame)
@pn.depends(frame=frame_slider)
def vline(frame):
return get_vline(frame)
vline_dmap = hv.DynamicMap(vline)
img_dmap = hv.DynamicMap(image)
plots = ((plot_a + plot_b + plot_c) * vline_dmap).cols(1)
Layout#
app = pn.Column(
app_bar,
pn.Spacer(height=10),
frame_slider,
pn.Row(
plots,
pn.Column(
pn.Spacer(height=20),
img_dmap,
),
),
)
app
You are now ready to serve the app to your users via panel serve dynamic_timeseries_image_analysis.ipynb
Notes#
The plots = ((plot_a + plot_b + plot_c) * vline_dmap).cols(1)
line is essential for making the app fast and responsive. Initially the plot_a + plot_b + plot_c
where regenerated together with the vline
everytime the frame_slider.value
was changed. That made the app slower because it had to recalculate and retransfer much more data.
App#
Lets wrap it into nice template that can be served via panel serve dynamic_timeseries_image_analysis.ipynb
pn.template.FastListTemplate(
site="Panel", title="Dynamic Timeseries Image Analysis",
main=[
"The purpose of this app is to illustrate how you can **make an interactive and responsive tool for timeseries analysis of images** by combining a Panel `IntSlider`, some `@pn.depends` annotated plotting functions and a few HoloViews `DynamicMap`.",
*app[2:]]
).servable();
Download this notebook from GitHub (right-click to download).