TikZ-externalizing a PGF image (e.g. from matplotlib)

externalizegraphicspgfplotstikz-externaltikz-pgf

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 🙂

\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!

Best Answer

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}%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%