9

When the matrix library is loaded and the matrix of nodes key is activated, each node can be accessed according to the name-row-column syntax.

In some cases, the arrows are built in the opposite direction of what is requested. To illustrate this, I have colored in red the arrows that are drawn in the opposite direction of what is requested.

I colored the background of the cells from which the arrows start in blue.

Update without shorten <=-3pt,shorten >=-3pt

By default, when cells are placed side by side, the arrows are reversed.

screenshot

\documentclass[border=10pt,tikz]{standalone}

\usetikzlibrary{matrix} \begin{document}

\begin{tikzpicture} \matrix (magic) [matrix of nodes] { 8 & 1 & 6 \ 3 & 5 & 7 \ 4 & 9 & 2 \ }; \draw[thick,blue,->] (magic-1-1) |- (magic-2-3); \draw[thick,blue,->] (magic-1-1) -- (magic-2-3); \draw[thick,red,->] (magic-1-1) -- (magic-1-2); \end{tikzpicture}

\end{document}

screenshot

\documentclass[border=10pt,tikz]{standalone}

\usetikzlibrary{matrix} \begin{document}

\begin{tikzpicture} \matrix (magic) [matrix of nodes, row 1 column 1/.style={nodes={fill=blue!20}}, row 2 column 3/.style={nodes={fill=blue!20}}, row 4 column 1/.style={nodes={fill=blue!20}}, row 1 column 5/.style={nodes={fill=blue!20}}, row 2 column 6/.style={nodes={fill=blue!20}}, row 3 column 5/.style={nodes={fill=blue!20}}, row 4 column 6/.style={nodes={fill=blue!20}}, row 7 column 4/.style={nodes={fill=blue!20}}, row 4 column 4/.style={nodes={fill=blue!20}}] { 8 & 8 & 8 & 8 & 8 & 8 & 8\ 3 & 3 & 5 & 7 & 7 & 6 & 5\ 4 & 4 & 9 & 2 & 6 & 5 & 4 \ 4 & 4 & 9 & 2 & 5 & 4 & 3 \ 8 & 8 & 8 & 8 & 8 & 8 & 8\ 3 & 3 & 5 & 7 & 7 & 6 & 5\ 4 & 4 & 9 & 2 & 6 & 5 & 4 \ 4 & 4 & 9 & 2 & 5 & 4 & 3 \ }; \draw[thick,blue,->,shorten <=-3pt,shorten >=-3pt] (magic-1-1) |- (magic-2-2); \draw[thick,red,->,shorten <=-3pt,shorten >=-3pt] (magic-1-1) -- (magic-2-2); \draw[thick,blue,->,shorten <=-3pt,shorten >=-3pt] (magic-1-1) -| (magic-2-2);

\draw[thick,blue,->,shorten <=-3pt,shorten >=-3pt] (magic-4-4) |- (magic-3-3); \draw[thick,red,->,shorten <=-3pt,shorten >=-3pt] (magic-4-4) -- (magic-3-3); \draw[thick,blue,->,shorten <=-3pt,shorten >=-3pt] (magic-4-4) -| (magic-3-3);

\draw[thick,red,->,shorten <=-3pt,shorten >=-3pt] (magic-4-1) -- (magic-3-2); \draw[thick,blue,->,shorten <=-3pt,shorten >=-3pt] (magic-4-1) |- (magic-3-2); \draw[thick,blue,->,shorten <=-3pt,shorten >=-3pt] (magic-4-1) -| (magic-3-2);

\draw[thick,red,->,shorten <=-3pt,shorten >=-3pt] (magic-2-3) -- (magic-1-4); \draw[thick,blue,->,shorten <=-3pt,shorten >=-3pt] (magic-2-3) |- (magic-1-4); \draw[thick,blue,->,shorten <=-3pt,shorten >=-3pt] (magic-2-3) -| (magic-1-4);

\draw[thick,red,->,shorten <=-3pt,shorten >=-3pt] (magic-1-5) -- (magic-2-5); \draw[thick,red,->,shorten <=-3pt,shorten >=-3pt] (magic-2-6) -- (magic-1-6);

\draw[thick,red,->,shorten <=-3pt,shorten >=-3pt] (magic-3-5) -- (magic-3-6); \draw[thick,red,->,shorten <=-3pt,shorten >=-3pt] (magic-4-6) -- (magic-4-5);

\draw[thick,blue,->,shorten <=-3pt,shorten >=-3pt] (magic-7-4) -- (magic-6-1); \draw[thick,blue,->,shorten <=-3pt,shorten >=-3pt] (magic-7-4) -- (magic-6-2); \draw[thick,red,->,shorten <=-3pt,shorten >=-3pt] (magic-7-4) -- (magic-6-3); \draw[thick,red,->,shorten <=-3pt,shorten >=-3pt] (magic-7-4) -- (magic-6-4); \draw[thick,red,->,shorten <=-3pt,shorten >=-3pt] (magic-7-4) -- (magic-6-5); \draw[thick,blue,->,shorten <=-3pt,shorten >=-3pt] (magic-7-4) -- (magic-6-6); \draw[thick,blue,->,shorten <=-3pt,shorten >=-3pt] (magic-7-4) -- (magic-6-7);

\draw[thick,blue,->,shorten <=-3pt,shorten >=-3pt] (magic-7-4) -- (magic-8-1); \draw[thick,blue,->,shorten <=-3pt,shorten >=-3pt] (magic-7-4) -- (magic-8-2); \draw[thick,red,->,shorten <=-3pt,shorten >=-3pt] (magic-7-4) -- (magic-8-3); \draw[thick,red,->,shorten <=-3pt,shorten >=-3pt] (magic-7-4) -- (magic-8-4); \draw[thick,red,->,shorten <=-3pt,shorten >=-3pt] (magic-7-4) -- (magic-8-5); \draw[thick,blue,->,shorten <=-3pt,shorten >=-3pt] (magic-7-4) -- (magic-8-6); \draw[thick,blue,->,shorten <=-3pt,shorten >=-3pt] (magic-7-4) -- (magic-8-7); \end{tikzpicture}

\end{document}

AndréC
  • 24,137
  • 1
    You might want to choose a different title that makes this easer to find in the future. – daleif Aug 13 '20 at 12:09
  • As I am not English-speaking, please change the title to suit you. – AndréC Aug 13 '20 at 12:11
  • 1
    That is a funny one, try adding row sep=1em, column sep=1em, then it works. It might be a combination of (1) each box basically touching and (2) you using -3pt and and we are drawing from the edge of the boxes. The negative shorten then ens up sitting on opposite sides of the boxes and the arrow is reversed – daleif Aug 13 '20 at 12:23
  • Also it works correctly then between .center – daleif Aug 13 '20 at 12:26
  • If i delete shorten <=-3pt,shorten >=-3pt then, the arrows are drawn but in the wrong direction. It is then necessary to space the rows and the columns so that it becomes normal again as you did. – AndréC Aug 13 '20 at 12:28
  • This is an example why mentioning the word bug in the title is not a good idea ;-) – daleif Aug 13 '20 at 12:32
  • 1
    @AndréC What is the use of this ? – projetmbc Aug 13 '20 at 13:00
  • @projetmbc I had this problem when I wanted to create a foreach loop to build an arrow path here How to create a cost matrix?, I had to make the code heavier to avoid this problem. – AndréC Aug 13 '20 at 13:03
  • Oh, stumpled on something, try setting outer sep=0pt then it works. It is seems to be using outer sep as a limit as to then the switch happens, if inside then it switches – daleif Aug 13 '20 at 13:09
  • 1
    Also it has nothing to do with the matrix library. It can be done with normal nodes. – daleif Aug 13 '20 at 13:11
  • @daleif Can you give an answer that explains when this happens and the minimum condition that solves this problem? – AndréC Aug 13 '20 at 14:43
  • 1
    Not really as I'm not 100% sure. I just found some strange values. – daleif Aug 13 '20 at 14:46
  • @daleif I think like you that the problem is certainly due to an approximation of the coordinates of the edges of the nodes. The track of outer sep or so of column sep and row sep seems to me to need to be explored further. The ideal would be to find the exact cause so that you can propose a fix in the TikZ repository. – AndréC Aug 13 '20 at 15:00
  • @daleif In my opinion, inner anchors should be added to the node like north text, south text north east text (there is an anchor called text as shown in the shape library). This would allow the arrows to start not from the node boundary, but from the text boundary. – AndréC Aug 14 '20 at 05:53

2 Answers2

7

The nodes touch each other.

With inner sep=0pt, I create smaller nodes and I use row sep and column sep to separate them.

With shorten > =0pt and shorten < = 0pt, I draw the ``exact'' arrows between the nodes and they are as expected (with nodes which don't touche each other).

\documentclass[border=10pt,tikz]{standalone}

\usetikzlibrary{matrix} \begin{document}

\begin{tikzpicture} \matrix (magic) [matrix of nodes,inner sep = 0pt, row sep = 2mm, column sep =2mm, row 1 column 1/.style={nodes={fill=blue!20}}, row 2 column 3/.style={nodes={fill=blue!20}}, row 4 column 1/.style={nodes={fill=blue!20}}, row 1 column 5/.style={nodes={fill=blue!20}}, row 2 column 6/.style={nodes={fill=blue!20}}, row 3 column 5/.style={nodes={fill=blue!20}}, row 4 column 6/.style={nodes={fill=blue!20}}, row 7 column 4/.style={nodes={fill=blue!20}}, row 4 column 4/.style={nodes={fill=blue!20}}] { 8 & 8 & 8 & 8 & 8 & 8 & 8\ 3 & 3 & 5 & 7 & 7 & 6 & 5\ 4 & 4 & 9 & 2 & 6 & 5 & 4 \ 4 & 4 & 9 & 2 & 5 & 4 & 3 \ 8 & 8 & 8 & 8 & 8 & 8 & 8\ 3 & 3 & 5 & 7 & 7 & 6 & 5\ 4 & 4 & 9 & 2 & 6 & 5 & 4 \ 4 & 4 & 9 & 2 & 5 & 4 & 3 \ }; \draw[thick,blue,->,shorten <=0pt,shorten >=0pt] (magic-1-1) |- (magic-2-2); \draw[thick,red, ->,shorten <=0pt,shorten >=0pt] (magic-1-1) -- (magic-2-2); \draw[thick,blue,->,shorten <=0pt,shorten >=0pt] (magic-1-1) -| (magic-2-2);

\draw[thick,blue,->,shorten <=0pt,shorten >=0pt] (magic-4-4) |- (magic-3-3); \draw[thick,red, ->,shorten <=0pt,shorten >=0pt] (magic-4-4) -- (magic-3-3); \draw[thick,blue,->,shorten <=0pt,shorten >=0pt] (magic-4-4) -| (magic-3-3);

\draw[thick,red, ->,shorten <=0pt,shorten >=0pt] (magic-4-1) -- (magic-3-2); \draw[thick,blue,->,shorten <=0pt,shorten >=0pt] (magic-4-1) |- (magic-3-2); \draw[thick,blue,->,shorten <=0pt,shorten >=0pt] (magic-4-1) -| (magic-3-2);

\draw[thick,red, ->,shorten <=0pt,shorten >=0pt] (magic-2-3) -- (magic-1-4); \draw[thick,blue,->,shorten <=0pt,shorten >=0pt] (magic-2-3) |- (magic-1-4); \draw[thick,blue,->,shorten <=0pt,shorten >=0pt] (magic-2-3) -| (magic-1-4);

\draw[thick,red,->,shorten <=0pt,shorten >=0pt] (magic-1-5) -- (magic-2-5); \draw[thick,red,->,shorten <=0pt,shorten >=0pt] (magic-2-6) -- (magic-1-6);

\draw[thick,red,->,shorten <=0pt,shorten >=0pt] (magic-3-5) -- (magic-3-6); \draw[thick,red,->,shorten <=0pt,shorten >=0pt] (magic-4-6) -- (magic-4-5);

\draw[thick,blue,->,shorten <=0pt,shorten >=0pt] (magic-7-4) -- (magic-6-1); \draw[thick,blue,->,shorten <=0pt,shorten >=0pt] (magic-7-4) -- (magic-6-2); \draw[thick,red,->,shorten <=0pt,shorten >=0pt] (magic-7-4) -- (magic-6-3); \draw[thick,red,->,shorten <=0pt,shorten >=0pt] (magic-7-4) -- (magic-6-4); \draw[thick,red,->,shorten <=0pt,shorten >=0pt] (magic-7-4) -- (magic-6-5); \draw[thick,blue,->,shorten <=0pt,shorten >=0pt] (magic-7-4) -- (magic-6-6); \draw[thick,blue,->,shorten <=0pt,shorten >=0pt] (magic-7-4) -- (magic-6-7);

\draw[thick,blue,->,shorten <=0pt,shorten >=0pt] (magic-7-4) -- (magic-8-1); \draw[thick,blue,->,shorten <=0pt,shorten >=0pt] (magic-7-4) -- (magic-8-2); \draw[thick,red,->,shorten <=0pt,shorten >=0pt] (magic-7-4) -- (magic-8-3); \draw[thick,red,->,shorten <=0pt,shorten >=0pt] (magic-7-4) -- (magic-8-4); \draw[thick,red,->,shorten <=0pt,shorten >=0pt] (magic-7-4) -- (magic-8-5); \draw[thick,blue,->,shorten <=0pt,shorten >=0pt] (magic-7-4) -- (magic-8-6); \draw[thick,blue,->,shorten <=0pt,shorten >=0pt] (magic-7-4) -- (magic-8-7); \end{tikzpicture}

\end{document}

Output of the above code

F. Pantigny
  • 40,250
  • Yes, but if we do not space the rows and columns, the arrows are sometimes drawn in opposite directions. – AndréC Aug 13 '20 at 12:32
  • To pag. 29 of your package there is a word in French language. "Here is an example of utilisation":-) – Sebastiano Aug 13 '20 at 12:39
  • Can you explain why the negative shorten ends up placing the ends of the arrows out side the box? Might be that shorten for negative values aren't that welldefined – daleif Aug 13 '20 at 12:39
  • @Sebastiano which package? – daleif Aug 13 '20 at 12:40
  • @daleif nicematrix :-)...package – Sebastiano Aug 13 '20 at 12:40
  • If magic-1-1 touches magic-1-2, I think that Tikz will try to draw a rule from magic-1-1.east to magic-1-2.west. Since it's the same point, the straight line between both is not defined and, absolutetly, it's not possible to draw an arrow between both, even using shorten < and shorten >. Tikz draws something but I think that it must be considered as unpredictable. – F. Pantigny Aug 13 '20 at 12:42
  • @Sebastiano. I will correct (you should have sent me an email). – F. Pantigny Aug 13 '20 at 12:43
  • It looks a lot like the points chosen for the arrow are -1-1 +(3pt,-3pt) and -2-2 +(-3pt,3pt) – daleif Aug 13 '20 at 12:46
  • When drawing a line between two nodes, PGF uses \pgfpointshapeborder. In pgfmanual.pdf (p. 1123), it is said : This command returns the point on the border of the shape that lies on a straight line from the center of the node to hpointi. For complex shapes it is not guaranteed that this point will actually lie on the border, it may be on the border of a “simplified” version of the shape. I don't know the exact computations... – F. Pantigny Aug 13 '20 at 12:51
  • It is just strange that it looks like the ends are given +3pt not -3pt – daleif Aug 13 '20 at 12:52
  • Try with outer sep=0pt then it works. Seems outer sep is used as some kind of threshold here. – daleif Aug 13 '20 at 13:10
  • 2
    Probably that, when the nodes touch each other, the (initial) positive value of outer sep makes that the two points used as extremities of the line to draw are in the reverse order (compared to the position of the nodes). Sounds logical. – F. Pantigny Aug 13 '20 at 13:23
  • Lol, with the right distance one can even make the arrow horizontal. #notdefined – daleif Aug 13 '20 at 14:22
  • @F.Pantigny Now I have sent you the email. – Sebastiano Aug 13 '20 at 19:08
3

The line-drawing operations of TikZ are pretty smart when node names are used as start or target coordinates because TikZ takes a point on the border of the node for the real start or target point.

As smart as this it, it will produce not the best lines when the nodes are too close to each other (or too big).

When (a) -- (b) is used TikZ asks PGF

  • for the point on the border of a that is in the direction of b's center (i.e. b.center) and
  • for the point on the border of b that is in the direction of a's center.

Take a look at this example:

\begin{tikzpicture}[->, nodes={draw,gray}]
\node (a) {a};
\node at (.1,1) (b) {b};
\draw (a) |- (b);

\tikzset{xshift=1cm} \node[blue] (a) {a}; \node[green] at (.1,.4) (b) {b}; \draw[thick, shorten >=-3pt, shorten <=-3pt] (a) -- (b); \draw[red] (a) -- (b); \end{tikzpicture}

enter image description here

The red arrow in the right part starts at the border of a and goes to the border of b (that's what you asked for with (a) -- (b)).

(The shortening of the path is done much later in the process and can't help you here.)

Similar things happen with the -| and |- path operators. When TikZ finds (a) |- (b) it asks PGF

  • for the point on the border of a that is either upwards (when b is above a in the current coordinate system) or downwards (when b is below a) and
  • for the point on the border of b that is either to the left (when a is to the left of b) or to the right (when a is to the right of b).

Since a is every so lightly left of b it choose the left most point on the border even if it is more to the left than a's center.


But where is that border actually? With the default settings of PGF/TikZ the border lies on the outside of the shape's path.

But we can change that in relation to the shape's path, this is what the values of /pgf/outer xsep and /pgf/outer ysep are for. In fact, by default, this is set to .5\pgflinewidth so that the border lies exactly at the edge of the line.

So, instead of shortening the path we can just make the border smaller than the shape by using, say

outer sep = -3pt

I've chosen -.1666em in the example because I think it looks better and it is half the length of the default inner seps (the space between text and the shape's path).

Code

\documentclass[tikz]{standalone}
\usetikzlibrary{matrix}
\begin{document}

\begin{tikzpicture}[->, nodes={draw,gray}] \node (a) {a}; \node at (.1,1) (b) {b}; \draw (a) |- (b);

\tikzset{xshift=1cm} \node[blue] (a) {a}; \node[green] at (.1,.4) (b) {b}; \draw[thick, shorten >=-3pt, shorten <=-3pt] (a) -- (b); \draw[red] (a) -- (b); \end{tikzpicture}

\begin{tikzpicture}[ rc/.style 2 args={ @/.style args={r##1c##2}{row ##1 column ##2/.append style={#2}}, @/.list={#1}} ] \matrix (magic) [ matrix of nodes, nodes={outer sep=-.1666em}, rc={r1c1, r2c3, r4c1, r1c5, r2c6, r3c5, r4c6, r7c4, r4c4} {nodes={fill=blue!20}}, ] { 8 & 8 & 8 & 8 & 8 & 8 & 8 \ 3 & 3 & 5 & 7 & 7 & 6 & 5 \ 4 & 4 & 9 & 2 & 6 & 5 & 4 \ 4 & 4 & 9 & 2 & 5 & 4 & 3 \ 8 & 8 & 8 & 8 & 8 & 8 & 8 \ 3 & 3 & 5 & 7 & 7 & 6 & 5 \ 4 & 4 & 9 & 2 & 6 & 5 & 4 \ 4 & 4 & 9 & 2 & 5 & 4 & 3 \ };

\begin{scope}[thick, ->] \draw[blue] (magic-1-1) |- (magic-2-2); \draw[red] (magic-1-1) -- (magic-2-2); \draw[blue] (magic-1-1) -| (magic-2-2);

\draw[blue] (magic-4-4) |- (magic-3-3);
\draw[red] (magic-4-4) -- (magic-3-3);
\draw[blue] (magic-4-4) -| (magic-3-3);

\draw[red] (magic-4-1) -- (magic-3-2);
\draw[blue] (magic-4-1) |- (magic-3-2);
\draw[blue] (magic-4-1) -| (magic-3-2);

\draw[red] (magic-2-3) -- (magic-1-4);
\draw[blue] (magic-2-3) |- (magic-1-4);
\draw[blue] (magic-2-3) -| (magic-1-4);

\draw[red] (magic-1-5) -- (magic-2-5);
\draw[red] (magic-2-6) -- (magic-1-6);

\draw[red] (magic-3-5) -- (magic-3-6);
\draw[red] (magic-4-6) -- (magic-4-5);

\foreach \row in {6, 8} {
  \path[blue] (magic-7-4) edge (magic-\row-1)
                          edge (magic-\row-2)
                          edge (magic-\row-6)
                          edge (magic-\row-7);
  \path[red]  (magic-7-4) edge (magic-\row-3)
                          edge (magic-\row-4)
                          edge (magic-\row-5);
}

\end{scope} \end{tikzpicture} \end{document}

Output

enter image description here

Qrrbrbirlbel
  • 119,821