Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 0 additions & 3 deletions plotly/io/_base_renderers.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@

from plotly import optional_imports
from plotly.io import to_json, to_image, write_image, write_html
from plotly.io._utils import plotly_cdn_url
from plotly.offline.offline import _get_jconfig, get_plotlyjs
from plotly.tools import return_figure_from_figure_or_data

Expand Down Expand Up @@ -277,11 +276,9 @@ def activate(self):
{win_config}
{mathjax_config}
</script>
<script type="module">import \"{plotly_cdn}\"</script>
""".format(
win_config=_window_plotly_config,
mathjax_config=_mathjax_config,
plotly_cdn=plotly_cdn_url().rstrip(".js"),
)

else:
Expand Down
55 changes: 55 additions & 0 deletions plotly/io/_html.py
Original file line number Diff line number Diff line change
Expand Up @@ -260,7 +260,62 @@ def to_html(

load_plotlyjs = """\
{win_config}
<script type="text/javascript">\
window.__PLOTLY_PY_REQUIREJS_BACKUP__ = window.__PLOTLY_PY_REQUIREJS_BACKUP__ || [];\
window.__PLOTLY_PY_REQUIREJS_BACKUP__.push({{\
has_define: typeof window.define === "function",\
has_define_amd: typeof window.define === "function" && Object.prototype.hasOwnProperty.call(window.define, "amd"),\
define_amd: typeof window.define === "function" ? window.define.amd : undefined,\
has_module: Object.prototype.hasOwnProperty.call(window, "module"),\
module: window.module,\
has_exports: Object.prototype.hasOwnProperty.call(window, "exports"),\
exports: window.exports\
}});\
/*\
nbviewer loads RequireJS; plotly.js may register as an anonymous AMD module, triggering\
\"Mismatched anonymous define()\" and leaving `Plotly` undefined. Temporarily disable\
AMD/CommonJS detection while loading plotly.js from the CDN.\
*/\
if (typeof window.define === \"function\" && window.define.amd) {{\
window.define.amd = undefined;\
}}\
if (typeof window.module === \"object\" && window.module && window.module.exports) {{\
window.module = undefined;\
}}\
if (typeof window.exports === \"object\") {{\
window.exports = undefined;\
}}\
</script>
<script charset="utf-8" src="{cdn_url}" integrity="{integrity}" crossorigin="anonymous"></script>\
<script type="text/javascript">\
(function() {{\
var backups = window.__PLOTLY_PY_REQUIREJS_BACKUP__;\
if (!backups || !backups.length) {{\
return;\
}}\
var b = backups.pop();\
if (b.has_define) {{\
if (b.has_define_amd) {{\
window.define.amd = b.define_amd;\
}} else {{\
try {{ delete window.define.amd; }} catch (e) {{ window.define.amd = undefined; }}\
}}\
}}\
if (b.has_module) {{\
window.module = b.module;\
}} else {{\
try {{ delete window.module; }} catch (e) {{ window.module = undefined; }}\
}}\
if (b.has_exports) {{\
window.exports = b.exports;\
}} else {{\
try {{ delete window.exports; }} catch (e) {{ window.exports = undefined; }}\
}}\
if (!backups.length) {{\
try {{ delete window.__PLOTLY_PY_REQUIREJS_BACKUP__; }} catch (e) {{ window.__PLOTLY_PY_REQUIREJS_BACKUP__ = undefined; }}\
}}\
}})();\
</script>\
""".format(
win_config=_window_plotly_config,
cdn_url=plotly_cdn_url(),
Expand Down
74 changes: 62 additions & 12 deletions tests/test_io/test_renderers.py
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,13 @@ def assert_offline(html):
assert get_plotlyjs() in html


def assert_requirejs_workaround(html):
# nbviewer runs RequireJS; ensure we include the guard that prevents plotly.js
# from registering as an anonymous AMD module (which would leave `Plotly`
# undefined in the output).
assert "__PLOTLY_PY_REQUIREJS_BACKUP__" in html


def test_colab_renderer_show(fig1):
pio.renderers.default = "colab"

Expand All @@ -164,6 +171,7 @@ def test_colab_renderer_show(fig1):
html = mock_arg1["text/html"]
assert_full_html(html)
assert_html_renderer_connected(html)
assert_requirejs_workaround(html)

# check kwargs
mock_kwargs = mock_call_args[1]
Expand Down Expand Up @@ -191,7 +199,8 @@ def test_notebook_connected_show(fig1, name, connected):
# Check init display contents
bundle_display_html = mock_arg1_html
if connected:
assert_html_renderer_connected(bundle_display_html)
assert "window.PlotlyConfig" in bundle_display_html
assert get_plotlyjs() not in bundle_display_html
else:
assert_offline(bundle_display_html)

Expand All @@ -206,6 +215,9 @@ def test_notebook_connected_show(fig1, name, connected):
# Check html display contents
bundle_html = mock_arg1["text/html"]
assert_not_full_html(bundle_html)
if connected:
assert_html_renderer_connected(bundle_html)
assert_requirejs_workaround(bundle_html)

# check kwargs
mock_kwargs = mock_call_args[1]
Expand Down Expand Up @@ -305,22 +317,60 @@ def test_repr_html(renderer):
plotlyjs_content = get_plotlyjs()
sri_hash = _generate_sri_hash(plotlyjs_content)

requirejs_workaround_pre = (
'<script type="text/javascript">window.__PLOTLY_PY_REQUIREJS_BACKUP__ = '
"window.__PLOTLY_PY_REQUIREJS_BACKUP__ || [];"
"window.__PLOTLY_PY_REQUIREJS_BACKUP__.push({ has_define: typeof "
'window.define === "function", has_define_amd: typeof window.define === '
'"function" && Object.prototype.hasOwnProperty.call(window.define, "amd"), '
'define_amd: typeof window.define === "function" ? window.define.amd : '
"undefined, has_module: Object.prototype.hasOwnProperty.call(window, "
'"module"), module: window.module, has_exports: '
'Object.prototype.hasOwnProperty.call(window, "exports"), exports: '
"window.exports});/*nbviewer loads RequireJS; plotly.js may register as an "
'anonymous AMD module, triggering"Mismatched anonymous define()" and leaving '
"`Plotly` undefined. Temporarily disableAMD/CommonJS detection while loading "
'plotly.js from the CDN.*/if (typeof window.define === "function" && '
"window.define.amd) { window.define.amd = undefined;}if (typeof "
'window.module === "object" && window.module && window.module.exports) { '
'window.module = undefined;}if (typeof window.exports === "object") { '
"window.exports = undefined;} </script>\n "
)

requirejs_workaround_post = (
'<script type="text/javascript">(function() { var backups = '
"window.__PLOTLY_PY_REQUIREJS_BACKUP__; if (!backups || !backups.length) "
"{ return; } var b = backups.pop(); if (b.has_define) { "
"if (b.has_define_amd) { window.define.amd = b.define_amd; } "
"else { try { delete window.define.amd; } catch (e) { "
"window.define.amd = undefined; } } } if (b.has_module) { "
"window.module = b.module; } else { try { delete window.module; } "
"catch (e) { window.module = undefined; } } if (b.has_exports) { "
"window.exports = b.exports; } else { try { delete window.exports; } "
"catch (e) { window.exports = undefined; } } if (!backups.length) { "
"try { delete window.__PLOTLY_PY_REQUIREJS_BACKUP__; } catch (e) { "
"window.__PLOTLY_PY_REQUIREJS_BACKUP__ = undefined; } }})(); </script>"
)

template = (
'<div> <script type="text/javascript">'
"window.PlotlyConfig = {MathJaxConfig: 'local'};</script>\n "
'<script charset="utf-8" src="'
+ "window.PlotlyConfig = {MathJaxConfig: 'local'};</script>\n "
+ requirejs_workaround_pre
+ '<script charset="utf-8" src="'
+ plotly_cdn_url()
+ '" integrity="'
+ sri_hash
+ '" crossorigin="anonymous"></script> '
'<div id="cd462b94-79ce-42a2-887f-2650a761a144" class="plotly-graph-div" '
'style="height:100%; width:100%;"></div> <script type="text/javascript">'
" window.PLOTLYENV=window.PLOTLYENV || {};"
' if (document.getElementById("cd462b94-79ce-42a2-887f-2650a761a144"))'
' { Plotly.newPlot( "cd462b94-79ce-42a2-887f-2650a761a144",'
' [], {"template":{}},'
' {"responsive": true} ) };'
" </script> </div>"
+ '" crossorigin="anonymous"></script> '
+ requirejs_workaround_post
+ " "
+ '<div id="cd462b94-79ce-42a2-887f-2650a761a144" class="plotly-graph-div" '
+ 'style="height:100%; width:100%;"></div> <script type="text/javascript">'
+ " window.PLOTLYENV=window.PLOTLYENV || {};"
+ ' if (document.getElementById("cd462b94-79ce-42a2-887f-2650a761a144"))'
+ ' { Plotly.newPlot( "cd462b94-79ce-42a2-887f-2650a761a144",'
+ ' [], {"template":{}},'
+ ' {"responsive": true} ) };'
+ " </script> </div>"
)
if "text/html" in bundle:
str_bundle = bundle["text/html"]
Expand Down