# fit tikzpicture to page width or height (using macros)

I have a new environment defined that fits tikzpicture to the page width, but when tikzpicture is long in height the bottom part of the tikzpicture is cut and extra blank page appears because of the jump of the tikzpicture to the next page.

I want to find scalewidth and scaleheight parameters (a scale ration to fit page width and a scale ration to fit page height, respectively) and choose the smaller one for scaling in order to guarantee full appearance of tikzpicture.

Could you tell me how to modify the scaletikzpicturetowidth environment to achieve this?

  \NewEnviron{scaletikzpicturetowidth}[1]{%
\def\tikz@width{#1}     % what does this do?
\def\tikzscale{1}   %declares tikzscale parameter
\begin{lrbox}{\measure@tikzpicture}    % BODY is saved in measure@tikzpicture
\BODY
\end{lrbox}%
\pgfmathparse{#1/\wd\measure@tikzpicture}    % a scale ratio = page_width/tikzpic_width
\edef\tikzscale{\pgfmathresult}  % tikzscale = a scale ration
\BODY
}


So, the environmet will take two arguments:

#1 = \textwidth and #2 = \textheight,

then it calculates

widthscale = #1/\wd\measure@tikzpicture and

heightsacle = #2/\ht\measure@tikzpicture, and

\tikzscale = min(widthscale, heightsacle)

\documentclass[landscape]{article}
\setlength\textwidth{10in}
\setlength\textheight{8.5in}
\setlength\oddsidemargin{-.5in}
\setlength\evensidemargin{-.5in}
\setlength\topmargin{-.7in}
\setlength\topskip{0in}
\usepackage{tikz-qtree-compat}
\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}
\begin{scaletikzpicturetowidth}{\textwidth}
\begin{tikzpicture}[scale=\tikzscale, baseline=0pt, grow=down]
\tikzset{level distance = 25pt, sibling distance = -5pt}
\tikzset{every tree node/.style={align=center,anchor=north}}
\Tree
[. \node{ $s$};
[. \node{\begin{tabular}{c}
\texttt{run}\\
\textbf{run}\\
\normalsize{na}\\
\scriptsize{na}\\
\scriptsize{na}\\
\end{tabular} }; ]
[. \node{\begin{tabular}{c}
\textbf{$X_{3109}$}\\
\end{tabular} };
]
]
\end{tikzpicture}
\end{scaletikzpicturetowidth}
\clearpage
\begin{scaletikzpicturetowidth}{\textwidth}
\begin{tikzpicture}[scale=\tikzscale, baseline=0pt, grow=down]
\tikzset{level distance = 25pt, sibling distance = -5pt}
\tikzset{every tree node/.style={align=center,anchor=north}}
\Tree
[. \node{ $np$};
[. \node{\begin{tabular}{c}
\texttt{some}\\
\textbf{some}\\
\normalsize{na}\\
\scriptsize{na}\\
\scriptsize{na}\\
\end{tabular} }; ]
[. \node{\begin{tabular}{c}
\texttt{girl}\\
\textbf{girl}\\
\normalsize{na}\\
\scriptsize{na}\\
\scriptsize{na}\\
\end{tabular} }; ]
]
\end{tikzpicture}
\end{scaletikzpicturetowidth}
\clearpage
\end{document}

• You could just use \resizebox{} instead. – John Kormylo Jun 7 '14 at 17:48
• what about an aspect ratio then? It still needs to be calculated whether to fit to the page width or to the page height. – Fibo Kowalsky Jun 7 '14 at 18:05
• I think adjustbox can help you. It can scale to a maximum width or/and height. – Ignasi Jun 9 '14 at 6:12

You could probably do this using tikz internal scale, but this is fast and works on anything.

\documentclass{article}
\usepackage{tikz}
\usepackage{graphics}

\newlength{\xsize}
\newlength{\ysize}
\newsavebox{\tempbox}

\newcommand{\maxsize}[1]% #1=image to be scaled
{\savebox{\tempbox}{#1}%
\settoheight{\ysize}{\usebox{\tempbox}}%
\settowidth{\xsize}{\usebox{\tempbox}}%
\pgfmathparse{\xsize/\textwidth > \ysize/\textheight}%
\noindent%
\if\pgfmathresult1\resizebox{\textwidth}{!}{\usebox{\tempbox}}%
\else\centering\resizebox{!}{\textheight}{\usebox{\tempbox}}%
\fi}

\begin{document}
\vspace*{-\baselineskip}% first page only
\maxsize{\rule{3in}{1in}}

\maxsize{\rule{1in}{5in}}

\end{document}


Further study shows that the problem with the first page comes from round off error in \resizebox. Consequently I revised the solution to be more robust. It originally had additional code to test and truncate \MaxScale, but that turned out to be unnecessary.

\documentclass{article}
\usepackage{tikz}
\usepackage{graphics}

\newlength{\MaxWidth}
\newlength{\MaxHeight}
\newsavebox{\MaxBox}

\newcommand{\maxsize}[1]% #1=image to be scaled
{\savebox{\MaxBox}{#1}% get size of box
\settoheight{\MaxHeight}{\usebox{\MaxBox}}%
\settodepth{\MaxWidth}{\usebox{\MaxBox}}%
\settowidth{\MaxWidth}{\usebox{\MaxBox}}%
\pgfmathdivide{\textwidth}{\MaxWidth}% compute scale for width
\let\MaxScale=\pgfmathresult%
\ifdim\MaxScale\MaxHeight>\textheight% compute scale for height
\pgfmathdivide{\textheight}{\MaxHeight}
\let\MaxScale=\pgfmathresult%
\fi%
\noindent\centering\scalebox{\MaxScale}{\usebox{\MaxBox}}}

\begin{document}

\maxsize{\rule{1in}{5in}}

\maxsize{\rule{3in}{1in}}

\end{document}

• Thank you. This solution works and it is universal. Just it was leaving a blank page in the beginning. so, I had to decrease \textwidth in \else\resizebox{!}{\textheight-2cm}{\usebox{\tempbox}}% and use package calc – Fibo Kowalsky Jun 8 '14 at 11:30
• \vspace*{-12pt} on the first page only also works. – John Kormylo Jun 8 '14 at 13:29
• On further reflection, the reduced \textheight and \textwidth is more general. However, you only need to reduce it by 1pt or so. – John Kormylo Jun 8 '14 at 15:26