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();
This web page was generated from a Jupyter notebook and not all interactivity will work on this website. Right click to download and run locally for full Python-backed interactivity.

Download this notebook from GitHub (right-click to download).