12

I have a two-dimensional image plotted by Matplotlib using the PGF backend. It is stored in the figures subdirectory (since I have a lot of images and don't want to clutter up the main folder). As an example of the generation process:

from matplotlib import pyplot as plt
import numpy as np

plt.imshow(np.random.randn(200, 200))
plt.title('Some random data')
plt.savefig('figures/test.pgf')

The figures subdirectory now contains test.pgf and the raster image test-img0.png. The PGF file includes the command \pgfimage[interpolate=true,width=4.810000in,height=4.810000in]{test-img0.png}} to include the PNG. Since it (by design) does not contain the figures/ prefix, I need to find a workaround. According to a comment at a top of the PGF file (and backed up by this comment on the Matplotlib issue tracker) I can use the import package to make things work:

\documentclass{article}

\usepackage[margin=2cm]{geometry}
\usepackage{import}
\usepackage{pgf}

\begin{document}

\begin{figure}
\begin{center}
\import{figures/}{test.pgf}
\end{center}
\end{figure}

\end{document}

When I compile this (xelatex test), I get the message

Package pgf Warning: File "test-img0.png" not found when defining image "pgflastimage".
(pgf) Tried all extensions in ".pdf:.jpg:.jpeg:.png:" on input line 62.

The PGF file is found, so the resulting PDF has the axes, title etc, but just a placeholder instead of the PNG.

I also tried defining \graphicspath{{figures/}} but PGF doesn't seem to use that either.

Adding the figures directory to the TEXINPUTS environment variable prior to compiling works, but it isn't the cleanest workaround. I could also edit the PGF file to include the path, but I'd have to do that every time I regenerate the image. Can anybody suggest why import isn't working, or an alternative method?

Blair
  • 366

4 Answers4

12

For a more general workaround, in the case where you have multiple figure subfolders, you can define a new command which includes a localized redefinition:

\newcommand\inputpgf[2]{{
\let\pgfimageWithoutPath\pgfimage
\renewcommand{\pgfimage}[2][]{\pgfimageWithoutPath[##1]{#1/##2}}
\input{#1/#2}
}}

You then simply use it like so:

\inputpgf{path/to/figures}{figure.pgf}

The first argument specifies the local folder from which all image files for that figure will be included, and the second argument is just the filename of the PGF file.

Like the previous answer, this redefines the \pgfimage command, but only for the execution of the input command.

arthaigo
  • 135
glopes
  • 355
10

Quick answer

Since the command that imports the png files inside the pgf image is pgfimage, I redefined it like this:

\let\pgfimageWithoutPath\pgfimage 
\renewcommand{\pgfimage}[2][]{\pgfimageWithoutPath[#1]{figures/#2}}

The first line copies the original pgfimage command to a temporary pgfimageWithoutPath. The second line redefines pgfimage to be the same as pgfimage, but prefixing the path with figures/.

Read below for more details

I actually use the chapterfolder package, which allows me to split the document into subfolders, one per chapter. It's very cool for long documents but needs a workaround for importing the figures, exactly the same problem that you had. So in the end my importing for pgfs works like this:

  1. This is the same as above, but using chapterfolders' directives.

    \let\pgfimageWithoutCF\pgfimage
    \renewcommand{\pgfimage}[2][]{\pgfimageWithoutCF[#1]{\cfcurrentfolder\subfigurepath#2}}
    
  2. This is a wrapper to \input{figure.pgf}, which includes the chapter path:

    \newcommand{\includepgf}[1]{\input{\cfcurrentfolder\subfigurepath#1.pgf}}
    
  3. And finally this is a shortcut to make the figure fit exactly the width of the text (to be used like

    % usage: \resizepgf[<optional size (defaults to textwidth)>]{<filename>}
    \newcommand{\resizepgf}[2][\textwidth]{
        \resizebox{#1}{!}{\includepgf{#2}}
    }
    

Thanks to jevopi's little blog for the how-to.

gozzilli
  • 1,594
  • 3
  • 12
  • 15
  • Great, thanks. The chapterfolder example is also really useful -- finding something like this to break up my thesis is on my list of things to do :). – Blair Sep 02 '13 at 03:29
3

The solution is written in the output .pgf file.

From other directories you can use the import package

\usepackage{import}

and then include the figures with:

\import{<path to file>}{<filename>.pgf}
G M
  • 2,225
3

While glopes' answer worked fine for me several months ago, it just broke when trying to use a newly generated figure, probably due to a matplotlib update, which now uses \includegraphics internally inside my PGF file instead of \pgfimage. To also apply the fix to this command, we need to expand the \inputpgf definition as follows:

\newcommand\inputpgf[2]{{
\let\pgfimageWithoutPath\pgfimage
\renewcommand{\pgfimage}[2][]{\pgfimageWithoutPath[##1]{#1/##2}}
\let\includegraphicsWithoutPath\includegraphics
\renewcommand{\includegraphics}[2][]{\includegraphicsWithoutPath[##1]{#1/##2}}
\input{#1/#2}
}}

which works for me in a document using both old and new PGF files.