散景多选小部件回调不起作用 [英] Bokeh Multi-Select widget callback not Working

查看:100
本文介绍了散景多选小部件回调不起作用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我是Bokeh的新手.最近尝试实现一些小部件回调,并且很难在线找到任何资源.

I am new to Bokeh. Trying to implement few widget callbacks recently and hard to find any resources online.

方案:我有一个multi_select bokeh小部件,其中包含公司列表.根据选择的公司,必须更改Vbar中的数据.为此,我试图基于多选"中的值更改Vbar中使用的数据源.我无法获得理想的结果.有人可以帮我这个忙吗?

Scenario: I have a multi_select bokeh widget with the list of the companies. Based on the companies selcted, data in the Vbar has to be changed. For this, i am trying to change the datasource that is used in the Vbar based on the values from Multi select. I am unable to get desired results. Can someone please help me out with this.

我在CustomJs方面很差,因此在Bokeh Server上执行Callabcks.如果在CustomJs上也有解决方案,那将对我有很大帮助.

I am poor at CustomJs and hence doing this on Bokeh Server for callabcks. If there is a solution on CustomJs too, that would help me a lot.

非常感谢您的时间提前!

Thank you very much for your time in Advance !

下面是我正在使用的代码

Below is the code I am using

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列-DateExtendedPriceCompanyNo.我首先生成了1万行的随机数据,然后在CompanyNodaymonthyear级别对其进行了汇总.

Since I don't have the data, I generated it using following script. I have assumed your data has 3 columns - Date, ExtendedPrice, CompanyNo. I have generated first a random data of 10K rows and then summarized it at CompanyNo, day, month, year level.

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的条形图,即说公司'01'有2行, "02"(已选择),对于当前年份的第二个月(也由滑块选择),这两个的ExtendedPrice值分别为100和200.如果我们想显示一个总和,则需要在条形图中显示300.此摘要,您需要动态计算.

Now, what you want to accomplish is that given a day and set of company names, you need to publish a bar chart of some type of aggregation of ExtendedPrice, i.e. say there are 2 rows for company '01' and '02' (which are selected), and for month 2 (that is also selected by a slider) for current year, the ExtendedPrice value for these two is say 100, and 200. In case we want to show a sum, you need to show 300 in barchart. This summary, you need to calculate dynamically.

有两种方法可以实现它.

There are two ways to accomplish it.

1.散景回调

这将使用本机python函数,但是您需要使用bokeh serve来运行它,例如bokeh serve --show <filename.py>.参见下面的代码,本地python函数compsel正在过滤pandas数据框并进行汇总,然后用新创建的数据替换图表后端数据-

This will use native python functions, but you need to run it with bokeh serve , e.g bokeh serve --show <filename.py>. See the code below, a native python function compsel is filtering pandas dataframe and summarizing it and replacing the chart backend data with newly created data -

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

There are other options to host this application. See other option by typing bokeh serve --help in terminal

2. JavaScript回调

这将生成一个与图表进行交互的javascript函数,该函数不需要bokeh服务器,并且可以直接在浏览器上工作.这将需要JavaScript中非常简单的代码.在这里解决的示例中,我将ExtendedPrice总结为总和,但是代码将需要进行细微调整才能计算其他统计信息,例如意思是.此处的js回调函数与bokeh回调函数具有相似的功能,它读取较大的数据集并根据select和slider值对其进行过滤-

This will generate a javascript function to interact with the chart, which will not require bokeh server and work directly on the browser. This will require very simple code in javascript. In the example solved here, I am summarizing ExtendedPrice as sum, but code will require small tweaks to calculate other stats e.g. mean. The js callback function here does the similar thing as bokeh callback function, it reads the larger datasets and filters it based on the select and slider values -

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)

这篇关于散景多选小部件回调不起作用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆