Anchoring TiKZ pics

Apparently, the idea of scoping the relevant code in pics works.

Here is an example:

documentclass[tikz,border=2mm]{standalone}
usetikzlibrary{fit}

tikzset{pic shift/.store in=shiftcoord,
    pic shift={(0,0)},
    mytest/.pic = {
             begin{scope}[shift={shiftcoord}]
         node  (-A) at (0,0) {A};
         node  (-B) at (0,1) {B};
             node[fit=(-A) (-B),draw] (-C) {};
         end{scope}
    }
}

begin{document}
begin{tikzpicture}

draw[blue!20] (0,0) grid (3,3);

draw pic (S) at (0,0) {mytest};

draw pic (T) at (2,1) {mytest};

draw (S-A.north) to [out=90,in=-90] (T-B.south);

end{tikzpicture}
begin{tikzpicture}

draw[blue!20] (0,0) grid (3,3);

draw[pic shift={(1,1)}] pic (S) at (0,0) {mytest};

draw pic (T) at (2,1) {mytest};

draw (S-A.north) to [out=90,in=-90] (T-B.south);

end{tikzpicture}
end{document}

The result without shifts:

enter image description here

while shifting the first pic (S):

enter image description here

EDIT

Trying to answer to last Ignasi’s comment: Can I still use your code to place any internal pic coordinate on a desired place?

Probably, the answer is: yes, to some extent. Meaning that in a tikzpicture, while referring to a pic, you are actually taking into account his origin, namely whatever is placed in the coordinate (0,0). In the current case, node A. So, you can shift the complete pic with respect to this point, but I suspect you can not place any internal pic coordinate on a desired place. You can place any pic coordinate on a desired place as a consequence of having shifted the pic with respect to its origin.

Let us consider the following example:

documentclass[tikz,border=2mm]{standalone}
usetikzlibrary{fit,positioning}

% code by Andrew:
% https://tex.stackexchange.com/a/33765/13304
makeatletter
newcommand{gettikzxy}[3]{%
  [email protected]@[email protected][email protected]#1relax
  edef#2{the[email protected]}%
  edef#3{the[email protected]}%
}
makeatother

tikzset{pic shift/.store in=shiftcoord,
    pic shift={(0,0)},
    pic-a min height/.store in=picaminheight,
    pic-a min height=0pt,
    pic-a min width/.store in=picaminwidth,
    pic-a min width=0pt,
    mytest/.pic = {
         begin{scope}[shift={shiftcoord}]
         node[minimum height=picaminheight,
               minimum width=picaminwidth,
               draw]  (-A) at (0,0) {A};
         node  (-B) at (0,1) {B};
             node[fit=(-A) (-B),draw] (-C) {};
         end{scope}
    }
}

begin{document}

begin{tikzpicture}

draw[blue!20] (0,0) grid (3,3);

draw[pic-a min height=1cm,
 pic-a min width=1cm,
 pic shift={(1,1)}] pic (S) at (0,0) {mytest} node[coordinate] (sn){};

gettikzxy{(S-C.east)}{sbx}{sby}

draw[red,pic shift={(sbx,sby)}] pic (T) at (0,0) {mytest};

gettikzxy{(S-C.south)}{sdx}{sdy}
draw[blue,pic shift={(sdx,sdy)}] pic (T) at (0,0) {mytest};

gettikzxy{(S-C.east)}{sex}{sey}
draw[pic-a min width=0cm,green!75!black,pic shift={(sex,sey)}] pic (O) at (1,0) {mytest};

end{tikzpicture}
end{document}

which leads to:

enter image description here

Recalling that the origin of mytest is node -A, we have the first pic (S) with increased size denoted in black. It will be our reference.

Thanks to Andrew’s gettikzxy, we can grab coordinates of (S-C.east). The second mytest pic (T), in red, is placed in position (0,0) (of the general tikzpicture) and we operate a shift into (S-C.east) coordinates. As expected, (T-A) is put in (S-C.east). The same happens for pic M. However, apparently it is not possible to anchor pics with respect to their C node points. What you can do, is to take advantage of both pic shift and coordinate placement for anchoring a pic with respect to his C node (I admit, is not that elegant). For example the green (O) mytest pic is anchored with respect to his -C.south east point in (1,3).

As though Claudio has given a complete answer, I think there’s a simpler one, which may be either a bug or an undocumented feature of TikZ (because it’s not in the Manual). It’s not a complete answer because you cannot use all internal coordinates of the pic but rather just the coordinates from the node placed at the origin.

Out of curiosity I tried to put a node at the pic‘s origin and access its anchors through the pic command, and guess what? It works. So, apperantly just make a pic with a node as bounding box and you can place it with respect to its anchors!

documentclass[tikz,border=2mm]{standalone}

tikzset{mytest/.pic = {node[draw, minimum height=1.5cm, minimum width=.5cm] (-box) at (0,0) {};
                   node[above] (-A) at (-box.south) {A};
                   node[below] (-B) at (-box.north) {B};}
}

begin{document}
begin{tikzpicture}

draw[blue!20] (0,0) grid (3,3);

draw pic[anchor=south west] (S) at (0,0) {mytest};

draw pic[below left=1mm] (T) at (2,2) {mytest};

draw (S-A.north) to [out=90,in=-90] (T-B.south);

end{tikzpicture}
end{document}

enter image description here

Leave a Comment