fix: resolve 'no comm channel defined' error with plotly 6.x#220
Open
fix: resolve 'no comm channel defined' error with plotly 6.x#220
Conversation
Fixes posit-dev/py-shiny#2156 Plotly 6.0 switched FigureWidget to use anywidget, which doesn't have a destroy() method. When m.close() is called, ipywidgets deletes the comm before removing views, and the view removal tries to sync _view_count, causing "Syncing error: no comm channel defined". The fix sets comm_live=false before calling m.close(), which prevents save_changes() from attempting to sync during view removal. Also wraps the close operations in try-catch to suppress cleanup errors that don't affect functionality. Note: The model-score streaming example still has visibility issues with plotly 6.x, but this is a pre-existing problem (also present on main) and should be investigated separately. Co-Authored-By: Claude Opus 4.5 <[email protected]>
71fca1b to
e8859a6
Compare
Previously, widgets were cleaned up via `ctx.on_invalidate()` which fired whenever the render context was invalidated. This caused issues when effects were created inside render functions (like in `render_plotly_streaming`) - the effect's dependency changes would invalidate the context and destroy the widget prematurely. Now widgets are only closed when a NEW widget is rendered for the same output, not on every context invalidation. This properly supports patterns where effects update widgets in-place without re-creating them. Co-Authored-By: Claude Opus 4.5 <[email protected]>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes posit-dev/py-shiny#2156
Closes #215
Closes #137
This PR fixes two issues with plotly 6.x and shinywidgets:
Problem 1: Comm Channel Error
Symptoms
Error during model cleanup: Syncing error: no comm channel definedRoot Cause
Plotly 6.0 switched
FigureWidgetto useanywidgetinstead of their previous implementation. This introduced an incompatibility with how ipywidgets handles model cleanup:ipywidgets'
close()method deletesthis.commBEFORE removing views (widget.ts lines 232-243)When views are removed, they fire a
'remove'event that tries to sync_view_countback to the server (widget.ts lines 789-793):The sync fails because the comm was already deleted, throwing "Syncing error: no comm channel defined"
Solution
Set
comm_live = falsebefore callingm.close()- this preventssave_changes()from attempting to sync when views are removed.Problem 2: Widgets Not Visible with Streaming Patterns
Symptoms
render_plotly_streaming(effects inside render functions) would not appearRoot Cause
Previously, widgets were cleaned up via
ctx.on_invalidate()which fired whenever the render context was invalidated. When effects are created inside render functions (like inrender_plotly_streaming), the effect's dependency changes would invalidate the context and destroy the widget prematurely - even though the render function itself wasn't re-running.Solution
Changed widget cleanup to only close the old widget when a new widget is being rendered for the same output, rather than on every context invalidation. This properly supports patterns where effects update widgets in-place without re-creating them.
Key changes in
_shinywidgets.py:OUTPUT_WIDGET_MAPto track which widget is associated with each(session_id, output_id)pairon_invalidatecleanup hook that was causing premature destructionTest Plan
cd examples/model-score && shiny run app.py🤖 Generated with Claude Code