8

I thought I knew how the on grid option of TikZ (cf. version 2.10 manual section 16.5.3 pages 186-187) worked, but the results I get are different from what I expected.

I have a minimal example:

\documentclass{article}
\usepackage{tikz}
  \usetikzlibrary{positioning}
\begin{document}
\begin{tikzpicture}
  \begin{scope}[red]
    \coordinate (a) at (0,0);
    \node[below=of a,draw] (anode) {};
    \draw[-|] (anode) -- (a);
    \node (b) at (.3,0) {};
    \node[below=of b,draw] (bnode) {};
    \draw[-|] (bnode) -- (b);
  \end{scope}
  \begin{scope}[green,dashed]
    \coordinate (a) at (0,0);
    \node[on grid,below=of a,draw] (anode) {};
    \draw[->] (anode) -- (a);
    \node (b) at (.3,0) {};
    \node[on grid,below=of b,draw] (bnode) {};
    \draw[->] (bnode) -- (b);
  \end{scope}
\end{tikzpicture}
\end{document}

It results in the following figure:

illustration of 'on grid' node positioning option

I would have expected (and hoped...) that on the left, the dashed green node were positioned at the same height as the dashed green one on the right. (All other picture elements are correct, as far as I can tell.) From the description in the manual, I do not see why this is not the case:

When you say above=1cm of somenode with on grid set to true, the new node will be placed in such a way that its center is 1cm above the center of somenode.

The only non-standard thing in my example is that then reference node is a coordinate, but I do not see why it results in the observed behavior, as this is just a node with only a center.

I would be grateful for an explanation of the observed behavior, and perhaps workaround to get the behavior I expected.

0

2 Answers 2

5

A node will have inner sep unless you make it zero yourself, where as a co-ordinate doesn't. And further a node doesn't create a geometric point. Your code with all inner sep=0 will give

\documentclass{article}
\usepackage{tikz}
  \usetikzlibrary{positioning}
\begin{document}
\begin{tikzpicture}
  \begin{scope}[red]
    \coordinate (a) at (0,0);
    \node[inner sep=0,below=of a,draw] (anode) {};
    \draw[-|] (anode) -- (a);
    \node[inner sep=0] (b) at (.3,0) {};
    \node[inner sep=0,below=of b,draw] (bnode) {};
    \draw[-|] (bnode) -- (b);
  \end{scope}
  \begin{scope}[green,dashed]
    \coordinate (a) at (0,0);
    \node[inner sep=0,on grid,below=of a,draw] (anode) {};
    \draw[->] (anode) -- (a);
    \node[inner sep=0] (b) at (.3,0) {};
    \node[inner sep=0,on grid,below=of b,draw] (bnode) {};
    \draw[->] (bnode) -- (b);
  \end{scope}
\end{tikzpicture}
\end{document}

enter image description here

Note that the horizontal red line on right is lower than that on the left even though the inner sep is set to zero. (changing \node[inner sep=0] (b) at (.3,0) {}; to \coordinate (b) at (.3,0); will fix it and this is one option to get things right.)

Replacing

\coordinate (a) at (0,0);

with

\node[inner sep=0cm] (a) at (0,0) {};

inside the scope, gives

\documentclass{article}
\usepackage{tikz}
  \usetikzlibrary{positioning}
\begin{document}
\begin{tikzpicture}
  \begin{scope}[red]
    \coordinate (a) at (0,0);
    %\node[] (a) at (0,0) {};
    \node[inner sep=0,below=of a,draw] (anode) {};
    \draw[-|] (anode) -- (a);
    \node[inner sep=0] (b) at (.3,0) {};
    \node[inner sep=0,below=of b,draw] (bnode) {};
    \draw[-|] (bnode) -- (b);
  \end{scope}
  \begin{scope}[green,dashed]
    %\coordinate (a) at (0,0);
    %\node[] (a) at (0,0) {};
    \node[inner sep=0cm] (a) at (0,0) {};
    \node[inner sep=0,on grid,below=of a,draw] (anode) {};
    \draw[->] (anode) -- (a);
    \node[inner sep=0] (b) at (.3,0) {};
    %\coordinate (b) at (.3,0);
    \node[inner sep=0,on grid,below=of b,draw] (bnode) {};
    \draw[->] (bnode) -- (b);
  \end{scope}
\end{tikzpicture}
\end{document}

enter image description here

Without inner sep = 0 we will get,

\documentclass{article}
\usepackage{tikz}
  \usetikzlibrary{positioning}
\begin{document}
\begin{tikzpicture}
  \begin{scope}[red]
    \coordinate (a) at (0,0); 
    \node[below=of a,draw] (anode) {};
    \draw[-|] (anode) -- (a);
    \node[] (b) at (.3,0) {};
%    \coordinate (b) at (.3,0);
    \node[below=of b,draw] (bnode) {};
    \draw[-|] (bnode) -- (b);
  \end{scope}
  \begin{scope}[green,dashed]
    %\coordinate (a) at (0,0);
    %\node[] (a) at (0,0) {};
    \node (a) at (0,0) {};
    \node[on grid,below=of a,draw] (anode) {};
    \draw[->] (anode) -- (a);
    \node (b) at (.3,0) {};
    %\coordinate (b) at (.3,0);
    \node[on grid,below=of b,draw] (bnode) {};
    \draw[->] (bnode) -- (b);
  \end{scope}
\end{tikzpicture}
\end{document}

enter image description here

Option -2 Replacing \node[inner sep=0] (b) at (.3,0) {}; to \coordinate (b) at (.3,0); in your code gives

\documentclass{article}
\usepackage{tikz}
  \usetikzlibrary{positioning}
\begin{document}
\begin{tikzpicture}
  \begin{scope}[red]
    \coordinate (a) at (0,0);
    \node[below=of a,draw] (anode) {};
    \draw[-|] (anode) -- (a);
    \coordinate (b) at (.3,0);
    \node[below=of b,draw] (bnode) {};
    \draw[-|] (bnode) -- (b);
  \end{scope}
  \begin{scope}[green,dashed]
    \coordinate (a) at (0,0);
    \node[on grid,below=of a,draw] (anode) {};
    \draw[->] (anode) -- (a);
    \coordinate (b) at (.3,0);
    \node[on grid,below=of b,draw] (bnode) {};
    \draw[->] (bnode) -- (b);
  \end{scope}
\end{tikzpicture}
\end{document}

enter image description here

I do not see why this is not the case:

When you say above=1cm of somenode with on grid set to true, the new node will be placed in such a way that its center is 1cm above the center of somenode.

The only non-standard thing in my example is that then reference node is a coordinate, but I do not see why it results in the observed behavior, as this is just a node with only a center.

And I don't know how to answer this, with all the above facts. May be some experts will shed light on this.

4
  • Thanks for your elaborate answer. However, inner sep is not the issue; in your version with inner sep universally set to zero, you still get the same qualitative behavior as in my version. Also, I can't just change \coordinate by \node in my code just because the coordinates are points where in and outgoing lines should touch (which is not the case with nodes, even with zero inner sep).
    – equaeghe
    Oct 13, 2012 at 15:32
  • @equaeghe: The idea of on grid is meant for use with nodes so that everything is emulated as on grid. With coordinates I think it is meaningless. Hence it would be better to use all nodes than mixing them with coordinates IMO.
    – user11232
    Oct 13, 2012 at 18:11
  • Sorry, but it certainly does make sense when mixing nodes and coordinates. In my block diagram use case, some nodes correspond to summation blocks, but if only one signal (branch) enters the summation, the summation block is by convention removed, leading me to replace that node by a coordinate. And it would all work perfectly if only the on grid positioning option would work consistently with both nodes and coordinates. (I now think the current behavior may be a bug.)
    – equaeghe
    Oct 13, 2012 at 18:32
  • @equaeghe: :( Sorry I could not help much. :)
    – user11232
    Oct 13, 2012 at 18:34
3

The problem is that on grid and below = of <name> seem to have no effect if <name> belongs to a \coordinate instead of to a \node (see the summary diagram at the bottom). You can use a \node with inner sep=0pt instead of a \coordinate (I draw a grid only as a visual help):

\documentclass{article}
\usepackage{tikz}
  \usetikzlibrary{positioning}
\begin{document}
\begin{tikzpicture}
  \draw[help lines,gray!20] (-1,-2) grid[step=2mm] (1,1);
  \begin{scope}[red]
    \coordinate (a) at (0,0);
    \node[below=of a,draw] (anode) {};
    \draw[-|] (anode) -- (a);
    \node (b) at (.3,0) {};
    \node[below=of b,draw] (bnode) {};
    \draw[-|] (bnode) -- (b);
  \end{scope}
  \begin{scope}[green,dashed]
    \node[inner sep=0pt] (a) at (0,0) {};
    \node[on grid,below = of a,draw] (anode) {};
    \draw[->] (anode) -- (a);
    \node (b) at (.3,0) {};
    \node[on grid,below = of b,draw] (bnode) {};
    \draw[->] (bnode) -- (b);
  \end{scope}
\end{tikzpicture}
\end{document}

enter image description here

The following diagram summarizes the behaviour of the on grid option for pairs formed by all possible combinations of \coordinates and \nodes. Nodes are drawn (the squares in the diagram); small circles are used to show the center for the \nodes and the positioning of \coordinates.

As can be noticed, using below = of <name>, when <name> belongs to a coordinate makes on grid to have no effect (the red cross on the diagram), and that explains the problem with your original code:

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

\begin{document}

\begin{tikzpicture}[scale=1.3,transform shape,node distance=1cm]
\draw[help lines,gray!20] (-0.5,-2) grid[step=2mm] (7.5,1);
\draw[help lines] (-0.5,0) -- +(-0.6,0);
\draw[help lines] (-0.5,-1) -- +(-0.6,0);
\draw[help lines,<->] (-0.8,0) -- node[fill=white] {\tiny 1cm} (-0.8,-1);

\node[align=left,anchor=south] at (3.5,1) {behaviour of \texttt{on grid} with nodes and coordinates};

% a and b are coordinates (on grid true or false produce the same result)
\coordinate (a) at (0,0);
\coordinate[below=of a] (b);
\foreach \point in {a,b}
{
  \draw (\point) circle (1pt);
  \node[label=left:\tiny\point] at (\point) {};
}

% a and b are coordinates (on grid true or false produce the same result)
\coordinate (a) at (1,0);
\coordinate[on grid,below=of a] (b);
\foreach \point in {a,b}
{
  \draw (\point) circle (1pt);
  \node[label=left:\tiny\point] at (\point) {};
}

% c is a coordinate and d is a node
\coordinate (c) at (2,0);
\node[draw,below=of c] (d) {};
\foreach \point in {c,d}
{
  \draw (\point) circle (1pt);
  \node[label=left:\tiny\point] at (\point) {};
}

% c is a coordinate and d is an on grid node (on grid has no effect)
\coordinate (c) at (3,0);
\node[draw,on grid,below = of c] (d) {};
\foreach \point in {c,d}
{
  \draw (\point) circle (1pt);
  \node[label=left:\tiny\point] at (\point) {};
}
\draw[thick,red] ([yshift=-15pt]d.north west) -- ([yshift=-15pt]d.south east);
\draw[thick,red] ([yshift=-15pt]d.north east) -- ([yshift=-15pt]d.south west);

% e is a node and f is a coordinate
\node[draw] (e) at (4,0) {};
\coordinate[below=of e] (f);
\foreach \point in {e,f}
{
  \draw (\point) circle (1pt);
  \node[label=left:\tiny\point] at (\point) {};
}

% e is a node and f is an on grid coordinate (on grid has effect)
\node[draw] (e) at (5,0) {};
\coordinate[on grid,below=of e] (f);
\foreach \point in {e,f}
{
  \draw (\point) circle (1pt);
  \node[label=left:\tiny\point] at (\point) {};
}

% g is a node and h is a node
\node[draw] (g) at (6,0) {};
\node[draw,below=of g] (h) {};
\foreach \point in {g,h}
{
  \draw (\point) circle (1pt);
  \node[label=left:\tiny\point] at (\point) {};
}

% g is a node and h is an on grid node  (on grid has effect)
\node[draw] (g) at (7,0) {};
\node[draw,on grid,below = of g] (h) {};
\foreach \point in {g,h}
{
  \draw (\point) circle (1pt);
  \node[label=left:\tiny\point] at (\point) {};
}
\end{tikzpicture}

\end{document}

enter image description here

Of course, using a \node instead of a \coordinate is not the same thing and might require some additional adjustments, but you can use inner sep and outer sep to get the desired result:

\documentclass{article}
\usepackage{tikz}

\begin{document}

\begin{tikzpicture}
\node (a) at (0,0) {};
\node[inner sep=0pt] (b) at (0,1) {};
\node[inner sep=0pt,outer sep=-2\pgflinewidth] (c) at (0,2) {};
\draw (-1,0) -- (a) -- (1,0);
\draw (-1,1) -- (b) -- (1,1);
\draw (-1,2) -- (c) -- (1,2);
\end{tikzpicture}

\end{document}

enter image description here

6
  • Isn't the below of= syntax deprecated (by the below=of syntax with on grid)? [Cf. tex.stackexchange.com/questions/9386]
    – equaeghe
    Oct 14, 2012 at 9:27
  • This answer provides a (temporary? see comment above) solution to my problem. Thanks!
    – equaeghe
    Oct 14, 2012 at 9:35
  • @equaeghe the link you provided is broken (I get a "Page Not Found" massage). Oct 14, 2012 at 14:34
  • tex.stackexchange.com/questions/9386 should work (spurious ] at end in my previous attempt)
    – equaeghe
    Oct 14, 2012 at 16:11
  • @equaeghe you're right. Last night I mixed the syntax (too late, perhaps ;-)). I updated my answer. Oct 14, 2012 at 16:52

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .