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 following example draws three rectangles, each divided in two parts (they're Lisp cons cells). It works fine, but something doesn't seem right: I have used \begin{scope} inside the \cons macro, and inside that macro I have two nodes named a and b. However, if I use the names a and b outside the macro, things become confusing. Aren't the two names a and b inside \begin{scope} there supposed to be invisible to the rest of the document?

The example works fine, but changing aa to a, and so on exposes the problem.

Is there a better or easier way to do what I'm trying to do?

update: So, names are defined globally anyway... I'd like to use the \cons macro several times in the same picture -- which doesn't seem to work if node names are global. What can I do then? Should I use only relative positioning and not give the nodes any names? Is this the only way?

\documentclass{article}

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

\begin{document}

\newcommand{\cons}{%
\begin{tikzpicture}[cell/.style={draw,shape=rectangle,minimum size=0.4cm}]
\begin{scope}
\node[cell](a)[anchor=west]{};
\node[cell](b)[right=0mm of a.east,anchor=west]{};
\end{scope}
\end{tikzpicture}
}

\begin{tikzpicture}
\node(aa){\cons};
\node(bb)[below left=of aa]{\cons};
\node(cc)[below right=of aa]{\cons};
\draw[->,red]  (aa.west) -| (bb.north);
\draw[->,blue] (aa.east) -| (cc.north);
\end{tikzpicture}

\end{document}
share|improve this question
3  
No, the node names are defined globally regardless of the scoping. –  percusse Jun 29 '12 at 20:57
    
Oh, I see. I misunderstood what the scoping was about then... I'll update my question. –  Jay Jun 29 '12 at 21:01
3  
You can reuse node names without breaking anything so long as you don't need to refer to a previous incarnation of a particular node. So there's no difficulty with reusing the \cons macro from that point of view. (However, nesting tikzpictures is fraught with difficulty and it can be better to find an alternative that doesn't involve nesting, such as percusse's suggestion). –  Loop Space Jun 29 '12 at 21:07
1  
But there still is the question of why nodes are always defined globally, defying the meaning of scope. I assume there is a reason. –  Ahmed Musa Jun 30 '12 at 16:48
2  
@AhmedMusa For the very simple reason that scopes are often used for other reasons than grouping. It is common to use a scope to mean "Apply the following settings to all the following parts of the diagram", such as a style or a transformation. When applying this to nodes or coordinates, one wants to use them in the rest of the picture. I would expect to be able to use all nodes names within a tikzpicture with no regard to scoping, and since it is not expected that tikzpictures should be nested, making node names global is sensible. –  Loop Space Jun 30 '12 at 19:12

4 Answers 4

You can use the readily available multipart node shapes.

\documentclass{article}

\usepackage{tikz}
\usetikzlibrary{shapes.multipart,positioning}

\begin{document}


\begin{tikzpicture}[twocell/.style={draw,
                                    rectangle split, 
                                    rectangle split horizontal,
                                    rectangle split parts=2
                                   }
]
\node[twocell](aa){};
\node[twocell](bb)[below left=of aa]{};
\node[twocell](cc)[below right=of aa]{};
\draw[->,red]  (aa.west) -| (bb.north);
\draw[->,blue] (aa.east) -| (cc.north);
\end{tikzpicture}

\end{document}

enter image description here

share|improve this answer
    
Thanks -- that is certainly useful! It would be also nice if I could get rounded corners -- not only on the outer corners, but also in the split (as if they were really two squares with rounded corners). But this is already great! –  Jay Jun 29 '12 at 21:06
1  
@Jay that's a little bit tricky as you have to define a new shape. But if you are not going to write anything inside these, then maybe some extra tricks can be pulled off. –  percusse Jun 29 '12 at 21:08

Jay, I won't answer your original question, because Percusse did it, but the one you made in you comment: How to get cons rounded corners.

(I'm not sure if would be better to make a 'following' question and answer there. Let's see what moderators consider)

As Percusse suggestet, the solution is tricky. You use a non drawn multipart rectangle and draw rounded rectangles over each part with append after command option. Here you will find several answers using this option. In particular, I've taken code from Add new symbol to simple TikZ diagram and Problem with "append after command" and "insert path". I don't understand why command \pgfextra is necessary but it woks.

Here you have it:

\documentclass{standalone}

\usepackage{tikz}
\usetikzlibrary{shapes.multipart,positioning}

\begin{document}
\begin{tikzpicture}[%
cons/.style={%
    rectangle split,%
    rectangle split horizontal,%
    rectangle split parts=2,%
   outer sep=0pt,%
    append after command={%
    \pgfextra{%
     \draw[rounded corners=3pt] (\tikzlastnode.south west)      
          rectangle (\tikzlastnode.one split north);%
     \draw[rounded corners=3pt] (\tikzlastnode.north east)   
          rectangle (\tikzlastnode.one split south);}}}]
\node[cons](aa){};
\node[cons](bb)[below left=of aa]{};
\node[cons](cc)[below right=of aa]{};
\draw[->,red]  (aa.west) -| (bb.north);
\draw[->,blue] (aa.east) -| (cc.north);
\end{tikzpicture}
\end{document}

enter image description here

share|improve this answer
    
Thanks -- that is very helpful! –  Jay Jun 30 '12 at 11:49
3  
PGF manual on \pgfextra: "Note that this command should only be used by real experts and should only be used deep inside clever macros, not on normal paths." Hence we deduce that Ignasi is an "expert". –  Ahmed Musa Jun 30 '12 at 16:56
    
@AhmedMusa You can see in my answer that you can avoid the use of \pgfextra. –  Alain Matthes Jul 1 '12 at 9:03

It's possible to simplify the code because you use append after command without pgfextra.

You need to create a pathwith the option draw then you add a node to the path with the option cons. With this method you avoid the use of \draw inside `append after command .

\documentclass{standalone}
\usepackage{tikz}
\usetikzlibrary{shapes.multipart,positioning}

\begin{document}
\begin{tikzpicture}[%
cons/.style={%
    rectangle split,%
    rectangle split horizontal,%
    rectangle split parts=2,%
    outer sep=0pt,%
    append after command={%
     [rounded corners=3pt] (\tikzlastnode.south west)  rectangle (\tikzlastnode.one split north)
                           (\tikzlastnode.north east)  rectangle (\tikzlastnode.one split south)  
          }}]
\path [draw] node[cons](aa){};
\path [draw] node[cons](bb)[below left=of aa]{};
\path [draw] node[cons](cc)[below right=of aa]{};

\draw[->,red]  (aa.west) -| (bb.north);
\draw[->,blue] (aa.east) -| (cc.north);  
\end{tikzpicture}
\end{document}  

enter image description here

share|improve this answer
    
Before posting my answer with \pgfextra I tested without it and without success: \draw failed and \path node also but I didn't know \path [draw]. Thank you for showing it! –  Ignasi Jul 1 '12 at 16:31
    
@Ignasi A node is not really a part of a path. It's an object added to the path and the node add is personal option draw. So when you can draw a path but not the nodes added along the path. –  Alain Matthes Jul 1 '12 at 18:32

In response to Ignasi's remark that he doesn't know what \pgfextra does, it suspends path parsing or tracing so that an arbitrary code can be executed. This is risky or impossible otherwise. I demonstrate the use of an arbitrary code in the following.

After a lengthy trace, I saw that when using \pgfextra it is necessary to avoid spurious spaces, such as the space after \pgfextra{. Those spaces are not removed internally. Ignasi did it correctly in his solution, but it is easy to overlook. I hope PGF developers will attend to this internally later. In the meantime, when \pgfextra comes in the argument of at end node, the following solution can be used.

EDIT: I present the full code below in response to Altermundus' comment.

\documentclass{standalone}
\usepackage{tikz}
\usetikzlibrary{shapes.multipart,positioning}
\makeatletter
% If we load pgfkeyx.sty, we can normalize the list before parsing.
% Well, let's ignore difficult lists here.
% Using the delimiter \pgfeov for the callback of \pgfkeyscommaloop allows it 
% to be multi-parametered.
\def\pgfkeyscommaloop#1#2{\pgfkeys@commaloop{#1}#2,\pgfkeyscommaloop,}
\def\pgfkeys@commaloop#1#2,{%
  \expandafter\ifx\@car#2x\@nil\pgfkeyscommaloop
    \expandafter\@gobble\else\expandafter\@iden\fi
  {#1#2\pgfeov\pgfkeys@commaloop{#1}}%
}
\def\ifpgfkeydef#1{%
  \ifcsname pgfk@#1/.@cmd\endcsname
    % OK, the command is already in the hash table; no safeguard needed
    % against filling the hash.
    \expandafter\ifx\csname pgfk@#1/.@cmd\endcsname\relax
      \expandafter\expandafter\expandafter\@secondoftwo
    \else
      \expandafter\expandafter\expandafter\@firstoftwo
    \fi
  \else
    \expandafter\@secondoftwo
  \fi
}
\def\pgfkey@def@do#1\pgfeov{\ifpgfkeydef{#1}{-1}{+0}}
\def\pgfkey@undef@do#1\pgfeov{\ifpgfkeydef{#1}{+0}{-1}}
% Given a list of keys, I want to know if at least one of them is defined:
\def\ifonepgfkeydef#1{%
  \ifnum\numexpr\z@\pgfkeyscommaloop\pgfkey@def@do{#1}<\z@
    \expandafter\@firstoftwo
  \else
    \expandafter\@secondoftwo
  \fi
}
% Given a list of keys, I want to know if at least one of them is undefined:
\def\ifonepgfkeyundef#1{%
  \ifnum\numexpr\z@\pgfkeyscommaloop\pgfkey@undef@do{#1}<\z@
    \expandafter\@firstoftwo
  \else
    \expandafter\@secondoftwo
  \fi
}
\ifonepgfkeydef{/tikz/at end of node,/tikz/at end node}{%
  \@latexerr{Key(s) '/tikz/at end of node' and/or
    '/tikz/at end node' already exist}\@ehd
}{}

% The following acrobatics is just an academic exercise: Altermundus's approach
% is simpler and better:
\tikzset{at end of node/.code=
  \begingroup
  \def\pgf@@relax{\relax}%
  \pgfkeys@spdef\reserveda{#1}%
  \def\reservedb##1\pgfextra##2##3\pgf@nil{%
    \ifx\pgf@@relax##2\else
      \pgfkeys@spdef\reservedb{##2}%
      \def\reservedc##1\pgfextra\pgf@@relax{##1}%
      \edef\reserveda{\unexpanded{##1}\noexpand\pgfextra{\unexpanded
      \expandafter{\reservedb}}\unexpanded\expandafter{\reservedc##3}}%
    \fi
  }%
  \expandafter\reservedb\reserveda\pgfextra\pgf@@relax\pgf@nil
  \edef\reserveda{\endgroup
    \noexpand\pgfkeysalso{append after command=%
    {\unexpanded\expandafter{\reserveda}}}%
  }\reserveda
  ,
  at end node/.style={at end of node={#1}}
}
\def\minorrect#1#2#3{%
  \draw[rounded corners=#1] (\tikzlastnode.#2)
    rectangle (\tikzlastnode.one split #3);
}
\makeatother

\begin{document}
\begin{tikzpicture}[cons/.style={%
  rectangle split,
  rectangle split horizontal,
  rectangle split parts=2,
  outer sep=0pt,
  at end of node={
    \pgfextra{
      \minorrect{3pt}{south west}{north}%
      \minorrect{10pt}{north east}{south}%
    }%
  }%
}%
]
\node[cons](aa){};
\node[cons](bb)[below left=of aa]{};
\node[cons](cc)[below right=of aa]{};
\draw[->,red]  (aa.west) -| (bb.north);
\draw[->,blue] (aa.east) -| (cc.north);
\end{tikzpicture}
\end{document}

enter image description here

share|improve this answer
    
First, I try your last solution to avoid spurious spaces but I can't compile. Can you give the complete code ? Secondly, I you place % at the end of the definition of \minorrect with }%, I think you will remove the first spurious space. –  Alain Matthes Jul 1 '12 at 7:47

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.