【问题标题】:Filter Dataframe Using Bokeh Dropdown Widget/CustomJS使用 Bokeh Dropdown Widget/CustomJS 过滤数据框
【发布时间】:2019-10-28 01:48:05
【问题描述】:

我必须制作一个独立的 html 仪表板,因此我试图弄清楚如何使用 CustomJS 向散景下拉小部件添加回调。问题是即使在查阅了有关该主题变体的其他帖子之后,我仍然无法弄清楚。任何帮助,将不胜感激!最终,我会使用下拉列表来过滤堆叠条形图,但我想在先过滤数据表之后自己尝试解决这个问题。

我咨询过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))

''''

【问题讨论】:

    标签: pandas bokeh bokehjs


    【解决方案1】:

    在 JS 代码中唯一可作为命名变量访问的 Bokeh 对象是那些明确包含在 args 字典中的对象。这就是 args dict 的目的,自动使 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
    }
    

    【讨论】:

    • 谢谢。对我来说最棘手的部分是计划/创建将保存更新值的空数据框。例如,如果我的数据帧是长格式并且有一个额外的“部门”列,因此对于 APPLE 组织有 3 个部门等等,那么空数据帧的长度等于原始源的 len数据框?
    • 好的。经过大量的试验和错误以及对各种帖子的大量搜索后,我发现我不必创建一个空白数据框来保存更新的值。回调 和 可以这样写,当从列表中选择一个组织时,与该组织关联的其他行被隐藏。
    【解决方案2】:

    通过大量的试验和错误以及来自 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))
    

    【讨论】:

    • 复制/粘贴上面的代码,我不得不添加一些代码来让它运行,即:# new data table data_table2 = DataTable(source=src2, columns=table_columns2, width=400, height=280)(加上对错误标记的东西的一些小编辑(即没有callback2在代码末尾参考等)希望这对其他人有所帮助。
    • 解决方案的工作要点@alofgran gist.github.com/bede/7bfdac7f395d1ea4d1a1dcd1e80926ea
    猜你喜欢
    • 1970-01-01
    • 2017-09-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-18
    相关资源
    最近更新 更多