panel
panel copied to clipboard
Click event only generated when clicking in specific areas of Bar graph
This issue came out from a discussion on panel discourse, link here. I will reproduce below the main parts of it.
There is an integration problem between panel and plotly when trying to receive click events upon clicking on the bar graph using plotly. The event is only triggered when clicking in the space between the bars and not inside the Bar. if sizing_mode is not used (check the MRE below), situation gets even worse. Same reasoning holds true if orientation of the Bar changes from horizontal to vertical.
Relevant software version info
pandas 1.5.3 panel 1.2.0 plotly 5.15.0 plotly-express 0.4.1 python 3.9.17 ubuntu 20.04
Description of expected behavior and the observed behavior
Click events should only occur when clicking inside the Bar independent of the size mode or orientation used. Currently events are generated when clicking close to the Bar in the space between bars. If no size mode is used or orientation is changed, than click events are not triggered or occur randomly.
Complete, minimal, self-contained example code that reproduces the issue
import plotly.express as px
import pandas as pd
import panel as pn
from panel.template.react import ReactTemplate
df = pd.DataFrame(data = {'month':['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'],'value':[10,15,20,5,12,6,21,8,9,3,11,17]})
fig=px.bar(x=df['month'], y=df['value'])
def on_click(event):
if event.name == 'click_data':
if event.obj is not None:
print("on_click", event.obj.click_data)
print("on_click old", event.old)
print("on_click new", event.new)
plot_panel = pn.pane.Plotly(fig,
config={"responsive": True},
sizing_mode="scale_both"
)
plot_panel.param.watch(on_click, ["click_data"],onlychanged=False)
pn.Column(plot_panel).servable()
Stack traceback and/or browser JavaScript console output
N/A
Screenshots or screencasts of the bug in action
It is pretty easy to reproduce so I think a screenshot is not necessary.
I've been able to reproduce the issue. See the mentioned discourse discussion.
Here is another issue which also has issues with mouse clicks. It might be related.
https://github.com/holoviz/panel/issues/5195
Hi I've been hitting the exact same problem and been bashing my head all day trying to get it to work. I think the root cause lies within Plotly library not registering click events correctly within the ShadowDOM -> https://github.com/plotly/plotly.js/issues/6108
I have a workaround for now which was to download the plotly.js
file from https://github.com/plotly/plotly.js/blob/v2.25.2/dist/plotly.js and then comment out the lines 7914-7918:
module.exports = function click(gd, evt, subplot) {
var annotationsDone = Registry.getComponentMethod('annotations', 'onClick')(gd, gd._hoverdata);
// fallback to fail-safe in case the plot type's hover method doesn't pass the subplot.
// Ternary, for example, didn't, but it was caught because tested.
// !!! COMMENT THIS OUT to prevent retrigger of hover() on click !!!
// if (subplot !== undefined) {
// // The true flag at the end causes it to re-run the hover computation to figure out *which*
// // point is being clicked. Without this, clicking is somewhat unreliable.
// hover(gd, evt, subplot, true);
// }
function emitClick() {
gd.emit('plotly_click', {
points: gd._hoverdata,
event: evt
});
}
if (gd._hoverdata && evt && evt.target) {
if (annotationsDone && annotationsDone.then) {
annotationsDone.then(emitClick);
} else emitClick();
// why do we get a double event without this???
if (evt.stopImmediatePropagation) evt.stopImmediatePropagation();
}
};
Then I added to my app with pn.extension("plotly", js_files={'plotly_patched': 'assets/plotly-2.25.2_patched.js'})
(and serving that assets directory with panel serve app.py --show --static-dirs assets=./assets
) and the clicks on plots seem work as expected again. I have no idea if this will cause unintended consequences with more complex plots and other functionality but it allowed me to proceed with what I was working on.
Thanks for tracking this down @sblowers, I'll try to see if there is a way to this from within the panel.js bundle.