TransWikia.com

Multiple named arguments to tikz pic using keys

TeX - LaTeX Asked on April 25, 2021

I am passing an argument to a pic like so pic[n=3]. Am I doing it right? And how about passing several arguments, say two like so pic[n=3, r=1]?

I really like being able to write the argument explicitly inside square bracket, rather than say pic{3}{1} (difficult to remember the order of the arguments). I tried repeating what I did with pgfkeysgetvalue{/tikz/n}n for r and adding .pic 2 args ={ or .pic n args = {2}{, but that failed.

    documentclass[class=article,border=2mm,tikz]{standalone}
    usetikzlibrary{calc}

    tikzset{%
      circle pyramid/.pic ={
        begin{scope}
          pgfkeysgetvalue{/tikz/n}n
          foreach x in {n,...,1} {
            draw[fill=white]
              ifnumx=n
                (0,0)
              else
                (row)++(60:2)
              fi
              coordinate (row)%
                foreach y in {1,...,x} {
                  circle[radius=1]++(2,0)% circles of radius 1, would like to make it r
                };
            }
        end{scope}
      },
      n/.initial=2
    }

    % radius of the circumscribed circle in terms of the smaller circle r
    % R = r (3+2*(n-1)*sqrt(3))/3, and we set r = 1
    newcommand{radius}[1]{pgfmathparse{(3+2*(#1-1)*sqrt(3))/3}}%

    begin{document}
    begin{tikzpicture}
      radius{3}%
      draw[fill=black] circle[radius=pgfmathresult cm];
      path (-2,-1.16) pic[n=3]{circle pyramid}; % inelegant tweak of the center
    end{tikzpicture}

    end{document}

The code for the pyramid of circles was borrowed from skillmon. I tried to reduce it to the minimum elements I needed. But as you can see from the screenshot, there is some unwanted white space on the right-hand side. I’d like to fix that too.

enter image description here

2 Answers

The problem of the excess space arises because the code injects an excess coordinate in

circle[radius=1]++(2,0)

One should not add this ++(2,0) in the last coordinate. One can also compute (-2,-1.16) from first principles, it is the polar coordinate (-150:R-r), where R is the radius of the large background circle and r the radius of the smaller circles. As for the problem of passing arguments to the pic, I use the method from https://tex.stackexchange.com/a/534355, but it is also rather similar to what Andrew Stacey's answer does except that here I use pgfkeysvalueof, which avoids defining many extra macros (e.g. n could potentially clash with the syntax of calc, which you load but which is not needed in this very example). As for the radius function, I just use declare function to define cpradius. The background circle has been added to the pic, but it can be turned off with a switch. Here is code with a number of examples:

documentclass[class=article,border=2mm,tikz]{standalone}
%usetikzlibrary{calc}
newififtikzcirclepyramiddrawbackgroundcircle
tikzset{%
  declare function={cpradius(x)=(3+2*(x-1)*sqrt(3))/3;},
  pics/circle pyramid/.style={code={%
      tikzset{circle pyramid/.cd,#1}%
      defpv##1{pgfkeysvalueof{/tikz/circle pyramid/##1}}%
      iftikzcirclepyramiddrawbackgroundcircle
       path[circle pyramid/bg circle] circle[radius={pv{r}*cpradius(pv{n})}];
      fi
      foreach x in {pv{n},...,1} {
        draw[circle pyramid/fg circle]
          ifnumx=pv{n}
            (-150:{pv{r}*cpradius(pv{n})-pv{r}})
          else
            (row)++(60:2*pv{r})
          fi
          coordinate (row)%
            ifnumx>1
            foreach y in {1,...,thenumexprx-1} {
              circle[radius=pv{r}]++(2*pv{r},0)% circles of radius 1, would like to make it r
            }
            fi
            circle[radius=pv{r}];
        }
    }  
 },
  circle pyramid/.cd,n/.initial=2,r/.initial=1,
  background circle/.is if=tikzcirclepyramiddrawbackgroundcircle,
  background circle=true,bg circle/.style={draw,fill=black},
  fg circle/.style={draw,fill=white},
}


begin{document}
begin{tikzpicture}
  path pic{circle pyramid={r=1,n=3}} 
   (9,-3) pic{circle pyramid={r=1.5,n=3}}
   (0,-7) pic{circle pyramid={r=0.8,n=4}}
   (8,-10) pic{circle pyramid={r=0.6,n=2,background circle=false}}
   (11,-10) pic{circle pyramid={r=0.6,n=2,bg circle/.style={fill=blue},
    fg circle/.style={fill=orange}}}; 
end{tikzpicture}
end{document}

enter image description here

Correct answer by user238301 on April 25, 2021

One way to do this is to pass a set of key-value pairs as the single argument to the pic which are then reparsed by pgfkeys. I find it helps to put such keys in families to avoid issues with reusing them. The other thing I've changed is as mentioned in the comments then your method of setting the outer circle radius is not robust (in the non-TeX sense) as any intermediate calculation will overwrite the result. The following code produces the same result as in the question.

(I did wonder about the background circle - should that be part of the pic?)


    documentclass[class=article,border=2mm,tikz]{standalone}
    usetikzlibrary{calc}

    tikzset{%
      circle pyramid/.pic ={
        begin{scope}[circle pyramid options/.cd,#1]
          pgfkeysgetvalue{/tikz/circle pyramid options/n}n
          pgfkeysgetvalue{/tikz/circle pyramid options/r}r
          foreach x in {n,...,1} {
            draw[fill=white]
              ifnumx=n
                (0,0)
              else
                (row)++(60:2)
              fi
              coordinate (row)%
                foreach y in {1,...,x} {
                  circle[radius=r]++(2,0)% circles of radius 1, would like to make it r
                };
            }
        end{scope}
      },
      circle pyramid options/.is family,
      circle pyramid options/.cd,
      n/.initial=2,
      r/.initial=1
    }

    % radius of the circumscribed circle in terms of the smaller circle r
    % R = r (3+2*(n-1)*sqrt(3))/3, and we set r = 1
    newcommand{radius}[1]{((3+2*(#1-1)*sqrt(3))/3)}%

    begin{document}
    begin{tikzpicture}
      draw[fill=black] circle[radius=radius{3}];
      path (-2,-1.16) pic{circle pyramid={n=3,r=1}}; % inelegant tweak of the center
    end{tikzpicture}

    end{document}

Answered by Andrew Stacey on April 25, 2021

Add your own answers!

Ask a Question

Get help from others!

© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP