Plots + PlotlyJS + LaTeX

I love PlotlyJS interactivity mainly in Jupyter notebook or VS Code Plot pane, on the other hand, I had always problems with latex in labels.

Recently, I noticed that in one of my julia environment (Julia 1.3.1, jupyter 2.0.0, plotly extension) the LaTeX rendering in Jupyter notebook just works

using Plots, LaTeXStrings

font = Plots.font("arial", 12)

plotlyjs(guidefont=font, xtickfont=font, 
   ytickfont=font, legendfont=font, lw = 2, size=(600,400));

p = plot(rand(10))
p = xlabel!("\$\\alpha \\, F_\\mathrm{test}\$")
p = ylabel!(L"\Gamma^2")

plot(p)

Unknown

but

savefig("test.pdf")

gave errors IOError(Base.IOError("connect: connection refused (ECONNREFUSED)", -111) during request(http://localhost:7982)) and empty file.

I can save it only as an HTML, but in the web browser, the LaTeX formulas were not rendered. The same ouput I got in VS Code plot pane.

I followed the plotly.js readme and now I have plotly figure with correct LaTeX rendering.

Original HTML HEAD was

<head>
        <title>Plots.jl</title>
        <meta http-equiv="content-type" content="text/html; charset=UTF-8">
        <script src="https://cdn.plot.ly/plotly-latest.min.js"></script>
</head>

Unknown-2

The new HTML HEAD is

 <head>
         <title>Plots.jl</title>
         <meta http-equiv="content-type" content="text/html; charset=UTF-8">
         <script src="mathjax/MathJax.js?config=TeX-AMS-MML_SVG"></script>
         <script>
            window.PlotlyConfig = {MathJaxConfig: 'local'}
         </script>
         <script src="plotly.js"></script>
</head>

Here, I downloaded plotly.js GitHub - plotly/plotly.js: Open-source JavaScript charting library behind Plotly and Dash

Any chance to get it to work out of the box?

4 Likes

Best to open an issue at https://github.com/JuliaPlots/Plots.jl

https://wiki.archlinux.org/index.php/MathJax

If you are using plotly.js as well, loading MathJax before Plotly might fail to render TeX code. Loading Plotly before MathJax should work.

Auto generated HTML doc by Weave and Jupyter puts mathjax before plotly in the header. So you may work around by editing the doc manually but It would be great if users can control the ordering programatically.

According to plotly.js/README.md at master · plotly/plotly.js · GitHub it should be as it in my example above. The html with edited head section works fine.

Today, I found here in Plots docs that

Plotly needs to load mathjax to render LaTeX strings, therefore passing extra keywords with extra_kwargs = :plot is implemented. With that it is possible to pass a header to the extra include_mathjax keyword. It has the following options:

However, the example they provided does not work for me.

using Plots, LaTeXStrings
plotly()
plot(1:4, [[1,4,9,16]*10000, [0.5, 2, 4.5, 8]],
           labels = [L"\alpha_{1c} = 352 \pm 11 \text{ km s}^{-1}";
                     L"\beta_{1c} = 25 \pm 11 \text{ km s}^{-1}"] |> permutedims,
           xlabel = L"\sqrt{(n_\text{c}(t|{T_\text{early}}))}",
           ylabel = L"d, r \text{ (solar radius)}",
           yformatter = :plain,
           extra_plot_kwargs = KW(
               :include_mathjax => "cdn",
               :yaxis => KW(:automargin => true),
               :xaxis => KW(:domain => "auto")
               ),
       )

I have this error:

ERROR: Unknown key: extra_plot_kwargs
Stacktrace:
[1] default(::Symbol) at /Users/oto/.julia/packages/Plots/WwFyB/src/args.jl:632
[2] warnOnUnsupported_args(::Plots.PlotlyBackend, ::Dict{Symbol,Any}) at /Users/oto/.julia/packages/Plots/WwFyB/src/args.jl:1160
[3] _add_the_series(::Plots.Plot{Plots.PlotlyBackend}, ::Plots.Subplot{Plots.PlotlyBackend}, ::Dict{Symbol,Any}) at /Users/oto/.julia/packages/Plots/WwFyB/src/pipeline.jl:376
[4] _process_seriesrecipe(::Plots.Plot{Plots.PlotlyBackend}, ::Dict{Symbol,Any}) at /Users/oto/.julia/packages/Plots/WwFyB/src/pipeline.jl:404
[5] _plot!(::Plots.Plot{Plots.PlotlyBackend}, ::Dict{Symbol,Any}, ::Tuple{UnitRange{Int64},Array{Array{Float64,1},1}}) at /Users/oto/.julia/packages/Plots/WwFyB/src/plot.jl:234
[6] #plot#137(::Base.Iterators.Pairs{Symbol,Any,NTuple{5,Symbol},NamedTuple{(:labels, :xlabel, :ylabel, :yformatter, :extra_plot_kwargs),Tuple{Array{LaTeXString,2},LaTeXString,LaTeXString,Symbol,Dict{Symbol,Any}}}}, ::typeof(plot), ::UnitRange{Int64}, ::Vararg{Any,N} where N) at /Users/oto/.julia/packages/Plots/WwFyB/src/plot.jl:57
[7] (::RecipesBase.var"#kw##plot")(::NamedTuple{(:labels, :xlabel, :ylabel, :yformatter, :extra_plot_kwargs),Tuple{Array{LaTeXString,2},LaTeXString,LaTeXString,Symbol,Dict{Symbol,Any}}}, ::typeof(plot), ::UnitRange{Int64}, ::Array{Array{Float64,1},1}) at ./none:0
[8] top-level scope at REPL[3]:1

You are probably on an older version of Plots

1 Like

I see, you are right one package downgraded my Plots package.
Unfortunately, I have latex rendered only when saved as html.
In vs code plot pane and in PDF the latex is not correct.

For me it is similiar. In the html everything works, but if I save savefig(p1, <file_path>) i.e. as a pdf it isn´t working

PlotlyJS supports latex string via Mathjax, but only in html format. (Latex in Julia)
Is there any way how to convert html figure to pdf/eps?

1 Like

For me, even the original code does not work (disabled plot pane):
image

Guess, MathJax must be enabled for the standalone windows somehow.

You need to save it as HTML…

@JanKap @Oto_Brzobohaty
Well, I try to, but it does not works, here my codes:

using Plots, LaTeXStrings, Plots.PlotMeasures, MathJaxRenderer 
plotlyjs()

x = collect(-5:0.5:5)
y = collect(-5:0.5:5)

z(x, y) = x^2 - 3*y + 2

l = L"$x^2 - 3y + 2$"

plot(x, y, z, st = :surface, camera = (10, 10))
title!(l)

ylabel!(L"\Gamma^2")

savefig("test.html")

https://docs.juliaplots.org/stable/backends/#LaTeX-workflow

MathJax

Plotly needs to load MathJax to render LaTeX strings, therefore passing extra keywords with extra_kwargs = :plot is implemented. With that it is possible to pass a header to the extra include_mathjax keyword. It has the following options:

  • include_mathjax = "" (default): no mathjax header
  • include_mathjax = "cdn" include the standard online version of the header
  • include_mathjax = "<filename?config=xyz>" include a user-defined file

These can also be passed using the extra_plot_kwargs keyword.

using LaTeXStrings
plotlyjs()
plot(1:4, [[1,4,9,16]*10000, [0.5, 2, 4.5, 8]],
           labels = [L"\alpha_{1c} = 352 \pm 11 \text{ km s}^{-1}";
                     L"\beta_{1c} = 25 \pm 11 \text{ km s}^{-1}"] |> permutedims,
           xlabel = L"\sqrt{(n_\text{c}(t|{T_\text{early}}))}",
           ylabel = L"d, r \text{ (solar radius)}",
           yformatter = :plain,
           extra_plot_kwargs = KW(
               :include_mathjax => "cdn",
               :yaxis => KW(:automargin => true),
               :xaxis => KW(:domain => "auto")
               ),
       )
1 Like

I try your code, it works if I use "cdn", but not if only using ""

using LaTeXStrings, Plots
plotlyjs()


plot(1:4, [[1,4,9,16]*10000, [0.5, 2, 4.5, 8]],
           labels = [L"\alpha_{1c} = 352 \pm 11 \text{ km s}^{-1}";
                     L"\beta_{1c} = 25 \pm 11 \text{ km s}^{-1}"] |> permutedims,
           xlabel = L"\sqrt{(n_\text{c}(t|{T_\text{early}}))}",
           ylabel = L"d, r \text{ (solar radius)}",
           yformatter = :plain,
           extra_plot_kwargs = KW(
               :include_mathjax => "cdn",
               :yaxis => KW(:automargin => true),
               :xaxis => KW(:domain => "auto")
               ),
       )
savefig("test.html")

Thanks a Lot!

In the current version of PlotlyJS, which is v0.18.8, it is under OS WIN10 not necessary to specify the value of include_mathjaxt, it works fine out of the box for html-output.
What currently not yet work is, the propper output in another vector format.