Javascript Bokeh-使用Select小部件和CustomJS更新绘图
我正在尝试显示条形图,并通过选择对象筛选内容。虽然看起来很简单,但经过两天的研究,我还没有找到一个有效的解决方案。我需要用CustomJS来做这件事,而不是bokeh服务器 这是我正在尝试的代码,但是当我运行它时,没有显示任何内容,甚至没有一个空的绘图Javascript Bokeh-使用Select小部件和CustomJS更新绘图,javascript,python,pandas,callback,bokeh,Javascript,Python,Pandas,Callback,Bokeh,我正在尝试显示条形图,并通过选择对象筛选内容。虽然看起来很简单,但经过两天的研究,我还没有找到一个有效的解决方案。我需要用CustomJS来做这件事,而不是bokeh服务器 这是我正在尝试的代码,但是当我运行它时,没有显示任何内容,甚至没有一个空的绘图 import pandas as pd from bokeh.plotting import figure from bokeh.models import ColumnDataSource, CustomJS, CustomJSFilter,
import pandas as pd
from bokeh.plotting import figure
from bokeh.models import ColumnDataSource, CustomJS, CustomJSFilter, CDSView, Select, IndexFilter
from bokeh.io import show, output_notebook
from bokeh.layouts import column
output_notebook()
df = pd.DataFrame({'Subject': ['Math', 'Math', 'Math', 'Science', 'Science', 'Science'],
'Class': ['Algebra', 'Calculus', 'Trigonometry', 'Biology', 'Chemistry', 'Physics'],
'FailRate': [0.05, 0.16, 0.31, 0.12, 0.20, 0.08]})
src = ColumnDataSource(df)
subj_list = sorted(list(set(src.data['Subject'])))
callback = CustomJS(args=dict(src=src), code='''
src.change.emit();
''')
js_filter = CustomJSFilter(code='''
var indices = [];
for (var i = 0; i < src.get_length(); i++){
if (src.data['Subject'][i] == select.value){
indices.push(true);
} else {
indices.push(false);
}
}
return indices;
''')
options = ['Please select...'] + subj_list
select = Select(title='Subject Selection', value=options[0], options=options)
select.js_on_change('value', callback)
view = CDSView(source=src, filters=[js_filter])
class_list = sorted(list(src.data['Class']))
p = figure(x_range=class_list, plot_height=400, plot_width=400)
p.vbar('Class', top='FailRate', width=0.9, source=src, view=view)
show(column(select, p))
在我将“view=view”添加到上一行之前,我至少显示了一个选择框和绘图,即使交互不起作用。Bokeh可以神奇地跨运行时传输Python对象,使其在浏览器中显示为JavaScript对象,但这一魔法是有限的。通过向
CustomJS
对象提供args
参数,您必须准确地告诉Bokeh要传输哪些对象。此外,如果您使用回调更新IndexFilter
中的索引,这会更简单。那么您只需要一个回调:
filter = IndexFilter(indices=[])
callback = CustomJS(args=dict(src=src, filter=filter), code='''
const indices = []
for (var i = 0; i < src.get_length(); i++) {
console.log(i, src.data['Subject'][i], cb_obj.value)
if (src.data['Subject'][i] == cb_obj.value) {
indices.push(i)
}
}
filter.indices = indices
src.change.emit()
''')
select.js_on_change('value', callback)
view = CDSView(source=src, filters=[filter])
甚至在重复的单元格调用中。注意,cb_obj
没有什么错,但是许多人更喜欢显式地传递(和命名)小部件
最后我要提到的是,学习检查浏览器的JS控制台对于调试
CustomJS
类型回调是必不可少的。代码中的错误立即显示在那里 谢谢,这让我更接近,但结果有两个问题。第一种情况是,初始绘图(尚未进行选择时)显示为空白,并且在网格的左上角填充了一堆小文本。第二个问题是x_范围值没有得到更新,因此对于从绘图中筛选出来的项目,x轴上仍然有记号。您需要显式设置y_范围
(我在测试时使用了y_范围=(0,1)
),Bokeh无法在没有数据进行自动范围设置时自动范围,您已经将其设置为从空视图开始。或者,您可以选择从其中一个类别开始,以便在开始时存在数据。范围问题是一个单独的问题。请打开一个新主题(在本文中)
filter = IndexFilter(indices=[])
callback = CustomJS(args=dict(src=src, filter=filter), code='''
const indices = []
for (var i = 0; i < src.get_length(); i++) {
console.log(i, src.data['Subject'][i], cb_obj.value)
if (src.data['Subject'][i] == cb_obj.value) {
indices.push(i)
}
}
filter.indices = indices
src.change.emit()
''')
select.js_on_change('value', callback)
view = CDSView(source=src, filters=[filter])
options = ['Please select...'] + subj_list
select = Select(title='Subject Selection', value=options[0], options=options)
cb = CustomJS(args=dict(select=select, src=src, filter=filter), ...)