Skip to content

Commit 8dfce2a

Browse files
committed
fix: plotly regression
1 parent fb924e0 commit 8dfce2a

2 files changed

Lines changed: 55 additions & 8 deletions

File tree

panel/pane/plotly.py

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -159,20 +159,24 @@ def _update_figure(self):
159159
if (fig is None or isinstance(fig, (dict, list, tuple)) or fig is self._figure or not self.link_figure):
160160
return
161161

162-
# Monkey patch the message stubs used by FigureWidget.
163-
if not hasattr(fig, '_send_addTraces_msg'):
162+
def _from_plotly(attr):
163+
mod_attr = getattr(fig, attr, None)
164+
return mod_attr is None or getattr(mod_attr, "__module__", "").startswith('plotly')
165+
166+
# Monkey patch the message stubs used by FigureWidget, only if the method is from plotly
167+
if _from_plotly('_send_addTraces_msg'):
164168
fig._send_addTraces_msg = lambda *_, **__: self._update_from_figure('add')
165-
if not hasattr(fig, '_send_deleteTraces_msg'):
169+
if _from_plotly('_send_deleteTraces_msg'):
166170
fig._send_deleteTraces_msg = lambda *_, **__: self._update_from_figure('delete')
167-
if not hasattr(fig, '_send_moveTraces_msg'):
171+
if _from_plotly('_send_moveTraces_msg'):
168172
fig._send_moveTraces_msg = lambda *_, **__: self._update_from_figure('move')
169-
if not hasattr(fig, '_send_restyle_msg'):
173+
if _from_plotly('_send_restyle_msg'):
170174
fig._send_restyle_msg = self._send_restyle_msg
171-
if not hasattr(fig, '_send_relayout_msg'):
175+
if _from_plotly('_send_relayout_msg'):
172176
fig._send_relayout_msg = self._send_relayout_msg
173-
if not hasattr(fig, '_send_update_msg'):
177+
if _from_plotly('_send_update_msg'):
174178
fig._send_update_msg = self._send_update_msg
175-
if not hasattr(fig, '_send_animate_msg'):
179+
if _from_plotly('_send_animate_msg'):
176180
fig._send_animate_msg = lambda *_, **__: self._update_from_figure('animate')
177181
self._figure = fig
178182

panel/tests/ui/pane/test_plotly.py

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -274,6 +274,49 @@ def test_plotly_select_data(page, plotly_2d_plot):
274274

275275

276276

277+
def test_plotly_click_data_add_trace(page):
278+
# Regression test for https://github.com/holoviz/panel/issues/8470
279+
fig = go.Figure()
280+
fig.add_trace(go.Scatter(x=[0, 1, 2, 3], y=[0, 1, 2, 3], mode='markers'))
281+
fig.update_layout(uirevision='keep')
282+
283+
pane = Plotly(fig)
284+
285+
def on_click(event):
286+
if event.new is None:
287+
return
288+
pt = event.new['points'][0]
289+
fig.add_trace(go.Scatter(
290+
x=[pt['x']], y=[pt['y']], mode='markers', showlegend=False,
291+
))
292+
293+
pane.param.watch(on_click, 'click_data')
294+
295+
serve_component(page, pane)
296+
297+
point = page.locator('.js-plotly-plot path.point').first
298+
expect(point).to_be_visible()
299+
300+
for _ in range(3):
301+
point.click(force=True)
302+
page.wait_for_timeout(100)
303+
304+
GET_TRACE_COUNT_JS = """() => {
305+
function find(root) {
306+
for (const d of root.querySelectorAll('div')) {
307+
if (d.data && Array.isArray(d.data)) return d.data.length;
308+
}
309+
for (const el of root.querySelectorAll('*')) {
310+
if (el.shadowRoot) { const r = find(el.shadowRoot); if (r !== null) return r; }
311+
}
312+
return null;
313+
}
314+
return find(document);
315+
}"""
316+
317+
wait_until(lambda: page.evaluate(GET_TRACE_COUNT_JS) > 1, page)
318+
319+
277320
def test_plotly_img_plot(page, plotly_img_plot):
278321
msgs, _ = serve_component(page, plotly_img_plot)
279322

0 commit comments

Comments
 (0)