7

How is it possible to use multiple parameters in a single pic? It works nicely with just 1 parameter, but always results in errors in case of more than 1 parameter. I found this post, which didn't solve the issue.

\tikzset{pics/coordsys/.style n args={4}{
    code = {
        \draw [->, #1] (0,0,0) -- +(1,0,0)[red] node [pos=1.1]{#2};
        \draw [->, #1] (0,0,0) -- +(0,1,0)[green] node [pos=1.1]{#3};
        \draw [->, #1] (0,0,0) -- +(0,0,1)[blue] node [pos=1.1]{#4};
    }
}}
\draw [rotate=360] (origin) pic {coordsys={very thick}{x}{y}{z}};

This always results in errors like:

Package pgfkeys Error: I do not know the key '/tikz/every text node part'

  • 2
    It works for me: \documentclass[tikz,border=3mm]{standalone} \begin{document} \begin{tikzpicture} \tikzset{pics/coordsys/.style n args={4}{ code = { \draw [->, #1] (0,0,0) -- +(1,0,0)[red] node [pos=1.1]{#2}; \draw [->, #1] (0,0,0) -- +(0,1,0)[green] node [pos=1.1]{#3}; \draw [->, #1] (0,0,0) -- +(0,0,1)[blue] node [pos=1.1]{#4}; } }} \draw (0,0) coordinate (origin) [rotate=360] pic {coordsys={very thick}{x}{y}{z}}; \end{tikzpicture} \end{document} – Schrödinger's cat Sep 15 at 21:27
  • 1
8

Giving multiple arguments to a pic works for me, i.e.

\documentclass[tikz,border=3mm]{standalone}
\begin{document}
\begin{tikzpicture}
\tikzset{pics/coordsys/.style n args={4}{
    code = {
        \draw [->, #1] (0,0,0) -- +(1,0,0)[red] node [pos=1.1]{#2};
        \draw [->, #1] (0,0,0) -- +(0,1,0)[green] node [pos=1.1]{#3};
        \draw [->, #1] (0,0,0) -- +(0,0,1)[blue] node [pos=1.1]{#4};
    }
}}
\draw  (0,0) coordinate  (origin) [rotate=360] pic {coordsys={very thick}{x}{y}{z}};
\end{tikzpicture}
\end{document}

compiles without errors on my updated TeXLive installation. So I suspect the error comes from something that you did not disclose.

However, I would like to talk you out of this multiple argument thingy for this application. Rather, you could set some standard or initial (in a way default) values using pgf keys, and change them only if you have to. Also the argument thick in the way you use it may be better replaced by the pic actions, which are made for this. (This is the answer I had for your previous question, which got deleted just when I was about to press the submit button. Of course I have no problem deleting it.)

\documentclass[border=2mm,tikz]{standalone} 
\usepackage{tikz-3dplot} 
\begin{document} 
\tdplotsetmaincoords{60}{-15} 
\begin{tikzpicture}[tdplot_main_coords,scale=1.5,line join=round,>=latex, 
line cap=round,declare function={fA(\t)=-sin(\t*144/(1+\t/5));
fAprime(\t)=pow(60/(5+\t),2)*cos(\t*144/(1+\t/5))*pi/180;
fB(\t)=-sin(\t*216/(1+\t*4/15));
fBprime(\t)=6*pow(90/(15+\t*4),2)*cos(\t*216/(1+\t*4/15))*pi/180;},
pics/coordsys/.style = {
    code = {\tikzset{coordsys/.cd,#1}
        \draw [->,pic actions] (0,0,0) -- +(1,0,0)[red] node[pos=1.1]
        {$\pgfkeysvalueof{/tikz/coordsys/x}$};
        \draw [->,pic actions] (0,0,0) -- +(0,1,0)[green!60!black] node[pos=1.1]
        {$\pgfkeysvalueof{/tikz/coordsys/y}$};
        \draw [->,pic actions] (0,0,0) -- +(0,0,1)[blue] node[pos=1.1]
        {$\pgfkeysvalueof{/tikz/coordsys/z}$};
    }
},coordsys/.cd,x/.initial=x,y/.initial=y,z/.initial=z] 
 \draw[dashed] plot[variable=\t,domain=0:5] ({\t},3,{fA(\t)});
 \draw[dashed] plot[variable=\t,domain=0:3.25] ({\t},0,{fB(\t)});
 \foreach \X [count=\Y] in {0,...,4}
 {\draw ({\X*1.25},3,{fA(\X*1.25)}) coordinate (P\Y)
  -- ({\X*3.25/4},0,{fB(\X*3.25/4)}) coordinate (Q\Y);
 \tdplotsetrotatedcoords{0}{atan2(fAprime(\X*1.25),1)}{0} 
 \begin{scope}[tdplot_rotated_coords]
 \path (P\Y) pic{coordsys};
 \end{scope}
 \tdplotsetrotatedcoords{0}{atan2(fBprime(\X*3.25/4),1)}{0} 
 \begin{scope}[tdplot_rotated_coords]
 \path (Q\Y) pic{coordsys={x=x',y=y',z=z'}};
 \end{scope}
 } 
\end{tikzpicture} 
\end{document}

enter image description here

As you can see, the standard values for x, y, and z are just x, y and z, but by saying

 \path (Q\Y) pic{coordsys={x=x',y=y',z=z'}};

for the curve in front, they will become x', y' and z'.

As for the rotations of the coordinate systems: they are rotated such that the x axis is tangent to the curve, and the y axis remains fixed. To this end, one has to guess some functions, and the derivatives have to be done by hand or with a computer algebra system (i.e. plain LaTeX won't do it). From this one computes the slope which gets fed into

 \tdplotsetrotatedcoords{0}{atan2(fBprime(\X*3.25/4),1)}{0} 

where the second argument is the rotation angle about the y axis. For more details consult the manual of tikz-3dplot.

A very quickly written alternative that does not require you to compute the derivative. (Note, however, that when trying to add smooth to the plot options one encounters unexpected difficulties: transformations that cannot be undone. This is the first time I see something like this.)

\documentclass[border=2mm,tikz]{standalone} 
\usepackage{tikz-3dplot} 
\usetikzlibrary{decorations.markings}
\begin{document} 
\tdplotsetmaincoords{60}{-15} 
\begin{tikzpicture}[tdplot_main_coords,scale=2,line join=round,>=latex, 
line cap=round,declare function={fA(\t)=-sin(\t*144/(1+\t/5));
fB(\t)=-sin(\t*216/(1+\t*4/15));},
pics/coordsys/.style = {
    code = {\tikzset{nodes={transform shape},coordsys/.cd,#1}
        \draw [->,pic actions] (0,0,0) -- +(1,0,0)[red] node[pos=1.1,rotate=0]
        {$\pgfkeysvalueof{/tikz/coordsys/x}$};
        \draw [->,pic actions] (0,0,0) -- +(0,1,0)[green!60!black] node[pos=1.1]
        {$\pgfkeysvalueof{/tikz/coordsys/y}$};
        \draw [->,pic actions] (0,0,0) -- +(0,0,1)[blue] node[pos=1.1]
        {$\pgfkeysvalueof{/tikz/coordsys/z}$};
    }
},coordsys/.cd,x/.initial=x,y/.initial=y,z/.initial=z,/tikz/.cd,
rotated coordsys at/.style={postaction={decorate,decoration={markings,
mark=at position #1 with {\pgfmathtruncatemacro{\myint}{5*#1+0.1}
\path (0,0) coordinate (O'-\myint) (1,0) coordinate (X');
\path let \p1=($(X)-(O)$),\p2=($(X')-(O'-\myint)$) in \pgfextra{%
\pgfmathsetmacro{\myangle}{atan2(\y1,\x1)-atan2(\y2,\x2)}
\xdef\myangle{\myangle}};
\tdplotsetrotatedcoords{0}{\myangle}{0} 
\begin{scope}[tdplot_rotated_coords]
 \path (O'-\myint) pic[solid]{coordsys};
\end{scope}
}}}}] 
 \path (0,0,0) coordinate (O) (1,0,0) coordinate (X); 
 \draw[dashed,rotated coordsys at/.list={0,0.2,...,1}] 
    plot[variable=\t,domain=0:5,samples=71] ({\t},3,{fA(\t)});
 \path foreach \X in {0,...,5} {(O'-\X) coordinate (P-\X)};
 \draw[dashed,coordsys/x=x',coordsys/y=y',coordsys/z=z',
 rotated coordsys at/.list={0,0.2,...,1}] 
    plot[variable=\t,domain=0:3.25,samples=71] ({\t},0,{fB(\t)});
 \draw foreach \X in {0,...,5} {(P-\X) -- (O'-\X) coordinate (Q-\X)};   
\end{tikzpicture} 
\end{document}

enter image description here

As you can see, one can set the options coordsys/x=x' in the path.

  • 1
    Awesome! Sorry about deleting the question before, I was not expecting a full answer anymore. – avermaet Sep 15 at 21:37
  • @avermaet No worries and you're welcome! – Schrödinger's cat Sep 15 at 21:52
  • 1
    (Since the angle between x and z does not change, and since y is fixed, one could construct a pure LaTeX solution with decorations.markings. It wouldn't be as direct but would not require computing derivatives by hand.) – Schrödinger's cat Sep 15 at 22:04
  • I know this wasn't part of my original question, but I'd like the upper coordinate systems to be rotated with respect to the lower ones. Just some fixed relative rotation for all of them. Where would I need to multiply this? And also: How did you get the constants in the code? Just some random choice? – avermaet Sep 15 at 22:14
  • @avermaet There is now a second version in which you do not have to compute the derivative of the function. In addition you can play with the view angles, which are set in \tdplotsetmaincoords{60}{-15} . – Schrödinger's cat Sep 16 at 2:21

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.