14

I have a group plot and when I try to add a legend it repeats on all subgraphs. I want a single common legend line at the top of the whole graph.

\documentclass{standalone}
\usepackage{graphicx}
\usepackage{tikz}
\usepackage{pgfplots}
\usepgfplotslibrary{groupplots}
\pgfplotsset{compat=newest}
\begin{document}

\begin{tikzpicture}
    \begin{groupplot}[group style={group size= 2 by 4},height=5cm,width=6.4cm,legend entries = {curve1,curve2,curve3}]
        \nextgroupplot[title=type1,ylabel={Range1 },symbolic x coords={1,2,4,8,16,32,64,128},xtick=data]
                \addplot[blue]  table{Data/test.dat};
                \addplot[red]   table{Data/test1.dat};
                \addplot[green] table{Data/test2.dat};  
                \coordinate (top) at (rel axis cs:0,1);% coordinate at top of the first plot            
        \nextgroupplot[title=type2,symbolic x coords={1,2,4,8,16,32,64,128},xtick=data]
                \addplot[blue]  table{Data/test.dat};
                \addplot[red]   table{Data/test1.dat};
                \addplot[green] table{Data/test2.dat};
        \nextgroupplot[ylabel={Range2 },symbolic x coords={1,2,4,8,16,32,64,128},xtick=data]
                \addplot[blue]  table{Data/test.dat};
                \addplot[red]   table{Data/test1.dat};
                \addplot[green] table{Data/test2.dat};
        \nextgroupplot[symbolic x coords={1,2,4,8,16,32,64,128},xtick=data]
                \addplot[blue]  table{Data/test.dat};
                \addplot[red]   table{Data/test1.dat};
                \addplot[green] table{Data/test2.dat};
        \nextgroupplot[ylabel={Range3 },symbolic x coords={1,2,4,8,16,32,64,128},xtick=data]
                \addplot[blue]  table{Data/test.dat};
                \addplot[red]   table{Data/test1.dat};
                \addplot[green] table{Data/test2.dat};
        \nextgroupplot[symbolic x coords={1,2,4,8,16,32,64,128},xtick=data]
                \addplot[blue]  table{Data/test.dat};
                \addplot[red]   table{Data/test1.dat};
                \addplot[green] table{Data/test2.dat};
        \nextgroupplot[xlabel={Number of Threads},ylabel={Range4 },symbolic x coords={1,2,4,8,16,32,64,128},xtick=data]
                \addplot[blue]  table{Data/test.dat};
                \addplot[red]   table{Data/test1.dat};
                \addplot[green] table{Data/test2.dat};
        \nextgroupplot[xlabel={Number of Threads},symbolic x coords={1,2,4,8,16,32,64,128},xtick=data]
                \addplot[blue]  table{Data/test.dat};
                \addplot[red]   table{Data/test1.dat};
                \addplot[green] table{Data/test2.dat};
                \coordinate (bot) at (rel axis cs:0,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);
\end{tikzpicture}
\end{document}

output

arunmoezhi
  • 1,270

1 Answers1

13

Update

Use the group name to refer each single plot:

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

\begin{tikzpicture}
    \begin{groupplot}[group style={
                      group name=myplot,
                      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}
        \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};
    \end{groupplot}
    \path (myplot c1r1.outer north west)% plot in column 1 row 1
          -- node[anchor=south,rotate=90] {throughput}% label midway
          (myplot c1r4.outer south west)% plot in column 1 row 4
    ;
% legend
\path (myplot c1r1.north west|-current bounding box.north)--
      coordinate(legendpos)
      (myplot c2r1.north east|-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}

Original answer:

You can label the plots which should mentioned in the legend. Then you can set the legend outside of the plots refering to the labeled plots. Define coordinates similar to my answer to your other question. (Note: I have changed the definition of the bot node.)

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

\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 to get

enter image description here


Explanation of

\path(top|-current bounding box.north)--coordinate(legendpos)(bot|-current bounding box.north);

The coordinate top is set on the upper left corner of the first plot and the bot is set ot the lower right corner of the last plot. The coordinate (top|-current bounding box.north) lies on the intersection of a vertical line through top and a horizontal line through current bounding box.north. The same applies for (bot|-current bounding box.north) only with bot. So the new coordinate labelpos is positioned on the north border of the current bounding box and it is horizontally centered to the boxes of the plots.


Update (because of a comment by @arunmoehzi)

You can use a patch suggested by Ijon Tichy on TeXwelt (German) to externalize this tikzpicture:

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

esdd
  • 85,675
  • Thanks again!! It worked. But the legend box was left aligned. – arunmoezhi Jul 20 '14 at 23:07
  • Also it would be helpful if you can explain the line \path (top|-current bounding box.north)-- coordinate(legendpos) (bot|-current bounding box.north) – arunmoezhi Jul 20 '14 at 23:18
  • @arunmoezhi I have changed my answer. Did you note that bot is now on (rel axis cs:1,0) of the last groupplot? – esdd Jul 21 '14 at 00:05
  • this solution of yours uses \label instead of \legend. This doesn't seem to work if with tikz-external. Please see this post http://tex.stackexchange.com/questions/282843/pgfplots-tikz-external-labels-are-missing – arunmoezhi Dec 13 '15 at 02:06
  • @arunmoehzi See my updated answer. – esdd Dec 13 '15 at 12:52
  • It worked. can you post this as an answer here http://tex.stackexchange.com/questions/282843/pgfplots-tikz-external-legends-are-missing – arunmoezhi Dec 20 '15 at 23:56
  • I can't compile this code, I get error ! Undefined control sequence. <argument> \patchFailedError. What am I missing? – aaragon May 10 '21 at 14:32