Take the 2-minute tour ×
TeX - LaTeX Stack Exchange is a question and answer site for users of TeX, LaTeX, ConTeXt, and related typesetting systems. It's 100% free, no registration required.

When I draw a tikzpicture that includes paths, I get quite a bit of extra whitespace added around the elements of the picture. Depending on the elements the figure contains, this can work out in some dimensions and not others, but is never entirely what I want, for example:

enter image description here

If I attempt to fix this using overlay with the paths, the picture is shifted (closer) to the left, but I get too little whitespace, and elements overflow onto the text:

enter image description here

How do a make sure that there is no unwanted whitespace around a tikzpicture, while ensuring that there is no overflow onto adjacent elements?

Is there a way to set a whitespace "margin" around a tikzpicture?


\documentclass[]{article}

\usepackage{lipsum}

\usepackage{tikz}
\usetikzlibrary{topaths}
\usetikzlibrary{positioning}
\usetikzlibrary{arrows}
\usetikzlibrary{shapes.geometric} 
\usetikzlibrary{petri}
\tikzset{
    redarrow/.style={->, red, fill=none,>=angle 60, thick},  
    bluearrow/.style={->, blue, fill=none,>=angle 60, thick}}

\begin{document}

\newcommand{\demofig}{
    \begin{tikzpicture} [
        grpobject/.style={regular polygon, regular polygon sides=\grpdim,minimum height=2cm},
        grpmark/.style={circle,inner sep=2.0pt} ]
        \def\scale{\grpdim/1.4}
        \foreach \i [evaluate=\i as \angle using \grpstartangle+(\i-1)*360/\grpdim] in {1,...,\grpdim}{
            \def\nodeloc{({\scale*cos(\angle))},{\scale*sin(\angle))})}
            \begin{scope} [rotate around={(360/\grpdim)*(\i-1):\nodeloc },every node/.style={transform shape}]
                \node[grpobject,draw=black] (\i) at \nodeloc {}; 
                \node[grpobject,draw=black,minimum height=1.4cm,draw opacity=0.0] (markgrid) at \nodeloc {}; 
                \node[grpmark,fill=gray!75] at (markgrid.corner 1) {}; 
            \end{scope};}
        \foreach \i [remember=\i as \j (initially \grpdim)] in {1,...,\grpdim}{
            \draw[redarrow,overlay](\i)--(\j);}
        \draw[bluearrow,\doover](1)to[loop,looseness=4,min distance=2cm](1);
    \end{tikzpicture} }

Here's what happens when drawing a figure that includes paths. Quite a bit of white space is added around the \texttt{tikzpicture}, which looks alright vertically, but places the figure off to the right a bit:

\def\grpdim{4}
\def\grpstartangle{135}
\def\doover{}
\demofig

This is not what I want.

\pagebreak{}

Here's what happens if I use \texttt{overlay} when drawing paths; the \texttt{tikzpicture} ends up flowing over the text.

\def\grpdim{4}
\def\grpstartangle{135}
\def\doover{overlay}
\demofig

This is not what I want either

\bigskip{}

How do a make sure that there is no extra whitespace around a \texttt{tikzpicture}, while ensuring that there is no overflow onto adjacent elements? Is there a way to set a whitespace "margin" around a \texttt{tikzpicture}?

\end{document}

Note that focus here is the final question. I'm aware that there are methods measuring the actual extent of the tikzpicture, and for manually clipping and buffering the edges, the most accurate of which involve additional packages applied to the picture it its own document. The question here is whether TikZ knows the actual extent of figure elements so that one can simply create whitepace buffers, relative to extent of the visible content, similar to CSS margins.

share|improve this question
    
You should use \noindent\demofig, otherwise you get a para indent inserted. And you have a spurious space at the start of the \newcommand, so it should have a trailing %: \newcommand{\demofig}{% –  Peter Grill May 27 '12 at 4:13
1  
duplicate I think with bounding-box-is-larger-than-expected-when-drawing-a-curved-path tex.stackexchange.com/questions/43621/… –  Alain Matthes May 27 '12 at 5:54
    
@Altermundus: The setup is similar but the question is a bit different; namely, is there a way to set a margin — i.e., some padding relative to the actual extent of the image elements. I've added a note to the question to that effect. –  raxacoricofallapatorius May 27 '12 at 11:56
1  
That's actually slightly simpler: you just enlarge the bounding box with \useasboundingbox ([shift={(5mm,5mm)}]current bounding box.north east) rectangle ([shift={(-5mm,-5mm)}]current bounding box.south west); in the end of the picture. However, you have to first narrow down your bounding box free from any control points. Hence, I would recommend you to have a look at the red dots in the Peter's answer in the link that Altermundus provided. –  percusse May 27 '12 at 12:14
    
@Altermundus: Is there a simple general way to cut the control points out of the bounding box? –  raxacoricofallapatorius May 27 '12 at 12:18

4 Answers 4

up vote 17 down vote accepted

Once you remove the spurious space at the start of \newcommand:

\newcommand{\demofig}{%

and remove the paragraph indentation via:

\noindent\demofig

you get:

enter image description here

The bounding box was shown by adding:

\draw [brown] (current bounding box.south west) rectangle (current bounding box.north east);

Now the extra space is only from the picture itself. To eliminate that you could either use pfdcrop and read the BBox as per Bounding box is larger than expected when drawing a curved path, or draw a grid to figure out the coordinates to clip the figure.

Grid to determine \clip path:

Adding the following draw command:

\draw[gray,step=0.25] (-4,-3) grid (3, 4);

shows:

enter image description here

From this you can determine the clip path to be:

\clip (-3.25,-2.75) rectangle (2.75, 4);

Applying this clip path you get the desired results (with the showframe package used to show the page margins):

enter image description here

Code:

\documentclass[]{article}

\usepackage{lipsum}
\usepackage{showframe}

\usepackage{tikz}
\usetikzlibrary{topaths}
\usetikzlibrary{positioning}
\usetikzlibrary{arrows}
\usetikzlibrary{shapes.geometric} 
\usetikzlibrary{petri}
\tikzset{
    redarrow/.style={->, red, fill=none,>=angle 60, thick},  
    bluearrow/.style={->, blue, fill=none,>=angle 60, thick}}

\begin{document}

\newcommand{\demofig}{%
    \begin{tikzpicture} [
        grpobject/.style={regular polygon, regular polygon sides=\grpdim,minimum height=2cm},
        grpmark/.style={circle,inner sep=2.0pt} ]
        \clip (-3.25,-2.75) rectangle (2.75, 4);
        \def\scale{\grpdim/1.4}
        \foreach \i [evaluate=\i as \angle using \grpstartangle+(\i-1)*360/\grpdim] in {1,...,\grpdim}{
            \def\nodeloc{({\scale*cos(\angle))},{\scale*sin(\angle))})}
            \begin{scope} [rotate around={(360/\grpdim)*(\i-1):\nodeloc },every node/.style={transform shape}]
                \node[grpobject,draw=black] (\i) at \nodeloc {}; 
                \node[grpobject,draw=black,minimum height=1.4cm,draw opacity=0.0] (markgrid) at \nodeloc {}; 
                \node[grpmark,fill=gray!75] at (markgrid.corner 1) {}; 
            \end{scope};}
        \foreach \i [remember=\i as \j (initially \grpdim)] in {1,...,\grpdim}{
            \draw[redarrow,overlay](\i)--(\j);}
        \draw[bluearrow,\doover](1)to[loop,looseness=4,min distance=2cm](1);
    %\draw [brown] (current bounding box.south west) rectangle (current bounding box.north east);
    %\draw[gray,step=0.25] (-4,-3) grid (3, 4);
    \end{tikzpicture} }


\noindent
Once you add the clip path you get the image aligned all the way to the left margin as desired:

\def\grpdim{4}
\def\grpstartangle{135}
\def\doover{}
\noindent\demofig
\end{document}
share|improve this answer
1  
Thanks. This fully answers the first part of my question, and implicitly the second, but I want to make sure: The answer there appears to be "no" — that TikZ doesn't (always) know what the extent of its own pictures is—is that right? –  raxacoricofallapatorius May 27 '12 at 12:01
1  
@raxacoricofallapatorius: I am not aware of an automated method, but since pdfcrop can do it it certainly should be doable. –  Peter Grill May 27 '12 at 19:38

The TikZ picture is just another box, as far as TeX is concerned. Add as Peter mentioned in the comments add a \noindent and remove any spurious spaces.

I normally add an \fbox to see what is happening.

enter image description here

The \fbox is added as:

    \fbox{\begin{tikzpicture}...\end{tikzpicture}}

As your code is a bit involved, the easiest and quickest way to adjust the image is with an \hspace.

   \hspace*{-50pt}\begin{tikzpicture}...\end{tikzpicture}
share|improve this answer

You can use the adjustbox package/environment to add and remove space around any content including a tikzpicture. Simply use {adjustbox}{margin=..} to add white space or {adjustbox}{trim=..} to reduce the official size (i.e. reduce white space or let material overlap). Both keys allow for different values for the different sides.

share|improve this answer
    
But adjust box has no knowledge of the actual extent of the visual elements in the picture, correct? That is, the values for trim and margin are relative to how TikZ happens to size the picture (and not the actual extent of its visual elements), right? –  raxacoricofallapatorius May 27 '12 at 15:22
1  
@raxacoricofallapatorius: Yes, adjustbox does not now the real amount of white space in the content. You can however use relative amounts if you use the \width, \height, \depth and \totalheight macros as part of the trim or margin values. –  Martin Scharrer May 27 '12 at 15:27

I fixed this issue by adding an empty node below the lowest element:

\node[] () [below = 1.5em] at (sig.west) {};

Sort of manually adding the margin where needed.

Another (very useful, and possibly prettier) solution is using a trimbox:

\usepackage{adjustbox}
...
\trimbox{-1cm -.5cm -1cm 0cm}{ 
% your tikzpicture goes here
}

This adds margins of one cm left and right, and .5 cm below, and 0 cm at the top. Actually, this is comparable to the CSS margins you were looking for.

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.