Bokeh heatmap streaming not working with Panel

I have the following notebook:

from bokeh.models import ColumnDataSource
from bokeh.plotting import figure
from bokeh.palettes import YlGn9

import panel as pn
import pandas as pd
import numpy as np

import math
pn.extension()


def add_heat_map_to_figure(fig: figure, df: DataFrame, colors: List, glyph_size: float) -> figure:
    mapper = LinearColorMapper(palette=colors, low=df.value.min(), high=df.value.max())
    return fig.rect(x="timestamp",
                    y='Tags',
                    width=glyph_size,
                    height=1,
                    source=df,
                    line_color=None,
                    fill_color={'field': 'value', 'transform': mapper})  # transform('value', mapper)


def add_binary_heat_map_to_figure(fig: figure, df: DataFrame, colors: List = None, glyph_size: float = 1) -> figure:
    _colors = colors or ["#474747", "#7fff00"]
    mapper = LinearColorMapper(palette=_colors, low=0, high=1)
    return fig.rect(x="timestamp",
                    y='Tags',
                    width=glyph_size,
                    height=1,
                    source=df,
                    line_color=None,
                    fill_color={'field': 'value', 'transform': mapper})

def create_range_tool(connected_chart: figure, columns: List, add_plot_to_figure: Callable,
                      theme: Dict) -> figure:
    plot_theme = theme.get('plot', {})
    col_num = len(columns)
    plot_height = 50 * col_num
    # Create a figure
    select_fig = figure(title="Drag the middle and edges of the selection box to change the range above",
                        plot_height=plot_height,
                        y_range=columns,
                        x_axis_type="datetime",
                        x_axis_location="above",
                        tools="hover",
                        **plot_theme)

    # Add range tool to figure
    range_tool = RangeTool(x_range=connected_chart.x_range)
    range_tool.overlay.fill_color = "navy"
    range_tool.overlay.fill_alpha = 0.2

    select_fig.add_tools(range_tool)

    # Add plotting to figure
    add_plot_to_figure(select_fig)

    select_fig.x_range.range_padding = 0
    select_fig.outline_line_color = None
    select_fig.sizing_mode = 'stretch_width'
    select_fig.ygrid.grid_line_color = None
    select_fig.toolbar.active_multi = range_tool
    return select_fig, range_tool


minutes_in_month = 44200
sample_rate = 200
sample_rates_in_month = math.ceil(minutes_in_month / sample_rate)
four_weeks = max(len(cols) * sample_rates_in_month, 1)
one_month_dff = dff.loc[0:four_weeks].copy()

dates = one_month_dff.timestamp.values
glyph_size = 200*60*1000

fig = figure(x_axis_type="datetime", y_range=cols, x_range=(dates[0], dates[-1]), sizing_mode = 'stretch_width', tools="hover")
fig.outline_line_color = None

main_source = ColumnDataSource(one_month_dff)

add_binary_heat_map_to_figure(fig, main_source, glyph_size=glyph_size)

def add_to_figure(fig):
    return add_heat_map_to_figure(fig, header_dff, YlGn9, 604800000)


def to_time(time):
    if isinstance(time, float):
        return pd.Timestamp(time, unit='ms').replace(microsecond=0)
    return pd.Timestamp(time).replace(microsecond=0)

def update_chart(e):
    s, e = to_time(range_tool.x_range.start), to_time(range_tool.x_range.end)
    _start, _end = one_month_dff.iloc[[0, -1]].timestamp
    start = min(s, _start)
    end = max(e, _end)
    new_dff = dff[(dff.timestamp >= start) & (dff.timestamp <= end)]
    main_source.stream(new_dff)

    
f, range_tool = create_range_tool(fig, _cols, add_to_figure, {})
button = pn.widgets.Button(name='update')
button.on_click(update_chart)

pn.Column(button, f,fig, sizing_mode="scale_width")

Which generates:

Now, the following area in the code should stream data to the bottom heatmap on click.
But it is not.

def update_chart(e):
    s, e = to_time(range_tool.x_range.start), to_time(range_tool.x_range.end)
    _start, _end = one_month_dff.iloc[[0, -1]].timestamp
    start = min(s, _start)
    end = max(e, _end)
    new_dff = dff[(dff.timestamp >= start) & (dff.timestamp <= end)]
    main_source.stream(new_dff)

System:

bokeh==2.2.1
jupyter-bokeh==2.0.2
panel==0.10.0a18

Any idea what am i doing wrong?

Thanks in advance

So I can’t currently run your example since the data is missing but I think the issue is that Panel isn’t picking up on stream event and you may have to manually tell it to update. You can do this by wrapping your figure in a Panel object and then manually using fig.param.trigger('object') to generate the event.

def update_chart(e):
    s, e = to_time(range_tool.x_range.start), to_time(range_tool.x_range.end)
    _start, _end = one_month_dff.iloc[[0, -1]].timestamp
    start = min(s, _start)
    end = max(e, _end)
    new_dff = dff[(dff.timestamp >= start) & (dff.timestamp <= end)]
    main_source.stream(new_dff)
    fig.param.trigger('object') # Try adding this

fig = pn.panel(fig)

If that doesn’t work I can try to dig deeper (ideally with a fully runnable example).

1 Like