plotly / dash

Data Apps & Dashboards for Python. No JavaScript Required.
https://plotly.com/dash
MIT License
21.31k stars 2.06k forks source link

latex support #242

Closed Cyberfly100 closed 2 years ago

Cyberfly100 commented 6 years ago

I tried to use latex in dash, but it is not working. It seems that the mathjax javacript library is not loaded.

chriddyp commented 6 years ago

I wonder if the solution is just to add MathJax to https://github.com/plotly/dash-core-components/blob/d034e25f6f56423ef2de7e5905328396040cf4d8/dash_core_components/__init__.py#L25-L29

jessexknight commented 6 years ago

It is possible to render MathJax in static Dash content, but not in dynamic content.

Here is a MWE

import dash
import dash_html_components as html

app = dash.Dash(__name__)
mathjax = 'https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.4/MathJax.js?config=TeX-MML-AM_CHTML'
app.scripts.append_script({ 'external_url' : mathjax })

app.layout = html.Div(id='main',children=[
  html.Div(id='static',children='$$ x=1 $$'),
  html.Div(id='dynamic',children=''),
  html.Button('Add Math',id='button'),
])

@app.callback(
  dash.dependencies.Output('dynamic','children'),
 [dash.dependencies.Input('button','n_clicks')]
)
def addmath(n_clicks):
  if n_clicks:
    return '$$ x=1 $$'
  else:
    return None

if __name__ == '__main__':
  app.run_server(debug=True)

related community.plot.ly thread

aztan2 commented 6 years ago

Hi, I'm wondering if there has been progress on this issue? Specifically, I would like to be able to render latex in the axis titles/labels of a graph.

jessexknight commented 6 years ago

There is a pull request in progress to solve this issue, but it seems like it has stalled at the moment.

xhluca commented 5 years ago

I created dash-katex, a library that let you render latex inside a component DashKatex, obviously using katex js. This does not solve the problem of rendering latex inside a plotly graph object, but lets you dynamically run latex inside divs.

Link: https://github.com/xhlulu/dash-katex

vdkotian commented 5 years ago

Is this issue still available for development? I am seeking to contribute.

renatobellotti commented 4 years ago

Is there any progress on this? Latex support is quite important for scientific dashboards...

renatobellotti commented 4 years ago

What about now?

yueyericardo commented 4 years ago

After searching around, I found Latex to Image API very useful. And I wrote a function to make it work with $a+b$ and $$a+b$$ for dcc.markdown.

import dash_core_components as dcc
import dash_html_components as html
import dash
import urllib.parse
import re

def convert(text):
    def toimage(x):
        if x[1] and x[-2] == r'$':
            x = x[2:-2]
            img = "\n<img src='https://math.now.sh?from={}' style='display: block; margin: 0.5em auto;'>\n"
            return img.format(urllib.parse.quote_plus(x))
        else:
            x = x[1:-1]
            return r'![](https://math.now.sh?from={})'.format(urllib.parse.quote_plus(x))
    return re.sub(r'\${2}([^$]+)\${2}|\$(.+?)\$', lambda x: toimage(x.group()), text)

app = dash.Dash()

Markdown_text = r"""
Let's see if it works:  
$$\hat P \psi_k(x) =p \psi_k(x)$$ 

$$-i\hbar \frac{\partial {c\ e^{ikx}}}{\partial x} =-i\hbar\ c\ ik\ e^{ikx} $$ 

$$\hbar k\ c\ e^{ikx} = \hbar k\ \psi_k(x) \tag{2}$$
with $p=\hbar k$
"""

Markdown_text = convert(Markdown_text)

app.layout = html.Div([
    dcc.Markdown(Markdown_text, dangerously_allow_html=True)
])

if __name__ == '__main__':
    app.run_server(host='0.0.0.0')

renatobellotti commented 4 years ago

Does this also work for axis labels?

jessexknight commented 4 years ago

I will look into this in the next 2 weeks. For now, here are some ideas somebody may want to try:

yueyericardo commented 4 years ago

Does this also work for axis labels?

Hey, I just found some (tricky) workaround for axis labels, as well as latex in markdown. I'll put this into a repo soon and share how to use this.

An example image

Richard

renatobellotti commented 4 years ago

Does this also work for axis labels?

Hey, I just found some (tricky) workaround for axis labels, as well as latex in markdown. I'll put this into a repo soon and share how to use this.

An example image

Richard

This looks great! How did you do it? And is this something you could provide a pull request for? ;)

yueyericardo commented 4 years ago

This looks great! How did you do it? And is this something you could provide a pull request for? ;)

Hey sorry for the delay, I just created a complete example https://github.com/yueyericardo/dash_latex explain how to make it work.

Example2 will come later.

jessexknight commented 4 years ago

Well, now I'm confused. It looks like dynamic MathJax in axes labels now works. I thought that this was not working before. Can anybody confirm that this was part of the problem and now fixed?

This MWE will compile the user-input LaTeX live and render the result on y-axis label.

import dash
import dash_html_components as html
import dash_core_components as dcc
from dash.dependencies import Input, Output

app = dash.Dash(__name__, external_scripts=[
  'https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.4/MathJax.js?config=TeX-MML-AM_CHTML',
])

def fig_fun(label='default'):
  return {
    'data': [{'x': [-5, 0,+5], 'y': [0,0,5] }],
    'layout': {'yaxis': {'title': label}},
  }

ylabel = '$y = \\begin{cases} 0 & x < 0 \\\\ x & x \ge 0 \\end{cases}$'

app.layout = html.Div(id='main',children=[
  dcc.Input(id='input',value=ylabel,style={'width':'100%'}),
  dcc.Graph(id='graph',figure=fig_fun())
])

@app.callback( Output('graph','figure'), [Input('input','value')] )
def update_fun(label):
  return fig_fun(label=label)

if __name__ == '__main__':
  app.run_server(debug=True)

dash-axis-live

jessexknight commented 4 years ago

Okay. Here is another hack that will probably solve all dynamic LaTeX rendering issues but you have to decide the refresh rate (trading speed vs CPU).

After including MathJax like above:

app = dash.Dash(__name__, external_scripts=[
  'https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.4/MathJax.js?config=TeX-MML-AM_CHTML',
])

add the file ./assets/mathjax-refresh.js with the following content:

setInterval("MathJax.Hub.Queue(['Typeset',MathJax.Hub])",1000);

This asks MathJax to scan the page for any new $...$ every 1000 milliseconds, and re-render it. It solved all my MWE here without any extra modification of the Python code. You may want to increase the refresh rate by decreasing 1000. I tried 1 and it was very fast, but used CPU 5% ¯\_(ツ)_/¯.

more info:

renatobellotti commented 4 years ago

That workaround seems to work, thank you so much!

Just one thing is a bit suboptimal, but that's a luxury problem. When I set the axis label to something like $\sigma_x$ [mm], only the sigma_x part is rendered, and the units are omitted.

Workaround:

Use $\sigma_x \mathrm{[mm]}$ instead.

jessexknight commented 4 years ago

Ugh. It seems the mathjax-refresh hack somehow interferes with the dynamic axis labelling, making it very slow. Apologies that I didn't test this enough before.

@renatobellotti I wouldn't call that a luxury problem. Mixing TeX and non-TeX might be quite common, and we shouldn't have to wrap all non-TeX in \textrm{...}.

Sometime in the past year it seems TeX support was added to axis labels, but I can't find any commit that references this. Essentially I'd like to turn that off, since I'd prefer the refresh hack.

EDIT: It seems our problems might be upstream at: plotly.js

Davide-sd commented 3 years ago

@jessexknight , thank you for your solution, it works nice if there is a Graph output!

However, when there is no Graph output (but the app has some other outputs), then it seems MathJax is not loaded and the latex code in other controls is not rendered. Is there a quick workaround?

jessexknight commented 3 years ago

I don't have time to look into this right now but this may be useful, or perhaps any one of the the MathJax issues upstream at plotly.js

nicolaskruchten commented 3 years ago

To get standard Plotly.s LaTeX support in figure titles and axis labels, it looks like doing the Dash equivalent of what's in the Plotly.js readme does work:

  1. add external_scripts=["https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/MathJax.js?config=TeX-MML-AM_CHTML" ] to the app = dash.Dash() call
  2. ~add a JS file to assets containing window.PlotlyConfig = {MathJaxConfig: 'local'};~

edit: hmmm it doesn't seem like point 2 here is actually needed.

nicolaskruchten commented 3 years ago

When I set the axis label to something like $\sigma_x$ [mm], only the sigma_x part is rendered, and the units are omitted.

This is sort of a known feature of how Plotly.js works at the moment: labels in figures are either all-LaTex or all-not-LaTeX.

haduong83 commented 3 years ago

Hi,

I tried to add the configuration into my app:

mathJaxSxrip = ["https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/MathJax.js?config=TeX-MML-AM_CHTML" ]
server = Flask(__name__, instance_relative_config=False)
app = dash.Dash(server=server, external_scripts=mathJaxSxrip, external_stylesheets = [dbc.themes.BOOTSTRAP])
app.config.suppress_callback_exceptions = True
app.scripts.config.serve_locally = False

and render the following equation:

html.Div(children="Render formular \(\lim_{t \\rightarrow \infty} \pi = 0\)
$$\lim_{t \\rightarrow \infty} \pi = 0$$")

but it is not working. I am using the following dash version:

dash==1.19.0 dash-bootstrap-components==0.11.3 dash-core-components==1.15.0 dash-html-components==1.1.2 dash-renderer==1.9.0

I also tried the code @jessexknight posted in https://community.plotly.com/t/mathjax-latex-in-dash/6653/11 but it did not work either.

Any ideas on what could be wrong?

Thanks,

wvwhome commented 2 years ago

October 2021: MathJax and Plotly have mystery. I got this to work by adding an 'assets' folder as further posted by jessexknight. The bigger question is whether/when Plotly will provide official support for Latex/MathJax in general.

March 14, 2022: Dash 2.3.0 supports Mathjax 3 ... use it. Mystery solved for me. Thanks Plotly and Equinor.

nopria commented 2 years ago

Have you looked into this? https://chrisvoncsefalvay.com/2020/07/25/dash-latex/

chrisvoncsefalvay commented 2 years ago

Hey @haduong83, I think you're not invoking the script properly. Try checking here and take a look at the heading "Integrating MathJax into the template".

archmoj commented 2 years ago

Resolved by v2.3.0.