Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

latex support #242

Closed
Cyberfly100 opened this issue Apr 9, 2018 · 27 comments
Closed

latex support #242

Cyberfly100 opened this issue Apr 9, 2018 · 27 comments

Comments

@Cyberfly100
Copy link

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

@chriddyp
Copy link
Member

chriddyp commented Apr 9, 2018

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
Copy link

jessexknight commented May 24, 2018

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
Copy link

aztan2 commented Aug 22, 2018

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
Copy link

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

@xhluca
Copy link

xhluca commented Nov 2, 2018

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
Copy link

vdkotian commented Jan 4, 2019

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

@renatobellotti
Copy link

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

@renatobellotti
Copy link

What about now?

@yueyericardo
Copy link

yueyericardo commented Mar 20, 2020

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
Copy link

Does this also work for axis labels?

@jessexknight
Copy link

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

  • load mathjax as suggested above
  • define and include javascript function to re-render some element by mathjax: examples
  • add a clientside callback in plotly to trigger the js function to re-render

@yueyericardo
Copy link

yueyericardo commented Apr 12, 2020

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
Copy link

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
Copy link

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
Copy link

jessexknight commented Apr 16, 2020

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
Copy link

jessexknight commented Apr 16, 2020

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
Copy link

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
Copy link

jessexknight commented Apr 21, 2020

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
Copy link

@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
Copy link

jessexknight commented Oct 26, 2020

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
Copy link
Contributor

nicolaskruchten commented Feb 9, 2021

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
Copy link
Contributor

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
Copy link

haduong83 commented Sep 22, 2021

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
Copy link

wvwhome commented Oct 19, 2021

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
Copy link

nopria commented Oct 30, 2021

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

@chrisvoncsefalvay
Copy link

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
Copy link
Contributor

archmoj commented Mar 17, 2022

Resolved by v2.3.0.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests