Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/312.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python Bokeh多选小部件回调不工作_Python_Python 3.x_Callback_Bokeh_Multi Select - Fatal编程技术网

Python Bokeh多选小部件回调不工作

Python Bokeh多选小部件回调不工作,python,python-3.x,callback,bokeh,multi-select,Python,Python 3.x,Callback,Bokeh,Multi Select,我是博克的新手。最近尝试实现一些小部件回调,很难在网上找到任何资源 场景:我有一个带有公司列表的multi_select bokeh小部件。根据选择的公司,必须更改Vbar中的数据。为此,我尝试根据Multi-select中的值更改Vbar中使用的数据源。我无法得到想要的结果。有人能帮我解决这个问题吗 我在CustomJs方面很差,因此在Bokeh服务器上为callabcks这样做。如果CustomJs上也有解决方案,那将对我帮助很大 非常感谢您提前抽出时间 下面是我正在使用的代码 source

我是博克的新手。最近尝试实现一些小部件回调,很难在网上找到任何资源

场景:我有一个带有公司列表的multi_select bokeh小部件。根据选择的公司,必须更改Vbar中的数据。为此,我尝试根据Multi-select中的值更改Vbar中使用的数据源。我无法得到想要的结果。有人能帮我解决这个问题吗

我在CustomJs方面很差,因此在Bokeh服务器上为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)
现在,您要完成的是,给定一天和一组公司名称,您需要发布某种类型的聚合条形图,即,假设公司“01”和“02”(已选择)有两行,第2个月(也通过滑块选择)有两行,用于本年,这两个的扩展价格值分别为100和200。如果我们想显示一个总和,你需要在条形图中显示300。在这个总结中,您需要动态计算

有两种方法可以实现它

1。Bokeh回调

这将使用本机python函数,但您需要使用
bokeh-serve
运行它,例如
bokeh-serve--show
。参见下面的代码,一个本地python函数
compsel
正在过滤数据帧并对其进行汇总,并用新创建的数据替换图表后端数据-

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-service--help
查看其他选项

2。JavaScript回调

这将生成一个javascript函数来与图表交互,图表不需要bokeh服务器,直接在浏览器上工作。这需要非常简单的javascript代码。在这里解决的示例中,我将
ExtendedPrice
总结为sum,但是代码需要进行一些小的调整来计算其他统计数据,例如平均值。这里的js回调函数与bokeh回调函数的作用类似,它读取较大的数据集,并根据select和slider值对其进行过滤-

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)
source=source1[source1['year']==dt.now().year]
sourcex=source[source['month']==1]
sourcex=sourcex[sourcex['CompanyNo'].isin(['01'])]
sourcex.sort_值(按class='day',inplace=True)
总体=ColumnDataSource(源)
Curr=ColumnDataSource(sourcex['day','ExtendedPrice']]
当前删除('索引')
hover3=HoverTool(工具提示=[('day','day'),('Sales','ExtendedPrice}{0,0.00}'),
格式化程序={'day':'datetime','Sales':'numeric'})
p=图(标题=年销售额),图宽=600,图高=400,最小边框=3,
工具=[hover3、'box\u zoom'、'wheel\u zoom'、'pan'、'reset'],
工具栏_location=“以上”)
r=p.vbar(x='day',top='ExtendedPrice',width=0.2,color='#e8bc76',source=Curr)
p、 xaxis.axis_标签='Day'
p、 xaxis.axis\标签\文本\字体\样式='normal'
p、 xaxis.axis\标签\文本\字体\大小='12pt'
callms=CustomJS(args=dict(source=total,sc=Curr),code=“”
var comp=msel.attributes.value;
var f=滑块值;
sc.data['ExtendedPrice']=[];
sc.data['天]=[];
对于(变量i=0;i=0){
var d1=源数据['day'][i]
if(sc.data的类型['day'][d1-1]=“未定义”){
sc.data['天][d1-1]=d1
sc.data['ExtendedPrice'][d1-1]=源.data['ExtendedPrice'][i]
}
否则{
sc.data['ExtendedPrice'][d1-1]=sc.data['ExtendedPrice'][d1-1]+源数据['ExtendedPrice'][i]
}
}
}
}
sc.change.emit();
""")
companys=source['CompanyNo'].unique().tolist()
公司分类
multi_select=MultiSelect(title=“select:”,value=['01'],options=companys,height=200,width=100,callback=callms)
滑块=滑块(开始=1,结束=12,值=1,步骤=1,title=“Month”,callback=callms)
callms.args[“msel”]=multi_select
callms.args[“滑块”]=滑块
布局=列(多选、滑块、p)
输出文件(“Filterdata.html”)
显示(布局)

下面的答案非常详尽,但只是简单地说:真正的Python回调,即使用
on\u change
只在Bokeh服务器上运行(Bokeh服务器是实际运行代码的Python进程,您的浏览器无法运行Python代码)。下一个版本的Bokeh将在上述情况下发出详细的警告消息。这个很好用。非常感谢你。我有一个很好的想法来实现bokeh情节,并用你的例子回电。您是否知道如何将其作为HTML页面(使用Bokeh服务器调用绘图)共享给用户。我尝试打印脚本和Div,但没有得到任何输出。如果你有任何想法,你能帮我解决这个[链接]()