Velvet Star Monitor

Standout celebrity highlights with iconic style.

general

Define `\widebar` command in matplotlib when using LaTeX rendering

Writer Mia Lopez

When using matplotlib default's math rendering, you get the command $\widebar{A}$ "built-in":

import matplotlib.pyplot as plt
plt.plot([1,2])
plt.gca().set_ylabel(r"$\widebar{A}$")

and all is good.

However, if, for some reason, you need to activate LaTeX rendering (in my case, because I have to use Palatino as the math font), you lose the built-in ability to draw a wide bar on letters. LaTeX' $\overline$ would be a solution, but it's not optimal (see this question on TeX.SE). The best option would be Hendrik Vogt's definition, given as an answer to that same question. However, it seems quite tricky to add it to the preamble in matplotlib. I first tried to set it through my own .mplstyle without success. I inserted it as a one-liner, but still, I think, the # characters were interpreted as comments. So I thought to set it directly at runtime through:

plt.rc('text.latex', preamble=r'\usepackage{amsmath} \makeatletter \let\save@mathaccent\mathaccent \newcommand *\if@single[3]{% \setbox0\hbox{${\mathaccent"0362{#1}}^H$}% \setbox2\hbox{${\mathaccent"0362{\kern0pt#1}}^ H$}% \ifdim\ht0=\ht2 #3\else #2\fi } \newcommand*\rel@kern[1]{\kern#1\dimexpr\macc@kerna} \newcommand*\wid ebar[1]{\@ifnextchar^{{\wide@bar{#1}{0}}}{\wide@bar{#1}{1}}} \newcommand*\wide@bar[2]{\if@single{#1}{\wide@bar @{#1}{#2}{1}}{\wide@bar@{#1}{#2}{2}}} \newcommand*\wide@bar@[3]{% \begingroup \def\mathaccent##1##2{% \let\mathaccent\save@mathaccent \if#32 \let\macc@nucleus\first@char \fi \setbox\z@\hbox{$\macc@style{\ macc@nucleus}_{}$}% \setbox\tw@\hbox{$\macc@style{\macc@nucleus}{}_{}$}% \dimen@\wd\tw@ \advance\d imen@-\wd\z@ \divide\dimen@ 3 \@tempdima\wd\tw@ \advance\@tempdima-\scriptspace \divide\@tempd ima 10 \advance\dimen@-\@tempdima \ifdim\dimen@>\z@ \dimen@0pt\fi \rel@kern{0.6}\kern-\dimen@ \if#31 \overline{\rel@kern{-0.6}\kern\dimen@\macc@nucleus\rel@kern{0.4}\kern\dimen@}% \advance\dim [email protected]\dimexpr\macc@kerna \let\final@kern#2% \ifdim\dimen@<\z@ \let\final@kern1\fi \if\final @kern1 \kern-\dimen@\fi \else \overline{\rel@kern{-0.6}\kern\dimen@#1}% \fi }% \macc@depth\@ ne \let\math@bgroup\@empty \let\math@egroup\macc@set@skewchar \mathsurround\z@ \frozen@everymath{\mathgrou p\macc@group\relax}% \macc@set@skewchar\relax \let\mathaccentV\macc@nested@a \if#31 \macc@nested@a\r elax111{#1}% \else \def\gobble@till@marker##1\endmarker{}% \futurelet\first@char\gobble@till@marker# 1\endmarker \ifcat\noexpand\first@char A\else \def\first@char{}% \fi \macc@nested@a\relax111 {\first@char}% \fi \endgroup } \makeatother')

With no surprise, it didn't work.

Here's LaTeX' report:

This is pdfTeX, Version 3.14159265-2.6-1.40.20 (TeX Live 2019/Debian) (preloaded format=latex) restricted \write18 enabled.
entering extended mode
(../d49352dbf7e233191e06411a7bb3d1ee.tex
LaTeX2e <2020-02-02> patch level 2
L3 programming layer <2020-02-14>
(/usr/share/texlive/texmf-dist/tex/latex/base/article.cls
Document Class: article 2019/12/20 v1.4l 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)))
(/usr/share/texlive/texmf-dist/tex/latex/amsmath/amsmath.sty
For additional information on amsmath, use the `?' option.
(/usr/share/texlive/texmf-dist/tex/latex/amsmath/amstext.sty
(/usr/share/texlive/texmf-dist/tex/latex/amsmath/amsgen.sty))
(/usr/share/texlive/texmf-dist/tex/latex/amsmath/amsbsy.sty)
(/usr/share/texlive/texmf-dist/tex/latex/amsmath/amsopn.sty)))
Runaway argument?
{\makeatletter \@ifpackageloaded {underscore}{}{\usepackage [strings]\ETC.
! File ended while scanning use of \@argdef.
<inserted text> \par
<*> ../d49352dbf7e233191e06411a7bb3d1ee.tex
No pages of output.

Is there actually a way to define more complicated preambles than \usepackage{...} in matplotlib, e.g. by linking an external file containing it? Or is there a better way to get a well-working wide bar in latex mode?

1 Answer

After trying again, I realized I stupidly forgot to remove the LaTeX comments and all percent characters at the end of the lines.

So this

import matplotlib.pyplot as plt
preamble=r'\usepackage{amsmath} \makeatletter \let\save@mathaccent\mathaccent \newcommand*\if@single[3]{ \setbox0\hbox{${\mathaccent"0362{#1}}^H$} \setbox2\hbox{${\mathaccent"0362{\kern0pt#1}}^H$} \ifdim\ht0=\ht2 #3\else #2\fi } \newcommand*\rel@kern[1]{\kern#1\dimexpr\macc@kerna} \newcommand*\widebar[1]{\@ifnextchar^{{\wide@bar{#1}{0}}}{\wide@bar{#1}{1}}} \newcommand*\wide@bar[2]{\if@single{#1}{\wide@bar@{#1}{#2}{1}}{\wide@bar@{#1}{#2}{2}}} \newcommand*\wide@bar@[3]{ \begingroup \def\mathaccent##1##2{ \let\mathaccent\save@mathaccent \if#32 \let\macc@nucleus\first@char \fi \setbox\z@\hbox{$\macc@style{\macc@nucleus}_{}$} \setbox\tw@\hbox{$\macc@style{\macc@nucleus}{}_{}$} \dimen@\wd\tw@ \advance\dimen@-\wd\z@ \divide\dimen@ 3 \@tempdima\wd\tw@ \advance\@tempdima-\scriptspace \divide\@tempdima 10 \advance\dimen@-\@tempdima \ifdim\dimen@>\z@ \dimen@0pt\fi \rel@kern{0.6}\kern-\dimen@ \if#31 \overline{\rel@kern{-0.6}\kern\dimen@\macc@nucleus\rel@kern{0.4}\kern\dimen@} \advance\[email protected]\dimexpr\macc@kerna \let\final@kern#2 \ifdim\dimen@<\z@ \let\final@kern1\fi \if\final@kern1 \kern-\dimen@\fi \else \overline{\rel@kern{-0.6}\kern\dimen@#1} \fi } \macc@depth\@ne \let\math@bgroup\@empty \let\math@egroup\macc@set@skewchar \mathsurround\z@ \frozen@everymath{\mathgroup\macc@group\relax} \macc@set@skewchar\relax \let\mathaccentV\macc@nested@a \if#31 \macc@nested@a\relax111{#1} \else \def\gobble@till@marker##1\endmarker{} \futurelet\first@char\gobble@till@marker#1\endmarker \ifcat\noexpand\first@char A\else \def\first@char{} \fi \macc@nested@a\relax111{\first@char} \fi \endgroup } \makeatother'
plt.rc('text.latex', preamble=preamble)

actually works.

Unfortunately, it does not work in the .mplstyle, so I'll let this question open to see if anyone has a better solution.

Your Answer

Sign up or log in

Sign up using Google Sign up using Facebook Sign up using Email and Password

Post as a guest

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.