3

This question is a follow-up on a previous question: positioning of a matrix bigger than margins

That question dealt with positioning a pgf matrix that exceeded the horizontal margins of the page (although I imagine this works for floats as well?), and both answers provide a solution to the problem.

However, none of those solutions work if the matrix is bigger than the margins both horizontally and vertically.

How can I make sure that a matrix that is (slightly) too big for the margins is centered on the text area, both vertically and horizontally?

It seems to me that, out of the answers provided in the previous question, the one based on stackengine might be more up to the task (that's why I chose to use that one below), but this may well not be the case, and of course I'm open to all sorts of suggestions.

This is a sample document using the stackengine solution:

\documentclass{article}
\usepackage{tikz}
\usepackage{pgf}
\usetikzlibrary{matrix}
\usepackage{stackengine}
\newcommand\zerowidth[2][c]{\stackengine{0pt}{}{#2}{O}{#1}{F}{T}{L}}
\begin{document}
\newsavebox\toowide
\setbox0=\hbox{%
\begin{tikzpicture}
  \matrix [
      matrix of nodes,
      nodes={
        text depth=4em,
        text height=5em,
        minimum width=10em,
        draw
      },
      row sep=-\pgflinewidth,
      column sep=-\pgflinewidth,
    ]
  {
    A & B & C & D \\
    A & B & C & D \\
    A & B & C & D \\
    A & B & C & D \\
    A & B & C & D \\
    A & B & C & D \\
    A & B & C & D \\
    A & B & C & D \\
  };
\end{tikzpicture}
\unskip}

\sbox\toowide{\box0}

\centering\zerowidth{\usebox{\toowide}}

\noindent\rule{\textwidth}{1ex}
\end{document}

Update

Ok, I guess there are some more details that I should have added to make this question more closely reflect the actual problem. In the actual document the chart is within a table which is much wider than tall, so the table is also inside a landscape environment. This new MWE reflects that, and includes the partial solution by Qrrbrbirlbel:

\documentclass{article}
\usepackage{pdflscape}
\usepackage{tikz}
\usepackage{pgf}
\usetikzlibrary{matrix}
\newenvironment{xycenter}
  {\par\setbox0=\hbox\bgroup\ignorespaces}
  {\unskip\egroup\noindent\parbox[c][\textheight][c]{\hsize}{\makebox[\hsize]{\box0}}\par}
\begin{document}
\begin{landscape}
\begin{table}
\caption{This is my awesome caption}
\begin{xycenter}
\begin{tikzpicture}
  \matrix [matrix of nodes,
      nodes={
        text depth=3.5em,
        text height=4.5em,
        minimum width=9em,
        draw
      },
      row sep=-\pgflinewidth,
      column sep=-\pgflinewidth,
    ]
  {
    A & B & C & D & E & F & G \\
    A & B & C & D & E & F & G \\
    A & B & C & D & E & F & G \\
    A & B & C & D & E & F & G \\
    A & B & C & D & E & F & G \\
  };
\end{tikzpicture}
\end{xycenter}
\end{table}
\end{landscape}
\end{document}

The size of the matrix in this case might make it look like the caption should really not be on this page at all, but the actual chart is just a bit bigger than the page, so it's not as bad as this.

An alternative solution would be to be able to use scale in the tikzpicture options, but that's the first thing I tried and it didn't seem to change anything. If scaling were possible, then I wouldn't need to fiddle so much with trying to squeeze this into that page. I'm starting to think I should rename this question...

jja
  • 1,813

3 Answers3

3

TikZ/tikzpagenodes

With the tikzpagenodes package, all you need is the overlay-remember picture combination, the current page text area (pseudo) node and \newpages so that the page only has the matrix on it (the overlay option disables the calculation of the bounding box).

Code

\documentclass{article}
\usepackage{tikzpagenodes}
\usetikzlibrary{matrix}
\usepackage[showframe,pass]{geometry}
\begin{document}
\begin{tikzpicture}[overlay,remember picture]
  \matrix at (current page text area.center) [
      matrix of nodes,
      nodes={
        text depth=4em,
        text height=5em,
        minimum width=10em,
        draw
      },
      row sep=-\pgflinewidth,
      column sep=-\pgflinewidth
    ]
  {
    A & B & C & D \\
    A & B & C & D \\
    A & B & C & D \\
    A & B & C & D \\
    A & B & C & D \\
    A & B & C & D \\
    A & B & C & D \\
    A & B & C & D \\
  };
\end{tikzpicture}
\end{document}

More environments

Expanding on egreg’s answer, one could add the environments ycenter and xycenter.

Code

\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{matrix}
\usepackage[showframe,pass]{geometry}
\newenvironment{xcenter}
 {\par\setbox0=\hbox\bgroup\ignorespaces}
 {\unskip\egroup\noindent\makebox[\textwidth]{\box0}\par}
\newenvironment{ycenter}
 {\par\setbox0=\hbox\bgroup\ignorespaces}
 {\unskip\egroup\noindent\parbox[c][\textheight][c]{\textwidth}{\box0}\par}
\newenvironment{xycenter}
 {\par\setbox0=\hbox\bgroup\ignorespaces}
 {\unskip\egroup\noindent\parbox[c][\textheight][c]{\textwidth}{\makebox[\textwidth]{\box0}}\par}
\begin{document}
\begin{xycenter}
\begin{tikzpicture}
  \matrix [
      matrix of nodes,
      nodes={
        text depth=4em,
        text height=5em,
        minimum width=10em,
        draw
      },
      row sep=-\pgflinewidth,
      column sep=-\pgflinewidth
    ]
  {
    A & B & C & D \\
    A & B & C & D \\
    A & B & C & D \\
    A & B & C & D \\
    A & B & C & D \\
    A & B & C & D \\
    A & B & C & D \\
    A & B & C & D \\
  };
\end{tikzpicture}
\end{xycenter}
\end{document}

Output

enter image description here

Qrrbrbirlbel
  • 119,821
  • This does indeed work, but I've bumped into another problem: this matrix is taking the place of a table in the final document. If I put the table inside xycenter it fails with a not in outer par mode error; if I put the xycenter environment inside the table, it works ok as long as there is no caption. But using a caption inside the table but outside xycenter throws the alignment off, and including the caption in xycenter fails with a You can't use \hrule here except with leaders. I'll update the MWE to reflect these (more realistic) conflicts. – jja Aug 21 '13 at 11:48
  • @jja Yes, you can’t put a float inside a box, it wouldn’t be able float anymore. Though, to be fair, this doesn’t look like a float anymore, just a single page. For TeX, the TikZ picture is in a box the size of the text area thus the caption (between \end{xycenter} and \end{table}) will end up just below the text area. Maybe using \captionof without a float would be better but the same \hrule leaders error comes up. Maybe it would be easier to simply make the text area as big as possible while fixing its center but I am no geometry expert. – Qrrbrbirlbel Aug 21 '13 at 12:10
  • Thanks for the suggestions. In my case, percusse's answer seemed to work, but your comments may come in handy for others. – jja Aug 21 '13 at 13:04
3

You can also trim the bounding box such that the picture still occupies a box with nonzero width and height.

\documentclass{article}
\usepackage[pass,showframe]{geometry} % just to show the margins

\usepackage{tikz}
\usetikzlibrary{matrix,calc}

\tikzset{fit to page/.style={fit only width,fit only height},
         fit only width/.style={
                    trim left={($(current bounding box.center)-(0.5*\textwidth,0)$)},
                    trim right={($(current bounding box.center)+(0.5*\textwidth,0)$)},
          },
          fit only height/.style={
                     execute at end picture={%
                     \useasboundingbox let 
                           \p1=(current bounding box.north east),
                           \p2=(current bounding box.south west) in
                           \pgfextra{\pgfresetboundingbox}
                           (\x2,-0.5*\textheight) rectangle (\x1-(0,0.5*\textheight);
                    }
          }
}

\begin{document}
\noindent
\begin{tikzpicture}[fit to page]
 \matrix [matrix of nodes,
      nodes={
        text depth=4em,
        text height=5em,
        minimum width=10em,
        draw
      },
      row sep=-0.5\pgflinewidth,
      column sep=-0.5\pgflinewidth,
    ]
  {
    A & B & C & D \\
    A & B & C & D \\
    A & B & C & D \\ 
    A & B & C & D \\
    A & B & C & D \\
    A & B & C & D \\        
    A & B & C & D \\        
  };

\end{tikzpicture}
\end{document}

enter image description here

For the updated MWE,

\documentclass{article}
\usepackage[pass,showframe]{geometry} % just to show the margins
\usepackage{tikz,rotating}
\usetikzlibrary{matrix,calc}

\tikzset{fit to page/.style={fit only width,fit only height},
         fit only width/.style={
                    trim left={($(current bounding box.center)-(0.5*\textwidth,0)$)},
                    trim right={($(current bounding box.center)+(0.5*\textwidth,0)$)},
          },
          fit only height/.style={
                     execute at end picture={%
                     \useasboundingbox let 
                           \p1=(current bounding box.north east),
                           \p2=(current bounding box.south west) in
                           \pgfextra{\pgfresetboundingbox}
                           (\x2,-0.5*\textheight) rectangle (\x1-(0,0.5*\textheight);
                    }
          }
}

\begin{document}
\begin{sidewaystable}
\begin{tikzpicture}[fit only width]
 \matrix [matrix of nodes,
      nodes={
        text depth=4em,
        text height=5em,
        minimum width=10em,
        draw
      },
      row sep=-0.5\pgflinewidth,
      column sep=-0.5\pgflinewidth,
    ]
  {
    A & B & C & D & B & C & D \\
    A & B & C & D & B & C & D \\
    A & B & C & D & B & C & D \\        
  };

\end{tikzpicture}
\caption{AGA}
\label{asdf}
\end{sidewaystable}
\end{document}

enter image description here

percusse
  • 157,807
  • This did it. Interestingly, the caption wouldn't show unless I typed the tikzpicture into the source file. If I used input to load it from a separate file the caption would not print. – jja Aug 21 '13 at 13:02
1

The stackengine approach...

\documentclass{article}
\usepackage{tikz}
\usepackage{pgf}
\usetikzlibrary{matrix}
\usepackage{stackengine}
\usepackage[pass,showframe]{geometry}
\newcommand\zerowidth[2][c]{\stackengine{0pt}{}{#2}{O}{#1}{F}{T}{L}}
\begin{document}
\newsavebox\toowideANDtall
\setbox0=\hbox{%
\begin{tikzpicture}
  \matrix [
      matrix of nodes,
      nodes={
        text depth=4em,
        text height=5em,
        minimum width=10em,
        draw
      },
      row sep=-\pgflinewidth,
      column sep=-\pgflinewidth,
    ]
  {
    A & B & C & D \\
    A & B & C & D \\ 
    A & B & C & D \\
    A & B & C & D \\
    A & B & C & D \\
    A & B & C & D \\
    A & B & C & D \\
    A & B & C & D \\
  };
\end{tikzpicture}
\unskip}
\sbox\toowideANDtall{\box0}
\def\useanchorwidth{T}
\def\stacktype{L}
\savestack{\XYZ}{\belowbaseline[.5\ht\toowideANDtall-\baselineskip]{%
  \zerowidth{\usebox{\toowideANDtall}}}}
{\centering
\belowbaseline[.5\textheight]{\smash{\XYZ}}\par
}
\end{document}

enter image description here