1

I am working on a project to visualize a set of data using different diagrams. Using Bokeh's ColumnDataSource along with sliders for callbacks, I have set up a program that illustrates the data using bar charts and pie charts. I also want to add a Sankey diagram to illustrate the same data, where the plotted values change based on the value of the sliders. To do this I have to use HoloViews' Sankey module.

I have set up a javascript callback that automatically updates the values in the ColumnDataSource, and have linked those to the values the Sankey is meant to use. The issue I am having is that the Sankey diagram does not update in response to the value of the sliders changing, and I haven't been able to figure out why. If I add separate sliders from HoloViews, it ends up working. But this is not an ideal solution, as I want the Sankey to be able to interact with the sliders from Bokeh, and update itself in real-time.

There were not a lot of helpful resources online, but I suspect the issue can be resolved using the DynamicMap+streams modules. I just haven't been able to figure out how

Here is my code:

import holoviews as hv
hv.extension('bokeh')
from holoviews import opts, dim, streams, param

from bokeh.io import show
from bokeh.models import ColumnDataSource, TextInput
from bokeh.palettes import Paired12, Pastel1_3
from bokeh.plotting import figure
from bokeh.transform import factor_cmap

from bokeh.layouts import column, row
from bokeh.models import CustomJS, Slider, Dropdown, Panel, Tabs, HoverTool, Paragraph

fruits = ['El Biom', 'El CS', 'El NEE', 'Fuel Biom', 'Fuel CS',
          'Fuel NEE', 'CU Biom', 'CU CS', 'CU NEE', 'NET Biom',
          'NET CS', 'NET NEE']

counts = [0, 0.25, 0.425, 0.0261420833, 0.035854375, 0.079944375, 0.0368772727, 0.0426204545, 0.228336818,
          0.0216474074, 0.0172977778, 0.0586568889]

empty = [0, 0.25, 0.425, 0.0261420833, 0.035854375, 0.079944375, 0.0368772727, 0.0426204545, 0.228336818,
          0.0216474074, 0.0172977778, 0.0586568889]

source = ColumnDataSource(data=dict(fruits=fruits, counts=counts, empty=empty))


slider = Slider(start=0, end=2, value=1, step=.05, title="El Gen")
slider2 = Slider(start=0, end=2, value=1, step=.05, title="Fuel")
slider3 = Slider(start=0, end=2, value=1, step=.05, title="CU")
slider4 = Slider(start=0, end=2, value=1, step=.05, title="NET")

callback = CustomJS(args=dict(source=source, source_zer=source_zer, slider=slider, slider2=slider2, slider3=slider3, slider4=slider4),
                    code="""
    let x = source.data['empty']
    let y = source.data['counts'];
    for (let i = 0; i < y.length; i++) {
        x[0] = y[0] * slider.value
        x[1] = y[1] * slider.value
        x[2] = y[2] * slider.value
        x[3] = y[3] * slider2.value
        x[4] = y[4] * slider2.value
        x[5] = y[5] * slider2.value
        x[6] = y[6] * slider3.value
        x[7] = y[7] * slider3.value
        x[8] = y[8] * slider3.value
        x[9] = y[9] * slider4.value
        x[10] = y[10] * slider4.value
        x[11] = y[11] * slider4.value
        }

    source.change.emit();
""")


slider.js_on_change('value', callback)
slider2.js_on_change('value', callback)
slider3.js_on_change('value', callback)
slider4.js_on_change('value', callback)



data_zer = [
    ['Electricity', 'Biom', source.data['empty'][0]],
    ['Electricity', 'CS', source.data['empty'][1]],
    ['Electricity', 'NEE', source.data['empty'][2]],
    ['Fuel', 'Biom', source.data['empty'][3]],
    ['Fuel', 'CS', source.data['empty'][4]],
    ['Fuel', 'NEE', source.data['empty'][5]],
    ['CU', 'Biom', source.data['empty'][6]],
    ['CU', 'CS', source.data['empty'][7]],
    ['CU', 'NEE', source.data['empty'][8]],
    ['NET', 'Biom', source.data['empty'][9]],
    ['NET', 'CS', source.data['empty'][10]],
    ['NET', 'NEE', source.data['empty'][11]]]

sankey.opts(
    opts.Sankey(height=500, width=750, cmap='Paired')
)

tab3 = Panel(child=hv.render(sankey), title="Sankey")



layout = row(column(slider, slider2, slider3, slider4), Tabs(tabs=[tab3]))

show(layout)

0 Answers0