Search code examples
pythonmatplotliblatextikz

tikzpicture cropped from `.dvi` when used in matplotlib.plt.text()


Disclaimer: I fully understand that the use of text.latex.preamble in rcparams is not officially supported by matploltib.

Note: the same question was posted on the matplotlib discourse "Community" page. I re-post it here to reach, hopefully, a wider "LaTeX/tikz audience".

Dear hive mind,

I need/want to use the tikz LaTeX package to draw symbols in matplotlib plt.text() calls. It all works smoothly (in the sense that I get no LaTeX/matplotlib errors) ... except that no symbols are actually drawn on the figures ?!

Here is a MWE:

from matplotlib import pyplot as plt

plt.style.use('./latex.mplstyle')

plt.close(1)
plt.figure(1, figsize=(4, 3))
plt.text(0.5, 0.7, r'This is regular text', ha='center', va='center')
plt.text(0.5, 0.5, r'$\rightarrow$ \begin{tikzpicture}\draw [thick] (0,0) circle [radius=2ex];\end{tikzpicture}', ha='center', va='center')
plt.savefig('test.png')
plt.show()

The content of latex.mplstyle is:

text.usetex: True
text.latex.preamble: \usepackage{tikz}

The output looks like that:

demo plot

Problem: there should be a circle to the right of the arrow.

So what could matplotlib be doing differently compared to pdflatex that returns the following image:

LaTeX demo

when processing the following (same) LaTeX code:

\documentclass[11pt]{article}

\usepackage{tikz}

\begin{document}

$\rightarrow$ \begin{tikzpicture}\draw [thick] (0,0) circle [radius=2ex];\end{tikzpicture}

\end{document}

The tikz package is definitely being loaded correctly, as the \tikzpicture command does not raise any error when compiling the matplotlib figure.

Side-note 1: as far as I can tell, the same behavior implies that symbols from the tikzsymbols LaTeX package do not appear either in plt.text() calls.

Side-note 2: I evidently need to draw more (but not THAT much more) than a circle with tikz ... That's just the MWE!

Edit (after some digging thanks to @samcarter_is_at_topanswers.xyz suggestions)

It turns out that the .dvi files generated by LaTeX look as expected. However, these seemingly get cropped before being ingested by the matplotlib figure. Whatever is doing this cropping does not seem aware of the tikzpicture existence. Here's a picture with what I see in the .dvi, on-screen, in the .png, and in the .pdf from matplotlib:

enter image description here

So the question becomes:

What mechanism is responsible for inserting the LaTeX .dvi inside the matplotlib figure, and why isn't it aware of the \tikzpicture existence ?

and, possibly:

Could I put the \tikzpicture inside some sort of LaTeX bounding box to have it become visible to matplotlib ?


Solution

  • See this Matplotlib's discourse question for the full thread leading to the following answer

    Cause: Matplotlib requires font metrics like the baseline, ascends and descends to include text. The \tikzpicture does not provide any, and so it is not taken into account in the crop of the dvi.

    Solution/work-around: Use the pgf backend to export the figure to pdf and/or png format, i.e.: plt.savefig(..., backend='pgf')

    This method can also successfully handle the inclusion of items from the tiksymbols LaTeX package. However, it does not allow to display these elements on-screen.