Skip to content Skip to sidebar Skip to footer

How To Delete/add Rows In Bokeh Heatmap And Maintain Row Height?

I've made a Bokeh heatmap linked to a CheckBoxGroup, so that the active items in the CheckBoxGroup correspond to the rows displayed in the heatmap. i.e. checking/unchecking boxes i

Solution 1:

In the last lines of the CustomJS callback, right after the update the yrange to reflect the deleted data comment, you explicitly change the range - and that's exactly what makes the plot behave the way it does.

Just remove everything after source.data = newdata; - you don't need source.change.emit(); either since you change the whole data attribute.

Solution 2:

What was needed here was to adjust frame_height in the callback and call plot.properties.height.change.emit() - answered with some help from here: https://discourse.bokeh.org/t/how-to-delete-add-rows-in-bokeh-heatmap-and-maintain-row-height/4917/10

Final MWE:

from bokeh.io import output_file, show
from bokeh.models import ColorBar, ColumnDataSource, LinearColorMapper
from bokeh.plotting import figure
from bokeh.transform import transform
from bokeh.layouts import row, widgetbox
from bokeh.models.callbacks import CustomJS
from bokeh.models.widgets import CheckboxGroup
import pandas as pd

output_file("test.html")

# set up data
df = pd.DataFrame([["1", "1", 0.09], ["2", "1", 0.21], ["3", "1", 0.31], ["4", "1", 0.41],
                   ["1", "2", 0.5], ["2", "2", 0.61], ["3", "2", 0.71], ["4", "2", 0.81]],
                  columns=["x", "y", "values"])

# source data for plot
source = ColumnDataSource(df)

# original source dataset, does not get changed
savedsource = ColumnDataSource(df)

# set up plot
colors = ["#5A736F", "#75968f", "#a5bab7", "#c9d9d3", "#e2e2e2", "#dfccce", "#ddb7b1", "#cc7878", "#933b41",
          "#550b1d"]
mapper = LinearColorMapper(palette=colors, low=0, high=1)

p = figure(title="Test", plot_width=200, plot_height=240,
           x_range=["1", "2", "3", "4"], y_range=["1", "2"],
           toolbar_location=None, tools="", x_axis_location="above")

p.frame_height = 240# 2 rows of height 120

p.rect(x="x", y="y", width=1, height=1, source=source,
       line_color=None, fill_color=transform('values', mapper))

p.axis.axis_line_color = None
p.axis.major_tick_line_color = None
p.axis.major_label_text_font_size = "9pt"
p.axis.major_label_standoff = 0
p.xaxis.major_label_orientation = 1.0# Create the checkbox selection element
rows = ["1", "2"]
selection = CheckboxGroup(labels=rows,
                          active=[i for i inrange(0, len(rows))])

callback = CustomJS(args=dict(source=source, savedsource=savedsource, plot=p),
                    code="""

                    // get selected checkboxes
                    var active = cb_obj.active;

                    // get full original dataset
                    var origdata = savedsource.data;

                    // number of x-values
                    var numxs = plot.x_range.factors.length;

                    // this will be the new dataset
                    var newdata = {"index": [], "values": [], "x": [], "y": []};

                    // new y labels
                    var newlabels = [];

                    // slice out the data we want and put it into newdata
                    var i, j;
                    for (j=0; j<active.length; j++)
                    {
                        i = active[j]; // next active checkbox

                        newdata.index.push(...origdata.index.slice(i*numxs, i*numxs + numxs));
                        newdata.values.push(...origdata.values.slice(i*numxs, i*numxs + numxs));
                        newdata.x.push(...origdata.x.slice(i*numxs, i*numxs + numxs));
                        newdata.y.push(...origdata.y.slice(i*numxs, i*numxs + numxs));

                        newlabels.push(...origdata.y.slice(i*numxs, i*numxs + 1));
                    }

                    // replace the plot source data with newdata
                    source.data = newdata;

                    // update the yrange to reflect the deleted data
                    plot.y_range.factors = newlabels;
                    plot.y_range.end = newlabels.length;

                    // update plot height
                    new_height = newlabels.length * 120; //rowheight is 120
                    plot.frame_height = new_height;
                    plot.properties.height.change.emit();
                """)

selection.js_on_change('active', callback)

layout = row(widgetbox(selection), p)

show(layout)

Post a Comment for "How To Delete/add Rows In Bokeh Heatmap And Maintain Row Height?"