1

I'm using this macro to scale my pgfplots to a desired size:

\newsavebox{\measuredSize}
\newcounter{int}
\newcommand{\resizeToMeasure}[3]{%
    \pgfmathsetmacro{\pgfplotswidthtarget}{#2}%
    \pgfmathsetmacro{\pgfplotswidth}{#2}%
    \pgfmathsetmacro{\pgfplotsheighttarget}{#3}%
    \pgfmathsetmacro{\pgfplotsheight}{#3}%
    \setcounter{int}{1}%
    \loop%
    \addtocounter{int}{1}%
    \begin{lrbox}{\measuredSize}%
    \tikzset{external/export next=false,external/optimize=false}%
    \input{#1}%
    \end{lrbox}%
    \pgfmathsetmacro{\pgfplotswidth}{\pgfplotswidth+\pgfplotswidthtarget-\wd\measuredSize}%
    \pgfmathsetmacro{\pgfplotsheight}{\pgfplotsheight+\pgfplotsheighttarget-\ht\measuredSize}%
    \ifnum \value{int}<\nIter
    \repeat
    \filename@parse{#1}
    \tikzsetnextfilename{\filename@base}
    \input{#1}}

However, when recompling without making changes to a pgfplots file I don't want to loop over that file again but just use the created pdf from the external library. So I thought it would be a nice idea to make a manual check for that file and omit the loop once the file is up to date. In the library source code I found that \def\tikzexternal@externalizefig@systemcall@uptodatecheck#1 makes that check and takes the content of the tikzpicture as the argument #1. Now my problem is, I cannot find out how the library reads the tikzpicture to put it in that function.

Here's a MWE:

\documentclass{standalone}
\usepackage{tikz}
\usepackage{pgfplots}
\pgfplotsset{compat=newest}
\usepackage{filecontents}
\usetikzlibrary{external}

\makeatletter \newsavebox{\measuredSize} \newcounter{int} \newcommand{\resizeToMeasure}[3]{% \pgfmathsetmacro{\pgfplotswidthtarget}{#2}% \pgfmathsetmacro{\pgfplotswidth}{#2}% \pgfmathsetmacro{\pgfplotsheighttarget}{#3}% \pgfmathsetmacro{\pgfplotsheight}{#3}% \setcounter{int}{1}% \loop% \addtocounter{int}{1}% \begin{lrbox}{\measuredSize}% \tikzset{external/export next=false,external/optimize=false}% \input{#1}% \end{lrbox}% \pgfmathsetmacro{\pgfplotswidth}{\pgfplotswidth+\pgfplotswidthtarget-\wd\measuredSize}% \pgfmathsetmacro{\pgfplotsheight}{\pgfplotsheight+\pgfplotsheighttarget-\ht\measuredSize}% \ifnum \value{int}<5 \repeat \filename@parse{#1} \tikzsetnextfilename{\filename@base} \input{#1}} \makeatother

\begin{document}

\begin{filecontents}{tikzpicture01.tikz} \begin{tikzpicture} \begin{axis}[ height=\pgfplotsheight, width=\pgfplotswidth ] \addplot coordinates { ( 1.5, 1.28 ) ( 1.75, 1.43 ) ( 2.0, 1.59 ) ( 2.25, 1.75 ) ( 2.5, 1.91 ) ( 2.75, 2.07 ) ( 3.0, 2.23 ) }; \end{axis} \end{tikzpicture} \end{filecontents}

\resizeToMeasure{tikzpicture01.tikz}{7cm}{7cm}

\end{document}

  • I don't really understand what you are doing. Could you please give a complete minimal example? – pschulz Jul 09 '23 at 20:00
  • @pschulz: Thanks for that hint, I added a MWE. – ValenStein Jul 09 '23 at 20:22
  • Thank you. Unfortunately, I don't really get why you are doing this. Could you elaborate on this? If I understand correctly, you don't want to rely on the scaling mechanism of pgfplots, which could cause the pictures size to slightly vary. Is this correct? If yes, then I believe there are better and simpler methods to do this. I'm happy to expand on this, I have some strategies that I use, that I found to be quite effecitve. – pschulz Jul 10 '23 at 03:16
  • Have a look at this: https://tex.stackexchange.com/questions/36297/pgfplots-how-can-i-scale-to-text-width/56473#56473. Unfortunately, tikzscale doesnt work for my needs... – ValenStein Jul 10 '23 at 07:39
  • Thank you for the link. I can't answer your question, but you might consider if this is really worth it. Personally, I don't care too much if the picture actually fits the textwidth perfectly, I care more about consistency across figures. I mostly write scientific papers in a two-column format, there I want all plots to have the same axis size and alignment. I place the ylabels at a fixed location, adjust the width so that figures roughly fit the column and then placed them \raggedleft with a little fixed space from the right yaxis. – pschulz Jul 10 '23 at 16:43

1 Answers1

0

Ok, I figured out a solution how to make that manual up-to-date check. Unfortunately, I couldn't find a way to use the interal macros from the external library but therefore wrote my own macro \make@uptodate@check that is very similar to the ones used in the package.

    \def\make@uptodate@check#1{
    \def\scanText{}%
    \def\name@tikzpicture{tikzpicture}%
    \CatchFileDef{\myTikz}{#1}{}%
    \long\def\collect@tikz@from@begin##1\begin##2{%
        \def\name@environment@begin{##2}%
        \ifx\name@environment@begin\name@tikzpicture%
            \expandafter\collect@tikz@after@begin%
        \else%
            \expandafter\collect@tikz@from@begin%
        \fi%
    }
    \long\def\collect@tikz@after@begin##1\end##2{%
        \def\name@environment@end{##2}%
        \ifx\name@tikzpicture\name@environment@end%
            \g@addto@macro\scanText{##1}
        \else%
            \g@addto@macro\scanText{##1\end{##2}}%
            \expandafter\collect@tikz@after@begin%
        \fi%
    }
    \expandafter\collect@tikz@from@begin\myTikz
    \filename@parse{#1}%
    \tikzsetnextfilename{\filename@base}%
    \expandafter\tikzexternal@check@uptodate@mode\expandafter{\scanText}%
    }

For checking if the picture has to be updated, it extracts the content from the tikzpicture environment and passes it to \tikzexternal@check@uptodate@mode from the external library which also updates \tikzexternal@file@isuptodate. Then in resizeToMeasure it checks if the file is up-to-date to skip the for loop and directly insert the pdf file.

Here is a full MWE:

    \documentclass{article}
    \usepackage{tikz}
    \usepackage{catchfile}
    \usepackage{pgfplots}
    \usetikzlibrary{external} %
    \tikzexternalize
\makeatletter
\def\make@uptodate@check#1{
    \def\scanText{}%
    \def\name@tikzpicture{tikzpicture}%
    \CatchFileDef{\myTikz}{#1}{}%
    \long\def\collect@tikz@from@begin##1\begin##2{%
        \def\name@environment@begin{##2}%
        \ifx\name@environment@begin\name@tikzpicture%
            \expandafter\collect@tikz@after@begin%
        \else%
            \expandafter\collect@tikz@from@begin%
        \fi%
    }
    \long\def\collect@tikz@after@begin##1\end##2{%
        \def\name@environment@end{##2}%
        \ifx\name@tikzpicture\name@environment@end%
            \g@addto@macro\scanText{##1}
        \else%
            \g@addto@macro\scanText{##1\end{##2}}%
            \expandafter\collect@tikz@after@begin%
        \fi%
    }
    \expandafter\collect@tikz@from@begin\myTikz
    \filename@parse{#1}%
    \def\tikzexternal@curfilename{\tikzexternal@filenameprefix\filename@base}%
\expandafter\tikzexternal@check@uptodate@mode\expandafter{\scanText}%
}

\def\pgfmathsetglobalmacro#1#2{\pgfmathparse{#2}%
\global\let#1\pgfmathresult}

\newsavebox{\measuredSize}
\newcounter{int}
\newcommand{\resizeToMeasure}[3]{%
\pgfmathsetglobalmacro{\pgfplotswidthtarget}{#2}%
         \pgfmathsetglobalmacro{\pgfplotswidth}{#2}%
         \pgfmathsetglobalmacro{\pgfplotsheighttarget}{#3}%
         \pgfmathsetglobalmacro{\pgfplotsheight}{#3}%
    \make@uptodate@check{#1}%
    \filename@parse{#1}%
    \iftikzexternal@file@isuptodate%
        \typeout{File is up to date! No loop needed!}%
        \tikzsetnextfilename{\filename@base}
        \input{#1}%
    \else%
        \typeout{Update File!}%
         \setcounter{int}{1}
         \loop
         \typeout{1}
         \addtocounter{int}{1}
         \begin{lrbox}{\measuredSize}\tikzset{external/export next=false,external/optimize=false}\input{#1}\end{lrbox}%
         \typeout{2}
         \pgfmathsetglobalmacro{\pgfplotswidth}{\pgfplotswidth+\pgfplotswidthtarget-\wd\measuredSize}%
         \pgfmathsetglobalmacro{\pgfplotsheight}{\pgfplotsheight+\pgfplotsheighttarget-\ht\measuredSize}%
         \typeout{3}
         \ifnum \value{int}&lt;3%
         \repeat%
         \tikzset{external/force remake}
         \tikzsetnextfilename{\filename@base}
         \input{#1}%
     \fi%
}

\makeatother
\begin{document}

\begin{filecontents*}{tikzpicture01.tikz}
\begin{tikzpicture}
\begin{axis}[
height=\pgfplotsheight,
width=\pgfplotswidth
]
\addplot coordinates {
    ( 1.5, 1.28 )
    ( 1.75, 1.43 )
    ( 2.0, 1.59 )
    ( 2.25, 1.75 )
    ( 2.5, 1.91 )
    ( 2.75, 2.07 )
    ( 3.0, 2.23 )
};
\end{axis}
\end{tikzpicture}
\end{filecontents*}

\resizeToMeasure{tikzpicture01.tikz}{7cm}{7cm}

\end{document}