This question was asked on comp.text.tex and received a good answer by Ulrike Fischer. It works by typesetting the {tikzpicture}
once, measure its width and then retypeset it to the correct width by automatically computing the required scale.
Here's a more user-friendly interface for this solution using the environ package. It works by using a {scaletikzpicturetowidth}
environment with the desired width as first argument in combination with specifying the [scale=\tikzscale]
option to the tikzpicture. For example, to scale a tikzpicture
to \textwidth
, you would use:
\begin{center}
\begin{scaletikzpicturetowidth}{\textwidth}
\begin{tikzpicture}[scale=\tikzscale]
\draw (0,0) rectangle (1,1) node[below left] {$A$};
\draw (2,1) circle (1cm) node [below] {$B$};
\end{tikzpicture}
\end{scaletikzpicturetowidth}
\end{center}
Here's a complete compilable code which shows both the unscaled tikzpicture
and the scaled one:

\documentclass{article}
\usepackage{tikz}
\usepackage{environ}
\makeatletter
\newsavebox{\measure@tikzpicture}
\NewEnviron{scaletikzpicturetowidth}[1]{%
\def\tikz@width{#1}%
\def\tikzscale{1}\begin{lrbox}{\measure@tikzpicture}%
\BODY
\end{lrbox}%
\pgfmathparse{#1/\wd\measure@tikzpicture}%
\edef\tikzscale{\pgfmathresult}%
\BODY
}
\makeatother
\begin{document}
Bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla.
\begin{center}
\begin{tikzpicture}
\draw (0,0) rectangle (1,1) node[below left] {$A$};
\draw (2,1) circle (1cm) node [below] {$B$};
\end{tikzpicture}
\end{center}
Bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla.
\begin{center}
\begin{scaletikzpicturetowidth}{\textwidth}
\begin{tikzpicture}[scale=\tikzscale]
\draw (0,0) rectangle (1,1) node[below left] {$A$};
\draw (2,1) circle (1cm) node [below] {$B$};
\end{tikzpicture}
\end{scaletikzpicturetowidth}
\end{center}
Bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla.
\end{document}
If you need to use the external
tikzlibrary, here is a workaround:
\documentclass{article}
\usepackage{tikz}
\usepackage{environ}
\usetikzlibrary{external}\tikzexternalize%\tikzset{external/force remake}
\makeatletter
\newcounter{tikz@scale@num}
\newsavebox{\measure@tikzpicture}
\NewEnviron{scaletikzpicturetowidth}[2][]{%
% optional argument #1 is passed to \tikzsetnextfilename if not empty
\stepcounter{tikz@scale@num}%
\def\tikz@width{#2}%
\def\tikzscale{1}\begin{lrbox}{\measure@tikzpicture}%
\BODY
\end{lrbox}%
\pgfmathparse{#2/\wd\measure@tikzpicture}%
\ifcsname tikzscale\number\value{tikz@scale@num}\endcsname\else
\expandafter\xdef\csname tikzscale\number\value{tikz@scale@num}\endcsname{\pgfmathresult}%
\fi
\tikzset{external/system call={pdflatex \tikzexternalcheckshellescape -halt-on-error -interaction=batchmode -jobname "\image" "\string\expandafter\string\edef\string\csname\space tikzscale\number\value{tikz@scale@num}\string\endcsname{\csname tikzscale\number\value{tikz@scale@num}\endcsname}\texsource"}}%
\edef\tikzscale{\csname tikzscale\number\value{tikz@scale@num}\endcsname}%
\ifcat$#1$\else\tikzsetnextfilename{#1}\fi
\BODY
}
\makeatother
\begin{document}
Bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla.
\begin{center}
\begin{tikzpicture}
\draw (0,0) rectangle (1,1) node[below left] {$A$};
\draw (2,1) circle (1cm) node [below] {$B$};
\end{tikzpicture}
\end{center}
Bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla.
\begin{center}
\begin{scaletikzpicturetowidth}{\textwidth}
\begin{tikzpicture}[scale=\tikzscale]
\draw (0,0) rectangle (1,1) node[below left] {$A$};
\draw (2,1) circle (1cm) node [below] {$B$};
\end{tikzpicture}
\end{scaletikzpicturetowidth}
\end{center}
Bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla.
\end{document}
If you need to use \tikzsetnextfilename{name}
for an automatically scaled picture, use instead the syntax \begin{scaletikzpicturetowidth}[name]{\textwidth}
.
You can use \resizebox{\linewidth}{!}{<tikz picture>}
from the graphics
package which is already loaded by tikz
anyway. It scales its content to the given width and height (!
for the height means that it scales with the width). One drawback of this approach is that everything is scaled including the line width and node texts which might not be what some people want.
Note that \resizebox
reads the whole picture as a macro argument, which isn't very efficient and does not allow verbatim or other special content. Alternatives are \Resizebox
(same syntax) from my realboxes
package or the {adjustbox}{width=\linewidth}
environment from my adjustbox
package.
Best Answer
In some cases
\linewidth
instead of\textwidth
may be the better option. For example will it be the same as\textwidth
in a single column document, but the same as\columnwidth
in a two column document.\linewidth
may also change in list environments, becoming smaller in nested lists.As commented by Christian Lindig, see Difference between \textwidth, \linewidth and \hsize for a discussion of this.