12

I would like to change the DataTable object row selection programmatically (without JS, just python). I have tried to so using the selected property of the underlying ColumnsSource with no success. How can this be done?

Pablo
  • 4,821
  • 12
  • 52
  • 82
Hanan Shteingart
  • 8,480
  • 10
  • 53
  • 66
  • I know this is not a full answer at all. I am basically trying to do the same thing. My experience with it is currently like this. From Python, I can set ds.selected['1d']['indices'] = [list of selected indices], but this does not propagate to the front-end. Conversely, when I set the indices through js in a similar way, I can get the data table to select the rows. But somehow, these changes - though "emited" - do not then register. Hence if there is an event listener like: ds.onchange('selected', ....), these changes on the selected property are not recognized. I am thinking of filing a bug. – Thornhale Jul 19 '17 at 15:28
  • 1
    What you are asking, I was/am trying to find answers to here as well: https://stackoverflow.com/questions/44960975/how-do-i-pre-select-rows-in-a-bokeh-widget-datatable. – Thornhale Jul 19 '17 at 15:28
  • Is this in a bokeh app or a notebook? – mattjegan Jul 20 '17 at 06:55
  • I am looking for a solution that works in a bokeh app. – Thornhale Jul 20 '17 at 18:05
  • Is this somewhat what you're looking for? https://github.com/bokeh/bokeh/wiki/Filterable-Data-Source Or you're looking for Python method to select and change the rows? – 0bserver07 Jul 21 '17 at 22:10
  • It's not what I am looking for. The link shows how you can select rows by clicking on the datatable and propagate that to a graph. What I am looking for i's clicking a button to trigger selection of desired rows. That selection then had to propage to the graph. Conceptionally this may not be that different, I at least have not been successfully been able to propagate a change in datatable selection triggered via js to the graph, hence this bounty. – Thornhale Jul 23 '17 at 17:35
  • Or even better, finding a way to propagate changes to ds.selected['1d']['indices'] to the front end would be even better. – Thornhale Jul 23 '17 at 17:37

3 Answers3

3

See an example app (needs bokeh serve to run) where pressing the button changes the selected rows, then updates both a table and plot. Is this all the functionality you need?

By the way you could just do it in JS and not need to use bokeh server, but if you have more python functionality going on then i guess you need it.

from datetime import date
from random import randint

from bokeh.io import output_file, show, curdoc
from bokeh.plotting import figure
from bokeh.layouts import widgetbox, row
from bokeh.models import ColumnDataSource
from bokeh.models.widgets import DataTable, DateFormatter, TableColumn,Button

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)],
    )

def update():
    #set inds to be selected
    inds = [1,2,3,4]
    source.selected = {'0d': {'glyph': None, 'indices': []},
                                '1d': {'indices': inds}, '2d': {}}
    # set plot data
    plot_dates = [data['dates'][i] for i in inds]
    plot_downloads = [data['downloads'][i] for i in inds]
    plot_source.data['dates'] = plot_dates
    plot_source.data['downloads'] = plot_downloads


source = ColumnDataSource(data)
plot_source = ColumnDataSource({'dates':[],'downloads':[]})


table_button = Button(label="Press to set", button_type="success")
table_button.on_click(update)
columns = [
        TableColumn(field="dates", title="Date", formatter=DateFormatter()),
        TableColumn(field="downloads", title="Downloads"),
    ]
data_table = DataTable(source=source, columns=columns, width=400, height=280)

p = figure(plot_width=400, plot_height=400)

# add a circle renderer with a size, color, and alpha
p.circle('dates','downloads',source=plot_source, size=20, color="navy", alpha=0.5)


curdoc().add_root(row([table_button,data_table,p]))
Anthonydouc
  • 3,334
  • 1
  • 16
  • 29
  • It looks like the key to making the selection stick is this line that the entire selected object needs to be updated. I need to verify that in my own app. But running the application as above does correctly select for things. And yes, you are right, there are other things I need to do with this that require an app and not just js. – Thornhale Jul 27 '17 at 00:01
  • 1
    Yea you do need to replace the entire object, I think it may be something to do with a change not being detected due to the level of nesting? – Anthonydouc Jul 27 '17 at 06:01
  • For future folks. A recent bokeh update has made this OBE. the `selected` property is now read only and cannot be directly rewritten: ```RuntimeError: ColumnDataSource.selected is a readonly property ``` – hobbitmessiah Aug 17 '21 at 00:50
3

You can select DataTable rows programmatically in python in this way:

source.selected.indices = [list of indices to be selected]

where source is the ColumnDataSource for the DataTable. If you have any callbacks for the source.selected here, remember to select the rows only after registering the callbacks so that they will get called.

WebDev
  • 1,211
  • 11
  • 17
0

Just for clarity you have to replace the source.selected property completely to trigger the changes. So the important line is:

source.selected = {'0d': {'glyph': None, 'indices': []},
                            '1d': {'indices': inds}, '2d': {}}

Individually setting the items in source.selected doesn't work

source.selected['1d']['indices'] = inds # Doesn't work
Redlegjed
  • 187
  • 2
  • 11