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.

I have a figure drawn using tikz. I am trying to add a legend, which consists in two types of arrows with different meanings. My problem is how to add the correct vertical space between the nodes with arrows.

In the MWE, I have the a reference node and the text within it is separated by \\. How can I align the nodes with arrows with latter keeping the same vertical space between the text of nodes (n2) and (n3) as within (n1)?

\documentclass{article}

\usepackage{tikz}
\usetikzlibrary{calc}

\begin{document}
\begin{tikzpicture}
    \node[align=right,inner ysep=0pt] (n1) {BLA\\ BLB};
    \draw[->,red,align=center] ($(n1.north east)+(1cm,0cm)$) -- ++(0:8pt) node[at end,anchor=west] (n2) {BLA BLA};
    \draw[<-,red] ($(n1.north east)+(1cm,-\baselineskip)$) -- ++(0:8pt) node[at end,anchor=west] (n3) {BLA BLB};
\end{tikzpicture}
\end{document}
share|improve this question

1 Answer 1

up vote 3 down vote accepted

Basic solution

This solution provides two keys:

  • line and
  • line default font.

The line key accepts its argument either with : or without :. If the colon is given, the value is simply forwarded to the internal @line key which uses the part before the colon as a font argument (which hopefully set \baselineskip correctly. The part after the : is the line number, 1 being the bottom line.

Isn’t the colon present the value of line default font will be forwarded to @line and will be used as the font-argument.

Code

\documentclass[tikz,convert=false]{standalone}
\makeatletter
\tikzset{
  line default font/.initial=\normalsize,
  line/.code=\pgfutil@in@{:}{#1}%
    \ifpgfutil@in@
      \pgfkeysalso{@line={#1}}\else
      \pgfkeysalso{@line={\pgfkeysvalueof{/tikz/line default font}:#1}}%
    \fi,
  @line/.code args={#1:#2}{% internal
    \begingroup
      #1%
      \pgfutil@tempcnta#2\relax
      \advance\pgfutil@tempcnta-1\relax
      \pgf@xa\pgfutil@tempcnta\baselineskip\relax
      \pgfmath@returnone\pgf@xa
    \endgroup
    \pgftransformshift{\pgfqpoint{0pt}{\pgfmathresult pt}}%
  }
}
\begin{document}
\begin{tikzpicture}
    \node[align=right, font=\small, draw=lightgray] (n1) {BL\\ BLB};
    \draw[->] ([line=\small:2,xshift=1cm] n1.base east) -- ++(0:8pt)
                                        node[at end,anchor=base west] (n2) {Line 2};
    \draw[<-] ([line=1,       xshift=1cm] n1.base east) -- ++(0:8pt)
                                            node[at end,anchor=base west] (n3) {Line 1};
    \tikzset{line default font=\small, radius=.6pt}
    \fill ([line=1] n1.base west) circle[]
          ([line=2] n1.base west) circle[] [red];
    \fill ([line=1] n1.base)      circle[]
          ([line=2] n1.base)      circle[];
    \fill ([line=1] n1.text)      circle[]
          ([line=2] n1.text)      circle[] [blue];
    \fill ([line=1] n1.base east) circle[]
          ([line=2] n1.base east) circle[] [green];
\end{tikzpicture}
\end{document}

Output

enter image description here

Sophisticated solution

This solution includes:

  • the save baseline key that saves the \baselineskip length at the end of the node in a macro (it might be helpful to include this style in the every node style);

  • an addition to the explicit node coordinate system in the form of the line key (it checks whether save baseline has been used on the node); and

  • an addition to the implicit node coordinate. The line is separated from the anchor by the character ' (it is not possible to use : or ,, it could be possible to use . again).

It is not possible to use the line key without an anchor (implicitly or explicitly). This could be fixed. I advise against using ' in a node name (especially if it should be possible to use the line ' without an anchor).

Shortcomings

Don’t transform!

Seriously, if either the node is rotated or the path which uses the line-anchor is rotated or one of the scaleings is active I can guarantee nothing.

Code

\documentclass[tikz,convert=false]{standalone}
\makeatletter
\tikzset{
  save baseline/.style={
    execute at end node=\expandafter\xdef\csname pgf@sh@bls@\tikz@fig@name\endcsname{\the\baselineskip}
  }
}
\pgfqkeys{/tikz/cs}{%
  line/.store in=\tikz@cs@line,% addition
  anchor/.store in=\tikz@cs@angle% small fix to reduce the code of the 'node' cs
}
\tikzdeclarecoordinatesystem{node}{%
  \tikzset{cs/.cd,name=,anchor=none,line=none,#1}%
  \ifx\tikz@cs@angle\tikz@nonetext%
    \expandafter\ifx\csname pgf@sh@ns@\tikz@cs@node\endcsname\tikz@coordinate@text%
    \else
      \aftergroup\tikz@shapebordertrue%
      \edef\tikz@shapeborder@name{\tikz@cs@node}%
    \fi%
    \pgfpointanchor{\tikz@cs@node}{center}%
  \else%
    \ifx\tikz@cs@line\tikz@nonetext
      \pgfpointanchor{\tikz@cs@node}{\tikz@cs@angle}%
    \else
      \expandafter\ifx\csname pgf@sh@bls@\tikz@cs@node\endcsname\relax
        \PackageError{TikZ}{The \tikz@cs@node\space has no saved baseline, use the 'save baseline' option}{}
        \pgfpointanchor{\tikz@cs@node}{\tikz@cs@angle}
      \else
        \pgfutil@tempcnta=\tikz@cs@line\relax
        \advance\pgfutil@tempcnta-1\relax
        \pgfutil@tempdima=\csname pgf@sh@bls@\tikz@cs@node\endcsname
        \pgfpointadd{\pgfpointanchor{\tikz@cs@node}{\tikz@cs@angle}}
                    {\pgfqpoint{0pt}{\pgfutil@tempcnta\pgfutil@tempdima}}%
      \fi
    \fi
  \fi%
}
\def\tikz@calc@anchor#1.#2\tikz@stop{%
  \pgfutil@in@{'}{#2}
  \ifpgfutil@in@
    \expandafter\ifx\csname pgf@sh@bls@#1\endcsname\relax
      \PackageError{TikZ}{The #1 has no saved baseline, use the 'save baseline' option}{}
      \pgfpointanchor{#1}{#2}
    \else
      \tikz@calc@anchor@line#1.#2\tikz@stop
    \fi
  \else
    \pgfpointanchor{#1}{#2}%
  \fi
}
\def\tikz@calc@anchor@line#1.#2'#3\tikz@stop{%
  \pgfutil@tempcnta=#3\relax
  \advance\pgfutil@tempcnta-1\relax
  \pgfutil@tempdima=\csname pgf@sh@bls@#1\endcsname
  \pgfpointadd{\pgfpointanchor{#1}{#2}}
              {\pgfqpoint{0pt}{\pgfutil@tempcnta\pgfutil@tempdima}}%
}
\makeatother
\begin{document}
\begin{tikzpicture}
    \node[align=right, font=\small, draw=lightgray, save baseline] (n1) {BL\\ BLB};
    \draw[->] (node cs: name=n1, anchor=base east, line=2) -- ++(0:8pt)
                                        node[at end,anchor=base west] (n2) {Line 2};
    \draw[<-] (node cs: name=n1, anchor=base east) -- ++(0:8pt)
                                            node[at end,anchor=base west] (n3) {Line 1};
    \tikzset{radius=.6pt}
    \fill (n1.base west'1) circle[]
          (n1.base west'2) circle[] [red];
    \fill (n1.base'1)      circle[]
          (n1.base'2)      circle[];
    \fill (n1.text'1)      circle[]
          (n1.text'2)      circle[] [blue];
    \fill (n1.base east'1) circle[]
          (n1.base east'2) circle[] [green];
\end{tikzpicture}
\end{document}

Output

enter image description here

share|improve this answer
    
Your code doesn't work. It gives l.6 ...[->,red] ([line=2,xshift=1cm] n1.base east) -- ++(0:8pt) ? –  cacamailg Jul 23 '13 at 0:58
    
The code works now. But the vertical space is correct only if font=\normalsize. Since I am using font=\small for all the nodes, I had to do \tikzset{line/.style={shift={(+0pt,{(#1-1)*\baselineskip*0.91})}}}. This 0.91 is achieved by trial-error tentatives. How can we introduce a factor if font size chances to \small, \footnotesize, etc.? –  cacamailg Jul 23 '13 at 12:00
    
@cacamailg Yes, that is annoying (and is one of the things I meant with “[i]f \baselineskip is not specifically changed inside the node”). I am afraid there is no easy solution. If you typeset all nodes in \small you could issue \small after \begin{tikzpicture}[…] (which changes also all em and ex dimensions of course). Or you can use ([/utils/exec=\small,line=2,xshift=1cm] n1.base east) (best hidden in another style). If you want to go very sophisticated, you let \baselineskip be stored away and reference it later (could be a special cs). Would this be needed? –  Qrrbrbirlbel Jul 23 '13 at 12:26
    
Well, all nodes are typeset in \small because of space constraints. That special style that you mention, probably is the best solution, because I don't know if I need to typeset some nodes in \footnotesize. Or change the style that you have defined to include a second parameter. –  cacamailg Jul 23 '13 at 12:37
    
@cacamailg Please see my update. The “Sophisticated solution” is what I was talking about in my previous comment. But don’t use any transformations (besides shifting I think). This could go horrible wrong (but that's true even for the other solutions). I will take a look into the transformations nonetheless. –  Qrrbrbirlbel Jul 23 '13 at 14:59

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.