3

This is an issue with an answer to a previous question:

The proposed solution uses a picture-within-a-picture. As its author noted:

Note: (foo) and (age) will not be defined in the final tikzpicture.

It makes sense to me that an included picture would be in some sense atomic, but I wanted to see how it would break if I tried to reference an inner picture's node from the outer picture:

\documentclass[border=10pt]{standalone}

\usepackage{tikz}
\usetikzlibrary{arrows,intersections,shapes,backgrounds,scopes,positioning,fit,matrix}

%% Language and font encodings
\usepackage[english]{babel}% Really?

\newsavebox{\tempbox}

\begin{document}

\tikzset{varname/.style={rectangle,thin,inner sep=0.3ex,font=\ttfamily,text height=1.5ex,text depth=0.35ex}}
\tikzset{vartype/.style={rectangle,text=red,thin,inner sep=0.3ex,font=\ttfamily,text height=1.5ex,text depth=0.35ex}}
\tikzset{struct/.style={draw,matrix of nodes,column 1/.style={anchor=base west},column 2/.style={anchor=base west}}}
\tikzset{structtype/.style={rectangle,draw,fill=white,thin,inner sep=0.3ex,font=\ttfamily,text height=1.5ex,text depth=0.35ex}}

\setbox\tempbox=\hbox{\begin{tikzpicture}[baseline=(age.text)]
\matrix[struct] (attributes)
    {
        \node[varname] (age) {age};    & \node[vartype]       {int*}; & \\
        \node[varname]       {height}; & \node[vartype]       {float}; & \\
        \node[varname]       {weight}; & \node[vartype] (zzz) {float}; & \\
    };
\node[structtype,above=0.5ex of attributes.north west,anchor=west]  {Attributes};
\end{tikzpicture}}%

\begin{tikzpicture}
\matrix[struct] (person)
{
    \node[varname] {name};  & \node[vartype] {const char*}; \\
    \node[varname] {attrs}; & \node{\usebox{\tempbox}}; \\
    \node[varname] {xxx};   & \node (xxx) {TODO};  \\
};
\node[structtype,above=0.5ex of person.north west,anchor=west]  {Person};

\draw[->,very thick] (xxx.east) -- ++(2,0) |- (zzz.east);
\end{tikzpicture}

\end{document})

enter image description here

The problem is that the (zzz) node can be referenced but the outer image sees it in the wrong position. The problem can be highlighted by inserting extra stuff.

enter image description here

If the code worked at all, I would have expected something like this

enter image description here

I wasn't expecting the (zzz) node to even compile, but given that it does, why does the arrow land where it does?

(Note that adding X pixels of stuff above the inner picture does not move the arrow's endpoint down by X pixels: the endpoint doesn't seem to be a fixed distance from anything else in the drawing.)

3

Add the option remember picture to both tikzpicture environments.

\setbox\tempbox=\hbox{\begin{tikzpicture}[baseline=(age.text),remember picture]
...
\begin{tikzpicture}[remember picture]

You have to run LaTeX twice to get the reference points right that are written to the aux file.

enter image description here

\documentclass[border=10pt]{standalone}

\usepackage{tikz}
\usetikzlibrary{arrows,intersections,shapes,backgrounds,scopes,positioning,fit,matrix}

%% Language and font encodings
\usepackage[english]{babel}% Really?

\newsavebox{\tempbox}

\begin{document}

\tikzset{varname/.style={rectangle,thin,inner sep=0.3ex,font=\ttfamily,text height=1.5ex,text depth=0.35ex}}
\tikzset{vartype/.style={rectangle,text=red,thin,inner sep=0.3ex,font=\ttfamily,text height=1.5ex,text depth=0.35ex}}
\tikzset{struct/.style={draw,matrix of nodes,column 1/.style={anchor=base west},column 2/.style={anchor=base west}}}
\tikzset{structtype/.style={rectangle,draw,fill=white,thin,inner sep=0.3ex,font=\ttfamily,text height=1.5ex,text depth=0.35ex}}

\setbox\tempbox=\hbox{\begin{tikzpicture}[baseline=(age.text),remember picture]
\matrix[struct] (attributes)
    {
        \node[varname] (age) {age};    & \node[vartype]       {int*}; & \\
        \node[varname]       {height}; & \node[vartype]       {float}; & \\
        \node[varname]       {weight}; & \node[vartype] (zzz) {float}; & \\
    };
\node[structtype,above=0.5ex of attributes.north west,anchor=west]  {Attributes};
\end{tikzpicture}}%

\begin{tikzpicture}[remember picture]
\matrix[struct] (person)
{
    \node[varname] {name};  & \node[vartype] {const char*}; \\
    \node[varname] {name};  & \node[vartype] {const char*}; \\
    \node[varname] {name};  & \node[vartype] {const char*}; \\
    \node[varname] {attrs}; & \node{\usebox{\tempbox}}; \\
    \node[varname] {xxx};   & \node (xxx) {TODO};  \\
};
\node[structtype,above=0.5ex of person.north west,anchor=west]  {Person};

\draw[->,very thick] (xxx.east) -- ++(2,0) |- (zzz.east);
\end{tikzpicture}

\end{document}
2
  • I wasn't sure that would work with a savebox. I should have realized that global definitions are saved imediately and the origin location will still be written to the aux file when the box is printed. – John Kormylo Mar 8 '17 at 21:15
  • @JohnKormylo I was also not sure until I had verified that it works. :-) – gernot Mar 8 '17 at 21:19

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.