0

I am trying to align multiple tikzpictures. It gets complicated as I need the following figures to be aligned

  • possibly two y-axis
  • possibly legends
  • captions

The pgfplots manual gives 3 possible methods (see "4.19.4 Alignment In Array Form (Subplots)")

  1. tikzpicture environment inside of tables
  2. matrix inside of tikzpicture
  3. groupplots

Currently I try option 1 as option 2 doesnot easily work together with legends. I have not tried option 3.

A minimal working example looks as follows

\documentclass[letterpaper,11pt,english]{article}
\usepackage[ascii]{inputenc}
\usepackage[T1]{fontenc}

\usepackage{subcaption}
\usepackage{graphicx}

\usepackage{pgfplots}
\pgfplotsset{compat=1.15, small}

\begin{document}

example ref to fig \ref{fig1}

\begin{center}
  \begin{tabular}{p{5cm}p{5cm}}                                        % "p{5cm}": predefined width is need for captionof to work
      \begin{tikzpicture}[baseline,trim axis left]
        \begin{axis}[ylabel={yname}]
          \addplot {x};
        \end{axis}
    \end{tikzpicture}
    \captionof{figure}{\textbf{Confusion Matrix foobar}}
    \label{fig1}
  &
    \begin{tikzpicture}[baseline,trim axis right]
      \pgfplotsset{set layers, scale only axis, xmin=-5,xmax=5,width=5cm}   % pgfplots' manual recommends those options: The Reference -> Axis Descriptions -> Two Ordinates
      \begin{axis}[
          ylabel={$f(x)=x^2$},
          yticklabel pos=upper,
          ylabel style={font=\Huge},
        ]
        \addplot {x^2};
        \label{x2}
      \end{axis}
      \begin{axis}[
          ylabel={$f(x)=x^5$},
          yticklabel pos=upper,
          ylabel style={font=\Huge},
          axis y line* = left,
          ymode=log
        ]

        % add potential to legend. only legend entries of last axis will be displayed.
        \addlegendimage{/pgfplots/refstyle=plot_x2}\addlegendentry{$x^2$}

        \addplot [red] {x^5};
        \addlegendentry{$x^5$}
      \end{axis}
    \end{tikzpicture}
  \\
    \begin{tikzpicture}[baseline,trim axis left]
      \begin{axis}[xlabel=$x$,xlabel style={font=\Huge}]
        \addplot {x^3};
      \end{axis}
    \end{tikzpicture}
  &
    \begin{tikzpicture}[baseline,trim axis right]
      \begin{axis}[yticklabel pos=upper]
        \addplot {x^4};
      \end{axis}
    \end{tikzpicture}
  \\
  \end{tabular}
\end{center}

\end{document}

enter image description here

2
  • 1
    Do you need to use one of those three methods or can you use other packages such as subfig or subcaption? – Jes Feb 10 at 21:52
  • I am open to any method, not just those 3. – jack Feb 10 at 22:13
2

The idea is to align the origins of all the tikzpictures by using a common cell size. First we determine the distances to the bounding box for each picture, then we add extra points to produce a common bounding box for each picture.

The resulting cell size is far too large for the page. Some savings can be obtained by doing each column separately, but it still won't fit inside the margins.

\documentclass[letterpaper,11pt,english]{article}
\usepackage[ascii]{inputenc}
\usepackage[T1]{fontenc}

\usepackage{subcaption}
\usepackage{graphicx}

\usepackage{pgfplots}
\pgfplotsset{compat=1.15, small}

%\usepackage{showframe}% MWE only

\newcommand{\xleft}{0pt}% reserve global names
\newcommand{\xright}{0pt}
\newcommand{\ybottom}{0pt}
\newcommand{\ytop}{0pt}

\newcommand{\maxborders}[1]{% #1 = \csname to store left offset
  \path (current bounding box.south west);
  \pgfgetlastxy{\x}{\y}
  \global\expandafter\let\csname #1\endcsname=\x
  \ifdim \xleft>\x\relax \global\let\xleft=\x \fi
  \ifdim \ybottom>\y\relax \global\let\ybottom=\y \fi
  \path (current bounding box.north east);
  \pgfgetlastxy{\x}{\y}
  \ifdim \xright<\x\relax \global\let\xright=\x \fi
  \ifdim \ytop<\y\relax \global\let\ytop=\y \fi}

\begin{document}

example ref to fig \ref{fig1}

\begin{center}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  \sbox0{\begin{tikzpicture}[baseline]
        \begin{axis}[ylabel={yname}]
          \addplot {x};
        \end{axis}
      \maxborders{left0}
    \end{tikzpicture}}
  \sbox1{\begin{tikzpicture}[baseline]
      \pgfplotsset{set layers, scale only axis, xmin=-5,xmax=5,width=5cm}   % pgfplots' manual recommends those options: The Reference -> Axis Descriptions -> Two Ordinates
      \begin{axis}[
          ylabel={$f(x)=x^2$},
          yticklabel pos=upper,
          ylabel style={font=\Huge},
        ]
        \addplot {x^2};
        \label{x2}
      \end{axis}
      \begin{axis}[
          ylabel={$f(x)=x^5$},
          yticklabel pos=upper,
          ylabel style={font=\Huge},
          axis y line* = left,
          ymode=log
        ]

        % add potential to legend. only legend entries of last axis will be displayed.
        \addlegendimage{/pgfplots/refstyle=plot_x2}\addlegendentry{$x^2$}

        \addplot [red] {x^5};
        \addlegendentry{$x^5$}
      \end{axis}
      \maxborders{left1}
    \end{tikzpicture}}
  \sbox2{\begin{tikzpicture}[baseline]
      \begin{axis}[xlabel=$x$,xlabel style={font=\Huge}]
        \addplot {x^3};
      \end{axis}
      \maxborders{left2}
    \end{tikzpicture}}
  \sbox3{\begin{tikzpicture}[baseline]
      \begin{axis}[yticklabel pos=upper]
        \addplot {x^4};
      \end{axis}
      \maxborders{left3}
    \end{tikzpicture}}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  \begin{tabular}{ll}
    \begin{tikzpicture}[baseline]
      \node[anchor=base west, inner sep=0pt] at ({\csname left0\endcsname},0) {\usebox0};
      \path (\xleft,\ybottom) (\xright,\ytop);
      \draw[red] (current bounding box.south west) rectangle (current bounding box.north east);
    \end{tikzpicture}
  &
    \begin{tikzpicture}[baseline]
      \node[anchor=base west, inner sep=0pt] at ({\csname left1\endcsname},0) {\usebox1};
      \path (\xleft,\ybottom) (\xright,\ytop);
      \draw[red] (current bounding box.south west) rectangle (current bounding box.north east);
    \end{tikzpicture}
  \\
    \parbox{\dimexpr \xright-\xleft}{% put captions is separate row
      \captionof{figure}{\textbf{Confusion Matrix foobar}}
      \label{fig1}}
  &
  \\
    \begin{tikzpicture}[baseline]
      \node[anchor=base west, inner sep=0pt] at ({\csname left2\endcsname},0) {\usebox2};
      \path (\xleft,\ybottom) (\xright,\ytop);
      \draw[red] (current bounding box.south west) rectangle (current bounding box.north east);
    \end{tikzpicture}
  &
    \begin{tikzpicture}[baseline]
      \node[anchor=base west, inner sep=0pt] at ({\csname left3\endcsname},0) {\usebox3};
      \path (\xleft,\ybottom) (\xright,\ytop);
      \draw[red] (current bounding box.south west) rectangle (current bounding box.north east);
    \end{tikzpicture}
  \\
  \end{tabular}
\end{center}

\end{document}
2
  • It works perfectly but I am amazed that one has to go to such lengths to accomplish something as trivial as aligning figures... – jack Feb 11 at 19:14
  • The top and bottom calculations were largely gratuitous, as TeX already separates height and depth relative to baselines. But width is not separated into left and right components. – John Kormylo Feb 11 at 22:51
0

Personally i find the use of groupplots much more appealing. Also for two y-axes within one plot environment please see this thread.

\documentclass[letterpaper,11pt,english]{article}
\usepackage{subcaption}
\usepackage{graphicx}

\usepackage{pgfplots}
\usepgfplotslibrary{groupplots}
\pgfplotsset{compat=1.15, small}

\begin{document}
    
\begin{figure}[htb]
    \centering
    \begin{tikzpicture}[
        subcaption/.style={anchor=north, font=\small},
        baseline,
        trim axis left
    ]
    \begin{groupplot}[
    group style={
        group name=plotGroup,
        group size=2 by 2,
        horizontal sep=1.5cm,
        vertical sep=1.5cm,
    },
    height=5cm,
    width=5cm,
    ]
    %
    %   plot creation
    \nextgroupplot[ylabel={yname}]
    \addplot {x};
    \nextgroupplot[
        xmin=-5,xmax=5, 
        ylabel={$f(x)=x^2$},
        yticklabel pos=upper,
        ylabel style={font=\Huge},
    ]
    \addplot {x^2};
    \addlegendimage{red}
    \legend{$x^2$,$x^5$}
    \nextgroupplot[
        xlabel=$x$, 
        xlabel style={font=\Huge}
    ]
    \addplot {x^3};
    \nextgroupplot[yticklabel pos=upper]
    \addplot {x^4};
    \end{groupplot}
    %
    %   post axis
    \path let \p1 = (plotGroup c1r2.below south), \p2 = (plotGroup c2r2.below south) in (\x2,\y1) coordinate (tmpCoord);
    %
    \node[subcaption] at (plotGroup c1r1.below south) {(a) subtext 1\phantomsubcaption\label{fig:1}};
    \node[subcaption] at (plotGroup c2r1.below south) {(b) subtext 2\phantomsubcaption\label{fig:2}};
    \node[subcaption] at (plotGroup c1r2.below south) {(c) subtext 3\phantomsubcaption\label{fig:3}};
    \node[subcaption] at (tmpCoord) {(d) subtext 4\phantomsubcaption\label{fig:4}};
    \end{tikzpicture}
    \caption[]{}
    \label{fig:all}
\end{figure}
\end{document}

compiled result

3
  • Sure, see edited answer. However, you could also simply use xlabel=\phantom{$x$}, xlabel style={font=\Huge} in the 4th subplot - the choice is yours. – Venez Feb 12 at 12:21
  • How would you define labels for the figures which could be referenced? You inserted the figure names (a)-(d) manually... – jack Feb 12 at 12:27
  • The figure and the subplot have already labels and can be referenced because of \phantomsubcaption\label{fig:X} (personally i would use \label{fig:X} for the overall and \label{fig:X:a-d} for the subitems). And i used (a)-(d) to stay in line with the default settings of the subcaption package. – Venez Feb 12 at 12:52

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.