1

I'm using tikz external to get plots rendered faster. But legends in the plots are missing if external is used.

Update: I'm using label to create legend. The same issue does not occur if \legend is used. I wanted to use label as it gives me more flexibility in groupplot. See question PGFplots - single legend in a group plot

main file

\documentclass{article}
\usepackage{tikz}
\usepackage{pgfplots}
\usetikzlibrary{pgfplots.groupplots,external}
\tikzexternalize[prefix=tikz/]
\tikzset{external/force remake}
\begin{document}
\begin{figure}
    \input{sample.tikz}         % input TiKZ figure code
    \caption{legends missing in tikz external}  % caption
    \label{fig:sample}              % label
\end{figure}
\end{document}

sample.tikz

% Style to select only points from #1 to #2 (inclusive)
\pgfplotsset
{
    select coords between index/.style 2 args=
    {
        x filter/.code=
        {
                \ifnum\coordindex<#1\def\pgfmathresult{}\fi
                \ifnum\coordindex>#2\def\pgfmathresult{}\fi
        }
    }
}
\begin{tikzpicture}
    \begin{groupplot}[group style={group size= 2 by 1},height=4cm,width=4cm,max space between ticks=20,minor tick num=1,tick label style={font=\footnotesize}]
        \nextgroupplot[title={2K},xtick=data]
                \addplot[blue,dotted,mark=asterisk]         [select coords between index={0}{4}] table[x=threads,y=foo-MOPS,col sep=space]{Data/mic/threadSweep.csv};       \label{plots:foo:cka}
                \addplot[green, dotted,mark=o]              [select coords between index={0}{4}] table[x=threads,y=bar-MOPS,col sep=space]{Data/mic/threadSweep.csv};       \label{plots:bar:cka}
                \coordinate (top) at (rel axis cs:0,1);% coordinate at top of the first plot
        \nextgroupplot[title={20K} ,xtick=data] 
                \addplot[blue,dotted,mark=asterisk]         [select coords between index={5}{9}] table[x=threads,y=foo-MOPS,col sep=space]{Data/mic/threadSweep.csv};  
                \addplot[green, dotted,mark=o]              [select coords between index={5}{9}] table[x=threads,y=bar-MOPS,col sep=space]{Data/mic/threadSweep.csv}; 
                \coordinate (bot) at (rel axis cs:1,0);% coordinate at bottom of the last plot
\end{groupplot}
    \path (top-|current bounding box.west)-- node[anchor=south,rotate=90] {\small system throughput} (bot-|current bounding box.west);
    \path (top|-current bounding box.north)-- coordinate(legendpos) (bot|-current bounding box.north);
    \matrix[matrix of nodes, anchor=south, draw, inner sep=0.2em, draw] at ([yshift=1ex]legendpos)
    {
        \ref{plots:foo:cka}&    foo         & [5pt]
        \ref{plots:bar:cka}&    bar         \\
    };
\end{tikzpicture}

output enter image description here

  • 1
    We do not have your threadSweep.csv. – esdd Dec 13 '15 at 12:55
2

You can use a patch suggested by Ijon Tichy on TeXwelt (German) to externalize a tikzpicture using \label and \ref for the legend.

The following example is from PGFplots - single legend in a group plot because I do not have the threadSweep.csv.

\documentclass[margin=5mm]{standalone}
\usepackage{pgfplots}
\usetikzlibrary{matrix}
\usepgfplotslibrary{groupplots}
\pgfplotsset{compat=newest}

\usepgfplotslibrary{external}
\tikzexternalize
\tikzsetexternalprefix{external_figs/}
\tikzset{external/up to date check=md5}% < added

%%% %http://texwelt.de/wissen/fragen/9476/labels-an-pgfplots/9527 (by Ijon Tichy)
\usepackage{scrlfile}
\usepackage{etoolbox}
\makeatletter
\newif\if@lateexternal
\newcommand*{\nextwithlateexternal}{\@lateexternaltrue}
\renewcommand*{\@lateexternalfalse}{\global\let\if@lateexternal\iffalse}
% Den Systemaufruf von external so ändern, dass er optional doppelt
% stattfindet: Zunächst wie gehabt unmittelbar und zusätzlich nachdem
% die aux-Datei geschlossen (und sogar neu gelesen) wurde.
\patchcmd\tikzexternal@externalizefig@systemcall@@
  {\immediate\write18{\pgf@tempa}}%
  {\immediate\write18{\pgf@tempa}%
    \if@lateexternal
      \begingroup
        \protected@edef\reserved@a{%
          \noexpand\endgroup
          \noexpand\AfterReadingMainAux{%
            \noexpand\immediate\noexpand\write18{%
              \expandafter\detokenize\expandafter{\pgf@tempa}}%
          }%
        }%
      \reserved@a
    \fi
  }%
  {}%
  {\patchFailedError}
% Nun dafür sorgen, dass der Aufruf \nextwithlateexternal nur auf
% den nächsten potentiellen Systemaufruf von external wirkt statt
% auf den nächsten tatsächlichen oder gar alle:
\apptocmd\tikzexternal@externalizefig@systemcall@@
  {\@lateexternalfalse}
  {}
  {\patchFailedError}
\makeatother
%%%


\begin{document}

\nextwithlateexternal% < added
\begin{tikzpicture}
    \begin{groupplot}[group style={group size= 2 by 4},height=5cm,width=6.4cm]
        \nextgroupplot[title=type1,ylabel={Range1 }]
                \addplot[blue] {x};\label{plots:plot1}
                \addplot[red] {x^2};\label{plots:plot2}
                \addplot[green] {2*x};\label{plots:plot3}
                \coordinate (top) at (rel axis cs:0,1);% coordinate at top of the first plot
        \nextgroupplot[title=type2]
                \addplot[blue]{x};
        \nextgroupplot[ylabel={Range2 }]
                \addplot[blue]{x};
        \nextgroupplot
                \addplot[blue]{x};
        \nextgroupplot[ylabel={Range3 }]
                \addplot[blue]{x};
        \nextgroupplot
                \addplot[blue]{x};
        \nextgroupplot[xlabel={Number of Threads},ylabel={Range4 }]
                \addplot[blue]{x};
        \nextgroupplot[xlabel={Number of Threads}]
                \addplot[blue]{x};
                \coordinate (bot) at (rel axis cs:1,0);% coordinate at bottom of the last plot
    \end{groupplot}
    \path (top-|current bounding box.west)-- 
          node[anchor=south,rotate=90] {throughput} 
          (bot-|current bounding box.west);
% legend
\path (top|-current bounding box.north)--
      coordinate(legendpos)
      (bot|-current bounding box.north);
\matrix[
    matrix of nodes,
    anchor=south,
    draw,
    inner sep=0.2em,
    draw
  ]at([yshift=1ex]legendpos)
  {
    \ref{plots:plot1}& curve 1&[5pt]
    \ref{plots:plot2}& curve2&[5pt]
    \ref{plots:plot3}& curve 3\\};
\end{tikzpicture}
\end{document}

Run twice.

Note: AFAIK this does not work with latexmk. And \tikzset{external/force remake} could only be used in the first run.

2

In the meantime (with the external library of PGFPlots v1.14) it is sufficient to compile the following MWE twice to get the desired result ...

(I just deleted the middle two rows of plots in the MWE to save some space.)

\documentclass{article}
\usepackage{pgfplots}
    \usetikzlibrary{
        matrix,
        pgfplots.external,
        pgfplots.groupplots,
    }
    \pgfplotsset{compat=1.3}
    \tikzexternalize
\begin{document}
    \begin{tikzpicture}
        \begin{groupplot}[
            group style={
                group size= 2 by 2,
            },
            height=5cm,
            width=6.4cm,
        ]
        \nextgroupplot[title=type1,ylabel={Range1 }]
            \addplot[blue] {x};\label{plots:plot1}
            \addplot[red] {x^2};\label{plots:plot2}
            \addplot[green] {2*x};\label{plots:plot3}
            \coordinate (top) at (rel axis cs:0,1);% coordinate at top of the first plot
        \nextgroupplot[title=type2]
            \addplot[blue]{x};
        \nextgroupplot[xlabel={Number of Threads},ylabel={Range4 }]
            \addplot[blue]{x};
        \nextgroupplot[xlabel={Number of Threads}]
            \addplot[blue]{x};
            \coordinate (bot) at (rel axis cs:1,0);% coordinate at bottom of the last plot
        \end{groupplot}
        \path (top-|current bounding box.west)--
              node[anchor=south,rotate=90] {throughput}
              (bot-|current bounding box.west);
        % legend
        \path (top|-current bounding box.north)--
              coordinate(legendpos)
              (bot|-current bounding box.north);
        \matrix[
            matrix of nodes,
            anchor=south,
            draw,
            inner sep=0.2em,
        ] at ([yshift=1ex]legendpos) {
            \ref{plots:plot1}& curve 1&[5pt]
            \ref{plots:plot2}& curve2&[5pt]
            \ref{plots:plot3}& curve 3\\
        };
    \end{tikzpicture}
\end{document}

image showing the result of above code without whitespace

  • I used part of this answer to answer a question which (currently) has an open bounty. Since it originally is your code, if you would like to add an answer there too, I could delete mine. – Max Aug 23 '18 at 21:28
  • @Max, it is perfectly fine for me if you get the bounty :) – Stefan Pinnow Aug 24 '18 at 4:31
1

You need to read the notes on use of \label and \ref in the pgfplots manual's section on externalisation. (Section 7.1 in my copy.)

You cannot use the default mode if you wish to combine these with externalisation. You need to use one of the available alternatives.

From page 473 of the pgfplots manual:

For point a), a \ref inside of an externalized graphics works only if you issue the required system call manually or by make. The initial configuration mode=convert with system call does not support \ref. But you can copy–paste the system call generated by mode=convert with system call and issue it manually. The reason is that \ref information is stored in the main .aux file – but this auxiliary file is not completely written when mode=convert with system call is invoked (there is a race condition). Note that \pageref is not supported (sorry). Thus: if you have \ref inside of external graphics, consider using mode=list and make or copy–paste the system call for the image(s) and issue it manually.

  • how do i specify mode=list. I tried \tikzset{external/mode list} and \tikzset{external/mode=list}. They threw errors. Then I tried \tikzexternalize[mode=list and make]. But the legend is still missing – arunmoezhi Dec 13 '15 at 4:58
  • Page 473: /tikz/external/mode=list and make}. So \tikzset{/tikz/external/mode=list and make} should be what you want. – cfr Dec 13 '15 at 14:19

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.