4

How can I set the width of a subfigure to fit its content, i. e. a tikzpicture.

In my MWE I do not want to specify 0.1\textwidth respectively 0.9\textwidth, but instead I want the whitespace to be distributed equally around both subfigures.

\documentclass{article}
\usepackage{showframe}
\usepackage{tikz}
\usepackage{subcaption}

\begin{document}

\begin{figure}[ht]
\hfill
\begin{subfigure}[b]{0.1\textwidth}
\centering
\begin{tikzpicture}
\node[draw] (pd1) {a};
\end{tikzpicture}
\caption{}
\end{subfigure}%
\hfill
\begin{subfigure}[b]{0.9\textwidth}
\centering
\begin{tikzpicture}
\node[draw] (b) at (0,0) {b};
\node[draw] (c) at (5,0) {c};

\draw (b) to (c);
\end{tikzpicture}
\caption{}
\end{subfigure}%
\hfill
\caption{}
\end{figure}

\end{document}

I found this answer How can I access the size of a tikzpicture's bounding box outside the tikzpicture? but didn't read it in detail until now. I was wondering if my aim could be achieved easier.

user1
  • 2,196

2 Answers2

5

You could place the tikzpicture in a \savebox and measure its size. This size can then be used for the subfigure.

\documentclass{article}
\usepackage{showframe}
\usepackage{tikz}
\usepackage{subcaption}

\newsavebox{\myboxb}
\newlength{\mylengthb}

\newsavebox{\myboxa}
\newlength{\mylengtha}

\begin{document}

\savebox{\myboxa}{\begin{tikzpicture}
\node[draw] (pd1) {a};
\end{tikzpicture}}
\settowidth{\mylengtha}{\usebox{\myboxa}}

\savebox{\myboxb}{\begin{tikzpicture}
\node[draw] (b) at (0,0) {b};
\node[draw] (c) at (5,0) {c};

\draw (b) to (c);
\end{tikzpicture}}
\settowidth{\mylengthb}{\usebox{\myboxb}}

\begin{figure}[ht]
\mbox{}
\hfill
\begin{subfigure}[b]{\mylengtha}
\usebox{\myboxa}
\caption{}
\end{subfigure}%
\hfill
\begin{subfigure}[b]{\mylengthb}
\usebox{\myboxb}
\caption{}
\end{subfigure}%
\hfill
\mbox{}
\caption{}
\end{figure}

\end{document}

(Thanks to @marmot for spotting the issue about the \hfill between the images and the boarders)

4

I think that @samcarter's nice proposal is the way to go. This is only if you need to access the nodes later (with remember picture), in which case \saveboxes may be inconvenient. This proposal measures the widths of the tikzpictures and writes them to the aux files such that they get used in the next run. Conceptually it is the same as e.g. this nice answer.

\documentclass{article}
\usepackage{showframe}
\usepackage{tikz}
\usetikzlibrary{calc}
\usepackage{subcaption}
\ifdefined\figwidthA
\else
\xdef\figwidthA{2cm}
\fi
\ifdefined\figwidthB
\else
\xdef\figwidthB{2cm}
\fi
\tikzset{save tikzpic width in/.style={execute at end picture={
\path let \p1=($(current bounding box.east)-(current bounding box.west)$)
in \pgfextra{\xdef#1{\x1}};}}}
\begin{document}

\begin{figure}[ht]
\hfill
\begin{subfigure}[b]{\figwidthA}
\centering
\begin{tikzpicture}[save tikzpic width in=\figwidthA]
\node[draw] (pd1) {a};
\end{tikzpicture}
\caption{}
\end{subfigure}%
\hfill%
\begin{subfigure}[b]{\figwidthB}
\centering
\begin{tikzpicture}[save tikzpic width in=\figwidthB]
\node[draw] (b) at (0,0) {b};
\node[draw] (c) at (5,0) {c};

\draw (b) to (c);
\end{tikzpicture}
\caption{}
\end{subfigure}%
\hfill{\vphantom{x}}
\caption{}
\end{figure}
\makeatletter 
\immediate\write\@mainaux{\xdef\string\figwidthA{\figwidthA}\relax} 
\immediate\write\@mainaux{\xdef\string\figwidthB{\figwidthB}\relax} 
\makeatother 
\end{document}

enter image description here