[Tex/LaTex] Create x and y label which overlaps for multiple plots

groupplotspgfplots

I have a groupplot of 5×3. 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 5×3 but what if I have a 2×2 groupplot, I don't have a plot in the middle then.

enter image description here

Best Answer

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}