If we \input the pgf file created by matplotlib with pgf backend, it assumes \mathdefault to exist. But unfortunately, this command is not provided by any of the recommended packages as far as I see: to produce the actual pdf file, matplotlib seems to actually define it manually like:
\def\mathdefault#1{#1}
as can be read from the automatically generated .pgf file… Manually adding this line in the .tex file before the \input works as a workaround, but this seems like a dirty workaround as this is not documented as far as I can see.
Would it be possible to either document it or provide these commands in a properly packaged latex library?
I would expect \input of the pgf file to work, but it is not. Here is the full file I use to both compile the python and include it (using the recent robust-externalize library, you might need to copy the .sty from to install it and you might want to compile with -shell-escape for simplicity)
\documentclass{article}
\usepackage{lipsum}
\usepackage{tikz}
\usepackage{robust-externalize}
\robExtConfigure{enable fallback to manual mode} % prints a helpful message in the document if you forgot --shell-escape
%% If you do not add this line, this will return an error:
%\def\mathdefault#1{#1}
\begin{document}
\lipsum[1]
\begin{figure}[ht]
\centering
\begin{CacheMeCode}{python, custom include command={\input{\robExtAddCachePathAndName{\robExtFinalHash.pgf}}}, set placeholder eval={__LINEWIDTH__}{\lenToCmNoUnit[in]{\linewidth}}}
import matplotlib.pyplot as plt
import matplotlib
from matplotlib.pyplot import figure
matplotlib.use("pgf")
# See this link for details on how to preview the image in jupyter
# https://matplotlib.org/stable/users/explain/text/pgf.html
matplotlib.rcParams.update({
"font.family": "serif",
"font.serif": [], # Use LaTeX default serif font.
"text.usetex": True, # use inline math for ticks
})
figure(figsize=(__LINEWIDTH__, 0.7*__LINEWIDTH__))
year = [2014, 2015, 2016, 2017, 2018, 2019]
tutorial_count = [39, 117, 111, 110, 67, 29]
plt.plot(year, tutorial_count, color="#6c3376", linewidth=2)
plt.title("Simple plot for $\delta = 2$")
plt.xlabel('Year')
plt.ylabel('Number of futurestud.io Tutorials')
print(get_filename_from_extension(".pgf"))
# https://stackoverflow.com/a/52587591/4987648
plt.savefig(get_filename_from_extension(".pgf"), bbox_inches="tight")
\end{CacheMeCode}
\caption{Test}%
\end{figure}
\end{document}
% Local Variables:
% TeX-command-extra-options: "--shell-escape -halt-on-error"
% End:
Expected outcome
I expect the use of \def\mathdefault#1{#1} to be at least documented, ideally automatically defined in the .pgf file if the command does not already exist with something like:
\providecommand\mathdefault[1]{#1}
Additional information
This seems to be a regression, as it used not to be a problem on 3.7 I think.
I think I found a workaround. In the PGF file itself there is a helpful commented out preamble that has some instructions for including/importing the image.
%% Matplotlib used the following preamble
%% \def\mathdefault#1{#1}
%% \everymath=\expandafter{\the\everymath\displaystyle}
It also has the code needed to define "\mathdefault" so I copied this into my main ".tex" file, and it appeared to work.
Would be helpful to make this more obvious to the library user. Could possibly prepend the definition to each PGF, checking if it's already defined.
Reacted by pltcldvlpr, Auss Abbood, Satoshi Sawai and Florian Anderl
To add \def\mathdefault#1{#1}\everymath=\expandafter{\the\everymath\displaystyle} to the document is not really a workaround, since it breaks the displaystyle of math in text, I think. If this is defined in the tex file, the siunitx settings
A working solution is to just use \def\mathdefault#1{\displaystyle #1}, without the "everymath" stuff, instead or with \textstyle, depending on what is needed.
This seems to have been undetected by the core developers...
I think the most feasible way is to add a parameter when saving as PGF that simply removes \mathdefault from the generated code.
Not sure if it is a regression or not. \mathdefault in the preamble was introduced in 3.3/#15695 but there can have been some additional use introduced in 3.8.
@anntzer do you have any idea if there is a better way to deal with this? If I get it correct, \mathdefault was removed before #15695, but that was considered brittle?
I suspect we should definitely include \def\mathdefault#1{#1} (or the equivalent providecommand) in the actual output pgf (without being commented), as the command just doesn't exist otherwise.
Whether the "everymath" command should be included is more tricky because what it does is to implement matplotlib's mathtext behavior where single-dollars actually mean the same as latex's double-dollars (i.e. displaymode) (and mathtext doesn't actually have double-dollars). (This breaks siunitx because it'll now think that inline-qtys are actually in double-dollars as well.) I guess a reasonable intermediate would be to only have that in effect within the scope of the pgf file output by matplotlib (i.e. emit pgf code entirely surrounded by {} and add \everymath... immediately after the opening brace; that setting will be undone once the scope exits.)
This problem affects me on Python 3.13.7 with Matplotlib 3.10.6 and PdfLaTeX 3.141592653-2.6-1.40.27 (TeX Live 2026/dev/Arch Linux). The workaround still works, but is only a workaround…
Still affected by this. It would be great if this could be fixed after more than two years because it takes quite a bit of time to understand the issue, find this workaround and implement it. Even just clearly telling the user to \def\mathdefault#1{#1} or \providecommand{\mathdefault}[1]{#1} in their LaTeX project would help a lot.
Activity
dflvunoooooo commented on Mar 27, 2024
I was struggling with this too.
nchristensen commented on Apr 4, 2024
I also encountered this issue. Downgrading to 3.7.1 appears to be a workaround.
SadPencil commented on Aug 26, 2024
I also had this issue. Many thanks to the workaround and hope it can be fixed
GrantDaly commented on Sep 16, 2024
I think I found a workaround. In the PGF file itself there is a helpful commented out preamble that has some instructions for including/importing the image.
%% Matplotlib used the following preamble
%% \def\mathdefault#1{#1}
%% \everymath=\expandafter{\the\everymath\displaystyle}
It also has the code needed to define "\mathdefault" so I copied this into my main ".tex" file, and it appeared to work.
Would be helpful to make this more obvious to the library user. Could possibly prepend the definition to each PGF, checking if it's already defined.
dflvunoooooo commented on Sep 27, 2024
To add \def\mathdefault#1{#1}\everymath=\expandafter{\the\everymath\displaystyle} to the document is not really a workaround, since it breaks the displaystyle of math in text, I think. If this is defined in the tex file, the siunitx settings
\sisetup{ display-per-mode = fraction , inline-per-mode = symbol, }Do no longer work. I am not sure where the problem lies or what to do.
MWE:
\documentclass{scrreport} \def\mathdefault#1{#1}\everymath=\expandafter{\the\everymath\displaystyle} \usepackage{siunitx} \sisetup{ display-per-mode = fraction , inline-per-mode = symbol, } \begin{document} \qty{15,9084}{\watt\per\square\meter} \(\qty{15,9084}{\watt\per\square\meter}\) \begin{equation} \qty{15,9084}{\watt\per\square\meter} \end{equation} \end{document}dflvunoooooo commented on Oct 2, 2024
A working solution is to just use \def\mathdefault#1{\displaystyle #1}, without the "everymath" stuff, instead or with \textstyle, depending on what is needed.
oscargus commented on Oct 2, 2024
This seems to have been undetected by the core developers...
I think the most feasible way is to add a parameter when saving as PGF that simply removes \mathdefault from the generated code.
Not sure if it is a regression or not. \mathdefault in the preamble was introduced in 3.3/#15695 but there can have been some additional use introduced in 3.8.
@anntzer do you have any idea if there is a better way to deal with this? If I get it correct, \mathdefault was removed before #15695, but that was considered brittle?
Socob commented on Oct 2, 2024
To fix the immediate problem, it seems to me that using the suggestion from the original report should be enough, i. e. including
\providecommand{\mathdefault}[1]{#1}in the PGF output?
anntzer commented on Oct 7, 2024
I suspect we should definitely include \def\mathdefault#1{#1} (or the equivalent providecommand) in the actual output pgf (without being commented), as the command just doesn't exist otherwise.
Whether the "everymath" command should be included is more tricky because what it does is to implement matplotlib's mathtext behavior where single-dollars actually mean the same as latex's double-dollars (i.e. displaymode) (and mathtext doesn't actually have double-dollars). (This breaks siunitx because it'll now think that inline-qtys are actually in double-dollars as well.) I guess a reasonable intermediate would be to only have that in effect within the scope of the pgf file output by matplotlib (i.e. emit pgf code entirely surrounded by {} and add \everymath... immediately after the opening brace; that setting will be undone once the scope exits.)
ReHoss commented on Dec 7, 2024
with seaborn I also had to use \usepackage[strings]{underscore} as specified by the preamble used by matplotlib.
jd-develop commented on Sep 14, 2025
This problem affects me on Python 3.13.7 with Matplotlib 3.10.6 and PdfLaTeX 3.141592653-2.6-1.40.27 (TeX Live 2026/dev/Arch Linux). The workaround still works, but is only a workaround…
tnwnx commented on Jun 29, 2026
Still affected by this. It would be great if this could be fixed after more than two years because it takes quite a bit of time to understand the issue, find this workaround and implement it. Even just clearly telling the user to \def\mathdefault#1{#1} or \providecommand{\mathdefault}[1]{#1} in their LaTeX project would help a lot.