16

I have a groupplot of 5x3. Now I want to be able to 'overlap', so to speak, the ylabel over all the plots vica versa for the xlabel. This enables me namely to make the groupplot smaller.

Currently I have the following code: http://pastebin.com/0s6CB9HT. Which gives me the output given below. Thus what I want is to be able to stretch the labels "Phase [*] Magnitude [dB]' over all the plots, as a 'general' ylabel. And 'Frequency [Hz]' for the xlabel.

How can I achieve this?

Currently I just setted the ylabel as {Phase [*] Magnitude [dB]\\Out2} and xlabel as {Frequency [Hz]}. And did some xshift on the ylabel such that the 'Out i' would align with each other. This looks nice now for a 5x3 but what if I have a 2x2 groupplot, I don't have a plot in the middle then.

enter image description here

14

Short answer: Paste the following code snippet into your preamble, and then define your overall labels using groupplot ylabel=<label> (they can be styled using every groupplot y label/.style):

\makeatletter
\pgfplotsset{
    groupplot xlabel/.initial={},
    every groupplot x label/.style={
        at={($({\pgfplots@group@name\space c1r\pgfplots@group@rows.west}|-{\pgfplots@group@name\space c1r\pgfplots@group@rows.outer south})!0.5!({\pgfplots@group@name\space c\pgfplots@group@columns r\pgfplots@group@rows.east}|-{\pgfplots@group@name\space c\pgfplots@group@columns r\pgfplots@group@rows.outer south})$)},
        anchor=north,
    },
    groupplot ylabel/.initial={},
    every groupplot y label/.style={
            rotate=90,
        at={($({\pgfplots@group@name\space c1r1.north}-|{\pgfplots@group@name\space c1r1.outer
west})!0.5!({\pgfplots@group@name\space c1r\pgfplots@group@rows.south}-|{\pgfplots@group@name\space c1r\pgfplots@group@rows.outer west})$)},
        anchor=south
    },
    execute at end groupplot/.code={%
      \node [/pgfplots/every groupplot x label]
{\pgfkeysvalueof{/pgfplots/groupplot xlabel}};  
      \node [/pgfplots/every groupplot y label] 
{\pgfkeysvalueof{/pgfplots/groupplot ylabel}};  
    }
}

\def\endpgfplots@environment@groupplot{%
    \endpgfplots@environment@opt%
    \pgfkeys{/pgfplots/execute at end groupplot}%
    \endgroup%
}
\makeatother


Explanation:

To position the labels "properly", you can use the nodes and anchors the groupplot environment defines for every axis in a calc expression: The point ($(group c1r1.north west)!0.5!(group c1r6.south west)$) lies on the left edge of the plots exactly half way between the top left corner of the top left plot and the bottom left corner of the bottom left plot (if you have six rows of plots). To automate this solution to work without hard coding the number of rows, you can use the \pgfplots@group@rows macro, which stores the total number of rows in a groupplot environment. There's a tiny problem with this, though: The anchors are only defined properly after the groupplot environment is finished. At that time, the \pgfplots@group@rows macro no longer holds the number of rows. To deal with this, we can redefine the \endpgfplots@environment@groupplot macro a little bit to include a hook to execute code specified in a execute at end groupplot key.


Complete code (Note: conditional added so that tick labels only appear on outer plots - HVennekate)

\documentclass[border=5mm]{standalone}
\usepackage{graphics}
\usepackage{siunitx}
\usepackage{tikz}
\usepackage{pgfplots}
\usepgfplotslibrary{groupplots}
\pgfplotsset{compat=newest}
\pgfplotsset{plot coordinates/math parser=false}


\makeatletter
\pgfplotsset{
    groupplot xlabel/.initial={},
    every groupplot x label/.style={
        at={($({group c1r\pgfplots@group@rows.west}|-{group c1r\pgfplots@group@rows.outer south})!0.5!({group c\pgfplots@group@columns r\pgfplots@group@rows.east}|-{group c\pgfplots@group@columns r\pgfplots@group@rows.outer south})$)},
        anchor=north,
    },
    groupplot ylabel/.initial={},
    every groupplot y label/.style={
            rotate=90,
        at={($({group c1r1.north}-|{group c1r1.outer
west})!0.5!({group c1r\pgfplots@group@rows.south}-|{group c1r\pgfplots@group@rows.outer west})$)},
        anchor=south
    },
    execute at end groupplot/.code={%
      \node [/pgfplots/every groupplot x label]
{\pgfkeysvalueof{/pgfplots/groupplot xlabel}};  
      \node [/pgfplots/every groupplot y label] 
{\pgfkeysvalueof{/pgfplots/groupplot ylabel}};  
    },
    group/only outer labels/.style =
{
group/every plot/.code = {%
    \ifnum\pgfplots@group@current@row=\pgfplots@group@rows\else%
        \pgfkeys{xticklabels = {}, xlabel = {}}\fi%
    \ifnum\pgfplots@group@current@column=1\else%
        \pgfkeys{yticklabels = {}, ylabel = {}}\fi%
}
}
}

\def\endpgfplots@environment@groupplot{%
    \endpgfplots@environment@opt%
    \pgfkeys{/pgfplots/execute at end groupplot}%
    \endgroup%
}
\makeatother


\begin{document}
\begin{tikzpicture}

\pgfplotsset{%
  width=4cm,
  height=2cm,
  scale only axis,
  xmajorgrids,
  xminorgrids,
  ymajorgrids,
  yminorgrids
}

\begin{groupplot}[%
  group style={group size=3 by 6,
  horizontal sep=5pt,
  vertical sep=5pt},
  xmode=log,
  groupplot ylabel={Phase [\si{\degree}]\quad Magnitude [\si{\decibel}]},
  groupplot xlabel={Frequency [\si{\hertz}]},
  group/only outer labels
]

% ROW 1
\nextgroupplot[
  ylabel={Out 1},
  xmin=0.1,
  xmax=100000,
  ymin=-400,
  ymax=200,
  title={In 1}
]

\nextgroupplot[
  xmin=0.1,
  xmax=100000,
  ymin=-400,
  ymax=200,
  title={In 2}
]

\nextgroupplot[
  xmin=0.1,
  xmax=100000,
  ymin=-400,
  ymax=200,
  title={In 3}
]

% ROW 2
\nextgroupplot[
  ytick={-180,-90,0,90,180},
  ylabel={Out 1},
  xmin=0.1,
  xmax=100000,
  ymin=-200,
  ymax=200
]

\nextgroupplot[
  ytick={-180,-90,0,90,180},
  xmin=0.1,
  xmax=100000,
  ymin=-200,
  ymax=200
]

\nextgroupplot[
  ytick={-180,-90,0,90,180},
  xmin=0.1,
  xmax=100000,
  ymin=-200,
  ymax=200
]

% ROW 3
\nextgroupplot[
  ylabel={Out 2},
  xmin=0.1,
  xmax=100000,
  ymin=-400,
  ymax=200
]

\nextgroupplot[
  xmin=0.1,
  xmax=100000,
  ymin=-400,
  ymax=200
]

\nextgroupplot[
  xmin=0.1,
  xmax=100000,
  ymin=-400,
  ymax=200
]

% ROW 4
\nextgroupplot[
  ylabel={Out 2},
  ytick={-180,-90,0,90,180},
  xmin=0.1,
  xmax=100000,
  ymin=-200,
  ymax=200
]

\nextgroupplot[
  ytick={-180,-90,0,90,180},
  xmin=0.1,
  xmax=100000,
  ymin=-200,
  ymax=200
]

\nextgroupplot[
  ytick={-180,-90,0,90,180},
  xmin=0.1,
  xmax=100000,
  ymin=-200,
  ymax=200
]

% ROW 5
\nextgroupplot[
  ylabel={Out 3},
  xmin=0.1,
  xmax=100000,
  ymin=-400,
  ymax=200
]

\nextgroupplot[
  xmin=0.1,
  xmax=100000,
  ymin=-400,
  ymax=200
]

\nextgroupplot[
  xmin=0.1,
  xmax=100000,
  ymin=-400,
  ymax=200
]

% ROW 6
\nextgroupplot[
  ylabel={Out 3},
  ytick={-360,-180,0},
  xmin=0.1,
  xmax=100000,
  ymin=-380,
  ymax=20
]

\nextgroupplot[
  ytick={-360,-180,0},
  xmin=0.1,
  xmax=100000,
  ymin=-380,
  ymax=20
]

\nextgroupplot[
  ytick={-360,-180,0},
  xmin=0.1,
  xmax=100000,
  ymin=-380,
  ymax=20
]
\makeatletter
\end{groupplot}



\end{tikzpicture}

\end{document}
  • How can I extend this to the xlabel? I now have pastebin.com/Q7hhfUt1 – WG- Jun 6 '13 at 15:14
  • 1
    @WG-: I've edited my answer. – Jake Jun 6 '13 at 15:22
  • This is a bit strange, when I now remove the lines every axis x label/.style={at={(0.5,0)}, align=center, yshift=-28pt}, every axis y label/.style={at={(0,0.5)}, align=center, xshift=-38pt, rotate=90} from the pgfplotsset command I get the error ! Package tikz Error: Unknown coordinate system 'ticklabel'. See the tikz package documentation for explanation. Type H <return> for immediate help. ... l.60345 \end{groupplot} – WG- Jun 6 '13 at 15:38
  • 1
    @WG-: Ah, yes, sorry, that was an oversight on my part. I've corrected the code so that it should now work regardless of how the axis labels are placed. This also eliminates the need for a hard coded yshift value in the every groupplot y label style. – Jake Jun 6 '13 at 15:53
  • Question Jake. I now have 2 groupplots combined in 1 tex file. Now the above code doesn't work anymore since it tells me that No shape named right plots c1r3 is known. It is related to tex.stackexchange.com/questions/150980/create-groupplot-3-x-6. I tried exchanging all the group by a corresponding name for the right plots groupplot by using groupplot name=right plots. Could this be fixed? – WG- Dec 24 '13 at 14:34
3

You don't have to use Tikz to add the labels, you can add them afterwards to the constructed box.

\documentclass{standalone}
\usepackage{graphicx}
\usepackage{siunitx}
\usepackage{tikz}
\usepackage{pgfplots}
\usepackage{array}
\usepgfplotslibrary{groupplots}
\pgfplotsset{compat=newest}
\pgfplotsset{plot coordinates/math parser=false}
\begin{document}
\sbox8{\begin{tikzpicture}

\pgfplotsset{%
  width=4cm,
  height=2cm,
  scale only axis,
  every x tick label/.append style={font=\scriptsize\color{gray!80!black}},
  xmajorgrids,
  xminorgrids,
  every y tick label/.append style={font=\scriptsize\color{gray!80!black}},
  ymajorgrids,
  yminorgrids,
  every axis x label/.style={at={(0.5,0)}, align=center, yshift=-28pt},
  every axis y label/.style={at={(0,0.5)}, align=center, xshift=-38pt,
rotate=90}
}

\begin{groupplot}[%
  group style={group size=3 by 6,
  horizontal sep=5pt,
  vertical sep=5pt},
  xmode=log
]

% ROW 1
\nextgroupplot[
  xticklabels={},
% yticklabels={},
  xlabel={},
  ylabel={Out 1},
  xmin=0.1,
  xmax=100000,
  ymin=-400,
  ymax=200,
  title={In 1}
]

\nextgroupplot[
  xticklabels={},
  yticklabels={},
  xlabel={},
  ylabel={},
  xmin=0.1,
  xmax=100000,
  ymin=-400,
  ymax=200,
  title={In 2}
]

\nextgroupplot[
  xticklabels={},
  yticklabels={},
  xlabel={},
  ylabel={},
  xmin=0.1,
  xmax=100000,
  ymin=-400,
  ymax=200,
  title={In 3}
]

% ROW 2
\nextgroupplot[
  xticklabels={},
% yticklabels={},
  ytick={-180,-90,0,90,180},
  xlabel={},
  ylabel={Out 1},
  xmin=0.1,
  xmax=100000,
  ymin=-200,
  ymax=200
]

\nextgroupplot[
  xticklabels={},
  yticklabels={},
  ytick={-180,-90,0,90,180},
  xlabel={},
  ylabel={},
  xmin=0.1,
  xmax=100000,
  ymin=-200,
  ymax=200
]

\nextgroupplot[
  xticklabels={},
  yticklabels={},
  ytick={-180,-90,0,90,180},
  xlabel={},
  ylabel={},
  xmin=0.1,
  xmax=100000,
  ymin=-200,
  ymax=200
]

% ROW 3
\nextgroupplot[
  xticklabels={},
% yticklabels={},
  xlabel={},
  ylabel={Out 2},
  xmin=0.1,
  xmax=100000,
  ymin=-400,
  ymax=200
]

\nextgroupplot[
  xticklabels={},
  yticklabels={},
  xlabel={},
  ylabel={},
  xmin=0.1,
  xmax=100000,
  ymin=-400,
  ymax=200
]

\nextgroupplot[
  xticklabels={},
  yticklabels={},
  xlabel={},
  ylabel={},
  xmin=0.1,
  xmax=100000,
  ymin=-400,
  ymax=200
]

% ROW 4
\nextgroupplot[
  xticklabels={},
% yticklabels={},
  xlabel={},
  ylabel={Out 2},
  ytick={-180,-90,0,90,180},
  xmin=0.1,
  xmax=100000,
  ymin=-200,
  ymax=200
]

\nextgroupplot[
  xticklabels={},
  yticklabels={},
  xlabel={},
  ylabel={},
  ytick={-180,-90,0,90,180},
  xmin=0.1,
  xmax=100000,
  ymin=-200,
  ymax=200
]

\nextgroupplot[
  xticklabels={},
  yticklabels={},
  xlabel={},
  ylabel={},
  ytick={-180,-90,0,90,180},
  xmin=0.1,
  xmax=100000,
  ymin=-200,
  ymax=200
]

% ROW 5
\nextgroupplot[
  xticklabels={},
% yticklabels={},
  xlabel={},
  ylabel={Out 3},
  xmin=0.1,
  xmax=100000,
  ymin=-400,
  ymax=200
]

\nextgroupplot[
  xticklabels={},
  yticklabels={},
  xlabel={},
  ylabel={},
  xmin=0.1,
  xmax=100000,
  ymin=-400,
  ymax=200
]

\nextgroupplot[
  xticklabels={},
  yticklabels={},
  xlabel={},
  ylabel={},
  xmin=0.1,
  xmax=100000,
  ymin=-400,
  ymax=200
]

% ROW 6
\nextgroupplot[
% xticklabels={},
% yticklabels={},
  xlabel={},
  ylabel={Out 3},
  ytick={-360,-180,0},
  xmin=0.1,
  xmax=100000,
  ymin=-380,
  ymax=20
]

\nextgroupplot[
% xticklabels={},
  yticklabels={},
  xlabel={},
  ylabel={},
  ytick={-360,-180,0},
  xmin=0.1,
  xmax=100000,
  ymin=-380,
  ymax=20
]

\nextgroupplot[
% xticklabels={},
  yticklabels={},
  xlabel={},
  ylabel={},
  ytick={-360,-180,0},
  xmin=0.1,
  xmax=100000,
  ymin=-380,
  ymax=20
]

\end{groupplot}

\end{tikzpicture}}

\mbox{%
\rotatebox{90}{\makebox[\ht8]{Phase [\si{\degree}]  Magnitude [\si{\decibel}]}}
\begin{tabular}[t]{c}\usebox8\\Frequency [\si{\hertz}]\end{tabular}}

\end{document}
  • Hmmmm I always hate boxes, anyway the labels are now not really in the middle. Can you make it such that they are really in the middle? I can solve it proberbly simply by hspace and vspace but I would prefer a more elegant solution. – WG- Jun 5 '13 at 17:32
  • @WG- They are exactly in the middle of something but perhaps not the thing you want:-) for example the y label is centred on a region that includes the In 3 heading at the top and the 10^x ticks at the bottom rather than just centred on the bare grid If you want the latter no need to measure really as that size is predetermined by the size of each block and the sep keys. may put an alternative version later – David Carlisle Jun 5 '13 at 17:39

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.