Using TikZ Chains Library with labeled edges extension
The other day I need to create a diagram, and went in the TikZ way. I was using the chains library to produce the diagram. But I face some problems, I needed to add labels to the edges created by the chain. However, this is not supported natively by the library.
I found a cool code that exemplifies how to add the edges to the chain, but it removes the old notation
\chainin (node) [join=with srcNode by style]
and make you use a new definition. However, I still need to use the styles and the source node notation. So, I start digging in the chains library code and modify it to allow the use of the label notation from other examples. The fix is
\makeatletter \def\tikz@lib@parse@join#1{% \def\tikz@temp{#1}% \ifx\tikz@temp\pgfutil@empty% \tikz@lib@parse@join@by by \pgf@stop% \else% \pgfutil@in@{with }{#1}% \ifpgfutil@in@% 'with [by] [label]' \pgfutil@in@{by }{#1}% \ifpgfutil@in@% 'with by [label]' \pgfutil@in@{label }{#1}% \ifpgfutil@in@% 'with by label' \tikz@lib@parse@join@with@by@label#1\pgf@stop% \else% 'with by' \tikz@lib@parse@join@with@by#1\pgf@stop% \fi% \else% 'with [label]' \pgfutil@in@{label }{#1}% \ifpgfutil@in@% 'with label' \tikz@lib@parse@join@with@label#1\pgf@stop% \else% with \tikz@lib@parse@join@with@by#1 by \pgf@stop% \fi% \fi% \else% '[by] [label]' \pgfutil@in@{by }{#1}% \ifpgfutil@in@% 'by [label]' \pgfutil@in@{label }{#1}% \ifpgfutil@in@% 'by label' \tikz@lib@parse@join@by@label#1\pgf@stop% \else% 'by' \tikz@lib@parse@join@by#1\pgf@stop% \fi% \else% '[label]' \pgfutil@in@{label }{#1}% \ifpgfutil@in@% 'label' \tikz@lib@parse@join@label#1\pgf@stop% \else% \tikz@lib@parse@join@by#1 by \pgf@stop% \fi% \fi% \fi% \fi% } \def\tikz@lib@parse@join@with@by@label with #1 by #2 label #3\pgf@stop{% \tikzset{after node path={(#1)edge[every join,#2]#3(\tikzchaincurrent)}}% } \def\tikz@lib@parse@join@with@label with #1 label #2\pgf@stop{% \tikzset{after node path={(#1)edge[every join]#2(\tikzchaincurrent)}}% } \def\tikz@lib@parse@join@by@label by #1 label #2\pgf@stop{% \tikzset{after node path={\ifx\tikzchainprevious\pgfutil@empty\else(\tikzchainprevious)edge[every join,#1]#2(\tikzchaincurrent)\fi}}% } \def\tikz@lib@parse@join@label label #1\pgf@stop{% \tikzset{after node path={\ifx\tikzchainprevious\pgfutil@empty\else(\tikzchainprevious)edge[every join]#1(\tikzchaincurrent)\fi}}% } \makeatother
This allows one to use the chains like:
\chainin (node) [join=with anotherNode by myStyle label {node[above] {some Tag}}]; \chainin (node) [join=by myStyle label {node[above] {some Tag}}];
Note that the order needs to be maintained, so you can use [with] [label] [tag]
and omit any of those, while the order is maintained. A minimal working example is below:
\documentclass{standalone} \usepackage{tikz} \usetikzlibrary{shapes,% for the rectangle chains,% provides the chains scopes}% allows to replace \begin{scope} \end{scope} with {} \makeatletter \def\tikz@lib@parse@join#1{% \def\tikz@temp{#1}% \ifx\tikz@temp\pgfutil@empty% \tikz@lib@parse@join@by by \pgf@stop% \else% \pgfutil@in@{with }{#1}% \ifpgfutil@in@% 'with [by] [label]' \pgfutil@in@{by }{#1}% \ifpgfutil@in@% 'with by [label]' \pgfutil@in@{label }{#1}% \ifpgfutil@in@% 'with by label' \tikz@lib@parse@join@with@by@label#1\pgf@stop% \else% 'with by' \tikz@lib@parse@join@with@by#1\pgf@stop% \fi% \else% 'with [label]' \pgfutil@in@{label }{#1}% \ifpgfutil@in@% 'with label' \tikz@lib@parse@join@with@label#1\pgf@stop% \else% with \tikz@lib@parse@join@with@by#1 by \pgf@stop% \fi% \fi% \else% '[by] [label]' \pgfutil@in@{by }{#1}% \ifpgfutil@in@% 'by [label]' \pgfutil@in@{label }{#1}% \ifpgfutil@in@% 'by label' \tikz@lib@parse@join@by@label#1\pgf@stop% \else% 'by' \tikz@lib@parse@join@by#1\pgf@stop% \fi% \else% '[label]' \pgfutil@in@{label }{#1}% \ifpgfutil@in@% 'label' \tikz@lib@parse@join@label#1\pgf@stop% \else% \tikz@lib@parse@join@by#1 by \pgf@stop% \fi% \fi% \fi% \fi% } \def\tikz@lib@parse@join@with@by@label with #1 by #2 label #3\pgf@stop{% \tikzset{after node path={(#1)edge[every join,#2]#3(\tikzchaincurrent)}}% } \def\tikz@lib@parse@join@with@label with #1 label #2\pgf@stop{% \tikzset{after node path={(#1)edge[every join]#2(\tikzchaincurrent)}}% } \def\tikz@lib@parse@join@by@label by #1 label #2\pgf@stop{% \tikzset{after node path={\ifx\tikzchainprevious\pgfutil@empty\else(\tikzchainprevious)edge[every join,#1]#2(\tikzchaincurrent)\fi}}% } \def\tikz@lib@parse@join@label label #1\pgf@stop{% \tikzset{after node path={\ifx\tikzchainprevious\pgfutil@empty\else(\tikzchainprevious)edge[every join]#1(\tikzchaincurrent)\fi}}% } \makeatother \begin{document} \begin{tikzpicture}[ nonterminal/.style={ rectangle, minimum size=6mm, very thick, draw=red!50!black!50, top color=white, % a shading that is white at the top... bottom color=red!50!black!20, % and something else at the bottom font=\itshape }, terminal/.style={ rectangle,minimum size=6mm,rounded corners=3mm, very thick,draw=black!50, top color=white,bottom color=black!20, font=\ttfamily }, every on chain/.style={join}, every join/.style={->} ] \matrix[column sep=4mm] { % First row: & & & & \node (plus) [terminal] {+};&\\ % Second row: \node (ui1) [nonterminal] {unsigned integer};& \node (dot) [terminal] {.}; & \node (digit) [terminal] {digit}; & \node (e) [terminal] {E}; & & % space in between \node (ui2) [nonterminal] {unsigned integer};\\ % Third row: & & & & \node (minus)[terminal] {-};&\\ }; { [start chain] \chainin (ui1); \chainin (dot); \chainin (digit); \chainin (e); { [start branch=plus] \chainin (plus) [join=label {node[above left]{a label}}]; } { [start branch=minus] \chainin (minus); } \chainin (ui2) [join=with chain/plus-end label {node[above right] {plus label}}, join=with chain/minus-end by dashed label {node [below right]{minus label}}]; } \end{tikzpicture} \end{document}
PS. This post was inspired by this TeX.SX question, and I put this answer also there. You can found more about (La)TeX there.
Thanks so much, none of the other solutions I found worked for me. Can I suggest you submit this to texamples.net, to replace their http://www.texample.net/tikz/examples/labeled-chain/ example? Either way, this was incredibly useful and worked without the need for modification of existing joins so that was appreciated.