Hi,
I want to get the column index or name of a selected cell in a DataTable.
The table has over hundred rows and about fifty columns so it is scrollable.
Here is the way I populate the DataTable:
table_source = ColumnDataSource()
table_columns = []
data_table = DataTable(source=table_source, columns=table_columns, width=900, height=900, autosize_mode="none")# autosize_mode="fit_columns" takes time
def dat_table():
new_table_source = dict(ColumnDataSource(df1).data)
table_columns = []
for col in df1.columns:
if col in DateCols:
table_columns.append(TableColumn(field=col, title=col, width=100, formatter=DateFormatter(format="%d.%m.%Y %H:%M")))
else:
table_columns.append(TableColumn(field=col, title=col, width=np.ceil(6.5*len(col)).astype('int')))
data_table.source.data = new_table_source
data_table.columns = table_columns
# Update table:
dat_table()
I am most often displaying the table in JupyterLab, but I would like the code to also work in a bokeh served app started with bokeh serve --show my_app.py
displayed in a browser.
Based on this thread:
I tried following code:
def table_selection(attr, old, new):
print("old:", old)
print("new:", new)
print("indices", data_table.source.selected.indices)
print("line_indices", data_table.source.selected.line_indices)
print("multiline_indices", data_table.source.selected.multiline_indices)
data_table.source.selected.on_change('indices', callback)
But none of the attributes of ColumnDataSource.selected
provides the column index. Only the row(s) of the selected cell(s) will be returned.
I also tried a CustomJS approach based on this thread:
row_print = TextInput(value = "", title = "Row:", width = 200)
column_print = TextInput(value = "", title = "Column:", width = 200)
source_code = """
let grid = document.getElementsByClassName('grid-canvas')[0].children; // This line works without ".children" with Python 3.11 bokeh 3.1.0, but not with ".children"
let row, column = '';
for (let i = 0,max = grid.length; i < max; i++){
if (grid[i].outerHTML.includes('active')){
row = i;
for (let j = 0, jmax = grid[i].children.length; j < jmax; j++)
if(grid[i].children[j].outerHTML.includes('active'))
{ column = j }
}
}
row_print.value = String(row);
column_print.value = String(column); """
callback = CustomJS(args = dict(row_print=row_print, column_print=column_print), code = source_code)
data_table.source.selected.js_on_change('indices', callback)
And also on that thread:
row_print = TextInput(value = "", title = "Row:", width = 200)
column_print = TextInput(value = "", title = "Column:", width = 200)
source_code = """
let grid = document.getElementsByClassName('grid-canvas')[0];
let active_row = grid.querySelectorAll('.active')[0]; // This line doesn't works with Python 3.11 bokeh 3.1.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;
}
}
row_print.value = String(active_row_ID);
column_print.value = String(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 = [];
}
"""
callback = CustomJS(args = dict(row_print=row_print, column_print=column_print), code = source_code)
data_table.source.selected.js_on_change('indices', callback)
Though, I encounter following problems with these CustomJS approaches:
With Python 3.9 and bokeh 2.4.2, I can run these two scripts, but the column (and row) index get messed up as soon as I use the scroll bars of the table.
With Python 3.11. and bokeh 3.1.0, I didn’t manage to run the JS code (see comments in the code above).
Are there any other ways I can obtain the column number of a selected cell?