Possible to update lasso selection DataTable with updated CDS data?

Hello,

I have a table that displays CDS data from the plot lasso selection tool indices. If the CDS data gets updated, is there a way to update the table without having to redo the lasso selection? The DataTable gets updated with a CustomJS callback, while the CDS gets updated with a server callback.

source = ColumnDataSource(data=dict(LDA1=dataset_LDA2D.LDA1, 
                                         LDA2=dataset_LDA2D.LDA2,
                                         colors=dataset_LDA2D.color,
                                         map_value=dataset_LDA2D.map_value)

lasso_source = ColumnDataSource(data=dict(LDA1=[],
											LDA2=[],
											colors=[],
											map_value=[]))

tools_ = ['crosshair', 'zoom_in', 'zoom_out', 'save', 'reset', 'tap', 'box_zoom', 'pan', 'undo', 'redo', 'wheel_zoom']

p = figure(tools=tools_, active_drag="box_zoom", width=1800, height=2000)

p1 = p.circle('LDA1', 'LDA2', fill_color='colors',
              size=7, alpha=0.5, line_alpha=0,
              source=source, name='Data')

lasso_1 = LassoSelectTool(continuous=False)
p.add_tools(lasso_1)

lasso_table = DataTable(source=lasso_source, columns=[TableColumn(field='map_value', title="Map Value")], width=600, height=1500, fit_columns=True)

lasso_callback = CustomJS(args=dict(lasso_source=lasso_source, source=source, lasso_table=lasso_table), code="""
    var inds = cb_obj.indices;
    var s1 = source.data;
    var ld = lasso_source.data;
    ld['LDA1'] = [];
    ld['LDA2'] = [];
    ld['colors'] = [];
    ld['map_value'] = [];
    for (var i = 0; i < inds.length; i++) {
        ld['LDA1'].push(s1['LDA1'][inds[i]]);
        ld['LDA2'].push(s1['LDA2'][inds[i]]);
        ld['colors'].push(s1['colors'][inds[i]]);
        ld['map_value'].push(s1['map_value'][inds[i]]);
    }
    lasso_source.change.emit();
    lasso_table.change.emit();
""")

source.selected.js_on_change('indices', lasso_callback)

heat_slider = Slider(start=1, end=4, value=1, step=1, title="Heat")

def marker_callback(attr, old, new):
   path = '/myapp/data/'+directory+'/'+product_file+'.db'
   con = sqlite3.connect(path)
   query = 'SELECT * FROM '+product_file
   product_df = pd.read_sql_query(query, con)
   con.close()
   if(heat_slider.value == 1):
		source.data['map_value'] = product_df.product_values1.to_list()
   elif(heat_slider.value == 2):
		source.data['map_value'] = product_df.product_values2.to_list()
   elif(heat_slider.value == 3):
		source.data['map_value'] = product_df.product_values3.to_list()
   elif(heat_slider.value == 4):
		source.data['map_value'] = product_df.product_values4.to_list()

heat_slider.on_change('value', marker_callback)

If the CDS data gets updated, is there a way to update the table without having to redo the lasso selection?

No, hit-testing for selections only happens when the lasso is “completed” (i.e. the user raises the mouse button and the drag event stops) There is not currently any exposed, user-facing API for programmatically performing hit-testing. At best you can clear the selection when the data changes.

Edit: well, in principle you could register a callback for the SelectionGeometry event that saves the lasso geometry somewhere between events, and then do your own hit-testing against the saved geometry, in order to set the selection manually whenever the data changes. I don’t have any example code or anything to share, though, all I can offer is the outline above.

1 Like

Maybe I’m not interpreting the question properly, but could they not trigger an update/table redraw by storing the selected indices in a variable in marker_callback and then toggle source.selected.indices to an empty list then back to the stored indices to trigger lasso_callback?

e.g.

def marker_callback(attr,old,new):
    sel_inds = source.selected.indices #grab current selection
    #.... DO STUFF/UPDATE source data
   source.selected.indices = [] 
   source.selected.indices = sel_inds



1 Like

This worked! Thank you!

1 Like

My assumption was that the new data could have new positions and/or a different number of rows in the CDS, meaning that the the previous selection indices would no longer be valid in any meaningful way.

The approach above only seems reasonable to me under the strict assumption that the new data in the CDS has exactly the same number of rows and all the points have exactly the same coordinates. Otherwise the previous indices could be out of bounds with respect to the new data, or indices for previously selected points now refer to new points that are now not contained inside the lasso.

2 Likes

Ah yes, sorry my post was not more clear. In this case, the x-y coordinates would always be the same when changing the CDS data. Only the “map_value” would change, which is just a data annotation that is displayed in the table.

1 Like

The simple solution should be good, then. Thanks @gmerritt123 !

Yes thanks for pointing this out, very critical caveats to my quick and dirty solution. I inadvertently made those assumptions when interpreting the question.