I can't get matplotlib to work with Lualatex

Hi!
I am trying to use matplotlib to create graphs for my master thesis. I want to use some latex packages, however some of them don’t work with pdftex and need lualatex. One example is the fontspec package, that’s why I use it in my minimal example. I am aware that you can update the rc params with ‘pgf.texsystem’: “lualatex” to use lualatex instead of pdflatex, however that does not seem to work. In the error message it still says:
“This is pdfTeX, Version 3.141592653-2.6-1.40.22” and
“Fatal Package fontspec Error: The fontspec package requires either XeTeX or LuaTeX.”

(my minimal example below)

import matplotlib as mpl
mpl.use('pgf')
import matplotlib.pyplot as plt
%matplotlib widget
packages=["siunitx",
          "mathtools",
          "amsmath",
          "**fontspec**",
         ]
packages_string="\n".join([r"\usepackage{{{}}}".format(p) for p in packages])

commands=[r"\sisetup{locale = DE}",
          r"\setmainfont{TeX Gyre Termes}",
         ]
commands_string="\n".join(commands)

tex_header=packages_string+commands_string

plt.rc('pgf', texsystem='lualatex')

pgf_with_latex = {
                  'pgf.texsystem': "lualatex",
                  'text.usetex': True,
                  'pgf.rcfonts': False,
                  'font.size' : "12",
                  'text.latex.preamble': tex_header,
                  }

plt.rcParams.update(pgf_with_latex)

fig, ax = plt.subplots(1)
x=[i for i in range(100)]
y=[i**2 for i in range(100)]
ax.plot(x,y)
ax.set(ylabel=r'\TeX')
fig.tight_layout()

fig.savefig('minimal.pdf',format='pdf')

(Taceback below)

> CalledProcessError                        Traceback (most recent call last)
> C:\Program Files\WPy64-3860\python-3.8.6.amd64\lib\site-packages\matplotlib\texmanager.py in _run_checked_subprocess(self, command, tex)
>     274         try:
> --> 275             report = subprocess.check_output(command,
>     276                                              cwd=self.texcache,
> 
> C:\Program Files\WPy64-3860\python-3.8.6.amd64\lib\subprocess.py in check_output(timeout, *popenargs, **kwargs)
>     410 
> --> 411     return run(*popenargs, stdout=PIPE, timeout=timeout, check=True,
>     412                **kwargs).stdout
> 
> C:\Program Files\WPy64-3860\python-3.8.6.amd64\lib\subprocess.py in run(input, capture_output, timeout, check, *popenargs, **kwargs)
>     511         if check and retcode:
> --> 512             raise CalledProcessError(retcode, process.args,
>     513                                      output=stdout, stderr=stderr)
> 
> CalledProcessError: Command '['latex', '-interaction=nonstopmode', '--halt-on-error', 'C:\\Users\\stefa\\.matplotlib\\tex.cache\\944905cdd2a7e8789e7b38e5e52b6c71.tex']' returned non-zero exit status 1.
> 
> The above exception was the direct cause of the following exception:
> 
> RuntimeError                              Traceback (most recent call last)
> <ipython-input-12-54efa0522a53> in <module>
> ----> 1 fig.savefig('minimal.pdf',format='pdf')
> 
> C:\Program Files\WPy64-3860\python-3.8.6.amd64\lib\site-packages\matplotlib\figure.py in savefig(self, fname, transparent, **kwargs)
>    2309                 patch.set_edgecolor('none')
>    2310 
> -> 2311         self.canvas.print_figure(fname, **kwargs)
>    2312 
>    2313         if transparent:
> 
> C:\Program Files\WPy64-3860\python-3.8.6.amd64\lib\site-packages\matplotlib\backend_bases.py in print_figure(self, filename, dpi, facecolor, edgecolor, orientation, format, bbox_inches, pad_inches, bbox_extra_artists, backend, **kwargs)
>    2208 
>    2209             try:
> -> 2210                 result = print_method(
>    2211                     filename,
>    2212                     dpi=dpi,
> 
> C:\Program Files\WPy64-3860\python-3.8.6.amd64\lib\site-packages\matplotlib\backend_bases.py in wrapper(*args, **kwargs)
>    1637             kwargs.pop(arg)
>    1638 
> -> 1639         return func(*args, **kwargs)
>    1640 
>    1641     return wrapper
> 
> C:\Program Files\WPy64-3860\python-3.8.6.amd64\lib\site-packages\matplotlib\backends\backend_pdf.py in print_pdf(self, filename, dpi, bbox_inches_restore, metadata)
>    2591                 RendererPdf(file, dpi, height, width),
>    2592                 bbox_inches_restore=bbox_inches_restore)
> -> 2593             self.figure.draw(renderer)
>    2594             renderer.finalize()
>    2595             if not isinstance(filename, PdfPages):
> 
> C:\Program Files\WPy64-3860\python-3.8.6.amd64\lib\site-packages\matplotlib\artist.py in draw_wrapper(artist, renderer, *args, **kwargs)
>      39                 renderer.start_filter()
>      40 
> ---> 41             return draw(artist, renderer, *args, **kwargs)
>      42         finally:
>      43             if artist.get_agg_filter() is not None:
> 
> C:\Program Files\WPy64-3860\python-3.8.6.amd64\lib\site-packages\matplotlib\figure.py in draw(self, renderer)
>    1861 
>    1862             self.patch.draw(renderer)
> -> 1863             mimage._draw_list_compositing_images(
>    1864                 renderer, self, artists, self.suppressComposite)
>    1865 
> 
> C:\Program Files\WPy64-3860\python-3.8.6.amd64\lib\site-packages\matplotlib\image.py in _draw_list_compositing_images(renderer, parent, artists, suppress_composite)
>     129     if not_composite or not has_images:
>     130         for a in artists:
> --> 131             a.draw(renderer)
>     132     else:
>     133         # Composite any adjacent images together
> 
> C:\Program Files\WPy64-3860\python-3.8.6.amd64\lib\site-packages\matplotlib\artist.py in draw_wrapper(artist, renderer, *args, **kwargs)
>      39                 renderer.start_filter()
>      40 
> ---> 41             return draw(artist, renderer, *args, **kwargs)
>      42         finally:
>      43             if artist.get_agg_filter() is not None:
> 
> C:\Program Files\WPy64-3860\python-3.8.6.amd64\lib\site-packages\matplotlib\cbook\deprecation.py in wrapper(*inner_args, **inner_kwargs)
>     409                          else deprecation_addendum,
>     410                 **kwargs)
> --> 411         return func(*inner_args, **inner_kwargs)
>     412 
>     413     return wrapper
> 
> C:\Program Files\WPy64-3860\python-3.8.6.amd64\lib\site-packages\matplotlib\axes\_base.py in draw(self, renderer, inframe)
>    2745             renderer.stop_rasterizing()
>    2746 
> -> 2747         mimage._draw_list_compositing_images(renderer, self, artists)
>    2748 
>    2749         renderer.close_group('axes')
> 
> C:\Program Files\WPy64-3860\python-3.8.6.amd64\lib\site-packages\matplotlib\image.py in _draw_list_compositing_images(renderer, parent, artists, suppress_composite)
>     129     if not_composite or not has_images:
>     130         for a in artists:
> --> 131             a.draw(renderer)
>     132     else:
>     133         # Composite any adjacent images together
> 
> C:\Program Files\WPy64-3860\python-3.8.6.amd64\lib\site-packages\matplotlib\artist.py in draw_wrapper(artist, renderer, *args, **kwargs)
>      39                 renderer.start_filter()
>      40 
> ---> 41             return draw(artist, renderer, *args, **kwargs)
>      42         finally:
>      43             if artist.get_agg_filter() is not None:
> 
> C:\Program Files\WPy64-3860\python-3.8.6.amd64\lib\site-packages\matplotlib\axis.py in draw(self, renderer, *args, **kwargs)
>    1163 
>    1164         ticks_to_draw = self._update_ticks()
> -> 1165         ticklabelBoxes, ticklabelBoxes2 = self._get_tick_bboxes(ticks_to_draw,
>    1166                                                                 renderer)
>    1167 
> 
> C:\Program Files\WPy64-3860\python-3.8.6.amd64\lib\site-packages\matplotlib\axis.py in _get_tick_bboxes(self, ticks, renderer)
>    1089     def _get_tick_bboxes(self, ticks, renderer):
>    1090         """Return lists of bboxes for ticks' label1's and label2's."""
> -> 1091         return ([tick.label1.get_window_extent(renderer)
>    1092                  for tick in ticks if tick.label1.get_visible()],
>    1093                 [tick.label2.get_window_extent(renderer)
> 
> C:\Program Files\WPy64-3860\python-3.8.6.amd64\lib\site-packages\matplotlib\axis.py in <listcomp>(.0)
>    1089     def _get_tick_bboxes(self, ticks, renderer):
>    1090         """Return lists of bboxes for ticks' label1's and label2's."""
> -> 1091         return ([tick.label1.get_window_extent(renderer)
>    1092                  for tick in ticks if tick.label1.get_visible()],
>    1093                 [tick.label2.get_window_extent(renderer)
> 
> C:\Program Files\WPy64-3860\python-3.8.6.amd64\lib\site-packages\matplotlib\text.py in get_window_extent(self, renderer, dpi)
>     898 
>     899         with cbook._setattr_cm(self.figure, dpi=dpi):
> --> 900             bbox, info, descent = self._get_layout(self._renderer)
>     901             x, y = self.get_unitless_position()
>     902             x, y = self.get_transform().transform((x, y))
> 
> C:\Program Files\WPy64-3860\python-3.8.6.amd64\lib\site-packages\matplotlib\text.py in _get_layout(self, renderer)
>     283 
>     284         # Full vertical extent of font, including ascenders and descenders:
> --> 285         _, lp_h, lp_d = renderer.get_text_width_height_descent(
>     286             "lp", self._fontproperties,
>     287             ismath="TeX" if self.get_usetex() else False)
> 
> C:\Program Files\WPy64-3860\python-3.8.6.amd64\lib\site-packages\matplotlib\backends\_backend_pdf_ps.py in get_text_width_height_descent(self, s, prop, ismath)
>      84             texmanager = self.get_texmanager()
>      85             fontsize = prop.get_size_in_points()
> ---> 86             w, h, d = texmanager.get_text_width_height_descent(
>      87                 s, fontsize, renderer=self)
>      88             return w, h, d
> 
> C:\Program Files\WPy64-3860\python-3.8.6.amd64\lib\site-packages\matplotlib\texmanager.py in get_text_width_height_descent(self, tex, fontsize, renderer)
>     421         else:
>     422             # use dviread.
> --> 423             dvifile = self.make_dvi(tex, fontsize)
>     424             with dviread.Dvi(dvifile, 72 * dpi_fraction) as dvi:
>     425                 page, = dvi
> 
> C:\Program Files\WPy64-3860\python-3.8.6.amd64\lib\site-packages\matplotlib\texmanager.py in make_dvi(self, tex, fontsize)
>     307             texfile = self.make_tex(tex, fontsize)
>     308             with cbook._lock_path(texfile):
> --> 309                 self._run_checked_subprocess(
>     310                     ["latex", "-interaction=nonstopmode", "--halt-on-error",
>     311                      texfile], tex)
> 
> C:\Program Files\WPy64-3860\python-3.8.6.amd64\lib\site-packages\matplotlib\texmanager.py in _run_checked_subprocess(self, command, tex)
>     281                 'found'.format(command[0])) from exc
>     282         except subprocess.CalledProcessError as exc:
> --> 283             raise RuntimeError(
>     284                 '{prog} was not able to process the following string:\n'
>     285                 '{tex!r}\n\n'
> 
> 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 2021/W32TeX) (preloaded format=latex)
>  restricted \write18 enabled.
> entering extended mode
> (c:/Users/stefa/.matplotlib/tex.cache/944905cdd2a7e8789e7b38e5e52b6c71.tex
> LaTeX2e <2020-10-01> patch level 4
> L3 programming layer <2021-02-18>
> (c:/TeX/texlive/2021/texmf-dist/tex/latex/base/article.cls
> Document Class: article 2020/04/10 v1.4m Standard LaTeX document class
> (c:/TeX/texlive/2021/texmf-dist/tex/latex/base/size10.clo))
> (c:/TeX/texlive/2021/texmf-dist/tex/latex/type1cm/type1cm.sty)
> (c:/TeX/texlive/2021/texmf-dist/tex/latex/cm-super/type1ec.sty
> (c:/TeX/texlive/2021/texmf-dist/tex/latex/base/t1cmr.fd))
> (c:/TeX/texlive/2021/texmf-dist/tex/latex/base/inputenc.sty)
> (c:/TeX/texlive/2021/texmf-dist/tex/latex/geometry/geometry.sty
> (c:/TeX/texlive/2021/texmf-dist/tex/latex/graphics/keyval.sty)
> (c:/TeX/texlive/2021/texmf-dist/tex/generic/iftex/ifvtex.sty
> (c:/TeX/texlive/2021/texmf-dist/tex/generic/iftex/iftex.sty))
> 
> Package geometry Warning: Over-specification in `h'-direction.
>     `width' (5058.9pt) is ignored.
> 
> 
> Package geometry Warning: Over-specification in `v'-direction.
>     `height' (5058.9pt) is ignored.
> 
> ) (c:/TeX/texlive/2021/texmf-dist/tex/latex/siunitx/siunitx.sty
> (c:/TeX/texlive/2021/texmf-dist/tex/latex/l3kernel/expl3.sty
> (c:/TeX/texlive/2021/texmf-dist/tex/latex/l3backend/l3backend-dvips.def))
> (c:/TeX/texlive/2021/texmf-dist/tex/latex/l3packages/xparse/xparse.sty
> (c:/TeX/texlive/2021/texmf-dist/tex/latex/l3packages/xparse/xparse-2020-10-01.s
> ty
> (c:/TeX/texlive/2021/texmf-dist/tex/latex/l3packages/xparse/xparse-generic.tex)
> )) (c:/TeX/texlive/2021/texmf-dist/tex/latex/amsmath/amstext.sty
> (c:/TeX/texlive/2021/texmf-dist/tex/latex/amsmath/amsgen.sty))
> (c:/TeX/texlive/2021/texmf-dist/tex/latex/tools/array.sty)
> (c:/TeX/texlive/2021/texmf-dist/tex/latex/l3packages/l3keys2e/l3keys2e.sty)
> (c:/TeX/texlive/2021/texmf-dist/tex/latex/translator/translator.sty))
> (c:/TeX/texlive/2021/texmf-dist/tex/latex/mathtools/mathtools.sty
> (c:/TeX/texlive/2021/texmf-dist/tex/latex/tools/calc.sty)
> (c:/TeX/texlive/2021/texmf-dist/tex/latex/mathtools/mhsetup.sty)
> (c:/TeX/texlive/2021/texmf-dist/tex/latex/amsmath/amsmath.sty
> For additional information on amsmath, use the `?' option.
> (c:/TeX/texlive/2021/texmf-dist/tex/latex/amsmath/amsbsy.sty)
> (c:/TeX/texlive/2021/texmf-dist/tex/latex/amsmath/amsopn.sty)))
> (c:/TeX/texlive/2021/texmf-dist/tex/latex/fontspec/fontspec.sty
> 
> ! Fatal Package fontspec Error: The **fontspec** package requires either XeTeX or
> (fontspec)                      LuaTeX.
> (fontspec)                      
> (fontspec)                      You must change your typesetting engine to,
> (fontspec)                      e.g., "xelatex" or "lualatex"instead of
> (fontspec)                      "latex" or "pdflatex".
> 
> Type <return> to continue.
>  ...                                              
>                                                   
> l.45 \msg_fatal:nn {fontspec} {cannot-use-pdftex}
>                                                  
> No pages of output.
> Transcript written on 944905cdd2a7e8789e7b38e5e52b6c71.log.

I’d be super glad if anyone had any idea how to fix my Problem.

From the %matplotlib widget line I guess that you are running this in a jupyter notebook. Note that %matplotlib widget will change the current backend (away from pgf), hence the subsequent failure. You need to call use("pgf") after %matplotlib widget, or better, call savefig(..., backend="pgf") which will locally set the backend to pgf just for the savefig.