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 find a code that redefines the way one defines a chain (\chainin), and allows one to include labels in the chains. However, this code disables the style options (by and with keyword). However, I need to give individual styles to each chain.

How can I add individual styles to each chain, and at the same time being able to tag the connections by adding a node, like: node [left] {tag}. So I'm aiming for something like this: \chainin (node) [join=by myStyle, {node [left] {my Tag}}];

\documentclass{standalone}

\usepackage{tikz}
\usetikzlibrary{shapes,chains,scopes,matrix}
% This code makes it able to include the tag
\makeatletter
\tikzset{join/.code=\tikzset{after node path={%
\ifx\tikzchainprevious\pgfutil@empty\else(\tikzchainprevious)%
edge[every join]#1(\tikzchaincurrent)\fi}}}
\makeatother

\begin{document}

\begin{tikzpicture}[auto,
  decision/.style = {draw,
                     diamond,
                     text badly centered,
                     fill          = blue!5,
                     text width    = 15mm,
                     node distance = 2.5cm,
                     inner sep     = 0pt},
  block/.style    = {draw,
                     rectangle,
                     text centered,
                     rounded corners,
                     fill           = blue!5,
                     text width     = 20mm,
                     minimum height = 10mm},
  tip/.style      = {->,
                     very thick,
                     color = black!50}
]

\matrix[row sep=1cm]{
\node [block] (blk) {A block here}; \\
\node [decision] (dec) {Is something?};\\
};

{ [start chain]
  \chainin (blk);
  % By removing the 'by tip' style this compiles
  \chainin (dec) [join=by tip, {node [left] {yes}}];
}
\end{tikzpicture}
\end{document}
share|improve this question
    
I've added a feature request to TikZ for this. Feel free to improve it with comments! –  sampablokuper Jul 2 '12 at 3:56
    
@sampablokuper maybe they can implement (fix) the initial idea I proposed here –  adn Jul 2 '12 at 4:58
add comment

2 Answers 2

The problem is that the join is not used as a parametrized style, but the code is ran. That is, by tip, {node [left] {yes}} becomes #1 in join/.code and so it's placed after edge[every join]. That means that without the tip it would work fine, the node is placed after the edge and is applied as you would expect. The problem is that you want the tip to be placed as an option on the edge besides every join. The easiest way to accomplish this is to let join take two arguments, one to go in the edge options and another to represent possible nodes. This can be achieved by the following code:

\documentclass{standalone}

\usepackage{tikz}
\usetikzlibrary{shapes,chains,scopes,matrix}
% This code makes it able to include the tag
\makeatletter
\tikzset{join/.code 2 args=\tikzset{after node path={%
\ifx\tikzchainprevious\pgfutil@empty\else(\tikzchainprevious)%
edge[every join,#1]#2(\tikzchaincurrent)\fi}}}
\makeatother

\begin{document}

\begin{tikzpicture}[auto,
  decision/.style = {draw,
                     diamond,
                     text badly centered,
                     fill          = blue!5,
                     text width    = 15mm,
                     node distance = 2.5cm,
                     inner sep     = 0pt},
  block/.style    = {draw,
                     rectangle,
                     text centered,
                     rounded corners,
                     fill           = blue!5,
                     text width     = 20mm,
                     minimum height = 10mm},
  tip/.style      = {->,
                     very thick,
                     color = black!50}
]

\matrix[row sep=1cm]{
\node [block] (blk) {A block here}; \\
\node [decision] (dec) {Is something?};\\
};

{ [start chain]
  \chainin (blk);
  %tip and node:
  \chainin (dec) [join={tip}{node [left] {yes}}];
  %Only the tip:
  %\chainin (dec) [join={tip}{}];
  %Only the node:
  %\chainin (dec) [join={}{node [left] {yes}}];
}
\end{tikzpicture}
\end{document}

As you can see you can just leave the arguments empty if you don't want a specific part of the join.

Edit: I don't see a way to accomplish this. Since you have to change the code for the join key in order to get the desired behaviour. But to get the with .. by ... behaviour different code is required. Unfortunately you can only have one "code-related" key as far as I know (that is, TikZ can't determine which code to call depending on the parameters). The easiest way is probably to change the new join method introduced in the code above to myjoin and use that wherever you want labeling. So the tikzset would become:

tikzset{myjoin/.code 2 args=\tikzset{after node path={%
\ifx\tikzchainprevious\pgfutil@empty\else(\tikzchainprevious)%
edge[every join,#1]#2(\tikzchaincurrent)\fi}}}

Then you can use the myjoin={options}{labeling node} where you need labeling and join=with ... by ... where you need the old behaviour. It might be wise to choose a more apropriate name than myjoin though.

If you like this verbose (and perhaps more readable) way of working with keys, you can define the myjoin option as follows:

\tikzset{myjoin/.code args={style #1 and label #2}{%
\tikzset{after node path={\ifx\tikzchainprevious\pgfutil@empty%
\else(\tikzchainprevious)edge[every join,#1]#2(\tikzchaincurrent)\fi}}}}

Which can be used as

\chainin (dec) [myjoin=style tip and label {node [left] {yes}}];
share|improve this answer
    
Very good! Pedro commented similar on this blog post. I remember I tested it and could not make it compilable, perhaps a version issue then. –  Stefan Kottwitz Jan 17 '12 at 22:41
    
@StefanKottwitz: I see, That is very similar indeed. I am not sure why he leaves out the every join style on the edge, since that is a nice way to get some default behaviour on the edges. I don't know enough about when which command was introduced to be able to comment on whether or not it could have been a version issue. Perhaps the key management interface was less advanced in older versions. –  Roelof Spijker Jan 17 '12 at 23:39
    
This solves the issue of adding the style, but now the normal join behavior isn't working. Is there a way to have both worlds? That is, being able to use the join=by... with... command and the join={style}{node...} new definition in the same diagram? –  adn Jan 18 '12 at 4:55
    
@adn: not exactly, see the edited answer though. –  Roelof Spijker Jan 18 '12 at 9:04
    
Thanks, the verbose part makes it more readable. I think that having two keys is OK. The problem was that I have to modify all the other paths that aren't using labels. Your explanation helps a lot. –  adn Jan 18 '12 at 11:20
add comment
up vote 1 down vote accepted

So after analyzing the solution of wh1t3, and the chains library, I tried to implement a solution that allow me to use the join code and add the labels.

I'm not sure if this is a correct approach, because I never done this before, so let me know if there is a better way. I redefined the functions of the library to allow the label keyword to be added, and it will add the node with the label that I'm missing. The code to be added 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

After adding that part, now I'm able to call my chainin like:

\chainin (node) [join=with anotherNode by myStyle label {node[above] {some Tag}}];
\chainin (node) [join=by myStyle label {node[above] {some Tag}}];

A full example would be

\documentclass{standalone}

\usepackage{tikz}
\usetikzlibrary{shapes,chains,scopes,matrix}

\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}[auto,
  decision/.style = {draw,
                     diamond,
                     text badly centered,
                     fill          = blue!5,
                     text width    = 15mm,
                     node distance = 2.5cm,
                     inner sep     = 0pt},
  block/.style    = {draw,
                     rectangle,
                     text centered,
                     rounded corners,
                     fill           = blue!5,
                     text width     = 20mm,
                     minimum height = 10mm},
  tip/.style      = {->,
                     very thick,
                     color = black!50},
  tip2/.style      = {->,
                     very thick,
                     bend right,
                     color = black!50}
]

\matrix[row sep=1cm]{
\node [block] (blk) {A block here}; \\
\node [decision] (dec) {Is something?};\\
\node [block] (blk2) {Another block};\\
};

{ [start chain]
  \chainin (blk);
  % Removing the 'by tip' style this compiles
  \chainin (dec) [join=by tip label {node [left] {yes}}];
  \chainin (blk2) [join=by tip];
  \chainin (blk2) [join=with blk by {tip2} label {node[left]{my tag}}];
}

\end{tikzpicture}
\end{document}
share|improve this answer
add comment

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.