散景多 Select 小部件回调不工作
Bokeh Multi-Select widget callback not Working
我是 Bokeh 的新手。最近尝试实现一些小部件回调并且很难在网上找到任何资源。
场景:我有一个 multi_select 散景小部件,其中包含公司列表。根据选择的公司,必须更改 Vbar 中的数据。为此,我试图根据 Multi select 的值更改 Vbar 中使用的数据源。我无法获得想要的结果。有人可以帮我解决这个问题吗?
我不擅长 CustomJs,因此在 Bokeh Server 上为 callabcks 做这个。如果 CustomJs 也有解决方案,那将对我有很大帮助。
非常感谢您提前抽出时间!
下面是我使用的代码
source =source1[source1['year']== dt.now().year]
sourcex = source[source['month'] ==1 &
source['CompanyNo'].isin(['01','02','03','04','05','08']) ]
Overall= ColumnDataSource(source)
Curr= ColumnDataSource(sourcex)
boolinit = source['month']==1
view = CDSView(source=Overall, filters=[BooleanFilter(boolinit)])
hover3 = HoverTool(
tooltips = [
('day', '@day'),
('ExtendedPrice','@{ExtendedPrice}{0,0}'),
],
formatters = {
'day': 'datetime',
'ExtendedPrice': 'numeral'}
)
p = figure(
title='YEARLY SALES',
plot_width=600,
plot_height=400,
min_border=3,
tools = [hover3,'box_zoom','wheel_zoom', 'pan','reset'],
toolbar_location="above")
p.vbar(x='day', top='ExtendedPrice', width=0.2, color='#e8bc76',
source=Curr)
p.xaxis.axis_label = 'Day'
p.xaxis.axis_label_text_font_style = 'normal'
p.xaxis.axis_label_text_font_size = '12pt'
p.yaxis[0].formatter = NumeralTickFormatter(format="0,0")
def Multi_Selectupdate(attrname, old, new):
curr=sourcex[sourcex['CompanyNo'].isin(new)]
source.data=curr.data
companies=['All']+sourcex['CompanyNo'].unique().tolist()
multi_select = MultiSelect(title="Select:", value=['01'], options=companies,
height=200, width=100)
multi_select.on_change('value',Multi_Selectupdate )
layout = column(multi_select, p )
show(layout)
由于我没有数据,所以我使用以下脚本生成了它。我假设您的数据有 3 列 - Date
、ExtendedPrice
、CompanyNo
。我先生成了一个10K行的随机数据,然后在CompanyNo
、day
、month
、year
级别汇总。
import pandas as pd
import random
CopmanyList = ['00', '01', '02', '03', '04', '05', '06', '07', '08', '09', '10', '11', '12', '13', '14', '15']
df = pd.DataFrame({'base' : ["2017-01-01" for t in range(10000)],
'Date' : [random.randint(0, 1035) for t in range(10000)],
'ExtendedPrice' : [random.random() for t in range(10000)],
'CompanyNo' : [CopmanyList[random.randint(0, 15)] for t in range(10000)]})
df['base'] = pd.to_datetime(df['base'])
df["Date2"] = df.apply(lambda x: x["base"] + timedelta(days=x['Date']), axis=1)
df.drop(['base', 'Date'], axis=1, inplace=True)
df.set_index('Date2', inplace=True)
df['month'] = df.index.month
df['year'] = df.index.year
df['day'] = df.index.day
source1=df.groupby(['year','month','day', 'CompanyNo'], as_index = False)['ExtendedPrice'].sum()
source =source1[source1['year']== dt.now().year]
sourcex = source[source['month'] ==1]
sourcex = sourcex[sourcex['CompanyNo'].isin(['01'])]
sourcex.sort_values(by='day', inplace=True)
现在,您想要完成的是给定一天和一组公司名称,您需要发布 ExtendedPrice
的某种聚合类型的条形图,即公司有 2 行'01' 和 '02'(selected),以及当年的第 2 个月(也由滑块selected),这两个的 ExtendedPrice 值是 100,和 200。如果我们想显示总和,您需要在条形图中显示 300。这个总结,需要动态计算。
有两种方法可以实现。
1.散景回调
这将使用本机 python 函数,但您需要使用 bokeh serve
运行 它,例如 bokeh serve --show <filename.py>
。请参阅下面的代码,本机 python 函数 compsel
正在过滤 pandas 数据帧并对其进行汇总,并用新创建的数据替换图表后端数据 -
from datetime import timedelta
from datetime import datetime as dt
from bokeh.models.widgets import MultiSelect, Slider
from bokeh.layouts import widgetbox, column
from bokeh.models.ranges import FactorRange
from bokeh.plotting import figure, curdoc
from bokeh.models import ColumnDataSource, HoverTool, CustomJS
Overall= ColumnDataSource(source)
Curr= ColumnDataSource(sourcex[['day', 'ExtendedPrice']])
Curr.remove('index')
hover3 = HoverTool(tooltips = [('day', '@day'),('Sales','@{ExtendedPrice}{0,0.00}')],
formatters = {'day': 'datetime','Sales': 'numeral'})
p = figure(title='YEARLY SALES', plot_width=600, plot_height=400, min_border=3,
tools = [hover3,'box_zoom','wheel_zoom', 'pan','reset'],
toolbar_location="above")
r = p.vbar(x='day', top='ExtendedPrice', width=0.2, color='#e8bc76', source=Curr)
p.xaxis.axis_label = 'Day'
p.xaxis.axis_label_text_font_style = 'normal'
p.xaxis.axis_label_text_font_size = '12pt'
def compsel(attr, old, new):
vcomp = multi_select.value
vmonth = slider.value
sourcex = source[source['month'] ==vmonth]
sourcex = sourcex[sourcex['CompanyNo'].isin(vcomp)]
sourcex = sourcex.groupby(['day'], as_index = False)['ExtendedPrice'].sum()
Currnew= ColumnDataSource(sourcex[['day', 'ExtendedPrice']])
Currnew.remove('index')
r.data_source.data=Currnew.data
companies=source['CompanyNo'].unique().tolist()
companies.sort()
multi_select = MultiSelect(title="Select:", value=['01'], options=companies, height=200, width=100)
slider = Slider(start=1, end=12, value=1, step=1, title="Month")
slider.on_change("value", compsel)
multi_select.on_change("value", compsel)
layout = column(multi_select, slider, p)
curdoc().add_root(layout)
还有其他选项可以托管此应用程序。在终端
中输入 bokeh serve --help
查看其他选项
2。 JavaScript 回调
这将生成一个 javascript 函数来与图表交互,它不需要散景服务器并直接在浏览器上工作。这将需要 javascript 中非常简单的代码。在此处解决的示例中,我将 ExtendedPrice
总结为总和,但代码需要进行小的调整才能计算其他统计数据,例如意思。这里的 js 回调函数与 bokeh 回调函数类似,它读取较大的数据集并根据 select 和滑块值 -
对其进行过滤
source =source1[source1['year']== dt.now().year]
sourcex = source[source['month'] ==1]
sourcex = sourcex[sourcex['CompanyNo'].isin(['01'])]
sourcex.sort_values(by='day', inplace=True)
Overall= ColumnDataSource(source)
Curr= ColumnDataSource(sourcex[['day', 'ExtendedPrice']])
Curr.remove('index')
hover3 = HoverTool(tooltips = [('day', '@day'),('Sales','@{ExtendedPrice}{0,0.00}')],
formatters = {'day': 'datetime','Sales': 'numeral'})
p = figure(title='YEARLY SALES', plot_width=600, plot_height=400, min_border=3,
tools = [hover3,'box_zoom','wheel_zoom', 'pan','reset'],
toolbar_location="above")
r = p.vbar(x='day', top='ExtendedPrice', width=0.2, color='#e8bc76', source=Curr)
p.xaxis.axis_label = 'Day'
p.xaxis.axis_label_text_font_style = 'normal'
p.xaxis.axis_label_text_font_size = '12pt'
callms = CustomJS(args=dict(source=Overall, sc=Curr), code="""
var comp=msel.attributes.value;
var f = slider.value;
sc.data['ExtendedPrice'] = [];
sc.data['day'] = [];
for (var i = 0; i <= source.get_length(); i++){
if (source.data['month'][i] == f){
if (comp.indexOf(source.data['CompanyNo'][i]) >=0){
var d1 = source.data['day'][i]
if(typeof sc.data['day'][d1-1]=="undefined"){
sc.data['day'][d1-1] = d1
sc.data['ExtendedPrice'][d1-1] = source.data['ExtendedPrice'][i]
}
else{
sc.data['ExtendedPrice'][d1-1] = sc.data['ExtendedPrice'][d1-1] + source.data['ExtendedPrice'][i]
}
}
}
}
sc.change.emit();
""")
companies=source['CompanyNo'].unique().tolist()
companies.sort()
multi_select = MultiSelect(title="Select:", value=['01'], options=companies, height=200, width=100, callback=callms)
slider = Slider(start=1, end=12, value=1, step=1, title="Month", callback=callms)
callms.args["msel"] = multi_select
callms.args["slider"] = slider
layout = column(multi_select, slider, p)
output_file("Filterdata.html")
show(layout)
我是 Bokeh 的新手。最近尝试实现一些小部件回调并且很难在网上找到任何资源。
场景:我有一个 multi_select 散景小部件,其中包含公司列表。根据选择的公司,必须更改 Vbar 中的数据。为此,我试图根据 Multi select 的值更改 Vbar 中使用的数据源。我无法获得想要的结果。有人可以帮我解决这个问题吗?
我不擅长 CustomJs,因此在 Bokeh Server 上为 callabcks 做这个。如果 CustomJs 也有解决方案,那将对我有很大帮助。
非常感谢您提前抽出时间!
下面是我使用的代码
source =source1[source1['year']== dt.now().year]
sourcex = source[source['month'] ==1 &
source['CompanyNo'].isin(['01','02','03','04','05','08']) ]
Overall= ColumnDataSource(source)
Curr= ColumnDataSource(sourcex)
boolinit = source['month']==1
view = CDSView(source=Overall, filters=[BooleanFilter(boolinit)])
hover3 = HoverTool(
tooltips = [
('day', '@day'),
('ExtendedPrice','@{ExtendedPrice}{0,0}'),
],
formatters = {
'day': 'datetime',
'ExtendedPrice': 'numeral'}
)
p = figure(
title='YEARLY SALES',
plot_width=600,
plot_height=400,
min_border=3,
tools = [hover3,'box_zoom','wheel_zoom', 'pan','reset'],
toolbar_location="above")
p.vbar(x='day', top='ExtendedPrice', width=0.2, color='#e8bc76',
source=Curr)
p.xaxis.axis_label = 'Day'
p.xaxis.axis_label_text_font_style = 'normal'
p.xaxis.axis_label_text_font_size = '12pt'
p.yaxis[0].formatter = NumeralTickFormatter(format="0,0")
def Multi_Selectupdate(attrname, old, new):
curr=sourcex[sourcex['CompanyNo'].isin(new)]
source.data=curr.data
companies=['All']+sourcex['CompanyNo'].unique().tolist()
multi_select = MultiSelect(title="Select:", value=['01'], options=companies,
height=200, width=100)
multi_select.on_change('value',Multi_Selectupdate )
layout = column(multi_select, p )
show(layout)
由于我没有数据,所以我使用以下脚本生成了它。我假设您的数据有 3 列 - Date
、ExtendedPrice
、CompanyNo
。我先生成了一个10K行的随机数据,然后在CompanyNo
、day
、month
、year
级别汇总。
import pandas as pd
import random
CopmanyList = ['00', '01', '02', '03', '04', '05', '06', '07', '08', '09', '10', '11', '12', '13', '14', '15']
df = pd.DataFrame({'base' : ["2017-01-01" for t in range(10000)],
'Date' : [random.randint(0, 1035) for t in range(10000)],
'ExtendedPrice' : [random.random() for t in range(10000)],
'CompanyNo' : [CopmanyList[random.randint(0, 15)] for t in range(10000)]})
df['base'] = pd.to_datetime(df['base'])
df["Date2"] = df.apply(lambda x: x["base"] + timedelta(days=x['Date']), axis=1)
df.drop(['base', 'Date'], axis=1, inplace=True)
df.set_index('Date2', inplace=True)
df['month'] = df.index.month
df['year'] = df.index.year
df['day'] = df.index.day
source1=df.groupby(['year','month','day', 'CompanyNo'], as_index = False)['ExtendedPrice'].sum()
source =source1[source1['year']== dt.now().year]
sourcex = source[source['month'] ==1]
sourcex = sourcex[sourcex['CompanyNo'].isin(['01'])]
sourcex.sort_values(by='day', inplace=True)
现在,您想要完成的是给定一天和一组公司名称,您需要发布 ExtendedPrice
的某种聚合类型的条形图,即公司有 2 行'01' 和 '02'(selected),以及当年的第 2 个月(也由滑块selected),这两个的 ExtendedPrice 值是 100,和 200。如果我们想显示总和,您需要在条形图中显示 300。这个总结,需要动态计算。
有两种方法可以实现。
1.散景回调
这将使用本机 python 函数,但您需要使用 bokeh serve
运行 它,例如 bokeh serve --show <filename.py>
。请参阅下面的代码,本机 python 函数 compsel
正在过滤 pandas 数据帧并对其进行汇总,并用新创建的数据替换图表后端数据 -
from datetime import timedelta
from datetime import datetime as dt
from bokeh.models.widgets import MultiSelect, Slider
from bokeh.layouts import widgetbox, column
from bokeh.models.ranges import FactorRange
from bokeh.plotting import figure, curdoc
from bokeh.models import ColumnDataSource, HoverTool, CustomJS
Overall= ColumnDataSource(source)
Curr= ColumnDataSource(sourcex[['day', 'ExtendedPrice']])
Curr.remove('index')
hover3 = HoverTool(tooltips = [('day', '@day'),('Sales','@{ExtendedPrice}{0,0.00}')],
formatters = {'day': 'datetime','Sales': 'numeral'})
p = figure(title='YEARLY SALES', plot_width=600, plot_height=400, min_border=3,
tools = [hover3,'box_zoom','wheel_zoom', 'pan','reset'],
toolbar_location="above")
r = p.vbar(x='day', top='ExtendedPrice', width=0.2, color='#e8bc76', source=Curr)
p.xaxis.axis_label = 'Day'
p.xaxis.axis_label_text_font_style = 'normal'
p.xaxis.axis_label_text_font_size = '12pt'
def compsel(attr, old, new):
vcomp = multi_select.value
vmonth = slider.value
sourcex = source[source['month'] ==vmonth]
sourcex = sourcex[sourcex['CompanyNo'].isin(vcomp)]
sourcex = sourcex.groupby(['day'], as_index = False)['ExtendedPrice'].sum()
Currnew= ColumnDataSource(sourcex[['day', 'ExtendedPrice']])
Currnew.remove('index')
r.data_source.data=Currnew.data
companies=source['CompanyNo'].unique().tolist()
companies.sort()
multi_select = MultiSelect(title="Select:", value=['01'], options=companies, height=200, width=100)
slider = Slider(start=1, end=12, value=1, step=1, title="Month")
slider.on_change("value", compsel)
multi_select.on_change("value", compsel)
layout = column(multi_select, slider, p)
curdoc().add_root(layout)
还有其他选项可以托管此应用程序。在终端
中输入bokeh serve --help
查看其他选项
2。 JavaScript 回调
这将生成一个 javascript 函数来与图表交互,它不需要散景服务器并直接在浏览器上工作。这将需要 javascript 中非常简单的代码。在此处解决的示例中,我将 ExtendedPrice
总结为总和,但代码需要进行小的调整才能计算其他统计数据,例如意思。这里的 js 回调函数与 bokeh 回调函数类似,它读取较大的数据集并根据 select 和滑块值 -
source =source1[source1['year']== dt.now().year]
sourcex = source[source['month'] ==1]
sourcex = sourcex[sourcex['CompanyNo'].isin(['01'])]
sourcex.sort_values(by='day', inplace=True)
Overall= ColumnDataSource(source)
Curr= ColumnDataSource(sourcex[['day', 'ExtendedPrice']])
Curr.remove('index')
hover3 = HoverTool(tooltips = [('day', '@day'),('Sales','@{ExtendedPrice}{0,0.00}')],
formatters = {'day': 'datetime','Sales': 'numeral'})
p = figure(title='YEARLY SALES', plot_width=600, plot_height=400, min_border=3,
tools = [hover3,'box_zoom','wheel_zoom', 'pan','reset'],
toolbar_location="above")
r = p.vbar(x='day', top='ExtendedPrice', width=0.2, color='#e8bc76', source=Curr)
p.xaxis.axis_label = 'Day'
p.xaxis.axis_label_text_font_style = 'normal'
p.xaxis.axis_label_text_font_size = '12pt'
callms = CustomJS(args=dict(source=Overall, sc=Curr), code="""
var comp=msel.attributes.value;
var f = slider.value;
sc.data['ExtendedPrice'] = [];
sc.data['day'] = [];
for (var i = 0; i <= source.get_length(); i++){
if (source.data['month'][i] == f){
if (comp.indexOf(source.data['CompanyNo'][i]) >=0){
var d1 = source.data['day'][i]
if(typeof sc.data['day'][d1-1]=="undefined"){
sc.data['day'][d1-1] = d1
sc.data['ExtendedPrice'][d1-1] = source.data['ExtendedPrice'][i]
}
else{
sc.data['ExtendedPrice'][d1-1] = sc.data['ExtendedPrice'][d1-1] + source.data['ExtendedPrice'][i]
}
}
}
}
sc.change.emit();
""")
companies=source['CompanyNo'].unique().tolist()
companies.sort()
multi_select = MultiSelect(title="Select:", value=['01'], options=companies, height=200, width=100, callback=callms)
slider = Slider(start=1, end=12, value=1, step=1, title="Month", callback=callms)
callms.args["msel"] = multi_select
callms.args["slider"] = slider
layout = column(multi_select, slider, p)
output_file("Filterdata.html")
show(layout)