Skip to content

Feature request: add option to disable mathtext parsing #4938

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
aheays opened this issue Aug 17, 2015 · 21 comments
Closed

Feature request: add option to disable mathtext parsing #4938

aheays opened this issue Aug 17, 2015 · 21 comments

Comments

@aheays
Copy link

aheays commented Aug 17, 2015

Could not find a way to do this through current documentation discussion.

Requested feature: Simple way (rcParam?) to disable mathtext processing and instead display raw string.
An alternative might be to print raw string on error rather than fail parsing and entire script.

Use case: Normally process figure strings with latex strings. When prototyping use mathtext for speed, but fails in complex but useful latex cases (e.g., \ce{..} mhchem package). Would be annoying to add extensive try/except code.

@tacaswell tacaswell added this to the Color overhaul milestone Sep 23, 2015
@WeatherGod
Copy link
Member

I am amendable to this idea. It probably won't get worked on for a couple
more months as we sort out the (in-progress) 1.5 release and the
immediately following style-change-only 2.0 release. Once 2.0 gets
released, be sure to ping this issue again to remind us.

On Wed, Sep 23, 2015 at 5:09 AM, Sybren A. Stüvel notifications@github.com
wrote:

+1 for another reason: I embed my plots in a LaTeX file, and want to defer
the text rendering to LaTeX when it's rendering the entire document. That
way I can use custom LaTeX commands and styles in my figure. Inkscape can
convert SVG to LaTeX + PDF to support this workflow, and it would be very
nice if Matplotlib could too. All we need is a toggle to turn it off and
have raw "$\LaTeX$" in the output.


Reply to this email directly or view it on GitHub
#4938 (comment)
.

@sybrenstuvel
Copy link

+1 for another reason: I embed my plots in a LaTeX file, and want to defer
the text rendering to LaTeX when it's rendering the entire document. That
way I can use custom LaTeX commands and styles in my figure. Inkscape can
convert SVG to LaTeX + PDF to support this workflow, and it would be very
nice if Matplotlib could too. All we need is a toggle to turn it off and
have raw "$\LaTeX$" in the output.

I deleted my post (now quoted above), as it turned out it didn't work as easily as I expected. I got the raw "$\LaTeX$" in the output SVG, but it wasn't picked up by Inkscape to be removed from the SVG and transferred to a .pdf_tex file. Apparently, more has to be done to support my suggested workflow.

@tacaswell
Copy link
Member

@sybrenstuvel If you are solely targetting latex rendering, have a look at the pgf backend.

@mdboom mdboom modified the milestones: Color overhaul, next major release (2.0) Oct 8, 2015
@mdboom
Copy link
Member

mdboom commented Nov 8, 2015

Have you tried escaping the dollar signs? i.e. \$\LaTeX\$.

@mdboom mdboom modified the milestones: proposed next point release (2.1), next major release (2.0) Nov 8, 2015
@tacaswell tacaswell modified the milestones: 2.1 (next point release), 2.2 (next next feature release) Oct 3, 2017
@LukasDrude
Copy link

Yes. I would like to be able to disable it, too. It is particularly annoying if you use third party libraries for export, i.e. matplotlib2tikz.

@AJJLagerweij
Copy link

This would be a nice feature, currently I have to enable and disable all the escape symbols depending on what I use it for. Having a rcParams would be awesome and much quicker. I do use the same code for:

  • Images in my Presentations (these need to have appropriate functions rendered as functions)
  • Matplotlib interaction during coding should also have math rendered
  • For my latex papers and reports I would like to turn rendering off. As I like to have latex render it when it creates the report.

The latter requires:

plt.rcParams['svg.fonttype'] = 'none'

and saving the images as an .svg. Now one can edit it in Inkscape after which you can save it as a .pdf_tex and .pdf where the method to do this nicely is discussed here.

@jklymak
Copy link
Member

jklymak commented Feb 21, 2021

As noted above we have a pgf backend already, so what is the advantage of having an extra processing step?

@AJJLagerweij
Copy link

AJJLagerweij commented Feb 21, 2021

This link discusses how to import a drawing and or plot into your latex document in a way that:

  1. The drawing part of the plot is imported as an image (pdf)
  2. The text part is processed as latex code when the latex document is compiled.

Separating the text from the image can be done using Inkscape. This is, at least in my opinion better than the pgf backend as it ensures that the fontsize/type and other text properties in your image is exactly the same as in the rest of you document. Even if you rescale the image the font is rendered by latex in the same way as the rest of the document and does thus not scale with the image. The result is a more consistent document. See the following example:
afbeelding

It is not only more consistent, it is also easier to set up than the pgf backend, as it does not require matplotlib to do anything more than exporting the text as a text in the .svg. The text is then handled by your normal latex editor and compiler (not matplotlib or python). This is especially nice if you want your code or images to be portable. To be clear this behaviour works perfect already with the current matplotlib module, you just need to ensure that matplotlib does not interpret the math you write, as mentioned above this can be achieved with escape symbols. Here an example of a string:

>>> ax.set_ylabel(r"Local error $\sum_{d=1}^D \| u_d - \hat{u} \|^2$")
>>> ax.set_ylabel(r"Local error \$\\sum_{d=1}^D \\| u_d - \\hat{u} \\|^2\$")

The only problem that I have at the moment is that I would like to switch between these two printing modes (math represented as math and math represented as latex commands). This makes it easier to work with, as I can look at the nicely rendered functions when developing code. Hence, I would propose a command that turns-off the interpretation of the strings such that all labels, annotations and others are rendered as plain text.

I, and so I assume the original author, expected this to either exist already or for this to be an easy to implement. Again, the only thing that this setting should do is turn-off all string interpretation and just make it appear as plain text in the matplotlib window. Everything else will be handled by Inkscape and Latex.

@anntzer
Copy link
Contributor

anntzer commented Feb 21, 2021

Thank you for the detailed explanation.

  • Emitting unparsed mathtext means that matplotlib will get the text alignments wrong (because it will measure text boxes based on the raw string). Is this a problem for your use case? Is there a reasonable solution you can think of for that?
  • You could e.g. write something along the lines of
def _m(s): return s.replace("$", r"\$") if RAW_MATH else s

and wrap all your strings in _m(...), which would additionally make it easy for you to switch back and forth by changing the RAW_MATH global? (I think you only need to escape the $, not the backslashes(?), but also escaping the backslashes is easy.)

@AJJLagerweij
Copy link

Just for clarification I made an example:

import matplotlib.pyplot as plt
plt.rcParams['svg.fonttype'] = 'none'

plt.figure()
plt.xlabel(r"Just some text")
plt.ylabel(r"Local error \$\sum_{d=1}^D \| u_d - \hat{u} \|^2\$")
plt.savefig('plot.svg')

When you open this in Inkscape (or Illustrator), will cause your font to be recognized in Inkscape as letters.
I have this conversion from. svg to .pdf and .pdf_tex automated in my latex permeable.

\documentclass{article}
\usepackage{hyperref} % Import and set hyperrefs
\usepackage{geometry} % Tweakying page layout
\usepackage{graphicx} % Manage images and colors

% Reading and processing SVG files with correct fonts
% This can be replaced with using Inkscape and manually
% exporting the files as .pdf with text as latex. This
% automated process requires Inkscape to be in your
% global path, wich is a bit more difficult in windows.
\newcommand{\executeiffilenewer}[3]{%
	\ifnum\pdfstrcmp{\pdffilemoddate{#1}}%
	{\pdffilemoddate{#2}}>0%
	{\immediate\write18{#3}}\fi%
}
\newcommand{\includesvg}[1]{%
	\executeiffilenewer{#1.svg}{#1.pdf}%
	{inkscape -z -D --file=#1.svg --export-pdf=#1.pdf --export-latex}%
	\input{#1.pdf_tex}%
}

\begin{document}
\begin{figure}[t!]
	\centering
	\def\svgwidth{\textwidth}
	\includesvg{plot}
	\caption{An example plot with real latex rendering.}
\end{figure}
\end{document}

This is the resulting folder including the python, latex and image files.
test.zip

@AJJLagerweij
Copy link

Ahh, thanks for your swift response. I'll have a look at it tomorrow, as it is late already.
But the alignment is not very important, as the text doesn't scale with your image size the exact alignment is a bit flexible anyway. Generally I correct this in the .svg by hand. (or specify the spacing differently in python). As you mentioned the 'raw string' will be of different length than that it will be in the final .pdf. I had an issue with that ones before. However in general the impact is not to large. As you can see from my example in the previous post even a fairly long string to short rendered math with summations comes out quite nicely. And I did not have to tweak the files in anyway.

Your proposal where I use a function to convert is actually perfect and this solves all my issues. I'll make an extra example tomorrow to show how this can be use to make a python script that can quickly switch between rendered and non-rendered maths in matplotlib. Afterwards I'll close this request.

You are right, only the $ requires escaping when you use raw strings (r"$\lambda$" to r"\$\lambdla\$"). In case of other types of strings one will also need to escapes the \ that is "$\lambda$" to "\$\\lambdla\$". This can be useful when we want to combine this with to the string formatting syntax.

@jklymak
Copy link
Member

jklymak commented Feb 21, 2021

I still don't follow how that is preferable to

\documentclass{article}
\usepackage{hyperref} % Import and set hyperrefs
\usepackage{geometry} % Tweakying page layout
\usepackage{graphicx} % Manage images and colors
\usepackage{tikz,pgf}

\begin{document}
\begin{figure}
    \begin{center}
        \input{plot.pgf}
    \end{center}
    \caption{An example plot with real latex rendering.}
\end{figure}
\end{document}

which bypasses inkscape altogether:

testLatex.pdf

@AJJLagerweij
Copy link

I must be honest, I thought that the pgf background worked differently, clearly it is, as you already mentioned a lot closer to what I I need then I thought. In your example however there seems to be a different font in the caption compared to the font in the figure labels. That is exactly what we're trying to avoid, the fonts need to be exactly the same.
Nevertheless, this might be possible with the pgf backend. I'll try and post an update about this.

If I manage to fix than the pgf is far superior to the workflow that I'm currently using. I have to say that I'm worried about the latex compile time as it will have to render all the data, and not only the text of the figures. But using draft properly in TeX should allow us to circumvent that.

@AJJLagerweij
Copy link

I've not yet managed to have the font type and size adapt to my latex run automatically with the pgf backend of matplotlib. There is however a workaround that is relatively nice, it is called tikzplotlib. This converts the matplotlib image into a tikzpicture figure that can be processed with the latex package called pgfplots. See the examples here below:

import matplotlib.pyplot as plt
from tikzplotlib import save

plt.figure()
plt.xlabel(r"Just some text")
plt.ylabel(r"Local error $\sum_{d=1}^D \| u_d - \hat{u} \|^2$")

save("plot.tex",
     axis_height=r"\axheight",
     axis_width=r"\axwidth")
\documentclass{article}
\usepackage{geometry}
\usepackage{pgfplots}
\pgfplotsset{compat = 1.5}

\newlength\axheight
\newlength\axwidth
\newcommand{\plot}[3]{%
	\setlength\axheigaht{#1}%
	\setlength\axwidth{#2}%
	\input{#3}}


\begin{document}
	\begin{figure}
		\centering
		\plot{5cm}{5cm}{plot.tex}
		\caption{An example plot with real latex rendering.}
	\end{figure}

	\begin{figure}
	\centering\footnotesize
	\plot{5cm}{5cm}{plot.tex}
	\caption{Image of the same size but with different text size.}
	\end{figure}

	\begin{figure}
		\centering
		\plot{6cm}{0.9\textwidth}{plot.tex}
		\caption{The same image but with different dimensions, The text does not scale with the image.}
	\end{figure}
\end{document}

See the results here: test.zip.
This is not as flexible and nice as using matplotlib directly, but does do what I expect it to (for simple plots).

@aheays
Copy link
Author

aheays commented Feb 22, 2021

This is turning into a great tutorial on pgf and tikzplot etc! But to clarify my particular original problem, I was missing an easy way to display raw mathtext during the development of a plot without escaping everything or raising an error, and then later on switching to usetex with full latex support and perhaps custom \usepackages. For example, a label like:

plot([1,2,3],label=r'$x(\ce{CH4}) = \SI{1e16}{cm^{-3}}$')

@AJJLagerweij
Copy link

Clearly I had a wrong idea regarding your motivation, sorry for that. I think that @anntzer in #4938 (comment) has the solution for you.

Here is a minimal working example with your string:

import matplotlib.pyplot as plt
RAW_MATH = True

def _m(s):
    return s.replace("$", r"\$") if RAW_MATH else s

plt.figure()
plt.xlabel(_m("Just some text"))
plt.ylabel(_m("Local error $\sum_{d=1}^D \| u_d - \hat{u} \|^2$"))
plt.plot([1,2,3],label=_m('$x(\ce{CH4}) = \SI{1e16}{cm^{-3}}$'))
plt.legend()
plt.show()

@AJJLagerweij
Copy link

AJJLagerweij commented Mar 11, 2021

From what I understand, the question was answered and a workaround found. Can it be closed?

On a separate note, would it be interesting to open another discussion about workflows for matplotlib and latex. Not with the intention to make changes in matplotlib, but with the following goals:

  1. How do people use it (different workflows for probably different reasons),
  2. Drawbacks and benefits to the different approaches,

This could inform users and help them to improve their reports/publications. Where should such a discussion take place?

@jklymak
Copy link
Member

jklymak commented Mar 11, 2021

https://discourse.matplotlib.org is a great place to discuss this.

I think we will close this, because if I understand correctly, toggling this will lead to bad outcomes with the size of labels being mis-interpreted. So enabling this as a feature will leave us open to a lot of complaints if folks don't understand the drawbacks. The workaround above for those who really need to toggle this seems OK to me. But of course anyone can request a re-open, or make a PR that implements this anyways

@jklymak jklymak closed this as completed Mar 11, 2021
@spillz
Copy link

spillz commented Apr 22, 2022

The workaround is really inconvenient for plotting from third party libs like pandas. I read from databases into dataframes and the column names include liberal use of characters in database fields that get interpreted as mathtex (e.g. some of these column names include multiple $ signs) and I just want clean text output of those columns names in my chart legends. To do that on my side, I'm going to have to wrap all my DB API calls with string escaping. An rcParam would be far simpler.

@jklymak
Copy link
Member

jklymak commented Apr 22, 2022

@spillz Please open a new issue.

@oscargus
Copy link
Member

@spillz There will be one in 3.6: #22556

@tacaswell tacaswell modified the milestones: needs sorting, v3.6.0 Apr 22, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests