问题
I want to be able to only show the initial top 3 bars and then show more or less bars using the slider. I don't know if this is possible using the slider widget of bokeh or if there is a better method.
from bokeh.models.widgets import Slider
from bokeh.layouts import widgetbox, column
from bokeh.models import CustomJS, Slider
fruits = ['Apples', 'Pears', 'Nectarines', 'Plums', 'Grapes', 'Strawberries']
years = ["2015", "2016", "2017"]
colors = ["#c9d9d3", "#718dbf", "#e84d60"]
data = {'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=data)
p = figure(x_range=fruits, plot_height=350, title="Fruit Counts by Year",
toolbar_location=None, tools="")
p.vbar_stack(years, x='fruits', width=0.9, color=colors, source=source,
legend=[value(x) for x in years], name=years)
callback = CustomJS(args=dict(source = source), code="""
var data = source.data;
var start = slider.value;
var x = data['OOC_EQP'];
x_range.setv({"start":start, "end":start+10});
""")
p.y_range.start = 0
p.x_range.range_padding = 0.1
p.xgrid.grid_line_color = None
p.axis.minor_tick_line_color = None
p.outline_line_color = None
p.legend.location = "top_left"
p.legend.orientation = "horizontal"
slider = Slider(start=1, end=6, value=3, step=1, title="Range")
callback.args["slider"] = slider
layout = column(p, widgetbox(slider))
show(layout)
回答1:
I don't see a need to use javascript callback
here. A native python on_change
function can be used here. The function will change the x-axis range without changing any back-end data, and will be really fast -
from bokeh.models.widgets import Slider
from bokeh.layouts import widgetbox, column
from bokeh.models import Slider, ColumnDataSource
from bokeh.plotting import figure, curdoc
from bokeh.core.properties import value
from bokeh.models.ranges import FactorRange
fruits = ['Apples', 'Pears', 'Nectarines', 'Plums', 'Grapes', 'Strawberries']
years = ["2015", "2016", "2017"]
colors = ["#c9d9d3", "#718dbf", "#e84d60"]
data = {'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=data)
## Note [0:3] for first 3 fruits only in default graph
p = figure(x_range=fruits[0:3], plot_height=350, title="Fruit Counts by Year",
toolbar_location=None, tools="")
renderers= p.vbar_stack(years, x='fruits', width=0.9, color=colors, source=source, \
legend=[value(x) for x in years], name=years)
p.y_range.start = 0
p.x_range.range_padding = 0.1
p.xgrid.grid_line_color = None
p.axis.minor_tick_line_color = None
p.outline_line_color = None
p.legend.location = "top_left"
p.legend.orientation = "horizontal"
slider = Slider(start=1, end=6, value=3, step=1, title="Range")
#function to update axis range
def update_axis(attrname, old, new):
a=slider.value
p.x_range.factors=fruits[0:a]
#Adding fucntion to on_change
slider.on_change('value', update_axis)
layout = column(p, widgetbox(slider))
#use curdoc to be used with bokeh server - use 'bokeh serve --show <filename>.py'
curdoc().add_root(layout)
Call this using Bokeh serve, as it need python backend to run the function
In case you want to use Javascript only, and not the bokeh server, even in that case, I will suggest to change only x_range, and not the data. See code below -
from bokeh.models.widgets import Slider
from bokeh.layouts import widgetbox, column
from bokeh.models import Slider, ColumnDataSource, CustomJS
from bokeh.plotting import figure, curdoc
from bokeh.core.properties import value
from bokeh.models.ranges import FactorRange
from bokeh.plotting import figure, output_file, show, ColumnDataSource
fruits = ['Apples', 'Pears', 'Nectarines', 'Plums', 'Grapes', 'Strawberries']
years = ["2015", "2016", "2017"]
colors = ["#c9d9d3", "#718dbf", "#e84d60"]
data = {'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=data)
## Note [0:3] for first 3 fruits only in default graph
p = figure(x_range=fruits[0:3], plot_height=350, title="Fruit Counts by Year",
toolbar_location=None, tools="")
renderers= p.vbar_stack(years, x='fruits', width=0.9, color=colors, source=source, \
legend=[value(x) for x in years], name=years)
p.y_range.start = 0
p.x_range.range_padding = 0.1
p.xgrid.grid_line_color = None
p.axis.minor_tick_line_color = None
p.outline_line_color = None
p.legend.location = "top_left"
p.legend.orientation = "horizontal"
print(renderers[0].data_source.data['fruits'])
callback = CustomJS(args=dict(fig=p, xr=renderers[0].data_source.data['fruits']), code="""
var A = slider.value;
fig.x_range.factors = [];
for (i = 0; i < A; i++) {
fig.x_range.factors.push(xr[i])
}
""")
p.x_range.js_on_change('factors', callback)
slider = Slider(start=1, end=6, value=3, step=1, title="Range", callback=callback)
callback.args["slider"] = slider
layout = column(p, widgetbox(slider))
output_file("ChangenumCat.html")
show(layout)
来源:https://stackoverflow.com/questions/50681244/bokeh-slider-stacked-bar-chart