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.config.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.servable()

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.

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).