Home > database >  Define `\widebar` command in matplotlib when using LaTeX rendering
Define `\widebar` command in matplotlib when using LaTeX rendering

Time:08-14

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?

CodePudding user response:

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.

  • Related