Trouble with on_event for renderers

So on_event works beautifully for me when I apply it to a figure. However, this method is also provided for individual renderers. I figured this was the logical way to say, listen for a mouse scroll event while the mouse is hovering a certain patch, like this:

from bokeh.plotting import figure
from bokeh.events import MouseWheel
import panel as pn

f = figure()
p = f.patch([0, 1, 2], [0, 1, 0])
f.on_event(MouseWheel, lambda evt: print("Figure Event", evt))
p.on_event(MouseWheel, lambda evt: print("Patch Event", evt))
pn.pane.Bokeh(f).show()

However, I only ever get the “Figure Event” callback, not the “Patch Event”. This is on bokeh 2.2.3 (latest) with Chrome or Firefox on Windows 10. It’s the same if I try the Tap event.

Am I mis-interpreting or mis-using the patch’s on_event? Is there another way to listen for events happening over a specific patch?

Thanks a lot in advance!
Jonathan

Is there another way to listen for events happening over a specific patch?

There’s not any way to do this. [1] MouseWheel events only trigger on plots.


  1. outside of creating a custom extension ↩︎

Thanks a lot for the quick reply Bryan. However, I haven’t seen this work for other events either, so then what is the on_event method’s intended use on these models? For future reference do you know if this documented anywhere?

@nitrocalcite on_event is a generic mechanism that allows for catching any event that a model might trigger. I suppose your confusion here is expecting that every model might trigger every event, but that is not the case. The only model that triggers MouseWheel events is Plot, so the only place that calling .on_event(MouseWheel, ....) will be useful is on a plot. The reference docs do state that, but perhaps not clearly enough:

bokeh.events — Bokeh 3.3.2 Documentation

E.g. where it says

Announce a mouse wheel event on a Bokeh plot.

Is literal: on Plot objects (only).

Currently almost all the built-in events are only triggered by Plot. There are a handful that are triggered on Document and Button. There will probably be more/other/different events on new objects in the future, and of course anyone can write a custom extension that triggers events from any object they want (which would trigger an on_event on that object)

And I guess I would add: it would be nice if title.on_event(MouseWheel, ....) could issue a warning to the effect of

“Warning: Title objects do not emit MouseWheel events”

and perhaps that is your expectation. Unfortunately it is a very difficult proposition. The information aout which models emit which events does not exist anywhere on the “Python” side, it is only encoded implicitly in the codepaths in BokehJS that might happen to emit the event. There’s zero way to get that information to Python at runtime, so any solution would have to be some sort of build/packaging time automation step that some how scrapes BokehJS to determine what models emit what events, but it’s not at all clear how that might be done reliably.

Hmm, I understand much better what’s going on & why now, thanks so much for the explanation! Now re-reading the docs I see what you mean about Plot objects only; I definitely missed the nuance there.

I think my expectation was, as you suggest, to get a warning if I was trying something nonsensical. Admittedly now that I think of on_event in a more generic sense I’m less attached to that.

While the details you’re describing do sound difficult, perhaps the fastest solution is just an extra sentence in the on_event docstring warning that not all events are valid.

@Bryan I took a crack at it; let me know if you think this is appropriate. Thanks again for your help!

1 Like