Updating a calculated field on edits in DataTable

I have an editable DataTable with a column z that gets calculated by running some calculations (fast but non-trivial) on another column x. (example: z = x^2). I want to make the updates live in the z column to changes in row values for the x column. I am running this use case with a bokeh server.

I can listen to changes in x and y columns using the on_change callback on the data property for the underlying cds. This works as expected. But then how do I trigger a change in the z column? I can’t update the cds from its own on_change callback because that creates an infinite recursion situation.

I have read Data table editing - change when user changes input value - Community Support - Bokeh Discourse – But this doesn’t work because there is no patching event on the python server side as mentioned in the discussion here python - Callback to datatable when user changes a content of cell - Stack Overflow

You might be able to call source.patch from CDS on change callback without recursion. I am not sure though, you would just have to try. If that does not work ten this probably points to needing new development to actually, properly support derived expressions for table columns.

@Bryan Thanks for your reply, I tried patching the cds from within it’s on_change callback, and unfortunately, that creates the same infinite recursion situation.

I’m afraid that there is probably no simple or direct solution at present, then [1]. Please feel free to open a GitHub development discussion to propose a new feature.


  1. hacky, off-the-cuff ideas: managing an am_updating boolean flag to stop recursion, or updating something besides the CDS, and then responding with a JS callback on that other other thing to update the CDS using BokehJS APIs, which I might help. ↩︎

In situations where this was unavoidable/necessary in the past, I leveraged the tags property of objects to implement a lightweight state machine.

For example like setting/unsetting a Boolean flag or a descriptor of the originator/source of the callback. That state can be checked on entering the callback and set to something else as necessary to cleanly handle the recursion.

Sorry I don’t have an example in front of me at the moment, but hopefully this gives some ideas.

@_jm after so long trying to get them added, I forgot DataModels exist now. That’s what you can use instead of (ab)using tags or other random models properties. Here is an example:

bokeh/data_models.py at branch-2.4 · bokeh/bokeh · GitHub

And that could possibly be used by the OP as well:

  • first CDS (python) callback updates a data model property
  • second data models (JS) callback updates source.data in place, and calls source.change.emit()

I think that will cause the front end to up as desired, the drawback is that the change made on the JS side would not be refected back to Python. But if this is not important to you, then it should be workable.

2 Likes

Great. I’ll check it out. I was not aware of this new feature as I’ve been narrowly focused on low-level details and cleanup in my apps.

I’m sure it has a place for me going forward; for the stream-of-thought reply above I was going back to examples where I was working in a server context and I absolutely wanted the python-side aware of the current state of everything in the client.

@_jm and @Bryan thanks for your suggestions. I have never really thought much of tags this way before, I think it might work. I will report back here. And also a great tip on DataModel, I had no idea these even existed, can use them all over the place.

1 Like