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.

The plot

Using tikz, I have a main node containing several (three) lines of text, and three "legend" nodes that point to them.

If I use a rectangle node, then I can't access the positions of the individual lines, so I can only attach my legends to the main node itself, and can't vertically align them with their respective line:

A rectangle node containing three lines with a unique legend for the whole node.

If I use a matrix node, with each line in an individual cell, then the inter-line spacing is wrong. I could add row sep=42pt, but I don't know which value to put in place of 42:

A matrix node with a cell for each line, and a legend for each line, the lines are stuck together without any vertical spacing.

As a last ressort, I added an invisible rule with a height of \baselineskip to each line (cell) except the first one, which seems to give a result identical to the rectangular node, except I can access the position of individual lines:

A matrix node with a cell for each line, and a legend for each line, the vertical spacing is the same as in the rectangle node.

However, this won't work well if the line contains equations or anything that makes it higher than a regular line. This TeX.sx answer shows that the inter-line space in that case is given by \lineskip and \lineskiplimit, but I woul really fancy the idea of re-implementing that using tikz -- I wouldn't even know where to start I must admit.

The question

Is there any simpler/more robust way to access each individual line in a tikz node as if the line was a rectangle node?

The code

Preamble

\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{positioning, matrix}
\def\legendlines#1#2{
  \draw (#1) -- (#2);
  \draw (#2.north west) -- (#2.south west);
}
\begin{document}
\tikzset{
  mynode/.style={draw,fill=blue!30,align=center},
  mylegend/.style={align=left, font=\scriptsize, inner sep=1pt}
}

Rectangle node

% I can't access the position of each line using a rectangle node
\begin{tikzpicture}
  \node[mynode] (N123) {Node line one\\Node line two\\Node line three};
  \node[mylegend, xshift=1cm, at=(N123.east), anchor=west] (L123) {Legend 1\\Legend 2\\Legend 3};
  \legendlines{N123}{L123}
\end{tikzpicture}

Matrix node

% Using a matrix, the inter-line space is wrong. I can add row sep=42pt, but I don't know what is the correct value.
\begin{tikzpicture}
  \node[mynode, matrix, matrix of nodes, nodes={inner sep=0pt}] (N123) {Node line one\\Node line two\\Node line three\\};
  % Coordinates along the east side of N123
  \coordinate (N1east) at (N123-1-1.east -| N123.east);
  \coordinate (N2east) at (N123-2-1.east -| N123.east);
  \coordinate (N3east) at (N123-3-1.east -| N123.east);
  % Legend texts
  \node[mylegend, right=1.0cm of N1east] (L1) {Legend 1};
  \node[mylegend, right=1.2cm of N2east] (L2) {Legend 2};
  \node[mylegend, right=1.4cm of N3east] (L3) {Legend 3};
  % Legend lines
  \legendlines{N1east}{L1}
  \legendlines{N2east}{L2}
  \legendlines{N3east}{L3}
\end{tikzpicture}

Invisible rule

% Using an invisible rule
\begin{tikzpicture}
  \node[mynode, matrix, matrix of nodes, nodes={inner sep=0pt}] (N123) {Node line one\\\rule{0cm}{\baselineskip}Node line two\\\rule{0cm}{\baselineskip}Node line three\\};
  % Coordinates along the east side of N123
  \coordinate (N1east) at (N123-1-1.east -| N123.east);
  \coordinate (N2east) at (N123-2-1.east -| N123.east);
  \coordinate (N3east) at (N123-3-1.east -| N123.east);
  % Legend texts
  \node[mylegend, right=1.0cm of N1east] (L1) {Legend 1};
  \node[mylegend, right=1.2cm of N2east] (L2) {Legend 2};
  \node[mylegend, right=1.4cm of N3east] (L3) {Legend 3};
  % Legend lines
  \legendlines{N1east}{L1}
  \legendlines{N2east}{L2}
  \legendlines{N3east}{L3}
\end{tikzpicture}

Epilogue

\end{document}

Whole code

\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{positioning, matrix}
\def\legendlines#1#2{
  \draw (#1) -- (#2);
  \draw (#2.north west) -- (#2.south west);
}
\begin{document}
\tikzset{
  mynode/.style={draw,fill=blue!30,align=center},
  mylegend/.style={align=left, font=\scriptsize, inner sep=1pt}
}

% I can't access the position of each line using a rectangle node
\begin{tikzpicture}
  \node[mynode] (N123) {Node line one\\Node line two\\Node line three};
  \node[mylegend, xshift=1cm, at=(N123.east), anchor=west] (L123) {Legend 1\\Legend 2\\Legend 3};
  \legendlines{N123}{L123}
\end{tikzpicture}

% Using a matrix, the inter-line space is wrong. I can add row sep=42pt, but I don't know what is the correct value.
\begin{tikzpicture}
  \node[mynode, matrix, matrix of nodes, nodes={inner sep=0pt}] (N123) {Node line one\\Node line two\\Node line three\\};
  % Coordinates along the east side of N123
  \coordinate (N1east) at (N123-1-1.east -| N123.east);
  \coordinate (N2east) at (N123-2-1.east -| N123.east);
  \coordinate (N3east) at (N123-3-1.east -| N123.east);
  % Legend texts
  \node[mylegend, right=1.0cm of N1east] (L1) {Legend 1};
  \node[mylegend, right=1.2cm of N2east] (L2) {Legend 2};
  \node[mylegend, right=1.4cm of N3east] (L3) {Legend 3};
  % Legend lines
  \legendlines{N1east}{L1}
  \legendlines{N2east}{L2}
  \legendlines{N3east}{L3}
\end{tikzpicture}

% Using an invisible rule
\begin{tikzpicture}
  \node[mynode, matrix, matrix of nodes, nodes={inner sep=0pt}] (N123) {Node line one\\\rule{0cm}{\baselineskip}Node line two\\\rule{0cm}{\baselineskip}Node line three\\};
  % Coordinates along the east side of N123
  \coordinate (N1east) at (N123-1-1.east -| N123.east);
  \coordinate (N2east) at (N123-2-1.east -| N123.east);
  \coordinate (N3east) at (N123-3-1.east -| N123.east);
  % Legend texts
  \node[mylegend, right=1.0cm of N1east] (L1) {Legend 1};
  \node[mylegend, right=1.2cm of N2east] (L2) {Legend 2};
  \node[mylegend, right=1.4cm of N3east] (L3) {Legend 3};
  % Legend lines
  \legendlines{N1east}{L1}
  \legendlines{N2east}{L2}
  \legendlines{N3east}{L3}
\end{tikzpicture}
\end{document}
share|improve this question
    
You could put the text in a \subnode command from the experimental tikzmark package, would that be an acceptable solution? Then each line could be treated as a separate node while the line positioning and spacing are set by the container node. –  Loop Space Dec 10 '12 at 22:18
    
I forgot to say I tried manually putting a \tikz[remember picture]{ \coordinate (Line1) {};} at the end of each line, but that resulted in coordinates that were shifted from where they should have been. Hopefully tikzmark will give a better result than this brutal approach :) I don't have it installed, so I'll test that later. I also tried using multipart nodes, with the same inter-line spacing problems that the matrix solution has, only more difficult to solve. Please do post \subnode as a solution if you can do a quick check that it works. –  Georges Dupéron Dec 10 '12 at 22:25
    
Nesting tikzpictures is fraught with dangers. Subnodes get round this by not being tikzpictures but emulating the bare minimum. It's late for me now so I won't get a chance to try it out before tomorrow - if no-one beats me to it! –  Loop Space Dec 10 '12 at 22:38
    
In the meantime, you can see an example at tex.stackexchange.com/a/84457/86 –  Loop Space Dec 10 '12 at 22:40
    
Do you need to replicate the rectangle node exactly? Otherwise row sep=1ex seems sufficient for the matrix. –  percusse Dec 10 '12 at 22:47

3 Answers 3

up vote 5 down vote accepted

Here's a solution using \subnode from the experimental tikzmark package. "Experimental" in this case means "not yet on CTAN": you need to download it from the TeX-SX Launchpad site. Download the file tikzmark.dtx and run tex tikzmark.dtx (if you run latex or pdflatex it will complain of a missing file - ignore that). Put the resulting files somewhere that tex can find them.

Here's your code with the \subnode last.

\documentclass{article}
%\url{http://tex.stackexchange.com/q/86456/86}
\usepackage{tikz}
\usetikzlibrary{positioning, matrix,tikzmark}
\def\legendlines#1#2{
  \draw (#1) -- (#2);
  \draw (#2.north west) -- (#2.south west);
}
\begin{document}
\tikzset{
  mynode/.style={draw,fill=blue!30,align=center},
  mylegend/.style={align=left, font=\scriptsize, inner sep=1pt}
}
% I can't access the position of each line using a rectangle node
\begin{tikzpicture}
  \node[mynode] (N123) {Node line one\\Node line two\\Node line three};
  \node[mylegend, xshift=1cm, at=(N123.east), anchor=west] (L123) {Legend 1\\Legend 2\\Legend 3};
  \legendlines{N123}{L123}
\end{tikzpicture}

% Using a matrix, the inter-line space is wrong. I can add row sep=42pt, but I don't know what is the correct value.
\begin{tikzpicture}
  \node[mynode, matrix, matrix of nodes, nodes={inner sep=0pt}] (N123) {Node line one\\Node line two\\Node line three\\};
  % Coordinates along the east side of N123
  \coordinate (N1east) at (N123-1-1.east -| N123.east);
  \coordinate (N2east) at (N123-2-1.east -| N123.east);
  \coordinate (N3east) at (N123-3-1.east -| N123.east);
  % Legend texts
  \node[mylegend, right=1.0cm of N1east] (L1) {Legend 1};
  \node[mylegend, right=1.2cm of N2east] (L2) {Legend 2};
  \node[mylegend, right=1.4cm of N3east] (L3) {Legend 3};
  % Legend lines
  \legendlines{N1east}{L1}
  \legendlines{N2east}{L2}
  \legendlines{N3east}{L3}
\end{tikzpicture}

% Using an invisible rule
\begin{tikzpicture}
  \node[mynode, matrix, matrix of nodes, nodes={inner sep=0pt}] (N123) {Node line one\\\rule{0cm}{\baselineskip}Node line two\\\rule{0cm}{\baselineskip}Node line three\\};
  % Coordinates along the east side of N123
  \coordinate (N1east) at (N123-1-1.east -| N123.east);
  \coordinate (N2east) at (N123-2-1.east -| N123.east);
  \coordinate (N3east) at (N123-3-1.east -| N123.east);
  % Legend texts
  \node[mylegend, right=1.0cm of N1east] (L1) {Legend 1};
  \node[mylegend, right=1.2cm of N2east] (L2) {Legend 2};
  \node[mylegend, right=1.4cm of N3east] (L3) {Legend 3};
  % Legend lines
  \legendlines{N1east}{L1}
  \legendlines{N2east}{L2}
  \legendlines{N3east}{L3}
\end{tikzpicture}

\begin{tikzpicture}[remember picture]
  \node[mynode] (N123) {\subnode{mynode-1}{Node line one}\\\subnode{mynode-2}{Node line two}\\\subnode{mynode-3}{Node line three}};
  \coordinate (L123) at=(N123.east);
  \foreach \k in {1,2,3} {
  \node[mylegend,xshift=\k cm,anchor=base west] (L\k) at (mynode-\k.base -| L123) {Legend \k};
  \legendlines{mynode-\k.mid west -| N123.mid east}{L\k}
}
\end{tikzpicture}

\end{document}

This produces:

subnode division of node

share|improve this answer

The matrix is imho the best solution. If you don't want all lines crampled, why did you put node={inner sep=0pt}? Removing this option gives:

Result

As the OP noted in a comment, the above solution produces more padding than the standard rectangle solution. This can be avoided by giving inner sep=0pt to the outer matrix node, and inner sep=3.333pt (which is the default inner sep) to each of the inner nodes (cells). There is a MWE which includes the rectangle for comparison:

\usetikzlibrary{positioning, matrix}
\def\legendlines#1#2{
  \draw (#1) -- (#2);
  \draw (#2.north west) -- (#2.south west);
}
\tikzset{
  mynode/.style={draw,fill=blue!30,align=center},
  mylegend/.style={align=left, font=\scriptsize, inner sep=1pt}
}

% Using a matrix, the inter-line space is wrong. I can add row sep=42pt, but I don't know what is the correct value.
\begin{tikzpicture}
  \node[mynode, inner sep=0pt, matrix of nodes,nodes={inner sep=3.33pt}] (N123) {Node line one\\Node line two\\Node line three\\};
  % Coordinates along the east side of N123
  \coordinate (N1east) at (N123-1-1.east -| N123.east);
  \coordinate (N2east) at (N123-2-1.east -| N123.east);
  \coordinate (N3east) at (N123-3-1.east -| N123.east);
  % Legend texts
  \node[mylegend, right=1.0cm of N1east] (L1) {Legend 1};
  \node[mylegend, right=1.2cm of N2east] (L2) {Legend 2};
  \node[mylegend, right=1.4cm of N3east] (L3) {Legend 3};
  % Legend lines
  \legendlines{N1east}{L1}
  \legendlines{N2east}{L2}
  \legendlines{N3east}{L3}
\end{tikzpicture}

\begin{tikzpicture}
 \node[mynode] (N123) {Node line one\\Node line two\\Node line three};
  \node[mylegend, xshift=1cm, at=(N123.east), anchor=west] (L123) {Legend 1\\Legend 2\\Legend 3};
  \legendlines{N123}{L123}
\end{tikzpicture}

Result

share|improve this answer
    
If you don't put node={inner sep=0pt}, then you get some extra space on the sides and bottom/top: The matrix node has its own inner sep, that it puts around the cells, and if the cells themeselves have some inner sep, it's doubled. If you use inner sep=0pt on the matrix itself, but leave the nodes alone, then you'll have double space between nodes (inner sep of the upper node, and inner sep of the lower node), but only a single inner sep space between the text and the border. –  Georges Dupéron Dec 10 '12 at 23:05

The solution below with [remember picture] seems simpler and more flexible but need two compilation.

\documentclass{article}

\usepackage{tikz}
\usetikzlibrary{positioning, matrix}

\begin{document}


\begin{tikzpicture}[remember picture]

\node[text width=5cm,draw](tab){ ligne 1\tikz \coordinate(l1); \\
ligne 2 plus longue\tikz \coordinate(l2); \\
~\\
ligne 4\tikz \coordinate(l4); };

\draw[-|] (l1-|tab.east) -- ++(2,0) node[right]{legende 1};
\draw [-|](l2-|tab.east) -- ++(2.5,0) node[right]{legende 2};
\draw [-|](l4-|tab.east) -- ++(3,0) node[right]{legende 3};
\end{tikzpicture}

\end{document}

enter image description here

share|improve this answer
    
Unfortunately, this suffers from the "nested tikzpicture" problem. Try putting, say, baseline=15pt on the outer tikzpicture and see what happens. The \subnode command was written to get round this issue (it works on the same underlying principle). –  Loop Space Dec 12 '12 at 9:15
    
I had tried something similar, but the coordinates ended up in weird places. That's because I use beamer and overlays, so for the [remember picture] to stabilize, I need 3, 4 or even 5 compilations -- and I gave up before reaching that number. \subnode needs just as many compilations (since it relies on [remember picture] just like your \coordinates), but avoids some of the problems caused by nested tikzpictures, like Andrew said. –  Georges Dupéron Dec 12 '12 at 21:58

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.