Skip to content

Commit f378199

Browse files
authored
Merge pull request #1949 from plotly/mathjax-v3
Implement SVG rendering of equations in `dcc.Graph` and `dcc.Markdown` using `MathJax` v3
2 parents da43568 + d7e73d7 commit f378199

File tree

19 files changed

+766
-93
lines changed

19 files changed

+766
-93
lines changed

.circleci/config.yml

+2-2
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ jobs:
5454
pip install -e .[ci,dev,testing,celery,diskcache] --progress-bar off
5555
pip list | grep dash
5656
npm i
57-
npm run build
57+
npm run build.sequential
5858
python setup.py sdist
5959
mkdir dash-package && cp dist/*.tar.gz dash-package/dash-package.tar.gz
6060
ls -la dash-package
@@ -120,7 +120,7 @@ jobs:
120120
set -eo pipefail
121121
pip install -e . --progress-bar off && pip list | grep dash
122122
npm install npm run initialize
123-
npm run build
123+
npm run build.sequential
124124
npm run lint
125125
- run:
126126
name: 🐍 Python Unit Tests & ☕ JS Unit Tests

CHANGELOG.md

+17-1
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,26 @@ This project adheres to [Semantic Versioning](https://semver.org/).
44

55
## [Unreleased]
66

7+
### Added
8+
- [#1949](https://github.com/plotly/dash/pull/1915) Add built-in MathJax support to both `dcc.Markdown` and `dcc.Graph`. A new boolean prop `mathjax` was added to these two components, defaulting to `False`. Set `mathjax=True` to enable math rendering. This work uses MathJax v3, although `dcc.Graph` and Plotly.js can also be used with MathJax v2.
9+
- In `dcc.Markdown` this has two flavors: inline math is any content between single dollar signs, for example `"$E=mc^2$"`, and "display" math (on its own line, potentially multi-line) is delimited by double dollar signs.
10+
- In `dcc.Graph`, most text fields (graph and axis titles, trace names, scatter and bar text) can use math, and it's enabled with single dollar sign delimiters. A limitation here is that currently a given piece of text can only be one or the other: if math is found, everything outside the delimiters is ignored. See https://plotly.com/python/LaTeX/ for details.
11+
- For an intro to LaTeX math, see https://en.wikibooks.org/wiki/LaTeX/Mathematics.
12+
- Big thanks to [Equinor](https://www.equinor.com/) for sponsoring this development, including the related work in Plotly.js!
13+
14+
### Updated
15+
- [#1949](https://github.com/plotly/dash/pull/1915) Upgrade Plotly.js to v2.11.0 (from v2.9.0)
16+
- [Feature release 2.10.0](https://github.com/plotly/plotly.js/releases/tag/v2.10.0):
17+
- Support for MathJax v3
18+
- `fillpattern` for `scatter` traces with filled area
19+
- [Feature release 2.11.0](https://github.com/plotly/plotly.js/releases/tag/v2.11.0):
20+
- Every trace type can now be rendered in a stricter CSP environment, specifically avoiding `unsafe-eval`. Please note: the `regl`-based traces (`scattergl`, `scatterpolargl`, `parcoords`, and `splom`) are only strict in the `strict` bundle, which is NOT served by default in Dash. To use this bundle with Dash, you must either download it and put it in your `assets/` folder, or include it as an `external_script` from the CDN: https://cdn.plot.ly/plotly-strict-2.11.0.min.js. All other trace types are strict in the normal bundle.
21+
- Patch release [2.10.1](https://github.com/plotly/plotly.js/releases/tag/v2.5.1) containing a bugfix for `mesh3d` traces.
22+
23+
724
### Fixed
825
- [#1915](https://github.com/plotly/dash/pull/1915) Fix bug [#1474](https://github.com/plotly/dash/issues/1474) when both dcc.Graph and go.Figure have animation, and when the second animation in Figure is executed, the Frames from the first animation are played instead of the second one.
926

10-
### Fixed
1127
- [#1953](https://github.com/plotly/dash/pull/1953) Fix bug [#1783](https://github.com/plotly/dash/issues/1783) in which a failed hot reloader blocks the UI with alerts.
1228

1329
## [2.2.0] - 2022-02-18

components/dash-core-components/.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ venv/
1919
/build
2020
/dash_core_components
2121
dash_core_components_base/plotly.min.js
22+
dash_core_components_base/mathjax.js
2223
/deps
2324
/inst
2425
/man

components/dash-core-components/dash_core_components_base/__init__.py

+1
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@
4848
"graph",
4949
"highlight",
5050
"markdown",
51+
"mathjax",
5152
"slider",
5253
"upload",
5354
]

components/dash-core-components/package-lock.json

+33-7
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

components/dash-core-components/package.json

+4-2
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
"test": "run-s -c lint test:intg test:pyimport",
2424
"test:intg": "pytest --nopercyfinalize --headless tests/integration",
2525
"test:pyimport": "python -m unittest tests/test_dash_import.py",
26-
"prebuild:js": "cp node_modules/plotly.js-dist-min/plotly.min.js dash_core_components_base/plotly.min.js",
26+
"prebuild:js": "cp node_modules/plotly.js-dist-min/plotly.min.js dash_core_components_base/plotly.min.js && cp node_modules/mathjax/es5/tex-svg.js dash_core_components_base/mathjax.js",
2727
"build:js": "webpack --mode production",
2828
"build:backends": "dash-generate-components ./src/components dash_core_components -p package-info.json && cp dash_core_components_base/** dash_core_components/ && dash-generate-components ./src/components dash_core_components -p package-info.json -k RangeSlider,Slider,Dropdown,RadioItems,Checklist,DatePickerSingle,DatePickerRange,Input,Link --r-prefix 'dcc' --r-suggests 'dash,dashHtmlComponents,jsonlite,plotly' --jl-prefix 'dcc' && black dash_core_components",
2929
"build": "run-s prepublishOnly build:js build:backends",
@@ -46,9 +46,10 @@
4646
"fast-isnumeric": "^1.1.4",
4747
"file-saver": "^2.0.5",
4848
"highlight.js": "^11.4.0",
49+
"mathjax": "^3.2.0",
4950
"moment": "^2.29.1",
5051
"node-polyfill-webpack-plugin": "^1.1.4",
51-
"plotly.js-dist-min": "2.9.0",
52+
"plotly.js-dist-min": "2.11.0",
5253
"prop-types": "^15.7.2",
5354
"ramda": "^0.27.1",
5455
"rc-slider": "^9.7.5",
@@ -60,6 +61,7 @@
6061
"react-resize-detector": "^6.7.6",
6162
"react-select-fast-filter-options": "^0.2.3",
6263
"react-virtualized-select": "^3.1.3",
64+
"remark-math": "^3.0.1",
6365
"uniqid": "^5.4.0"
6466
},
6567
"devDependencies": {

components/dash-core-components/src/components/Graph.react.js

+16-1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import PropTypes from 'prop-types';
44
import {asyncDecorator} from '@plotly/dash-component-plugins';
55
import graph from '../utils/LazyLoader/graph';
66
import plotly from '../utils/LazyLoader/plotly';
7+
import lazyLoadMathJax from '../utils/LazyLoader/mathjax';
78
import {
89
privatePropTypes,
910
privateDefaultProps,
@@ -21,6 +22,10 @@ class PlotlyGraph extends Component {
2122
constructor(props) {
2223
super(props);
2324

25+
if (props.mathjax) {
26+
PlotlyGraph._loadMathjax = true;
27+
}
28+
2429
this.state = {
2530
prependData: [],
2631
extendData: [],
@@ -120,7 +125,11 @@ class PlotlyGraph extends Component {
120125
}
121126

122127
const RealPlotlyGraph = asyncDecorator(PlotlyGraph, () =>
123-
Promise.all([plotly(), graph()]).then(([, graph]) => graph)
128+
Promise.all([
129+
graph(),
130+
plotly(),
131+
PlotlyGraph._loadMathjax ? lazyLoadMathJax() : undefined,
132+
]).then(([graph]) => graph)
124133
);
125134

126135
const ControlledPlotlyGraph = memo(props => {
@@ -266,6 +275,11 @@ PlotlyGraph.propTypes = {
266275
*/
267276
className: PropTypes.string,
268277

278+
/**
279+
* If true, loads mathjax v3 (tex-svg) into the page and use it in the graph
280+
*/
281+
mathjax: PropTypes.bool,
282+
269283
/**
270284
* Beta: If true, animate between updates using
271285
* plotly.js's `animate` function
@@ -574,6 +588,7 @@ PlotlyGraph.defaultProps = {
574588
frames: [],
575589
},
576590
responsive: 'auto',
591+
mathjax: false,
577592
animate: false,
578593
animation_options: {
579594
frame: {

components/dash-core-components/src/components/Markdown.react.js

+24-3
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1+
import {asyncDecorator} from '@plotly/dash-component-plugins';
12
import PropTypes from 'prop-types';
2-
import React, {Component, lazy, Suspense} from 'react';
3+
import React, {Component, Suspense} from 'react';
34
import markdown from '../utils/LazyLoader/markdown';
4-
5-
const RealDashMarkdown = lazy(markdown);
5+
import lazyLoadMathJax from '../utils/LazyLoader/mathjax';
66

77
// eslint-disable-next-line valid-jsdoc
88
/**
@@ -11,6 +11,14 @@ const RealDashMarkdown = lazy(markdown);
1111
* [react-markdown](https://rexxars.github.io/react-markdown/) under the hood.
1212
*/
1313
export default class DashMarkdown extends Component {
14+
constructor(props) {
15+
super(props);
16+
17+
if (props.mathjax) {
18+
DashMarkdown._loadMathjax = true;
19+
}
20+
}
21+
1422
render() {
1523
return (
1624
<Suspense fallback={null}>
@@ -32,6 +40,11 @@ DashMarkdown.propTypes = {
3240
*/
3341
className: PropTypes.string,
3442

43+
/**
44+
* If true, loads mathjax v3 (tex-svg) into the page and use it in the markdown
45+
*/
46+
mathjax: PropTypes.bool,
47+
3548
/**
3649
* A boolean to control raw HTML escaping.
3750
* Setting HTML from code is risky because it's easy to
@@ -91,10 +104,18 @@ DashMarkdown.propTypes = {
91104
};
92105

93106
DashMarkdown.defaultProps = {
107+
mathjax: false,
94108
dangerously_allow_html: false,
95109
highlight_config: {},
96110
dedent: true,
97111
};
98112

113+
const RealDashMarkdown = asyncDecorator(DashMarkdown, () =>
114+
Promise.all([
115+
markdown(),
116+
DashMarkdown._loadMathjax ? lazyLoadMathJax() : undefined,
117+
]).then(([md]) => md)
118+
);
119+
99120
export const propTypes = DashMarkdown.propTypes;
100121
export const defaultProps = DashMarkdown.defaultProps;

0 commit comments

Comments
 (0)