The pgfplots axis
environment has options width
and height
to specify the approximate width and height of the picture drawn, but the resulting box is not exactly as wide or high as specified—it may be less or more than requested, depending on what goes in the title and tick labels, as below.
How can I set the exact width or height of a tikzpicture drawn by pgfplots?
I understand that with scale only axis
, the width
or height
options set the exact width or height of the axis box, but I'm looking to set the exact width or height of the TikZ picture drawn.
The prevailing wisdom (e.g., from Specifying the width and height of a tikzpicture) is that there is no built-in general way in TikZ to scale a picture to exact dimensions because with TikZ you can just draw the picture exactly to the dimensions you want, and then there's no need to scale it afterward.
But can this be done with pgfplots?
Documentation reference: https://tikz.dev/pgfplots/reference-scaling#sec-21.1
/pgfplots/width={⟨dimen⟩}
(initially empty)Sets the width of the final picture to {⟨dimen⟩}.
Any non-empty dimension like
width=5cm
sets the desired target width. Any TeX unit is accepted (like200pt
or5in
).
Unfortunately, this does not appear to be accurate, as the MWE below demonstrates and the caveat below explains:
Please note that pgfplots only estimates the size needed for axis- and tick labels. The estimate assumes a fixed amount of space for anything which is outside of the axis box. This has the effect that the final images may be slightly larger or slightly smaller than the prescribed dimensions. However, the fixed amount is always the same; it is set to 45pt. That means that multiple pictures with the same target dimensions will have the same size for their axis boxes – even if the size for descriptions varies.
Following the answers to Pgfplots height in subfigure not consistent to adjacent includegraphics, I tried using height=\mylength+\baselineskip, xlabel=\empty, title=\empty
, but it changes the picture drawn (adding disproportionately more whitespace) and still doesn't end up with exactly the requested height (and if used for width with ylabel, it is further from the requested width).
Ideally, I would like to do this without having to iteratively search for inputs minimizing the actual distance from expected before committing the inputs to the document.
\documentclass{article}
\usepackage{amsmath}
\usepackage{pgfplots}
\usepackage{tikz}
\pgfplotsset{compat=1.18}
\newsavebox{\mybox}
\newlength{\mylength} \setlength{\mylength}{100pt}
\begin{document}
\section*{Width}
\begin{lrbox}{\mybox}
\begin{tikzpicture}
\begin{axis}[width=\mylength]
\addplot[domain=0:2] {exp(-x)};
\end{axis}
\end{tikzpicture}
\end{lrbox}
\noindent expected=\the\mylength\smallskip\hrule width\mylength\relax
\vspace{\baselineskip}
\noindent actual=\the\wd\mybox\smallskip\hrule width\wd\mybox\relax
\vspace{\baselineskip}
\noindent\usebox{\mybox}
\section*{Height}
\begin{lrbox}{\mybox}
\begin{tikzpicture}
\begin{axis}[height=\mylength, xlabel={$\substack{X\\Y}$}, title={XXX}]
\addplot[domain=0:2] {exp(-x)};
\end{axis}
\end{tikzpicture}
\end{lrbox}
expected=\the\mylength\ \vrule height\mylength\relax\quad
actual=\the\ht\mybox\ \vrule height\ht\mybox\relax\quad
\usebox{\mybox}
\end{document}
scale only axis
and doing a couple of iterations, you could obtain more or less the desired height.\resizebox
(graphicx package) and the tikzscale package.