3

I am trying to include PGF figures from files (in my case created by matplotlib) and combine them with the TikZ-externalizing workflow.

The benefit of including PGF figures in the first place is that text such as labels, legends, etc are rendered using the font settings of the including .tex file. The benefit of using tikzexternalize is that during tex-compilation PDFs of the tikz figures are created so that (a) the time consuming "building" of the tikz figures need to be done only once and (b) the, e.g., publisher only needs to ever see and use the PDF versions of the tikz figures (they typically don't have a full tikz version installed).

I understand that PGF is a somewhat lower-level framework upon which tikz is built and which might cause some problems. Nonetheless, the pgf-manual seems to hint that the above described process should, in principle, be possible. As this questions has been asked before (Externalize pgfpicture) but was closed without a solution, I'd like to post a MWE and initiate a discussion :smile:

\documentclass{article}
\usepackage{filecontents}
\usepackage{tikz}

\begin{filecontents*}{img.pgf}
    \begingroup%
        \makeatletter%
        \begin{pgfpicture}%
            \pgfpathrectangle{\pgfpointorigin}{\pgfqpoint{3cm}{2cm}}%
            \pgfusepath{use as bounding box, clip}%
            \begin{pgfscope}%
                \pgfpathmoveto{\pgfpointorigin}%
                \pgfpathlineto{\pgfpoint{2cm}{2cm}}%
                \pgfusepath{stroke}%
            \pgftext[x=1cm,y=1cm]{\color{red}\large\selectfont 123456789}%
            \end{pgfscope}%
        \end{pgfpicture}%
        \makeatother%
    \endgroup%
\end{filecontents*}


\usetikzlibrary{external}
\tikzexternalize[mode=list and make]


\begin{document}%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    The first version is based on a simple tikz text and drawing and works OK:

    \begin{figure}[h]
        \centering
        \begin{tikzpicture}
            \draw[thick,rounded corners=8pt] (0,0) -- (2,2);
            \node at (1,1){\color{red}\large\selectfont 123456789};
        \end{tikzpicture}
        \caption{... using tikz}
    \end{figure}

    \vspace{4em}

    The second version uses the pgf file that was written using \texttt{filecontents}:

    \begin{figure}[h]
        \centering
        % uncomment the tikzpicture environment for using "externalizing"
        %\begin{tikzpicture}
            \input{img.pgf}
        %\end{tikzpicture}
        \caption{... using a PGF image}
    \end{figure}
\end{document}%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

Copy the code into a file mwe.tex and then compile it with

  1. pdflatex -shell-escape mwe.tex
  2. make -f mwe.makefile
  3. pdflatex -shell-escape mwe.tex.

This has created the file one.pdf that for all further compilation runs will be directly included instead of compiling the tikzpicture. The PDFs mwe.pdf also shows that the included PGF figure looks ok. However, when you un-comment the tikzpicture environment for the second figure and error occurs during make -f mwe.makefile:

(./img.pgf
! TeX capacity exceeded, sorry [input stack size=5000].
\pgf@selectfontorig ->\pgf@selectfontorig 
                                          \nullfont 
l.10 ...   \pgftext[x=1cm,y=1cm]{\color{red}\large
                                                  \selectfont 123456789}% 

Now, the question would be, how to fix this problem -- or how to adjust the whole workflow without manually changing/replacing code or files? Thanks!

2 Answers 2

2

UPDATE after follow-up. Create two pdf figures with externalize.

I will share my setup and its outcome. (Using MiKTeX and windows)

(1) Create a subdirectory FIGURES in the working directory.

(2) Add to your preamble

% **********************************************************
\tikzexternalize[%
up to date check={simple},
prefix=./FIGURES/]% Folder needs to be created before compiling

\tikzset{external/system call={%
        pdflatex \tikzexternalcheckshellescape
        -halt-on-error -shell-escape -interaction=batchmode
        -jobname "\image" "\texsource"}}
% **********************************************************

(3) Run

pdflatex.exe -synctex=1 -interaction=nonstopmode -shell-escape MWE.tex

(4) This is the tree of files after the run. In my system it runs twice as

pdflatex: security risk: running with elevated privileges This is pdfTeX, Version 3.141592653-2.6-1.40.22 (MiKTeX 21.3)

The first time reporting

===== 'mode=convert with system call': Invoking 'pdflatex -shell-escape -halt-on-error -shell-escape -interaction=batchmode -jobname "./FIG
URES/MWE-figure0" "\def\tikzexternalrealjob{MWE}\input{MWE}"' ========
(img.tex
pdflatex: security risk: running with elevated privileges
This is pdfTeX, Version 3.141592653-2.6-1.40.22 (MiKTeX 21.3)
entering extended mode
===== 'mode=convert with system call': Invoking 'pdflatex -shell-escape -halt-on-error -shell-escape -interaction=batchmode -jobname "./FIG
URES/MWE-figure1" "\def\tikzexternalrealjob{MWE}\input{MWE}"' ========
)

and the second time

===== Image './FIGURES/MWE-figure0' is up-to-date. ======
(img.tex
===== Image './FIGURES/MWE-figure1' is up-to-date. ======
)

x

(5) And this is the output.

z

(6) This is the file MWE.tex

    %%% File MWE.tex

% !TeX TS-program = pdflatex

\documentclass{article}
%%\usepackage{filecontents} % not needed anymore <<<<
\usepackage{tikz}   
\usetikzlibrary{external}

\begin{filecontents*}[overwrite]{img}
            \pgfpathrectangle{\pgfpointorigin}{\pgfqpoint{3cm}{2cm}}%
            \pgfusepath{use as bounding box, clip}%
            \begin{pgfscope}%
                \pgfpathmoveto{\pgfpointorigin}%
                \pgfpathlineto{\pgfpoint{2cm}{2cm}}%
                \pgfusepath{stroke}%
                \pgftext[x=1cm,y=1cm]{\color{red}\large\selectfont 123456789P}%
            \end{pgfscope}% 
\end{filecontents*}

% ********************************************************** added <<<<<<<<<<<<<<<<<<<<<<<
\tikzexternalize[%
up to date check={simple},
prefix=./FIGURES/]% Folder needs to be created before compiling

\tikzset{external/system call={%
        pdflatex \tikzexternalcheckshellescape
        -halt-on-error -shell-escape -interaction=batchmode
        -jobname "\image" "\texsource"}}
% **********************************************************

\begin{document}%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    The first version is based on a simple tikz text and drawing and works OK:
    
    \begin{figure}[h]
        \centering
        \begin{tikzpicture}
            \draw[thick,rounded corners=8pt] (0,0) -- (2,2);
            \node at (1,1){\color{red}\large\selectfont 123456789T};
        \end{tikzpicture}
        \caption{... using tikz}
    \end{figure}
    
    \vspace{4em}
    
    The second version uses the pgf file that was written using \texttt{filecontents}:
    
    \begin{figure}[h]
        \centering  
        \begin{tikzpicture}     
            \input{img} % PGF file from matplotli
        \end{tikzpicture}
        \caption{... using a PGF image}
    \end{figure}

\end{document}%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5
  • Thanks for you reply! In a way, this worked also before (even though I had to do one extra "make-run" which you nicely replaced by the \tikzset{external/system call=..}. But for the second figure, no PDF in figures was created. And when you uncomment the tikzpicture (see my mwe.tex) then you also get an error. In an ideal world, we would have one PDF for each of the images in the figure directory. Please let me know if you have any ideas about that or if I need to clarify something. Thanks!
    – BanDoP
    Commented Feb 16, 2022 at 12:58
  • @BanDoP You need \begin{tikzpicture} and \end{tikzpicture} in the created file or in the code in order to externalize to work. Please see the updated answer and code. Commented Feb 16, 2022 at 15:18
  • @BanDoP In your code only the tikx picture gets externalized. Use different contents to see what goes where. Commented Feb 16, 2022 at 15:32
  • Excellent! Could you move the \begin{tikzpicture}/\end{tikzpicture} back into the MWE.tex in your above answer? This is then the perfect solution (as the PGF file from matplotlib does not contain the tikz env.). Thanks a lot!
    – BanDoP
    Commented Feb 16, 2022 at 17:20
  • 1
    @BanDoP Done! The output is the same of course. Thank you for your feedback. Commented Feb 16, 2022 at 17:38
5

The error comes from having a pgfpicture environment inside a tikzpicture environment. Luckily, you can circumvent this by defining a node, i.e.

\begin{tikzpicture}
  \node {\input{img}};
\end{tikzpicture}

Everything should compile nicely then. You can automate this, remove the extra padding, and improve the externalized filenames with this command:

\newcommand{\inputpgf}[1]{%
  \tikzsetnextfilename{#1}%
  \begin{tikzpicture}%
  \node[inner sep=0pt] {\input{#1.pgf}};
  \end{tikzpicture}
}

Then you can import and externalize an img.pgf image via \inputpgf{img}. If the img.pgf is in some subdirectory you can use the import package to circumvent changing paths within the file:

\newcommand{\importpgf}[2]{%
  \tikzsetnextfilename{#1/#2}%
  \begin{tikzpicture}%
  \node[inner sep=0pt] {\import{#1}{#2.pgf}};
  \end{tikzpicture}
}

You can import and externalize an figures/img.pgf image via \importpgf{figures}{img}.

Note that almost all changes in Simon Dispa' answer are tangential. The only relevant suggestion is removing the pgfpicture environment from the img.tex file. But that would mean editing the matplotlib output, which is rather tedious and doesn't seem desired.

3
  • If the pgfpicture is located in figures/some.pgf and references figures/some.png using \includegraphics[]{some.png} so that it would normally be included as \import{figures}{some.pgf}, how would I update your \inputpgf?
    – user19087
    Commented May 15, 2022 at 0:27
  • First, it works with both \input and \import which is amazing. Second, you need \node[inner sep=0pt] to remove extra padding, as well as \begin{tikzpicture}% (notice the extra % at the end) to remove the trailing space which causes a horizontal shift.
    – user19087
    Commented May 15, 2022 at 1:31
  • Thank you for the suggestions! I've updated the answer to include these points. Commented May 16, 2022 at 12:02

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .