首页 > 解决方案 > Python Bokeh 和 Javascript 中的多个过滤器

问题描述

这建立在我之前的问题(在 Python 的 Bokeh 中使用 Javascript 回调过滤数据)已成功回答并更进一步。

当我尝试在 Python 的 Bokeh 中使用多个过滤器过滤我的图时,该函数返回一个空图。

我找不到与使用一个过滤器的工作解决方案的任何概念差异,因此希望有任何提示。

下面是一个可重现的例子:

# Packages
import bokeh.events as bev
import bokeh.layouts as bla
import bokeh.models as bmo
import numpy as np
import pandas as pd
from bokeh.plotting import figure, output_file, show

# Data
data = pd.DataFrame(
    data=np.array(
        [
            [1, 1, 'a', 'c', 0.5],
            [2, 2, 'a', 'c', 0.5],
            [3, 3, 'a', 'd', 0.75],
            [4, 4, 'b', 'd', 1],
            [5, 5, 'b', 'd', 2]
        ]
    ),
    columns=['x', 'y', 'category 1', 'category 2', 'other information']
)

# Setup
output_file('dashboard.html')

source = bmo.ColumnDataSource(data)

# Define dropdown options
dropdown_options1 = [
                       ('All', 'All'), None
                   ] + [(cat, cat)
                       for i, cat in enumerate(sorted(data['category 1'].unique()), 2)
                   ]
dropdown_options2 = [
                       ('All', 'All'), None
                   ] + [(cat, cat)
                       for i, cat in enumerate(sorted(data['category 2'].unique()), 2)
                   ]

# Generate dropdown widget
dropdown1 = bmo.Dropdown(label='Category1', button_type='default', menu=dropdown_options1)
dropdown2 = bmo.Dropdown(label='Category2', button_type='default', menu=dropdown_options2)

filtered_data = bmo.ColumnDataSource(data)
# Callback
callback = bmo.CustomJS(
    args = dict(unfiltered_data = source, filtered_data = filtered_data, dropdown1 = dropdown1 , dropdown2 = dropdown2 ),
    code = """

var data = unfiltered_data.data;
var ind = dropdown1.item;
var ctr = dropdown2.item;

function generateNewDataObject(oldDataObject){
    
    var newDataObject = {}
    
    for (var key of Object.keys(oldDataObject)){
            
        newDataObject[key] = [];
        
    }
    
    return newDataObject

}


function addRowToAccumulator(accumulator, dataObject, index) {
    
    for (var key of Object.keys(dataObject)){
            
        accumulator[key][index] = dataObject[key][index];
        
    }
    
    return accumulator;
}


if (ind === 'All' && ctr === 'All'){
                
    data = unfiltered_data.data;
                
} else if (ctr === 'All') {
            
    var new_data =  generateNewDataObject(data);
    
    for (var i = 0; i <= unfiltered_data.data['category 1'].length; i++){
            
        if (unfiltered_data.data['category 1'][i] == ind) {
                
            new_data = addRowToAccumulator(new_data, unfiltered_data.data, i);
            
        }
    }
    
    data = new_data;
    
} else if (ind === 'All'){
    
    var new_data =  generateNewDataObject(data);
    
    for (var i = 0; i <= unfiltered_data.data['category 2'].length; i++){
            
        if (unfiltered_data.data['category 2'][i] == ctr) {
                
            new_data = addRowToAccumulator(new_data, unfiltered_data.data, i);
            
        }
    }
    
    data = new_data;
        
} else {
        
    var new_data =  generateNewDataObject(data);
    
    for (var i = 0; i <= unfiltered_data.data['category 1'].length; i++){
            
        if (unfiltered_data.data['category 2'][i] == ctr && unfiltered_data.data['category 1'][i] == ind) {
                
            new_data = addRowToAccumulator(new_data, unfiltered_data.data, i);
            
        }
    }
    
    data = new_data;            
                        
}

filtered_data.data = data;
filtered_data.change.emit();
"""
)


# Link actions
dropdown1.js_on_event(bev.MenuItemClick, callback)
dropdown2.js_on_event(bev.MenuItemClick, callback)

# Plot
p1 = figure(plot_width=800, plot_height=530, title=None)

p1.scatter(x='x', y='y', source=filtered_data)

show(bla.column(bla.row(dropdown1, dropdown2), p1))

我尝试使用不同的方法(和)访问下拉列表的值.item,但没有任何成功。.value.text

感谢您的支持,奥利弗

标签: javascriptpythonfilterbokeh

解决方案


Dropdown 是一个单击事件,因此信息仅在事件中,而不是在小部件本身的任何属性上(如果您愿意,也许Select小部件会比 更好的选择Dropdown)。文档中有一个示例显示了如何访问事件中的项目:

dropdown = Dropdown(label="Dropdown button", menu=menu)
dropdown.js_on_event(
    "menu_item_click", 
    CustomJS(code="console.log('dropdown: ' + this.item")
)

推荐阅读