Skip to content

Commit 70e2ee9

Browse files
jonmmeasemichaelbabyn
authored andcommitted
Add MathJax / Latex support for offline plot/iplot/FigureWidget (plotly#1243)
* Add include_mathjax argument to plotly.offline.plot * Add MathJax support for plotly.offline.iplot in the notebook * Add MathJax/LaTeX support for FigureWidget
1 parent 4a7bfd6 commit 70e2ee9

File tree

5 files changed

+211
-25
lines changed

5 files changed

+211
-25
lines changed

Diff for: js/src/Figure.js

+8
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
var widgets = require("@jupyter-widgets/base");
22
var _ = require("lodash");
3+
4+
window.PlotlyConfig = {MathJaxConfig: 'local'};
35
var Plotly = require("plotly.js/dist/plotly");
46
var PlotlyIndex = require("plotly.js/src/lib/index");
57
var semver_range = "^" + require("../package.json").version;
@@ -720,6 +722,12 @@ var FigureView = widgets.DOMWidgetView.extend({
720722
this.model.on("change:_py2js_animate",
721723
this.do_animate, this);
722724

725+
// MathJax configuration
726+
// ---------------------
727+
if (window.MathJax) {
728+
MathJax.Hub.Config({SVG: {font: "STIX-Web"}});
729+
}
730+
723731
// Get message ids
724732
// ---------------------
725733
var layout_edit_id = this.model.get("_last_layout_edit_id");

Diff for: plotly/offline/offline.py

+94-24
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,34 @@ def get_plotlyjs():
9898
return plotlyjs
9999

100100

101+
def _build_resize_script(plotdivid):
102+
resize_script = (
103+
'<script type="text/javascript">'
104+
'window.addEventListener("resize", function(){{'
105+
'Plotly.Plots.resize(document.getElementById("{id}"));}});'
106+
'</script>'
107+
).format(id=plotdivid)
108+
return resize_script
109+
110+
111+
def _build_mathjax_script(url):
112+
return ('<script src="{url}?config=TeX-AMS-MML_SVG"></script>'
113+
.format(url=url))
114+
115+
116+
# Build script to set global PlotlyConfig object. This must execute before
117+
# plotly.js is loaded.
118+
_window_plotly_config = """\
119+
<script type="text/javascript">\
120+
window.PlotlyConfig = {MathJaxConfig: 'local'};\
121+
</script>"""
122+
123+
_mathjax_config = """\
124+
<script type="text/javascript">\
125+
if (window.MathJax) {MathJax.Hub.Config({SVG: {font: "STIX-Web"}});}\
126+
</script>"""
127+
128+
101129
def get_image_download_script(caller):
102130
"""
103131
This function will return a script that will download an image of a Plotly
@@ -168,23 +196,26 @@ def init_notebook_mode(connected=False):
168196
if connected:
169197
# Inject plotly.js into the output cell
170198
script_inject = (
171-
''
199+
'{win_config}'
200+
'{mathjax_config}'
172201
'<script>'
173-
'requirejs.config({'
174-
'paths: { '
202+
'requirejs.config({{'
203+
'paths: {{ '
175204
# Note we omit the extension .js because require will include it.
176-
'\'plotly\': [\'https://cdn.plot.ly/plotly-latest.min\']},'
177-
'});'
205+
'\'plotly\': [\'https://cdn.plot.ly/plotly-latest.min\']}},'
206+
'}});'
178207
'if(!window.Plotly) {{'
179208
'require([\'plotly\'],'
180-
'function(plotly) {window.Plotly=plotly;});'
209+
'function(plotly) {{window.Plotly=plotly;}});'
181210
'}}'
182211
'</script>'
183-
)
212+
).format(win_config=_window_plotly_config,
213+
mathjax_config=_mathjax_config)
184214
else:
185215
# Inject plotly.js into the output cell
186216
script_inject = (
187-
''
217+
'{win_config}'
218+
'{mathjax_config}'
188219
'<script type=\'text/javascript\'>'
189220
'if(!window.Plotly){{'
190221
'define(\'plotly\', function(require, exports, module) {{'
@@ -195,7 +226,9 @@ def init_notebook_mode(connected=False):
195226
'}});'
196227
'}}'
197228
'</script>'
198-
'').format(script=get_plotlyjs())
229+
'').format(script=get_plotlyjs(),
230+
win_config=_window_plotly_config,
231+
mathjax_config=_mathjax_config)
199232

200233
display_bundle = {
201234
'text/html': script_inject,
@@ -450,21 +483,11 @@ def iplot(figure_or_data, show_link=True, link_text='Export to plot.ly',
450483
ipython_display.display(ipython_display.HTML(script))
451484

452485

453-
def _build_resize_script(plotdivid):
454-
resize_script = (
455-
'<script type="text/javascript">'
456-
'window.addEventListener("resize", function(){{'
457-
'Plotly.Plots.resize(document.getElementById("{id}"));}});'
458-
'</script>'
459-
).format(id=plotdivid)
460-
return resize_script
461-
462-
463486
def plot(figure_or_data, show_link=True, link_text='Export to plot.ly',
464487
validate=True, output_type='file', include_plotlyjs=True,
465488
filename='temp-plot.html', auto_open=True, image=None,
466489
image_filename='plot_image', image_width=800, image_height=600,
467-
config=None):
490+
config=None, include_mathjax=False):
468491
""" Create a plotly graph locally as an HTML document or string.
469492
470493
Example:
@@ -558,6 +581,22 @@ def plot(figure_or_data, show_link=True, link_text='Export to plot.ly',
558581
config (default=None) -- Plot view options dictionary. Keyword arguments
559582
`show_link` and `link_text` set the associated options in this
560583
dictionary if it doesn't contain them already.
584+
include_mathjax (False | 'cdn' | path - default=False) --
585+
Specifies how the MathJax.js library is included in the output html
586+
file or div string. MathJax is required in order to display labels
587+
with LaTeX typesetting.
588+
589+
If False, no script tag referencing MathJax.js will be included in the
590+
output. HTML files generated with this option will not be able to
591+
display LaTeX typesetting.
592+
593+
If 'cdn', a script tag that references a MathJax CDN location will be
594+
included in the output. HTML files generated with this option will be
595+
able to display LaTeX typesetting as long as they have internet access.
596+
597+
If a string that ends in '.js', a script tag is included that
598+
references the specified path. This approach can be used to point the
599+
resulting HTML file to an alternative CDN.
561600
"""
562601
if output_type not in ['div', 'file']:
563602
raise ValueError(
@@ -577,31 +616,60 @@ def plot(figure_or_data, show_link=True, link_text='Export to plot.ly',
577616
figure_or_data, config, validate,
578617
'100%', '100%', global_requirejs=False)
579618

619+
# Build resize_script
580620
resize_script = ''
581621
if width == '100%' or height == '100%':
582622
resize_script = _build_resize_script(plotdivid)
583623

624+
# Process include_plotlyjs and build plotly_js_script
625+
include_plotlyjs_orig = include_plotlyjs
584626
if isinstance(include_plotlyjs, six.string_types):
585627
include_plotlyjs = include_plotlyjs.lower()
586628

587629
if include_plotlyjs == 'cdn':
588-
plotly_js_script = """\
630+
plotly_js_script = _window_plotly_config + """\
589631
<script src="https://cdn.plot.ly/plotly-latest.min.js"></script>"""
590632
elif include_plotlyjs == 'directory':
591-
plotly_js_script = '<script src="plotly.min.js"></script>'
633+
plotly_js_script = (_window_plotly_config +
634+
'<script src="plotly.min.js"></script>')
592635
elif (isinstance(include_plotlyjs, six.string_types) and
593636
include_plotlyjs.endswith('.js')):
594-
plotly_js_script = '<script src="{url}"></script>'.format(
595-
url=include_plotlyjs)
637+
plotly_js_script = (_window_plotly_config +
638+
'<script src="{url}"></script>'.format(
639+
url=include_plotlyjs_orig))
596640
elif include_plotlyjs:
597641
plotly_js_script = ''.join([
642+
_window_plotly_config,
598643
'<script type="text/javascript">',
599644
get_plotlyjs(),
600645
'</script>',
601646
])
602647
else:
603648
plotly_js_script = ''
604649

650+
# Process include_mathjax and build mathjax_script
651+
include_mathjax_orig = include_mathjax
652+
if isinstance(include_mathjax, six.string_types):
653+
include_mathjax = include_mathjax.lower()
654+
655+
if include_mathjax == 'cdn':
656+
mathjax_script = _build_mathjax_script(
657+
url=('https://cdnjs.cloudflare.com'
658+
'/ajax/libs/mathjax/2.7.5/MathJax.js')) + _mathjax_config
659+
elif (isinstance(include_mathjax, six.string_types) and
660+
include_mathjax.endswith('.js')):
661+
mathjax_script = _build_mathjax_script(
662+
url=include_mathjax_orig) + _mathjax_config
663+
elif not include_mathjax:
664+
mathjax_script = ''
665+
else:
666+
raise ValueError("""\
667+
Invalid value of type {typ} received as the include_mathjax argument
668+
Received value: {val}
669+
670+
include_mathjax may be specified as False, 'cdn', or a string ending with '.js'
671+
""".format(typ=type(include_mathjax), val=repr(include_mathjax)))
672+
605673
if output_type == 'file':
606674
with open(filename, 'w') as f:
607675
if image:
@@ -624,6 +692,7 @@ def plot(figure_or_data, show_link=True, link_text='Export to plot.ly',
624692
'<html>',
625693
'<head><meta charset="utf-8" /></head>',
626694
'<body>',
695+
mathjax_script,
627696
plotly_js_script,
628697
plot_html,
629698
resize_script,
@@ -650,6 +719,7 @@ def plot(figure_or_data, show_link=True, link_text='Export to plot.ly',
650719

651720
return ''.join([
652721
'<div>',
722+
mathjax_script,
653723
plotly_js_script,
654724
plot_html,
655725
resize_script,

0 commit comments

Comments
 (0)