Fix Plotly CDN rendering in nbviewer by mklilley · Pull Request #5504 · plotly/plotly.py
Fix Plotly CDN rendering in nbviewer (RequireJS “mismatched anonymous define()”)
Related issue: #5314 (reported by @mklilley)
Summary
This PR fixes a bug where Plotly figures render correctly in Google Colab, but fail to render when the same notebook is viewed on nbviewer. The failure presents as:
Uncaught Error: Mismatched anonymous define() module(RequireJS)Uncaught ReferenceError: Plotly is not defined
Root Cause
nbviewer loads RequireJS on the page. When Plotly is included via a plain CDN <script src="https://cdn.plot.ly/plotly-...min.js">, the Plotly bundle may detect an AMD/CommonJS environment (e.g. define.amd, module, exports) and register as an anonymous AMD module. RequireJS then throws the “mismatched anonymous define()” error, and Plotly does not end up attached to window.Plotly, causing subsequent Plotly.newPlot(...) calls to fail.
What This PR Changes
-
Guard Plotly CDN loading against RequireJS/AMD/CommonJS detection
- In
plotly/io/_html.py, wheninclude_plotlyjs="cdn", the generated HTML now:- Saves the current values of
define.amd,module, andexports. - Temporarily disables them while loading the CDN
plotly-*.min.js. - Restores the original values immediately after the script loads.
- Saves the current values of
- This forces Plotly’s CDN bundle to initialize in “browser global” mode so
window.Plotlyis reliably defined in nbviewer.
- In
-
Remove redundant connected renderer global-init module import
- In
plotly/io/_base_renderers.py,HtmlRenderer.activate()no longer injects an extra<script type="module">import ...</script>for connected renderers. - This import is redundant (the figure HTML already loads Plotly when connected) and can interact poorly with environments that already manage JS loaders.
- In
-
Tests updated
tests/test_io/test_renderers.pyupdated to validate:- The RequireJS guard is included in connected HTML outputs.
- The connected renderer init output no longer embeds/imports Plotly JS.
- Related suites were also run to ensure the new CDN HTML is still correct.
Why This Approach
- It’s targeted to the actual nbviewer failure mode: RequireJS + CDN script loading.
- It keeps the existing
include_plotlyjs="cdn"behavior (still uses versioned CDN URL + SRI), while making it robust in AMD loader contexts. - The guard is reversible (restores the environment after Plotly loads) to minimize interference with other notebook JS.
Files Changed
plotly/io/_html.pyplotly/io/_base_renderers.pytests/test_io/test_renderers.py
How To Reproduce / Verify (from the issue)
- Create a notebook that uses a connected renderer (e.g.
pio.renderers.default = "notebook_connected+colab"). - Save it with outputs.
- Open the notebook on nbviewer.
- Before this PR: RequireJS mismatch error +
Plotly is not defined, plot doesn’t render. - After this PR: no RequireJS mismatch; plot renders normally.
Code PR
- I have read through the contributing notes (CONTRIBUTING.md) and understand the structure of the package. In particular, if my PR modifies code of
plotly.graph_objects, my modifications concern the code generator and not the generated files. - I have added tests or modified existing tests.
- For a new feature, I have added documentation examples (not applicable; this is a bugfix).
- I have added a CHANGELOG entry if changing anything substantial (not added; please advise if maintainers want an entry).
- For a new feature or a change in behavior, I have updated the relevant docstrings in the code (not applicable; change is limited to generated HTML for
include_plotlyjs="cdn"to avoid nbviewer/RequireJS breakage).