Вот код с обратным вызовом JS, который позволяет узнать выбранную строку и столбец.
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))
Строка cb_obj.selected['1d'].indices = [];
просто сбрасывает выбранные индексы, так что обратный вызов может сработать, даже еслищелчок по одной и той же ячейке несколько раз
Затем вы можете делать то, что вы хотите, с индексом строки / столбца
Если вам нужно, вы также можете "перенести" значения обратно в python, обновив ColumnDatasourceсо значениями строки и столбца.
Я использую bokeh 0.12.10, так что это может потребовать некоторых изменений в последней версии
EDIT: протестировано с 0.12.16 и все еще работает
РЕДАКТИРОВАТЬ: обновление для боке 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))