AxoBlue
AxoBlue

Reputation: 11

Use slider to update stack bar value in bokeh

I have my data set up similar to the fruits example below. I have been trying to add a slider that controls for example the year '2015' and when I change the slider value, the stacked chart updates according to this new value.

Example: Current value: 2015:[2, 1, 4, 3, 2, 4] Slider value: 2 New value = Current value + slider value ---> 2015: [4,3,6,5,4,6]

Slider value:0 ---> 2015:[2, 1, 4, 3, 2, 4] (back to original value)

I hope someone can help me.

Thank you!

from bokeh.palettes import GnBu3, OrRd3
output_notebook()

years = ['2015', '2016', '2017']

exports = {'fruits' : fruits,
           '2015'   : [2, 1, 4, 3, 2, 4],
           '2016'   : [5, 3, 4, 2, 4, 6],
           '2017'   : [3, 2, 4, 4, 5, 3]}

p = figure(x_range=fruits, plot_height=250, y_range=(0, 16), title="Fruit import/export, by year")

p.vbar_stack(years, x='fruits', width=0.9, color=GnBu3, source=ColumnDataSource(exports))


p.x_range.range_padding = 0.1
p.xgrid.grid_line_color = None

slider = Slider(start=0, end=5, value=0, step=1, title="2015 exports")

show(column(p,slider))

Upvotes: 0

Views: 229

Answers (2)

AxoBlue
AxoBlue

Reputation: 11

Here's a solution that works by replacing the whole object.

def plot_stack_slider():
    years = ['2015', '2016', '2017']
    fruits = ['Apples', 'Pears', 'Nectarines', 'Plums', 'Grapes', 'Strawberries']
    exports = {'fruits' : fruits,
               '2015'   : [2, 1, 4, 3, 2, 4],
               '2016'   : [5, 3, 4, 2, 4, 6],
               '2017'   : [3, 2, 4, 4, 5, 3]
              }

    source = ColumnDataSource(data={
               'fruits' : fruits,
               '2015'   : [2, 1, 4, 3, 2, 4],
               '2016'   : [5, 3, 4, 2, 4, 6],
               '2017'   : [3, 2, 4, 4, 5, 3]
              })
    display = ColumnDataSource(data={'fruits' : fruits,
               '2015'   : [2, 1, 4, 3, 2, 4],
               '2016'   : [5, 3, 4, 2, 4, 6],
               '2017'   : [3, 2, 4, 4, 5, 3]
              })

    p = figure(x_range=fruits, plot_height=250, y_range=(0, 16), title="Fruit import/export, by year")

    p.vbar_stack(years, x='fruits', width=0.9, color=GnBu3, source=display)
    # p.Bar(test_display,fruits,stacked=True)

    p.x_range.range_padding = 0.1
    p.xgrid.grid_line_color = None

    slider = Slider(start=0, end=5, value=0, step=1, title="2015 exports")
    slider2 = Slider(start=0, end=5, value=0, step=1, title="2016 exports")

    callback = CustomJS(
        args=dict(source=source, display=display, slider=slider, slider2=slider2),
        code="""
        display.data = { 
            ...source.data, 
            '2015': source.data['2015'].map((c) => c + slider.value ),
            '2016': source.data['2016'].map((c) => c + slider2.value ),
        };
    
    """)

    slider.js_on_change('value', callback)
    slider2.js_on_change('value', callback)
    
    show(column(p,slider, slider2))

plot_stack_slider()

Upvotes: 1

mosc9575
mosc9575

Reputation: 6337

This should be possible with a CustomJS block and an aditional row to store the original value.

from bokeh.plotting import figure, show, output_notebook
from bokeh.models import CustomJS,ColumnDataSource, Slider
from bokeh.layouts import column
from bokeh.palettes import GnBu3, OrRd3
output_notebook()

years = ['2015', '2016', '2017']
fruits = ['Apples', 'Pears', 'Nectarines', 'Plums', 'Grapes', 'Strawberries']
exports = {'fruits' : fruits,
           '2015'   : [2, 1, 4, 3, 2, 4],
           '2015_org'   : [2, 1, 4, 3, 2, 4],
           '2016'   : [5, 3, 4, 2, 4, 6],
           '2017'   : [3, 2, 4, 4, 5, 3]
          }

source = ColumnDataSource(exports)

p = figure(x_range=fruits, plot_height=250, y_range=(0, 16), title="Fruit import/export, by year")

p.vbar_stack(years, x='fruits', width=0.9, color=GnBu3, source=source)

p.x_range.range_padding = 0.1
p.xgrid.grid_line_color = None

slider = Slider(start=0, end=5, value=0, step=1, title="2015 exports")

callback = CustomJS(
    args=dict(source=source, slider=slider),
    code="""
    let y = source.data['2015'];
    let y_org = source.data['2015_org']
    for (let i = 0; i < y.length; i++) {
        y[i] = y_org[i] + slider.value
    }

    source.change.emit();

""")

slider.js_on_change('value', callback)

show(column(p,slider))

Upvotes: 0

Related Questions