问题
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