5

Is there a way to have tikz ignore the white space produced by a node's inner sep when calculating the picture's bounding box?

Consider the following MWE:

\documentclass{article}

\usepackage[showframe,pass]{geometry}
\usepackage{tikz}

\begin{document}

\noindent \begin{tikzpicture}
\node[inner sep=0pt] (X) {X};
\draw (X) -- ++ (0.5, 0);
\draw[gray] (current bounding box.south west) rectangle (current bounding box.north east);
\end{tikzpicture}

\noindent X

\noindent \begin{tikzpicture}
\node[inner sep=2pt] (X) {X};
\draw (X) -- ++ (0.5, 0);
\draw[gray] (current bounding box.south west) rectangle (current bounding box.north east);
\end{tikzpicture}

\end{document}

Here's the output:

enter image description here

In this example, the inner sep is useful when drawing lines from/to the node (see the horizontal line in the example), but on the other side, it indents the second X with regard to the normal text. Some way of specifying the bounding box as the smallest rectangle containing all "ink" (and thereby clipping all inner seps and possibly other white spaces that needlessly extend the bounding box) would be great here...

  • use trim left=##pt key to shave off the amount you like – percusse Nov 18 '13 at 9:38
  • There is also outer sep for a node. You have to make it 0 too. – user11232 Nov 18 '13 at 9:43
  • The gray line adds also space. Also: tikz: double lines are shifted – Qrrbrbirlbel Nov 18 '13 at 12:29
  • @percusse: Thanks for the tip, I did not know that. However, I was looking for a (more) automated solution... – rainer Nov 19 '13 at 12:00
  • @HarishKumar, Qrrbrbirlbel: thanks for mentioning those, I did not yet think of them. – rainer Nov 19 '13 at 12:00
4

This solution does not really ignore inner sep for bounding box calculation, but might give the desired result in many cases.

It seems that the value of outer sep does not influence the bounding box. So using outer sep instead and setting inner sep = 0 does the trick.

This approach does even work partially for other shapes. In this case a negative inner sep (or inner xsep or inner ysep) may help with quick and dirty fine tuning.

\documentclass[border = 1, varwidth]{standalone}
\usepackage{tikz}
\begin{document}
    \begin{tikzpicture}
        \node[inner sep = 0, outer sep = 0.3333em] (X) {X};
        \foreach \a in {0, 5, ..., 90} \draw (X) -- ++(\a:2em);
        \fill[black, opacity = 0.25] (current bounding box.south west)
                           rectangle (current bounding box.north east);
    \end{tikzpicture}
    \begin{tikzpicture}
        \node[inner sep = 0em, outer sep = 0.3333em, circle] (X) {X};
        \foreach \a in {0, 5, ..., 90} \draw (X) -- ++(\a:2em);
        \fill[black, opacity = 0.25] (current bounding box.south west)
                           rectangle (current bounding box.north east);
    \end{tikzpicture}

    \pgfkeysvalueof{/pgf/inner xsep}
\end{document}

enter image description here

I have printed out the default value for inner sep for reference.

3

I like krnk's answer, which was exactly what I was looking for.

The amount of code copied from TikZ can be reduced by using the shape inheritance mechanism (which may not have been available at the time of the original answer, I don't know).

I also changed the background path so that the original rectangle is created without updating the bounding box. This makes it possible to fill the rectangle white, for instance.

\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{backgrounds}

\makeatletter
\pgfdeclareshape{tight}{
    % inherit as much stuff as possible from the rectangle shape
    \inheritsavedanchors[from=rectangle]
    \foreach \x in {east,west} \foreach \y in {north,mid,base,south} {
        \inheritanchor[from=rectangle]{\y\space\x}
    }
    \foreach \x in {east,west,north,mid,base,south,center,text} {
        \inheritanchor[from=rectangle]{\x}
    }
    \inheritanchorborder[from=rectangle]
    \inheritbackgroundpath[from=rectangle]

    \savedanchor\tightnortheast{%
        \pgfpoint{\wd\pgfnodeparttextbox}
                 {\ht\pgfnodeparttextbox}%
    }

    \savedanchor\tightsouthwest{%
        \pgfpoint{0pt}
                 {-\dp\pgfnodeparttextbox}%
    }

    \backgroundpath{%
        % move to each of the tight corners, updating the bounding box
        \pgfpathmoveto\tightsouthwest
        \pgfpathmoveto\tightnortheast
        \pgfpathmoveto{\tightsouthwest\pgf@xa=\pgf@x\tightnortheast\pgf@x=\pgf@xa}%
        \pgfpathmoveto{\tightsouthwest\pgf@ya=\pgf@y\tightnortheast\pgf@y=\pgf@ya}%

        % draw the usual recangle border without affecting the bounding box
        \pgf@relevantforpicturesizefalse
        \pgfpathrectanglecorners\southwest
                                \northeast
        % this is executed in a grop, so bounding box tracking automatically
        % gets re-enabled if it was enabled to begin with
    }
}
\makeatother

\begin{document}
    \foreach \shape in {rectangle, tight} {
        \par shape = \shape:\par
        \begin{tikzpicture}[framed,tight background]
            \node[\shape] at (0,0) (x) {x};
            \node[\shape] at (1,0) (y) {y};

            \draw (x) -- (y);
        \end{tikzpicture}
    }
\end{document}

output

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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