plotly / plotly.py

The interactive graphing library for Python :sparkles: This project now includes Plotly Express!
https://plotly.com/python/
MIT License
16.38k stars 2.56k forks source link

Figure does not display LaTeX title #1740

Open sursu opened 5 years ago

sursu commented 5 years ago

There is an issue with rendering LaTeX titles in JupyterLab:

fig = go.Figure()
fig.add_scatter(y=[1,3,2], mode='lines+markers')
fig.layout.update(title='$\\text{Negative Log of Estimated Survivor Function}$', 
                  xaxis_title='$t$', yaxis_title='$-log(S(t))$',
                  height=600)
fig.show()

Does not actually display the titles: newplot (1)

And this is strange as earlier today it did work fine.

I have encountered other anomalies in JupyterLab, such as after restarting the session, one image elongates and stays like that. Does not happen every time though.

Details
Plotly version: 4.0.0 Ubuntu 18.04.2

Here it is: Peek 2019-08-28 01-24

Sometimes it elongates and stays like that:

cut


UPDATE 1:

I've just updated to 4.1.0 and now the LaTeX titles are displayed. But, the mentioned anomaly is still there.


UPDATE 2:

I have opened the notebook today again and the title disappears.

If it is of any help. here is what is displayed in the terminal: image

cnydw commented 5 years ago

Related to outstanding issues in https://github.com/plotly/plotly.py/pull/1243#issue-225577662

The only outstanding issue is that unlike the classic notebook, JupyterLab doesn't seem to load the global MathJax instance until it is needed by the markdown renderer.

and https://github.com/jupyter-widgets/ipywidgets/issues/2253

LunarLanding commented 3 years ago

Same here: MVE:

Render markdown with latex (works), then:

import plotly.graph_objects as go
fig = go.Figure(
    data=go.Bar(y=[2,3,1]),
    layout={'title':'$a_b$'}
)
fig.show(config={'responsive':True});

Shows (notice no title): image

Plotly: 4.14.3 JupyteLab: 3.0.12

LunarLanding commented 3 years ago

I would like to solve this; any kind of initial help regarding at which code to look would be helpful. I briefly inspected the console and found MathJax in the window object. It does not seem related to #1243 or jupyter-widgets/ipywidgets#2253 since rendering markdown / loading ipywidgets and rendering latex before trying to render latex title in plotly does not solve the issue.

empet commented 3 years ago

@LunarLanding title is a dict:

import plotly.graph_objects as go
fig = go.Figure(
    data=go.Bar(y=[2,3,1]),
    layout={'title': {'text': '$a_b$', 
                      'x':0.5}})
fig.show(config={'responsive':True});

or you can avoid using dicts, as follows:

fig = go.Figure(go.Bar(y=[2,3,1]))
fig.update_layout(title_text='$a_b$', title_x=0.5)
fig.show(config={'responsive':True});
LunarLanding commented 3 years ago

@LunarLanding title is a dict:

import plotly.graph_objects as go
fig = go.Figure(
    data=go.Bar(y=[2,3,1]),
    layout={'title': {'text': '$a_b$', 
                      'x':0.5}})
fig.show(config={'responsive':True});

or you can avoid using dicts, as follows:

fig = go.Figure(go.Bar(y=[2,3,1]))
fig.update_layout(title_text='$a_b$', title_x=0.5)
fig.show(config={'responsive':True});

Latex with a dict does not work:

import plotly.graph_objects as go
fig = go.Figure(
    data=go.Bar(y=[2,3,1]),
    layout={'title': {'text':'$a_b$','x':.5}})
fig.show(config={'responsive':True});

image

Without latex, using title directly works, without latex (not the issue being discussed):

import plotly.graph_objects as go
fig = go.Figure(
    data=go.Bar(y=[2,3,1]),
    layout={'title': 'a'})
fig.show(config={'responsive':True});

image

empet commented 3 years ago

I read only your post and did not notice that you are working with jupyterlab. I checked it in Jupyter Notebook: title

LunarLanding commented 3 years ago

Thanks. This issue is specific to JupyterLab then; which is also what the original poster reported.

nicolaskruchten commented 3 years ago

I can replicate the JupyterLab problem on my end also. The issue is likely to be within the interaction between the way jupyterlab_plotly extension renders Plotly.js figures within JupyterLab, and these problems tend to be pretty hard to debug but if you want to give it a shot, the source for the extension is here: https://github.com/plotly/plotly.py/tree/master/packages/javascript/jupyterlab-plotly

nicolaskruchten commented 3 years ago

I'll add that the LaTeX information is not lost: rendering the same figure in a Dash app or in another context than JLab works (e.g. exporting a notebook to HTML), and in a pinch you can render it in JLab if you have Kaleido installed with fig.show("svg") (without interactivity, unfortunately)

LunarLanding commented 3 years ago

I think the issue is that Mathjax is not by default present in the global namespace anymore, the same as in https://github.com/jupyter-widgets/ipywidgets/issues/2253 which one extension worked around like this https://github.com/vidartf/phoila/commit/2b7ddf023ffdb4e2d77f18d32883734b6fd995b9 .

If I run this before running the plotly cell, latex is rendered correctly.

from IPython.display import display,HTML
display(HTML("""
<script type="text/javascript" async
  src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.7/MathJax.js?config=config=TeX-AMS-MML_SVG">
</script>
"""))

Having it render without a kernel/rerunning cells is WIP, this error shows up on the browser console and on the output cell there's a text only FigureWidget=(...

Resize must be passed a displayed plot div element.

If instead of a FigureWidget I use a Figure, the figure renders on opening with jupyterlab.

If I reload the page, MathJax dissapears from the global namespace and latex is not rendered.

At this point, the workaround above + using only go.Figure and not FigureWidgets gets almost to right place. I need to run in a different notebook the javascript that loads MathJax ( or via a user script in my browser), and then latex will load correctly. I did it via GreaseMonkey:

// ==UserScript==
// @name     jupyterlab_mathjax
// @version  1
// @grant    none
// @match http://localhost/
// ==/UserScript==
(function(d){
script = d.createElement('script');
script.type = 'text/javascript';
script.async = true;
script.onload = function(){
  // remote script has loaded
};
script.src = 'https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.7/MathJax.js?config=TeX-MML-AM_CHTML';
d.getElementsByTagName('head')[0].appendChild(script);
}(document));

Additionally, regarding size of the notebook, FigureWidget packs 3.6MB for ploty.js, while Figure refers to the jupyterlab extension. If I specify pio.renderers.default = 'jupyterlab', it's small again (83kB).

If I export the notebook to html, FigureWidget renders properly, Figure does not: only the static preview is shown, while FigureWidget updates to the dynamic javascript. This with the 'jupyterlab' renderer. 'iframe_connected' does not survive page reloads.

Dealing with rather simple Latex I found a dependency on browser https://github.com/plotly/plotly.js/issues/5374#issuecomment-945868017 ."Why do you use Edge? Plotly edge-case".

This was on: Firefox 93.0, Jupyterlab 3.2.0, plotly 5.3.1, python 3.9.7.

biopython                 1.79             py39h3811e60_0    conda-forge
bokeh                     2.4.1            py39hf3d152e_1    conda-forge
ipython                   7.28.0           py39hef51801_0    conda-forge
ipython_genutils          0.2.0                      py_1    conda-forge
ipywidgets                7.6.5              pyhd8ed1ab_0    conda-forge
jupyter-server-proxy      3.1.0              pyhd8ed1ab_0    conda-forge
jupyter_bokeh             3.0.2              pyhd8ed1ab_0    conda-forge
jupyter_client            7.0.3              pyhd8ed1ab_0    conda-forge
jupyter_core              4.8.1            py39hf3d152e_0    conda-forge
jupyter_server            1.11.0             pyhd8ed1ab_0    conda-forge
jupyterlab                3.2.0              pyhd8ed1ab_0    conda-forge
jupyterlab-mathjax3       4.2.2              pyhd8ed1ab_0    conda-forge
jupyterlab_execute_time   2.1.0              pyhd8ed1ab_0    conda-forge
jupyterlab_pygments       0.1.2              pyh9f0ad1d_0    conda-forge
jupyterlab_server         2.8.1              pyhd8ed1ab_0    conda-forge
jupyterlab_widgets        1.0.2              pyhd8ed1ab_0    conda-forge
mmtf-python               1.1.2                      py_0    conda-forge
msgpack-python            1.0.2            py39h1a9c180_1    conda-forge
panel                     0.12.4             pyhd8ed1ab_0    conda-forge
plotly                    5.3.1              pyhd8ed1ab_0    conda-forge
python                    3.9.7           hb7a2778_3_cpython    conda-forge
python-dateutil           2.8.2              pyhd8ed1ab_0    conda-forge
python-graphviz           0.17               pyhaef67bd_0    conda-forge
python-kaleido            0.2.1              pyhd8ed1ab_0    conda-forge
python-libarchive-c       3.1              py39hf3d152e_0    conda-forge
python-lmdb               0.99             py39he80948d_0    conda-forge
python-slugify            5.0.2              pyhd8ed1ab_0    conda-forge
python-utils              2.5.6              pyh44b312d_0    conda-forge
python_abi                3.9                      2_cp39    conda-forge
QuantumAudio commented 2 years ago

I found a solution that worked for me in the help documentation, changing the default renderer. I had the issue on multiple browsers. (https://plotly.com/python/renderers/)

  1. The jupyterlab-plotly extension must be installed in the current environment. For conda, this is conda install -c conda-forge jupyterlab-plotly-extension.

  2. Check the available renderers and ensure jupyterlab is available. import plotly.io as pio pio.renderers

Renderers configuration

Default renderer: 'jupyterlab'
Available renderers:
    ['plotly_mimetype', 'jupyterlab', 'nteract', 'vscode',
     'notebook', 'notebook_connected', 'kaggle', 'azure', 'colab',
     'cocalc', 'databricks', 'json', 'png', 'jpeg', 'jpg', 'svg',
     'pdf', 'browser', 'firefox', 'chrome', 'chromium', 'iframe',
     'iframe_connected', 'sphinx_gallery', 'sphinx_gallery_png']
  1. Set the default renderer to jupyterlab. pio.renderers.default = 'jupyterlab'