Python Боке - фильтровать таблицу с помощью двух синхронизированных виджетов выбора - PullRequest
0 голосов
/ 26 мая 2020

Я хочу отфильтровать таблицу с помощью двух виджетов выбора боке, см. Структуру кода ниже. Я определил два виджета: userm и location. Во-первых, выберите пользователя с виджетом userm (следует изменить таблицу, а также виджет «местоположения»), а во-вторых, выберите местоположение с виджетами местоположений (следует снова изменить таблицу).

Мой код отлично работает для фильтрации таблица на основе пользователей, но не обновлять виджеты местоположений и таблицу на основе выбора местоположения. Я не уверен, можно ли реализовать все в одной функции обратного вызова. Любые идеи? Спасибо!

#Import libraries
from bokeh.io import output_notebook, show
from bokeh.layouts import widgetbox
from bokeh.models.widgets import Select, DataTable, TableColumn
from bokeh.models.sources import ColumnDataSource, CDSView
from bokeh.models import CustomJS, Select
import pandas as pd

output_notebook()

#Create the dataframe
df = pd.DataFrame({'Index': ['9', '10', '11', '12', '13'],
        'Size': ['250', '150', '283', '433', '183'],
        'X': ['751', '673', '542', '762', '624'],
        'Y': ['458', '316', '287', '303', '297'],
        'User': ['u1', 'u1', 'u2', 'u2', 'u2'],
        'Location': ['A', 'B', 'C', 'C', 'D']
        })

#Create widgets
userm = Select(title = "Select user:", options=list(set(df['User'])), 
               value=list(set(df['User']))[0])
locations = Select(title="Select location:", options=list(set(df['Location'])), 
                   value=list(set(df['Location']))[0])

#Create data source
source=ColumnDataSource(data=dict(User=df['User'], Location=df['Location']))
filteredSource = ColumnDataSource(data=dict(User=[],Location=[]))

#Create data table
columns = [TableColumn(field="User",title="User"),
           TableColumn(field="Location",title="Location",sortable=True)]
data_table=DataTable(source=filteredSource,columns=columns, width=400 )
data_table_unfiltered=DataTable(source=source,columns=columns, width=400 )

callback = CustomJS(args=dict(source=source,
                              filteredSource=filteredSource,
                              data_table=data_table), code="""
    var data = source.data;
    var f = cb_obj.value;
    var df2 = filteredSource.data;
    df2['User']=[]
    df2['Location']=[]
    locations=[]


    for(i = 0; i < data['User'].length;i++){

    if(data['User'][i]==f){

        df2['User'].push(data['User'][i])
        df2['Location'].push(data['Location'][i])
    }

    }

    filteredSource.change.emit()
    data_table.change.emit()

""")

userm.js_on_change('value', callback)
show(widgetbox(userm, locations, data_table))

1 Ответ

1 голос
/ 26 мая 2020

Можно использовать один обратный вызов CustomJS между виджетами, но тогда вы не сможете использовать cb_obj. Вы должны явно передать виджеты.

callback = CustomJS(args=dict(source=source,
                              filteredSource=filteredSource,
                              userm=userm, locations=locations),
                    code="""
    const data = source.data;
    const userm_value = userm.value;
    const locations_value = locations.value;
    const df2 = filteredSource.data;
    df2['User'] = [];
    df2['Location'] = [];

    for (let i = 0; i < data['User'].length; i++) {
        if (data['User'][i] === userm_value && data['Location'][i] === locations_value) {
            df2['User'].push(data['User'][i])
            df2['Location'].push(data['Location'][i])
        }
    }

    filteredSource.change.emit()
""")

userm.js_on_change('value', callback)
locations.js_on_change('value', callback)
...