I read instruction how to use \pic in PGF 3.0.0 manual, but description how to give names to \pic are not clear to me and given example generate error: "No shape named EmmaEmma-left is known."

Example in manual (pp. 255):

\documentclass[tikz,border=3mm]{standalone}
\tikzset{
seagull/.pic={
% Code for a "seagull". Do you see it?...
\coordinate (-left wing) at (-3mm,0);
\coordinate (-head) at (0,0);
\coordinate (-right wing) at (3mm,0);
\draw (-left wing) to [bend left] (0,0) (-head) to [bend left] (-right wing);
}
}
        \begin{document}
    \begin{tikzpicture}%\small\sffamily
\pic (Emma) {seagull};
\pic (Alexandra) at (0,1) {seagull};
\draw (Emma-left wing) -- (Alexandra-right wing);
    \end{tikzpicture}
        \end{document}

It's obvious that something is missing in above example. Please enlighten me, what I missed.

up vote 14 down vote accepted

This is a work around rather than a solution. I wonder if this is a bug but my understanding of tikz is just not good enough to know for certain.

Apparently, tikz no longer likes something about the to operation here within the pic.

What tikz appears to be doing in the case of the \draw... to.. operation is doubling the prefix so that it looks for EmmaEmma-left wing which obviously does not exist. It doesn't do this if you replace the command with a straight line, apparently.

You can get the example to work by temporarily resetting the pic prefix to the value it has outside the pic and then passing the name of the pic through as an option. Clearly this is extremely clumsy and definitely shouldn't be needed. So either this is a bug or something is staring at me and I'm just not seeing it. (This is, after all, basically verbatim from the manual. So it should work!)

\documentclass[tikz,border=3mm]{standalone}
\tikzset{
  seagull/.pic={
    % Code for a "seagull". Do you see it?...
    \coordinate (-left wing) at (-3mm,0);
    \coordinate (-head) at (0,0);
    \coordinate (-right wing) at (3mm,0);
    \draw [name prefix ..] (#1-left wing) to [bend left] (0,0) (#1-head) to [bend left] (#1-right wing);
  }
}
\begin{document}
  \begin{tikzpicture}%\small\sffamily
    \pic (Emma) at (0,0) {seagull=Emma};
    \pic (Alexandra) at (0,1) {seagull=Alexandra};
    \draw  (Emma-left wing) -- (Alexandra-right wing);
  \end{tikzpicture}
\end{document}

Result

  • your workaround solve this particular example. But in case, if you like to positioning seagull "Alexandra" relative to seagull "Emma", for example wit help of positioning library: \pic[above=1cm of Emma] (Alexandra) {seagull=Alexandra}; than the error -- no shape named Emma is known -- arise. Since i like to draw set of symbols drawn by pic and each symbol displaced from previous one for distance set for tikzpicture, I need more general workaround about naming of pic (small pictures). I must confess, that after many careful reading of pic description it is still very mysterious to me. – Zarko Aug 2 '14 at 0:32
  • 1
    @Zarko You cannot say above=1cm of Emma. You can only reference nodes/coordinates inside the pic - not the pic itself. So you wouldn't be able to say that regardless. However, you are quite right that my workaround is extremely unsatisfactory. Just not for that reason. (That problem is just a fact about pics. If you need to be able to reference the whole thing, then you need a node rather than a pic. As I understand the documentation, in any case.) – cfr Aug 2 '14 at 0:34
  • I see now. I expected, that the \pic pictures behave similarly as nodes. To this conclusions leads me example "different ways of placing pi" on page 253. In this example I replace absolute coordinate with relative respect to some node and it works. So I expect, that tested example actually show, how to give names to pic (not to elements inside pic) for use in "outside" of pic. Now I'm confused, if I correctly understand you, pic cannot be named on the same way as nodes. If it is so, than for me the example for naming of pic is misleading. – Zarko Aug 2 '14 at 1:11
  • cfr: Now I fill quit embraced ... I find solution which gives essdd for one my other question (tikz, conditional setting of shape parameters, tex.stackexchange.com/questions/183036/…). Now I need to rethink my question. – Zarko Aug 2 '14 at 1:32
  • 2
    A not so elegant workaround which does not require an argument to the pic consists in using the "let" syntax to avoid the bug, e.g. with \draw let \p{left wing} = (-left wing), \p{head} = (-head), \p{right wing} = (-right wing) in (\p{left wing}) to [bend left] (0,0) (\p{head}) to [bend left] (\p{right wing}); ... maybe it can be of some help. By the way, was this bug reported to the pgf/tikz maintainers ? – Georg Sievelson Sep 15 '16 at 10:09

This is indeed a bug, but for a different reason, I think this is happening at the same place when the parsing is done in \tikz@subpicture@handle@ but still I didn't understand perfectly how it goes wrong.

When TikZ starts parsing the last \draw command in the pic code and encounters node names, the name prefix is already set. But the object it is parsing is a node (coordinates are also nodes) so it starts thinking hey, I gotta add a prefix to this reference. Hence another node name prefix is triggered and it looks for that shape. The easiest fix as far as I can see is to refer to explicit coordinates such that node name parsing is avoided, example;

\documentclass[tikz]{standalone}

\tikzset{
seagull/.pic={
% Code for a "seagull". Do you see it?...
\coordinate (-left wing) at (-3mm,0);
\coordinate (-head) at (0,0);
\coordinate (-right wing) at (3mm,0);
\draw (-left wing.center) to [bend left] (0,0) (-head.center) to [bend left] (-right wing.center);
}
}


\begin{document}
\begin{tikzpicture}
  \pic (Emma) {seagull};
  \pic (Alexandra) at (0,1) {seagull};
  \draw (Emma-left wing) -- (Alexandra-right wing);
\end{tikzpicture}
\end{document}

This compiles and gives the same result with cfr's picture. Strange indeed. But I think it's not that straightforward to remedy. It might be the case that node name parsing goes awry too, but I didn't check it.

I tried to read the name prefix and see if it matches the node name and if so skip it but didn't succeed. I think this one is for Till Tantau to fix.

  • I don't see that this identifies a 'different reason' from my answer. My answer did not identify any reason whatsoever. It just threw up its hands in horror and expressed confused dismay... (I also found this bit of the tikz code but couldn't understand it well enough to get anywhere with it.) Your workaround is much more straightforward than mine since you clearly have more idea what is going wrong... – cfr Aug 3 '14 at 1:08
  • @cfr I meant it is not immediately related to to paths per se. But maybe I was too concise – percusse Aug 4 '14 at 4:44
  • No. I probably wasn't very clear. I only meant that to to path triggered something which looked like a bug. I should have said that I didn't think the bug had to do with that as such - only that was what triggered the bug in this particular case. – cfr Aug 4 '14 at 15:13
  • 1
    So apparently this bug hasn't been fixed since almost three years ago! – Evan Aad Jul 12 '17 at 12:32

I dig a little bit and this is what I found:

When TikZ encounters \draw(A)to(B), this is what will happen

  • \def\tikztostart{\tikz@pp@name{A}}; usually this is simply A;
  • \def\tikztotarget{\tikz@pp@name{B}}; usually this is simply B;
  • The every to/.code is applied here.

In the simplest case, to is merely --, so TikZ now executes

 \draw(\tikztostart)--(\tikztotarget);

Remember that this is equivalent to

 \draw(A)--(B);

So everything is fine.


However, inside a .pic, node names have prefix and suffix. In this case, provided that the pic is names Emma,

  • \tikztostart is EmmaA;
  • \tikztotarget is EmmaB;
  • TikZ ececutes \draw(\tikztostart)--(\tikztotarget);

That is equivalent to

\draw(EmmaA)--(EmmaB);

When TikZ try to parse this node name, the prefix (and suffix) is added again. At the end you see that it cannot find EmmaEmmaA.

Appendix

In tikz.code.tex line 5157

\def\tikz@shapeborder@name{\tikz@pp@name{#2}}%

The same file, line 2969-2975

\def\tikz@to@use@last@coordinate{%
  \iftikz@shapeborder%
    \edef\tikztostart{\tikz@shapeborder@name}%
  \else%
    \edef\tikztostart{\the\tikz@lastx,\the\tikz@lasty}%
  \fi%
}

In my humble opinion, one should fix the definition of tikztostart.

  • Nice explanation! (+1), I hope that "one" will fix this soon (near future) :-) – Zarko Jun 18 '17 at 14:37
  • Why the problem is not present in \tikztotarget ? – Kpym Apr 24 at 6:25
  • @Kpym I forgot the details. But I would say "it should; just the compiler stops when parsing \tikztostart". – Symbol 1 Apr 24 at 20:08
  • @Symbol1 no, it is not. For examples paths like (0,0) to (a) works, but paths like (a) to (0,0) don't. – Kpym Apr 24 at 20:11
  • @Kpym geeee, I do not know... do you bother asking a follow-up? – Symbol 1 Apr 24 at 23:32

Your Answer

 

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

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