1

This is a follow-on question from here. Things are almost working but something strange is going on with my \band command. It renders the first band correctly, but then the second band causes things to go haywire.

\documentclass[]{scrartcl}

\usepackage{tikz}
\usepackage{listofitems}

\begin{document}

\newtoks\pathtoks
\newcommand\addpathtoks[1]{%
    \pathtoks\expandafter{\the\pathtoks#1}}
\newcommand\xaddpathtoks[1]{%
    \expandafter\addpathtoks\expandafter{#1}}
\newcommand\xxaddpathtoks[1]{%
    \expandafter\xaddpathtoks\expandafter{#1}}

\newcommand{\band}[2]{
    \readlist*\valuelist{#2}
    \pathtoks{}
    \foreachitem\x\in\valuelist[]{%
        \ifnum\xcnt=1\relax \addpathtoks{\draw[#1]}\else
            \addpathtoks{--}
        \fi
        \addpathtoks{(360/}\xxaddpathtoks{\listlen\valuelist[]*}%
        \xaddpathtoks{\x:}\xaddpathtoks{\x)}
        \ifnum\xcnt=\listlen\valuelist[]\relax\addpathtoks{--cycle;}\fi
    }

    \the\pathtoks
}

\begin{tikzpicture}
    % This is what I expect the below \band invocations to produce, and this renders correctly.
    \draw[red] (360/3:1) -- (360/3*2:2) -- (360/3*3:3) --cycle;
    \draw[blue] (360/3:3) -- (360/3*2:2) -- (360/3*3:1) --cycle;
\end{tikzpicture}

\vspace{1cm}

\begin{tikzpicture}
    % These bands, which should be equivalent to the above are not rendering correctly.
    \band{red}{1,2,3};
    \band{blue}{3,2,1};
\end{tikzpicture}

\end{document}

This renders like this:

enter image description here

The top picture is what I'd expect, but the bottom seems to re-render the same shape over the top of the existing one.

Weirder still, if two values are the same:

\band{red}{2,3,3};

It renders a straight line:

enter image description here

And if all three values are the same, it renders nothing at all! It's like it's de-duplicating the list...?

So my questions are:

  1. Why does my repro above render the same triangle twice instead of the expected triangles?
  2. Why do duplicate values cause weird things to happen?

Update

My requirements are:

  1. Being able to specify any number of values in the band and having the band automatically place those values that distance from the center of a circle, with each value being placed an equal number of degrees apart.
  2. Being able to invoke this band command/environment/whatever it is with varying numbers of values and with different styles for the band.
  3. Be able to compose whatever this band thing ends up being into an environment so I can do something like:
\begin{thething}
    \band{red}{1,3,2}
    \band{blue}{1,2,4}
\end{thething}

\begin{thething}
    \band{green}{5,3,4,1}
    \band{yellow}{1,1,4,5}
\end{thething}

The thething environment (which I believe I already have working) adds the requisite tikzpicture along with some default rendering. In reality, thething takes a list of labels to render - one for each value in the bands. The band calls then add to that rendering.

2

TikZ has all the means built in to simplify this quite a bit. All these macros can be absorbed in a simple style

band/.style={insert path={plot[samples at={0,1,2}]
    ({360/3*(\x+1)}:{#1}[\x]) -- cycle}}

with which you only need to say

\draw[red,band={1,2,3}];

You could make this a macro, but this would make it less powerful. MWE:

\documentclass[tikz,border=3.14mm]{standalone}
\begin{document}
\begin{tikzpicture}[band/.style={insert path={plot[samples at={0,1,2}]
    ({360/3*(\x+1)}:{#1}[\x]) -- cycle}},font=\sffamily]

  \begin{scope}[xshift=-5cm,local bounding box=by hand]
    \draw[red] (360/3:1) -- (360/3*2:2) -- (360/3*3:3) --cycle;
    \draw[blue] (360/3:3) -- (360/3*2:2) -- (360/3*3:1) --cycle;
  \end{scope}   
  \node[above=1ex] at (by hand.north){by hand};
  %
  \begin{scope}[local bounding box=automatic]
    \draw[red,band={1,2,3}];
    \draw[blue,band={3,2,1}];
  \end{scope}   
  \node[above=1ex] at (automatic.north){automatic};
\end{tikzpicture}
\end{document}

enter image description here

It is easy to generalize it to something that takes an arbitrary number of arguments.

\documentclass[tikz,border=3.14mm]{standalone}
\begin{document}
\begin{tikzpicture}[band/.style={/utils/exec={\foreach \dummy[count=\cnt
starting from 0] in {#1} {\xdef\cnt{\cnt}}},
insert path={plot[samples at={0,...,\cnt}]
    ({360/(\cnt+1)*(\x+1)}:{#1}[\x]) -- cycle}},font=\sffamily]

  \begin{scope}[xshift=-5cm,local bounding box=by hand]
    \draw[red] (360/3:1) -- (360/3*2:2) -- (360/3*3:3) --cycle;
    \draw[blue] (360/3:3) -- (360/3*2:2) -- (360/3*3:1) --cycle;
  \end{scope}   
  \node[above=1ex] at (by hand.north){by hand};
  %
  \begin{scope}[local bounding box=automatic]
    \draw[red,band={1,2,3}];
    \draw[blue,band={3,2,1}];
    \draw[orange,band={3,2,1,4,3,5}];
  \end{scope}   
  \node[above=1ex] at (automatic.north){automatic};
\end{tikzpicture}
\end{document}

enter image description here

  • Thanks, but this seems to embed the number of allowed values into the style...? I wanted the flexibility of passing in a list of values and having it just work regardless of how many. – me-- Jun 13 at 4:06
  • I updated my question and just saw your response. Trying it now. – me-- Jun 13 at 4:29
  • Actually, no. The problem will be the #1 because I am trying to use it inside an environment and that seems not to work. – me-- Jun 13 at 4:29
  • @me-- There is the standard thingy that you need to add #. This has nothing to do with the solution here. And you can define a new command \newcommand{\band}[2][]{\draw[#1,band={#2}]} so if newcommand works this will wor. – marmot Jun 13 at 4:32
  • Oh wow, I think it's actually working. I feel completely mystified by how this all works, but thanks very much for the help @marmot! – me-- Jun 13 at 4:39

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.