yol
yol

Reputation: 19

How to create a dashboard with widgets (selector) and interactivity (tap stream) between plots in HoloViews/Bokeh?

I'm trying to create a dashboard that consists of two plots (heatmap and line graph) and one widget (selector):

enter image description here

Currently I'm trying to do it in HoloViews. It seems that this should be very easy to do but I somehow can't wrap my head around it.

The code below shows how it should look like. However, the selector is not connected in any way to the dashboard since I don't know how to do it.

import pandas as pd
import numpy as np

import panel as pn
import holoviews as hv


hv.extension('bokeh')


def create_test_df(k_features, n_tickers=5, m_windows=5):
    start_date = pd.Timestamp('01-01-2020')
    window_len = pd.Timedelta(days=1)
    cols = ['window_dt', 'ticker'] + [f'feature_{i}' for i in range(k_features)]
    data = {c: [] for c in cols}
    
    for w in range(m_windows):
        window_dt = start_date + w*window_len
        for t in range(n_tickers):
            ticker = f'ticker_{t}'
            data['window_dt'].append(window_dt)
            data['ticker'].append(ticker)
            for f in range(k_features):
                data[f'feature_{f}'].append(np.random.rand())
    return pd.DataFrame(data)

k_features = 3
features = [f'feature_{i}' for i in range(k_features)]
df = create_test_df(k_features)

selector = pn.widgets.Select(options=features)
heatmap = hv.HeatMap(df[['window_dt', 'ticker', f'{selector.value}']])
posxy = hv.streams.Tap(source=heatmap, x='01-01-2020', y='ticker_4')

def tap_heatmap(x, y):
    scalar = np.random.randn()
    x = np.linspace(-2*np.pi, 2*np.pi, 100)
    data = list(zip(x, np.sin(x*scalar)))
    return hv.Curve(data)

pn.Row(heatmap, hv.DynamicMap(tap_heatmap, streams=[posxy]), selector)

Upvotes: 0

Views: 481

Answers (1)

yol
yol

Reputation: 19

Ok I finally got it. It turned out to be simple (just as expected) but not quite intuitive. Basically, different approach for implementing selector (dropdown menu) should be used. Working code for such example is below:

import pandas as pd
import numpy as np

import panel as pn
import holoviews as hv


hv.extension('bokeh')


def create_test_df(k_features, n_tickers=5, m_windows=5):
    start_date = pd.Timestamp('01-01-2020')
    window_len = pd.Timedelta(days=1)
    cols = ['window_dt', 'ticker'] + [f'feature_{i}' for i in range(k_features)]
    data = {c: [] for c in cols}
    
    for w in range(m_windows):
        window_dt = start_date + w*window_len
        for t in range(n_tickers):
            ticker = f'ticker_{t}'
            data['window_dt'].append(window_dt)
            data['ticker'].append(ticker)
            for f in range(k_features):
                data[f'feature_{f}'].append(np.random.rand())
    return pd.DataFrame(data)


def load_heatmap(feature):
    return hv.HeatMap(df[['window_dt', 'ticker', f'{feature}']])


def tap_heatmap(x, y):
    scalar = np.random.randn()
    x = np.linspace(-2*np.pi, 2*np.pi, 100)
    data = list(zip(x, np.sin(x*scalar)))
    return hv.Curve(data)


k_features = 3
features = [f'feature_{i}' for i in range(k_features)]
df = create_test_df(k_features)

heatmap_dmap = hv.DynamicMap(load_heatmap, kdims='Feature').redim.values(Feature=features)
posxy = hv.streams.Tap(source=heatmap_dmap, x='01-01-2020', y='ticker_0')
sidegraph_dmap = hv.DynamicMap(tap_heatmap, streams=[posxy])

pn.Row(heatmap_dmap, sidegraph_dmap)

Upvotes: 1

Related Questions