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.

My problem is to define blocks (mainly rectangles) that has labels in them in terms of matrices (mostly block diagonal) such that the n-many arrows that goes in this rectangle visually is at the same height as the corresponding element on the diagonal of the label. Consider the following example

\documentclass{article}
\usepackage{tikz}
\begin{document}
\begin{tikzpicture}[>=stealth]
\node[draw,rectangle,inner sep=0.5cm] (y) at (0,0) {$A$};
\node[draw,rectangle,inner sep=0.3cm] (d) at (0,2) {$\begin{array}{cc}B&\\&C \end{array}$};
\draw[->] (y.west) -| ++(-1,1) |- (d.west);
\draw[->] (d.east) -| ++(1,-1) |- (y.east);
\end{tikzpicture}
\end{document}

Now, let me start by creating two subproblems:

  1. When I create this label, the inner sep option of node shape (the visible rectangle around B and C) is kind of annoying to adjust. So I don't think it would survive in a better solution. So this question would be obsolete if the following problem is solved.
  2. I would like to get a handle of the node height resulting from the matrix label that I have put in and then somehow obtain a subdivision of n+1 of this height creating n nodes to connect to and from on the west and east sides. such that in the minimal example above I would connect to two arrows going out from A (not from the same location but separate and equally dividing the height of A) and connecting to B and C respectively (and vice versa).
share|improve this question
    
Just to be clear: you want the arrow from A->B to line up with B and the arrow from C->A to line up with C, hopefully all automatically, right? –  Alan Munn May 26 '11 at 20:22
    
Actually I have to further clarify my problem. What has been requested is quite nice but missing the detail of having also the A block different arrow starting and ending positions. So the arrows do not originate from the same root but rather from equally seperated positions. But I will try to employ the same solution done for the upper block, to the bottom block. –  percusse May 26 '11 at 21:41

2 Answers 2

up vote 4 down vote accepted

You could use the .<angle> syntax to manually control the position of the arrows; another option would be to use a matrix of (math) nodes instead of the array environment, to get access to the nodes in the matrix. The following example illustrates both these ideas:

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

\begin{document}

\begin{tikzpicture}[>=stealth]
  \node[draw,rectangle,inner sep=0.5cm] (y) at (0,0) {$A$};
  \node[draw,rectangle,inner sep=0.3cm] (d) at (0,2) {$\begin{array}{cc}B&\\&C \end{array}$};
  \draw[->] (y.west) -| ++(-1,1) |- (d.160);
  \draw[->] (y.west) -| ++(-0.8,1) |- (d.190);
  \draw[->] (d.-10) -| ++(0.8,-1) |- (y.east);
  \draw[->] (d.20) -| ++(1,-1) |- (y.east);
\end{tikzpicture}

\vspace*{10pt}

\begin{tikzpicture}[>=stealth,remember picture]
\node[draw,rectangle,inner sep=0.5cm] (y) at (0,0) {$A$};
\node[draw] (d) at (0,2) {%
  \begin{tikzpicture}[remember picture]
    \matrix [matrix of math nodes] (mat)
  {
    B & \phantom{C}   \\
    \phantom{B} & C \\
  };
  \end{tikzpicture}
  };
\draw[->,shorten >= 6pt] (y.west) -| ++(-1,1) |- (mat-1-1);
\draw[->,shorten >= 6pt] (y.west) -| ++(-0.8,1) |- (mat-2-1);
\draw[->] ($(mat-2-2)+(14pt,0)$) -| ++(0.8,-1) |- (y.east);
\draw[->] ($(mat-1-2)+(14pt,0)$) -| ++(1,-1) |- (y.east);
\end{tikzpicture}

\end{document}

Image 1

EDIT: a variant on kgr's solution, but using two matrices of nodes:

\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{calc,matrix,positioning}

\begin{document}

\begin{tikzpicture}[>=stealth]
\matrix[matrix of math nodes,nodes in empty cells,draw] (d) at (0,2)
{
  A & & & & \\
  & B & & & \\
  & & C  & & \\
  & & & D & \\
  & & & & E \\
};
\matrix[matrix of math nodes,nodes in empty cells,draw,minimum width=30pt,below=of d] (y) 
{
   \\ \\ \\ \\ \\
};
\node at (y) {$D$};

\foreach \i in {1,2,3,4,5}
  {
  \draw[->] let \p1 = (d.west), \p2 = (d-\i-\i.west), \p3 = (y.west), \p4 = (y-\i-1.west) in (\x3,\y4) -| 
    ++(-2.4+0.2*\i,1) |- (\x1,\y2);
  \draw[->] let \p1 = (d.east), \p2 = (d-\i-\i.east), \p3 = (y.east), \p4 = (y-\i-1.east) in (\x1,\y2) -|
    ++(1.6-0.2*\i,-1) |- (\x3,\y4);
  }
\end{tikzpicture}

\end{document}

Image 2

share|improve this answer
    
Thanks for the solution. I have tried to make the same to the A block. But then I couldn't make the two arrows start and end in the block seperately because then there is no matrix to be referenced in A block. Tried to make the A by multicol multirow trick but no avail. –  percusse May 26 '11 at 21:45
    
@percusse: I've updated my answer showing one possible way to consider two matrices of nodes. My example builds on kgr's solution; all the credit goes to him, of course. –  Gonzalo Medina May 27 '11 at 2:35
    
which is perfect. Thank you for the update and the example. –  percusse May 27 '11 at 2:42

I'm not perfectly clear on what you want, but here is a first pass, using tikz matrices:

\documentclass[11pt]{memoir}

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

\begin{document}

\begin{tikzpicture}[>=stealth]
\node[draw,rectangle,inner sep=0.5cm] (y) at (0,0) {$A$};
\matrix[matrix of nodes,nodes in empty cells,rectangle,draw] (d) at (0,2)
{
  $B$ & \\
  & $C$ \\
};
\draw[->] let \p1 = (d.west), \p2=(d-1-1.west) in (y.west) -| ++(-1,1) |- (\x1,\y2);
\draw[->] let \p1 = (d.west), \p2=(d-2-2.west) in (y.west) -| ++(-0.8,1) |- (\x1,\y2);
\draw[->] let \p1 = (d.east), \p2=(d-2-2.east) in (\x1,\y2) -| ++(0.8,-1) |- (y.east);
\draw[->] let \p1 = (d.east), \p2=(d-1-1.east) in (\x1,\y2) -| ++(1,-1) |- (y.east);
\end{tikzpicture}

\end{document}

The line drawing could probably be simplified quite a bit by writing some macros.

demonstration

For getting the lines to start/end in the right place, there is also an even simpler syntax for the line drawing you could use, that I didn't do above because it is slightly less transparent. Instead of e.g. the first draw line above, you could do:

\draw[->] (y.west) -| ++(-1,1) |- (d.west |- d-1-1.west);

and so on.

(Edited this a bit to match Gonzalo Medina's interpretation of the request, which seems more correct than mine initially was.)

Ok, and one more edit:

Just for fun I made something a little more interesting.

\documentclass[11pt]{memoir}

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

\begin{document}


\begin{tikzpicture}[>=stealth]
\node[draw,rectangle,inner sep=0.5cm] (y) at (0,0) {$A$};
\matrix[matrix of nodes,nodes in empty cells,rectangle,draw] (d) at (0,3)
{
  $B$ & & & &\\
 & $C$ & & & \\
 & & $D$ & & \\
 & & & $E$ & \\
 & & & & $F$ \\
};

\foreach \z in {1,...,5}
{
  \draw[->] let \n1={\z * -0.2cm - 0.5cm} in
      (y.west) -| ([xshift=\n1] d.west |- y.west) |- (d.west |- d-\z-\z.west);
  \draw[->] let \n1={\z * 0.2cm + 0.5cm} in
      (d.east |- d-\z-\z.east) -| ([xshift=\n1] d.east |- y.east) |- (y.east);
}

\end{tikzpicture}
\end{document}

enter image description here

share|improve this answer
    
Also, by the way, that syntax for referring to parts of a matrix, which I think is exactly what you want, is documented in section 38 (the libraries section), not in the actual matrix documentation; I guess this is because it is really only a feature of the "matrix of nodes" option. But it took me a while to find it, originally, so I thought I'd mention it. –  kgr May 26 '11 at 20:34
    
Wow, that would come in handy. Thanks a lot. As I commented below, I couldn't find a way to apply this trick to the A block also. So I will keep trying. –  percusse May 26 '11 at 21:46
    
@percusse can you clarify what you are trying to do with the A block that isn't working? For this particular diagram it should be easy to put a 1x1 matrix containing $A$ as the only node. (And btw a matrix is a node itself, so in practice there isn't really a difference between the node y as-is and a node containing a 1x1 matrix.) –  kgr May 26 '11 at 22:00
    
@percusse, maybe I see: even though the A block has just one letter in it, do you want the height of the arrows to match where they hit the larger block? If so, I can think of a brute-force way of doing this with empty matrices...I don't have time to work up a detailed solution, but just put a blank matrix using phantom (as in G.M.'s answer) instead of actual letters to match the node sizes, and draw the A over that. Then you can refer to the nodes in the matrix. –  kgr May 26 '11 at 22:24
    
Yep, that is exactly what I did actually. Thanks though, the fun part gave me a fresh look. I was expecting to find an iterative solution as in your final for loop but couldn't get it. It was really helpful to automate the process. –  percusse May 27 '11 at 0:15

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.