Missing Plots.pyrcparams in Plots version 1.37.2

Hey all,
in previous version of the Plots.jl package it was possible to configure the pyplot() backend using
the Plots.pyrcparams. With this, one could use LaTex for the axis labels etc and also had full control over the Font etc. Example:

Plots.pyrcparams["text.usetex"] = true
Plots.pyrcparams["font.family"] = "serif"
Plots.pyrcparams["text.latex.preamble"] = [s"\usepackage{dsfont}", s"\usepackge{lmodern}"];

With the newest version v1.37.2 this is not possible anymore. It also seems to have the pyplot() backend deprecated. Sadly, I don’t know wich is the last version supporting the pyrcparams. I guess this was dropped after switching to usage of the Reference package for selecting the backend.

Is there any way to have the same flexibility in the newest version?

Hi,
This was not part of the API before, however, it shouldn’t be too difficult to find an alternative:

julia> using Plots; pythonplot()
julia> mpl = Plots.PythonCall.pyimport("matplotlib")
julia> mpl.rcParams["text.usetex"] = true
julia> mpl.rc("lines", linewidth=4, linestyle="-.")
# etc ...

Again, this is not a promise that Plots.PythonCall will be exposed to users in future Plots versions (currently only a convenience for the backend code), so you might want to use Plots.PythonPlot.PythonCall instead.

Mhm ok. It seems to do the job, for the most parts. It actually fails for setting some custom preamble with some LaTeX error. Thanks!

Also, please note that the pyplot backend is still available.

Using Plots.PyPlot.PyCall.pyimport("matplotlib") should also work, but it is advised to use pythonplot instead, as no more bug fixes will occur for pyplot.

What preamble error ?

Yes this is what I meant by pyplot is deprecated.

The error occurs after

Plots.pyrcparams["text.latex.preamble"] = [s"\usepackage{dsfont}", s"\usepackge{lmodern}"];

and reads:

Error showing value of type Plots.Plot{Plots.PythonPlotBackend}:
ERROR: Python: RuntimeError: latex was not able to process the following string:
b'lp'

Here is the full report generated by latex:
This is pdfTeX, Version 3.141592653-2.6-1.40.22 (TeX Live 2022/dev/Debian) (preloaded format=latex)
 restricted \write18 enabled.
entering extended mode
(../930e435536a8e60c1bb6f4789d98300e.tex
LaTeX2e <2021-11-15> patch level 1
L3 programming layer <2022-01-21>
(/usr/share/texlive/texmf-dist/tex/latex/base/article.cls
Document Class: article 2021/10/04 v1.4n Standard LaTeX document class
(/usr/share/texlive/texmf-dist/tex/latex/base/size10.clo))
(/usr/share/texlive/texmf-dist/tex/latex/type1cm/type1cm.sty)
(/usr/share/texmf/tex/latex/cm-super/type1ec.sty
(/usr/share/texlive/texmf-dist/tex/latex/base/t1cmr.fd))
(/usr/share/texlive/texmf-dist/tex/latex/base/inputenc.sty)
(/usr/share/texlive/texmf-dist/tex/latex/geometry/geometry.sty
(/usr/share/texlive/texmf-dist/tex/latex/graphics/keyval.sty)
(/usr/share/texlive/texmf-dist/tex/generic/iftex/ifvtex.sty
(/usr/share/texlive/texmf-dist/tex/generic/iftex/iftex.sty)))

! LaTeX Error: Missing \begin{document}.

See the LaTeX manual or LaTeX Companion for explanation.
Type  H <return>  for immediate help.
 ...                                              
                                                  
l.9 A
     ny[]
No pages of output.
Transcript written on 930e435536a8e60c1bb6f4789d98300e.log.

which is only the LaTeX part. The part of the error related to Julia is given by:

Python stacktrace:
 [1] _run_checked_subprocess
   @ matplotlib.texmanager ~/.julia/environments/v1.8/.CondaPkg/env/lib/python3.10/site-packages/matplotlib/texmanager.py:241
 [2] make_dvi
   @ matplotlib.texmanager ~/.julia/environments/v1.8/.CondaPkg/env/lib/python3.10/site-packages/matplotlib/texmanager.py:271
 [3] get_text_width_height_descent
   @ matplotlib.texmanager ~/.julia/environments/v1.8/.CondaPkg/env/lib/python3.10/site-packages/matplotlib/texmanager.py:335
 [4] get_text_width_height_descent
   @ matplotlib.backends.backend_agg ~/.julia/environments/v1.8/.CondaPkg/env/lib/python3.10/site-packages/matplotlib/backends/backend_agg.py:259
 [5] _get_layout
   @ matplotlib.text ~/.julia/environments/v1.8/.CondaPkg/env/lib/python3.10/site-packages/matplotlib/text.py:309
 [6] get_window_extent
   @ matplotlib.text ~/.julia/environments/v1.8/.CondaPkg/env/lib/python3.10/site-packages/matplotlib/text.py:910
 [7] <listcomp>
   @ matplotlib.axis ~/.julia/environments/v1.8/.CondaPkg/env/lib/python3.10/site-packages/matplotlib/axis.py:1085
 [8] _get_tick_bboxes
   @ matplotlib.axis ~/.julia/environments/v1.8/.CondaPkg/env/lib/python3.10/site-packages/matplotlib/axis.py:1085
 [9] draw
   @ matplotlib.axis ~/.julia/environments/v1.8/.CondaPkg/env/lib/python3.10/site-packages/matplotlib/axis.py:1159
 [10] draw_wrapper
   @ matplotlib.artist ~/.julia/environments/v1.8/.CondaPkg/env/lib/python3.10/site-packages/matplotlib/artist.py:50
 [11] _draw_list_compositing_images
   @ matplotlib.image ~/.julia/environments/v1.8/.CondaPkg/env/lib/python3.10/site-packages/matplotlib/image.py:132
 [12] draw
   @ matplotlib.axes._base ~/.julia/environments/v1.8/.CondaPkg/env/lib/python3.10/site-packages/matplotlib/axes/_base.py:3091
 [13] draw_wrapper
   @ matplotlib.artist ~/.julia/environments/v1.8/.CondaPkg/env/lib/python3.10/site-packages/matplotlib/artist.py:50
 [14] _draw_list_compositing_images
   @ matplotlib.image ~/.julia/environments/v1.8/.CondaPkg/env/lib/python3.10/site-packages/matplotlib/image.py:132
 [15] draw
   @ matplotlib.figure ~/.julia/environments/v1.8/.CondaPkg/env/lib/python3.10/site-packages/matplotlib/figure.py:2837
 [16] draw_wrapper
   @ matplotlib.artist ~/.julia/environments/v1.8/.CondaPkg/env/lib/python3.10/site-packages/matplotlib/artist.py:50
 [17] draw_wrapper
   @ matplotlib.artist ~/.julia/environments/v1.8/.CondaPkg/env/lib/python3.10/site-packages/matplotlib/artist.py:73
Stacktrace:
  [1] pythrow()
    @ PythonCall ~/.julia/packages/PythonCall/3GRYN/src/err.jl:94
  [2] errcheck
    @ ~/.julia/packages/PythonCall/3GRYN/src/err.jl:10 [inlined]
  [3] pycallargs(f::PythonCall.Py, args::PythonCall.Py)
    @ PythonCall ~/.julia/packages/PythonCall/3GRYN/src/abstract/object.jl:210
  [4] pycall(f::PythonCall.Py, args::PythonCall.Py; kwargs::Base.Pairs{Symbol, Union{}, Tuple{}, NamedTuple{(), Tuple{}}})
    @ PythonCall ~/.julia/packages/PythonCall/3GRYN/src/abstract/object.jl:228
  [5] pycall
    @ ~/.julia/packages/PythonCall/3GRYN/src/abstract/object.jl:218 [inlined]
  [6] #_#11
    @ ~/.julia/packages/PythonCall/3GRYN/src/Py.jl:352 [inlined]
  [7] Py
    @ ~/.julia/packages/PythonCall/3GRYN/src/Py.jl:352 [inlined]
  [8] _py_drawfig(fig::PythonPlot.Figure)
    @ Plots ~/.julia/packages/Plots/Hxe7H/src/backends/pythonplot.jl:204
  [9] _before_layout_calcs(plt::Plots.Plot{Plots.PythonPlotBackend})
    @ Plots ~/.julia/packages/Plots/Hxe7H/src/backends/pythonplot.jl:1229
 [10] prepare_output(plt::Plots.Plot{Plots.PythonPlotBackend})
    @ Plots ~/.julia/packages/Plots/Hxe7H/src/plot.jl:232
 [11] display(#unused#::Plots.PlotsDisplay, plt::Plots.Plot{Plots.PythonPlotBackend})
    @ Plots ~/.julia/packages/Plots/Hxe7H/src/output.jl:173
 [12] display(x::Any)
    @ Base.Multimedia ./multimedia.jl:328
 [13] #invokelatest#2
    @ ./essentials.jl:729 [inlined]
 [14] invokelatest
    @ ./essentials.jl:726 [inlined]
 [15] print_response(errio::IO, response::Any, show_value::Bool, have_color::Bool, specialdisplay::Union{Nothing, AbstractDisplay})
    @ REPL ~/julia_versions/julia-1.8.2/share/julia/stdlib/v1.8/REPL/src/REPL.jl:296
 [16] (::REPL.var"#45#46"{REPL.LineEditREPL, Pair{Any, Bool}, Bool, Bool})(io::Any)
    @ REPL ~/julia_versions/julia-1.8.2/share/julia/stdlib/v1.8/REPL/src/REPL.jl:278
 [17] with_repl_linfo(f::Any, repl::REPL.LineEditREPL)
    @ REPL ~/julia_versions/julia-1.8.2/share/julia/stdlib/v1.8/REPL/src/REPL.jl:521
 [18] print_response(repl::REPL.AbstractREPL, response::Any, show_value::Bool, have_color::Bool)
    @ REPL ~/julia_versions/julia-1.8.2/share/julia/stdlib/v1.8/REPL/src/REPL.jl:276
 [19] (::REPL.var"#do_respond#66"{Bool, Bool, REPL.var"#77#87"{REPL.LineEditREPL, REPL.REPLHistoryProvider}, REPL.LineEditREPL, REPL.LineEdit.Prompt})(s::REPL.LineEdit.MIState, buf::Any, ok::Bool)
    @ REPL ~/julia_versions/julia-1.8.2/share/julia/stdlib/v1.8/REPL/src/REPL.jl:857
 [20] #invokelatest#2
    @ ./essentials.jl:729 [inlined]
 [21] invokelatest
    @ ./essentials.jl:726 [inlined]
 [22] run_interface(terminal::REPL.Terminals.TextTerminal, m::REPL.LineEdit.ModalInterface, s::REPL.LineEdit.MIState)
    @ REPL.LineEdit ~/julia_versions/julia-1.8.2/share/julia/stdlib/v1.8/REPL/src/LineEdit.jl:2510
 [23] run_frontend(repl::REPL.LineEditREPL, backend::REPL.REPLBackendRef)
    @ REPL ~/julia_versions/julia-1.8.2/share/julia/stdlib/v1.8/REPL/src/REPL.jl:1248
 [24] (::REPL.var"#49#54"{REPL.LineEditREPL, REPL.REPLBackendRef})()
    @ REPL ./task.jl:484

And the full code to reproduce:

using Plots, LaTeXStrings
pyplot()
mpl = Plots.PythonCall.pyimport("matplotlib")Plots.PythonPlotBackend()
mpl = Plots.PythonCall.pyimport("matplotlib")Plots.PythonPlotBackend()
mpl.rcParams["font.family"] = "serif"
Plots.pyrcparams["text.latex.preamble"] = [s"\usepackage{dsfont}", s"\usepackge{lmodern}"]

plot(x -> x^2, 0:0.1:1, L"x^2")

And remains even if one resets:

Plots.pyrcparams["text.latex.preamble"] = []

Version before breakage: 1.36

The version before the recent changes is 1.36.6.

Here are the former definitions in Plots 1.36.6. The current version is 1.37.2. If something breaks, I would back to the prior minor version 1.36.x according to semantic versioning.

pycolors = PyPlot.pyimport("matplotlib.colors")
pypath = PyPlot.pyimport("matplotlib.path")
mplot3d = PyPlot.pyimport("mpl_toolkits.mplot3d")
axes_grid1 = PyPlot.pyimport("mpl_toolkits.axes_grid1")
pypatches = PyPlot.pyimport("matplotlib.patches")
pyfont = PyPlot.pyimport("matplotlib.font_manager")
pyticker = PyPlot.pyimport("matplotlib.ticker")
pycmap = PyPlot.pyimport("matplotlib.cm")
pynp = PyPlot.pyimport("numpy")
pynp."seterr"(invalid = "ignore")
pytransforms = PyPlot.pyimport("matplotlib.transforms")
pycollections = PyPlot.pyimport("matplotlib.collections")
pyart3d = PyPlot.art3D
pyrcparams = PyPlot.PyDict(PyPlot.matplotlib."rcParams")

Using PyPlot with Plots v1.37.2

This uses the deprecated PyCall.jl / PyPlot.jl support in Plots.jl v1.37.2. To be honest, I think the deprecation may be premature. Note that we are using pyplot() and PyCall here.

using Plots, LaTeXStrings
pyplot() # not pythonplot() !!!
mpl = Plots.PyCall.pyimport("matplotlib") # not PythonCall !!!
mpl.rcParams["font.family"] = "serif"
mpl.rcParams["text.latex.preamble"] = s"\usepackage{dsfont}\n\usepackge{lmodern}" # note matplotlib deprecates setting this to a list. Use a single string it recommends.
plot(x -> x^2, 0:0.1:1; label =  L"x^2")

Using PythonPlot with Plots v1.37.2

This uses the new PythonCall.jl / PythonPlot.jl support. Try not to mix PythonCall.jl and PyCall.jl, but see this guide if you must:
https://cjdoris.github.io/PythonCall.jl/stable/pycall/

using Plots, LaTeXStrings
pythonplot() # not pyplot() !!!
mpl = Plots.PythonCall.pyimport("matplotlib") # not PyCall !!!
mpl.rcParams["font.family"] = "serif"
mpl.rcParams["text.latex.preamble"] = s"\usepackage{dsfont}\n\usepackge{lmodern}" # note matplotlib deprecates setting this to a list. Use a single string it recommends.
plot(x -> x^2, 0:0.1:1; label =  L"x^2")

image

1 Like