使用Bokeh下拉小部件/ CustomJS过滤数据框

时间:2019-10-20 15:17:32

标签: pandas bokeh bokehjs

我必须制作一个独立的html仪表板,所以我试图弄清楚如何使用CustomJS向bokeh下拉窗口小部件添加回调。问题甚至在咨询了有关该主题变化的其他文章之后,我仍然无法弄清楚。任何帮助,将不胜感激!最终,我将使用该下拉列表来过滤堆积的条形图,但在首先弄乱了过滤数据表之后,我想自己弄清楚这一点。

我已经咨询了Filtering dataframe using Bokeh/Widget/CallbackBokeh datatable filtering inconsistencyFiltering dataframe using Bokeh/Widget/CallbackPython bokeh CustomJS callback update DataTable widget。此外,我一直在浏览https://docs.bokeh.org/en/1.3.4/docs/user_guide/interaction/callbacks.html#userguide-interaction-jscallbacks上的文档,

import pandas as pd
from bokeh.models.widgets import Dropdown
from bokeh.layouts import widgetbox
from bokeh.models import ColumnDataSource, DataTable, TableColumn, CustomJS
from bokeh.io import show, output_file, output_notebook, reset_output


raw_data = {'ORG': ['APPLE', 'ORANGE', 'MELON'],
            'APPROVED': [5, 10, 15],
            'CREATED': [1, 3, 5],
            'INPROCESS': [4,2,16]}

df = pd.DataFrame(raw_data)

# create list of orgs to use later
org_l = list(df['ORG'].unique())

# create CDS for source
src = ColumnDataSource(df)

# create cols
table_columns = [TableColumn(field = Ci, title = Ci) for Ci in df.columns] 


# create filtered table
filtered_df = df.loc[df['ORG']=='f']

# create CDS for filtered source
new_src = ColumnDataSource(filtered_df)

# create dropdown
dropdown = Dropdown(label="Dropdown button", button_type="warning", menu = org_l)

callback_code = """"
                var data = src.data;
                var new_data = new_src.data;
                var f = cb_obj.value;
                var list = org_l;
                if var i = org_list[i] {
                new_src.data = src.data
                }

              """

callback=CustomJS(args=dict(dropdown = dropdown,source=src),
             code=callback_code)

# create table
member_table = DataTable(source = new_src, columns = table_columns)

dropdown.js_on_change('value', callback)

show(widgetbox(dropdown, member_table))

''''

2 个答案:

答案 0 :(得分:1)

在JS代码中作为命名变量可访问的唯一Bokeh对象是那些您明确包含在args字典中的对象。这就是args指令的目的,目的是自动使 Python Bokeh对象的JavaScript对应对象易于访问。浏览器对Python或脚本中的Python变量一无所知。您在JS代码中引用了srcnew_src,但是在args字典中没有传递任何这些。同样,纯python值org_l还需要按原样包含在JS代码文本中,并采用字符串文本格式,例如%运算符。

您在JS代码中还存在语法错误,该错误在浏览器的JS控制台中报告(您应该熟悉它,因为它是调试这些问题的最佳工具)。这是无效的JS代码:

if var i = org_list[i] {
    new_src.data = src.data
}

答案 1 :(得分:1)

好几次尝试和错误,并使用bigreddot的指针,我可以完成以下工作。

import pandas as pd
from bokeh.models.widgets import Select
from bokeh.layouts import widgetbox
from bokeh.models import ColumnDataSource, DataTable, TableColumn, CustomJS
from bokeh.io import show, output_file, output_notebook, reset_output
from bokeh.layouts import row, column, layout


raw_data = {'ORG': ['APPLE', 'ORANGE', 'MELON'],
        'APPROVED': [5, 10, 15],
        'CREATED': [1, 3, 5],
        'INPROCESS': [4,2,16]}

df = pd.DataFrame(raw_data)

# create CDS for source
src1 = ColumnDataSource(df)

# create cols
table_columns1 = [TableColumn(field = Ci, title = Ci) for Ci in df.columns]

# original data table
data_table1 = DataTable(source=src1, 
                   columns=table_columns, width=400, height=280)

# create empty dataframe to hold variables based on selected ORG value
df2 = pd.DataFrame({'status':['APPROVED', 'CREATED', 'INPROCESS'],
               'count':[float('nan'), float('nan'), float('nan')]})

# create CDS for empty dataframe
src2 = ColumnDataSource(df2)

# create cols
table_columns2 = [TableColumn(field = Ci, title = Ci) for Ci in    df2.columns] 

callback = CustomJS(args=dict(src1=src1, src2=src2), code='''
var count = ['APPROVED', 'CREATED', 'INPROCESS'];
if (cb_obj.value != 'Please choose...') {
    var org = src1.data['ORG'];
    var ind = org.indexOf(cb_obj.value);
    for (var i = 0; i < count.length; i++) {
        src2.data['count'][i] = src1.data[count[i]][ind];
    }
}
else {
    for (var i = 0; i < status.length; i++) {
        src2.data['status'][i] = undefined;
    }

}
src2.change.emit();
''')

options = ['Please choose...'] + list(src1.data['ORG'])
select = Select(title='Test', value=options[0], options=options)
select.js_on_change('value', callback2)

show(column(select, data_table2))