# Drawing Spirograph patterns using \foreach loops

I used the following code from the answer to this question, to draw a Spirograph pattern

\documentclass{beamer}
\usepackage{tikz}
\begin{document}
\tikzset{pics/spiro/.style={code={
\tikzset{spiro/.cd,#1}
\def\pv##1{\pgfkeysvalueof{/tikz/spiro/##1}}
plot[variable=\t,domain=0:2*pi*\pv{nRotations}, samples=90*\pv{nRotations}+1, smooth cycle]
(
{(\pv{R}+\pv{r})*cos(\t)+\pv{p}*cos((\pv{R}+\pv{r})*\t/\pv{r})},
{(\pv{R}+\pv{r})*sin(\t)+\pv{p}*sin((\pv{R}+\pv{r})*\t/\pv{r})}
);
}},
spiro/.cd,R/.initial=6,r/.initial=-1.5,p/.initial=1,nRotations/.initial=1}
\begin{frame}[t]
\frametitle{}
\begin{center}
\begin{tikzpicture}[line width=.2mm]
\foreach \i/\clr in {5/blue,10/blue,15/blue,20/blue,25/blue,30/blue,35/blue,40/blue,45/blue,50/green,55/green,60/green,65/green,70/green,75/green,80/green,85/green,90/green,95/orange,100/orange,105/orange,110/orange,115/orange,120/orange,125/orange,130/orange,135/orange,140/purple,145/purple,150/purple,155/purple,160/purple,165/purple,170/purple,175/purple,180/purple}
{
(0,0) \pic[draw=\clr,rotate=\i,scale=.4]{spiro={R=10.5,r=-5.25,p=3,nRotations=1}};
}
\end{tikzpicture}
\end{center}
\end{frame}
\end{document}


I tried using the following code to simplify repeating each rotation angle, but something is not right!

\begin{frame}[t]
\frametitle{}
\begin{center}
\begin{tikzpicture}[line width=.2mm]
\foreach \b in {5,10,...,45}
\foreach \g in {50,55,...,90}
\foreach \o in {95,100,...,135}
\foreach \p in {140,145,...,180}
\foreach \i/\clr in {\b/blue,\g/green,\o/orange,\p/purple}
{
(0,0) \pic[draw=\clr,rotate=\i,scale=.4]{spiro={R=10.5,r=-5.25,p=3,nRotations=1}};
}
\end{tikzpicture}
\end{center}
\end{frame}


I also tried to apply the code from the answer to this question to avoid overlapping tha last pattern over the older ones to produce the following drawing (using the option fill=\clr!40) but I could not figure out how to apply it.

You may want something like this:

\documentclass{beamer}
\usepackage{tikz}
\begin{document}
\tikzset{pics/spiro/.style={code={
\tikzset{spiro/.cd,#1}
\def\pv##1{\pgfkeysvalueof{/tikz/spiro/##1}}
plot[variable=\t,domain=0:2*pi*\pv{nRotations}, samples=90*\pv{nRotations}+1, smooth cycle]
(
{(\pv{R}+\pv{r})*cos(\t)+\pv{p}*cos((\pv{R}+\pv{r})*\t/\pv{r})},
{(\pv{R}+\pv{r})*sin(\t)+\pv{p}*sin((\pv{R}+\pv{r})*\t/\pv{r})}
);
}},
spiro/.cd,R/.initial=6,r/.initial=-1.5,p/.initial=1,nRotations/.initial=1}
\begin{frame}[t]
\frametitle{}
\begin{center}
\begin{tikzpicture}[line width=.2mm]
\path foreach \clr [count=\X starting from 0] in {blue,green,orange,purple}
{foreach \Y in {1,...,9}
{(0,0) pic[draw=\clr,rotate=45*\X+5*\Y,scale=.4]{spiro={R=10.5,r=-5.25,p=3,nRotations=1}}
}};
\end{tikzpicture}
\end{center}
\end{frame}
\end{document}


This loops over the colors and draws for each color the graph in 9 versions, relatively rotated by 5 degrees each. Please also notice that (0,0) in your code had no effect, and that I slightly change the foreachs to be in the path.

One may also want to interpolate between the colors.

\documentclass{beamer}
\usepackage{tikz}
\begin{document}
\tikzset{pics/spiro/.style={code={
\tikzset{spiro/.cd,#1}
\def\pv##1{\pgfkeysvalueof{/tikz/spiro/##1}}
plot[variable=\t,domain=0:2*pi*\pv{nRotations}, samples=90*\pv{nRotations}+1, smooth cycle]
(
{(\pv{R}+\pv{r})*cos(\t)+\pv{p}*cos((\pv{R}+\pv{r})*\t/\pv{r})},
{(\pv{R}+\pv{r})*sin(\t)+\pv{p}*sin((\pv{R}+\pv{r})*\t/\pv{r})}
);
}},
spiro/.cd,R/.initial=6,r/.initial=-1.5,p/.initial=1,nRotations/.initial=1}
\begin{frame}[t]
\frametitle{}
\begin{center}
\begin{tikzpicture}[line width=.2mm]
\path foreach \clr [count=\X starting from 0,
remember=\clr as \lastclr (initially purple)] in {blue,green,orange,purple}
{foreach \Y [evaluate=\Y as \mycf using {int(100*\Y/9)}] in {1,...,9}
{(0,0) pic[draw=\clr!\mycf!\lastclr,rotate=45*\X+5*\Y-22.5,scale=.4]{spiro={R=10.5,r=-5.25,p=3,nRotations=1}}
}};
\end{tikzpicture}
\end{center}
\end{frame}
\end{document}


ADDENDUM: You can also produce filled graphs. However, in this case your definition may not be optimal. So I changed that.

\documentclass{beamer}
\usepackage{tikz}
\begin{document}
\tikzset{pics/spiro/.style={code={
\tikzset{spiro/.cd,#1}
\def\pv##1{\pgfkeysvalueof{/tikz/spiro/##1}}
plot[variable=\t,domain=pi/2:3*pi/2, samples=31, smooth]
(
{(\pv{R}+\pv{r})*cos(\t)+\pv{p}*cos((\pv{R}+\pv{r})*\t/\pv{r})},
{(\pv{R}+\pv{r})*sin(\t)+\pv{p}*sin((\pv{R}+\pv{r})*\t/\pv{r})}
);
}},
spiro path/.code={\def\pv##1{\pgfkeysvalueof{/tikz/spiro/##1}}
\tikzset{insert path={
smooth,domain=pi:pi/2]
(
{(\pv{R}+\pv{r})*cos(\t)+\pv{p}*cos((\pv{R}+\pv{r})*\t/\pv{r})},
{(\pv{R}+\pv{r})*sin(\t)+\pv{p}*sin((\pv{R}+\pv{r})*\t/\pv{r})}
)
|- (\pv{R}+\pv{r}+\pv{p},-\pv{R}-\pv{r}-\pv{p})
--
(\pv{R}+\pv{r}+\pv{p},\pv{R}+\pv{r}+\pv{p})  --
(-\pv{R}-\pv{r}-\pv{p},\pv{R}+\pv{r}+\pv{p})
--  cycle
}}},
spiro/.cd,R/.initial=6,r/.initial=-1.5,p/.initial=1}
\begin{frame}[t]
\frametitle{}
\begin{center}
\begin{tikzpicture}[line width=.2mm,spiro/.cd,R=10.5,r=-5.25,p=3]
\begin{scope}
\foreach\Z in {0,1}
{\foreach \clr [count=\X starting from 0] in {blue,green,orange,purple}
{\foreach \Y in {1,...,9}
{\ifnum\Z\X\Y=102
\clip[scale=.4,rotate=5,spiro path];
\fi
\pic[draw=\clr,rotate=45*\X+5*\Y+\Z*180,scale=.4,fill=\clr!40]{spiro};
}}}
\end{scope}
\pgfkeysvalueof{/tikz/spiro/r}-\pgfkeysvalueof{/tikz/spiro/p})}];
\end{tikzpicture}
\end{center}
\end{frame}
\end{document}


With color interpolation it does not look too bad IMHO.

\documentclass{beamer}
\usepackage{tikz}
\begin{document}
\tikzset{pics/spiro/.style={code={
\tikzset{spiro/.cd,#1}
\def\pv##1{\pgfkeysvalueof{/tikz/spiro/##1}}
plot[variable=\t,domain=pi/2:3*pi/2, samples=31, smooth]
(
{(\pv{R}+\pv{r})*cos(\t)+\pv{p}*cos((\pv{R}+\pv{r})*\t/\pv{r})},
{(\pv{R}+\pv{r})*sin(\t)+\pv{p}*sin((\pv{R}+\pv{r})*\t/\pv{r})}
);
}},
spiro path/.code={\def\pv##1{\pgfkeysvalueof{/tikz/spiro/##1}}
\tikzset{insert path={
smooth,domain=pi:pi/2]
(
{(\pv{R}+\pv{r})*cos(\t)+\pv{p}*cos((\pv{R}+\pv{r})*\t/\pv{r})},
{(\pv{R}+\pv{r})*sin(\t)+\pv{p}*sin((\pv{R}+\pv{r})*\t/\pv{r})}
)
|- (\pv{R}+\pv{r}+\pv{p},-\pv{R}-\pv{r}-\pv{p})
--
(\pv{R}+\pv{r}+\pv{p},\pv{R}+\pv{r}+\pv{p})  --
(-\pv{R}-\pv{r}-\pv{p},\pv{R}+\pv{r}+\pv{p})
--  cycle
}}},
spiro/.cd,R/.initial=6,r/.initial=-1.5,p/.initial=1}
\begin{frame}[t]
\frametitle{}
\begin{center}
\begin{tikzpicture}[line width=.2mm,spiro/.cd,R=10.5,r=-5.25,p=3]
\foreach\Z in {0,1}
{\foreach \clr [count=\X starting from 0,
remember=\clr as \lastclr (initially purple)] in {blue,green,orange,purple}
{\foreach \Y [evaluate=\Y as \mycf using {int(100*\Y/9)}] in {1,...,9}
{\ifnum\Z\X\Y=102
\clip[scale=.4,rotate=5,spiro path];
\fi
\pic[draw=\clr!\mycf!\lastclr,rotate=45*\X+5*\Y+\Z*180,scale=.4,fill=\clr!\mycf!\lastclr!40]{spiro};
}}}
\end{tikzpicture}
\end{center}
\end{frame}
\end{document}


• Thank you for your answer. What about solving the filling issue by applying your code in the answer to tex.stackexchange.com/questions/521165/… to avoid overlapping the last pattern over the previous ones! I could not figure out how to apply it. – Hany Jan 18 at 16:03
• @Hany Sorry, I did not read this part of the question in that way, also because there is no code. However, I also do not understand how the target output should look like. What would you like to do with the inner circle? – Schrödinger's cat Jan 18 at 18:01
• @ Schrödinger's cat Thank you very much for your answers. This is what I had in mind. i.stack.imgur.com/Tmved.png Your answers are as close as possible. – Hany Jan 19 at 5:11
• @Hany You're welcome! You can just add a white disk to achieve this. – Schrödinger's cat Jan 19 at 5:20
• @Hany Added it. – Schrödinger's cat Jan 19 at 5:30