Plotly LaTeX fonts different in Jupyter and exported PDF or PNG
Asked Answered
S

1

8

I'm trying to create PDFs of plots that I have done with plotly in jupyter lab, but I'm having a lot of trouble with the fonts. Plotly is using the correct font for all the normal text in the browser, but all labels that are LaTeX code use a different font. This is to be expected, because plotly uses MathJax for rendering and apparently it's configured to use STIX. I could live with that and change the non-LaTeX font to STIX if it was consistent with exported graphics. The thing that really bothers me is that LaTeX labels use yet another font, when I export the plot as PDF. For some reason MathJax then defaults to MathJax_Main. And for the sake of complete confusion if exported as PNG or PDF the normal font defaults Liberation Serif.

So, here's some example code to create a plot. I'm running this on Debian 11 and python 3.9. I can add the full requirements.txt if that's of any use.

import plotly.graph_objects as go
from plotly.express.colors import qualitative

layout = go.Layout(
    font=dict(
        family='Latin Modern Math',
        color='black',
        size=20,
    ),
    colorway=qualitative.D3,
    width=600,
    height=320,
    margin=dict(l=10,r=10,t=10,b=10),
    paper_bgcolor='rgba(255,255,255,1)',
    plot_bgcolor='rgba(0,0,0,0)',
    xaxis=dict(
        showline=True,
        linecolor='black',
        ticks='inside',
        exponentformat='e',
        mirror='ticks',
    ),
    yaxis=dict(
        showline=True,
        linecolor='black',
        ticks='inside',
        exponentformat='e',
        mirror='ticks',
    ),
    legend=dict(
        xanchor="left",
        yanchor="bottom",
        x=0.1,
        y=1.01,
    ),
)

fig = go.Figure(layout=layout)

X = np.linspace(0, 2 * np.pi, 100)
Y1 = np.sin(X)
Y2 = np.cos(X)
fig.add_trace(go.Scatter(x=X, y=Y1, name=r'$\text{The quick brown fox jumps over the lazy dog}$'))
fig.add_trace(go.Scatter(x=X, y=Y2, name='The quick brown fox jumps over the lazy dog'))
fig.show()

Browser Output

LaTeX: STIX
Normal: Latin Modern Math

Browser output

PDF Export

LaTeX: MathJax_Main
Normal: Liberation Serif

PDF Export

PNG Export

LaTeX: MathJax_Main
Normal: Liberation Serif

PNG Export

I guess the root of the problem is that whatever does the export in the background (Kaleido, maybe) and/or MathJax either don't find the right fonts or use a different config. But I have no clue where that config is or how it should look like.

Edit 1

I looked into the source code of plotly and kaleido. It looks like kaleido ships with its own mathjax, so this might be the problem. If I understand correctly, plotly hands the figure over to Kaleido (https://github.com/plotly/plotly.py/blob/24cda54b22b7c541a30fd6a080e4ccf5a0684106/packages/python/plotly/plotly/io/_kaleido.py#L145), which implements a PlotlyScope. Kaleido then calls _perform_transform (https://github.com/plotly/Kaleido/blob/6a46ecae926b4c004bf7232383cf7c74c70748fd/repos/kaleido/py/kaleido/scopes/plotly.py#L153), which creates a JSON dump and pipes that to some subprocess, which returns the final image. You can see that PlotlyScope has a member mathjax which in my case points to $HOME/venvs/jupyter/lib/python3.9/site-packages/kaleido/executable/etc/mathjax/MathJax.js. At no point in this chain I can see that any font specification is altered. So I assume that the subprocess (that Kaleido is running) receives the correct font specification, but then defaults to whatever, because it can't find the fonts. Unfortunately, no errors are printed, when that happens.

Seaquake answered 28/6, 2021 at 12:4 Comment(4)
JupyterLab uses nbconvert to convert notebooks under the hood, you may want to search among open issues at github.com/jupyter/nbconvert or possibly open one.Flatting
Did you find any work around? I have the same problem.Capriccioso
On the same ship here, your investigation is great and I really want to know how to work around this issueIntertwist
Unfortunately, I couldn't find a solution and I've resorted to using matplotlib for publications.Seaquake
P
3

I know this is a 2 year old post but to anyone whom may concern. I was also having the same problem and your analysis was pretty good. I created a fork of kaleido that at least on my laptop fixed the problem.

There is this open issue at the moment about the same problem which mentions your post here. I have posted my detailed solution there if anyone is interested. The link is https://github.com/plotly/plotly.py/issues/3828#issuecomment-1798544806.

As mentioned there I will probably create a pull request soon but it would be good if other people tested it as well.

Parma answered 7/11, 2023 at 13:51 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.