Select columns (not rows) in Bokeh Table Widget?

北战南征 提交于 2019-12-08 05:28:33

问题


I have a bokeh table that is linked to a plot, and is working as intended. Selecting a row in the table mutes all the non-selected rows in the plot display.

However, what if someone wants to select a column, and hide all other columns in the plot? Is this possible using a bokeh widget? Or does some custom code need to be written for this feature? I have attached to code used to produce the widget table on the bokeh website, as it is the most simple example I can think of (and quickest).

from datetime import date
from random import randint

from bokeh.io import output_file, show
from bokeh.layouts import widgetbox
from bokeh.models import ColumnDataSource
from bokeh.models.widgets import DataTable, DateFormatter, TableColumn

output_file("data_table.html")

data = dict(
        dates=[date(2014, 3, i+1) for i in range(10)],
        downloads=[randint(0, 100) for i in range(10)],
    )
source = ColumnDataSource(data)

columns = [
        TableColumn(field="dates", title="Date", formatter=DateFormatter()),
        TableColumn(field="downloads", title="Downloads"),
    ]
data_table = DataTable(source=source, columns=columns, width=400, height=280)

show(widgetbox(data_table))

回答1:


Here is a code with a JS callback that allows you to know the selected row and column.

from bokeh.io import show
from bokeh.layouts import widgetbox
from bokeh.models import ColumnDataSource, CustomJS
from bokeh.models.widgets import DataTable,TableColumn

column_list = ['col1','col2','col3']

source = ColumnDataSource(data = {key:range(10) for key in column_list})

columns = [TableColumn(field=col, title=col) for col in column_list]

data_table = DataTable(source=source, columns=columns, width=400, height=280,selectable=True)

source_code = """
var grid = document.getElementsByClassName('grid-canvas')[0].children;

var row = '';
var col = '';

for (var i=0,max=grid.length;i<max;i++){
    if (grid[i].outerHTML.includes('active')){
        row=i;
        for (var j=0,jmax=grid[i].children.length;j<jmax;j++){
            if(grid[i].children[j].outerHTML.includes('active')){col=j}
        }
    }
}

console.log('row',row);
console.log('col',col);

cb_obj.selected['1d'].indices = [];
"""

source.callback = CustomJS(code= source_code)

show(widgetbox(data_table))

The line cb_obj.selected['1d'].indices = []; just resets the selected indices so that the callback can trigger even if the same cell is clicked multiple times

You can then do what you want with the row/column index

If you need to you can also "transfer" the values back to python by updating a ColumnDatasource with the row and column values.

I use bokeh 0.12.10 so this may require some change with the latest version

EDIT: tested with 0.12.16 and it still works

EDIT: update for bokeh 1.1.0

from bokeh.io import show
from bokeh.layouts import widgetbox
from bokeh.models import ColumnDataSource, CustomJS
from bokeh.models.widgets import DataTable,TableColumn

column_list = ['col1','col2','col3']

source = ColumnDataSource(data = {key:range(20) for key in column_list})

columns = [TableColumn(field=col, title=col) for col in column_list]

data_table = DataTable(source=source, columns=columns, width=400, height=280,selectable=True)

source_code = """
var grid = document.getElementsByClassName('grid-canvas')[0];

var active_row = grid.querySelectorAll('.active')[0];

if (active_row!=undefined){

    var active_row_ID = Number(active_row.children[0].innerText);

    for (var i=1, imax=active_row.children.length; i<imax; i++){
        if (active_row.children[i].className.includes('active')){
            var active_col_ID = i-1;
        }
    }

    console.log('row',active_row_ID);
    console.log('col',active_col_ID);

    var active_cells = grid.querySelectorAll('.active');
    for (i=0, imax=active_cells.length;i<imax;i++){
        active_cells[i].classList.remove('active');
    }

    cb_obj.indices = [];
}
"""

source.selected.js_on_change('indices', CustomJS(args={'source':source},code= source_code) )

show(widgetbox(data_table))



回答2:


As of Bokeh 0.12.16 the built-in DataTable does not support any sort of column selection or click events. Looking at the descriptions of Grid Events for the underlying SlickGrid implementation, it appears that onClick and onHeaderClick are supported at the low level. So the immediately accessible option would be Extending Bokeh with a custom DataTable subclass. Otherwise you can submit a GitHub feature request issue to discuss exposing these events somehow in the built in table.



来源:https://stackoverflow.com/questions/50593326/select-columns-not-rows-in-bokeh-table-widget

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!