# Fractal using Spirograph in Python

Introduction Spirograph toy that is used to produce complex patterns using plastic cogs and colored pens. A fractal is a curve, that is developed using a recurring pattern that repeats itself infinitely on a low scale. Fractals are used for modeling structures (such as snowflakes) or for describing partly chaotic phenomena. Spirograph can be used to draw various fractals. Some of them are given below You can visit benice-equation-blogspot.in for more fractals design with their parametric equation. Some of them are given below Mathematics behind the curtain These are the two parametric equation to form a spirograph fractals, to understand these equations you have to consider a generalized figure of spirograph. For the mathematics part you can refer to Wiki although i’ll try to explain a little of that mathematics in a short here. If we are interested behind the maths then you can check out the referred links. So as of now, these various curve can be drawn by using a parametric equation and varying some values of that equation we can get different fractals. So here’s the parametric equation: where, R is a scaling parameter and does not affect the structure of the Spirograph. and, So, now let’s try to implement this in code.
 `#importing the required libraries ``import` `random, argparse ``import` `math ``import` `turtle ``from` `PIL ``import` `Image ``from` `datetime ``import` `datetime     ``from` `fractions ``import` `gcd `` ` `# A class that draws a spirograph ``class` `Spiro: ``    ``# constructor ``    ``def` `__init__(``self``, xc, yc, col, R, r, l): `` ` `        ``# create own turtle ``        ``self``.t ``=` `turtle.Turtle() ``        ``# set cursor shape ``        ``self``.t.shape(``'turtle'``) ``        ``# set step in degrees ``        ``self``.step ``=` `5``        ``# set drawing complete flag ``        ``self``.drawingComplete ``=` `False`` ` `        ``# set parameters ``        ``self``.setparams(xc, yc, col, R, r, l) `` ` `        ``# initiatize drawing ``        ``self``.restart() `` ` `    ``# set parameters ``    ``def` `setparams(``self``, xc, yc, col, R, r, l): ``        ``# spirograph parameters ``        ``self``.xc ``=` `xc ``        ``self``.yc ``=` `yc ``        ``self``.R ``=` `int``(R) ``        ``self``.r ``=` `int``(r) ``        ``self``.l ``=` `l ``        ``self``.col ``=` `col ``        ``# reduce r/R to smallest form by dividing with GCD ``        ``gcdVal ``=` `gcd(``self``.r, ``self``.R) ``        ``self``.nRot ``=` `self``.r``/``/``gcdVal ``        ``# get ratio of radii ``        ``self``.k ``=` `r``/``float``(R) ``        ``# set color ``        ``self``.t.color(``*``col) ``        ``# current angle ``        ``self``.a ``=` `0`` ` `    ``# restart drawing ``    ``def` `restart(``self``): ``        ``# set flag ``        ``self``.drawingComplete ``=` `False``        ``# show turtle ``        ``self``.t.showturtle() ``        ``# go to first point ``        ``self``.t.up() ``        ``R, k, l ``=` `self``.R, ``self``.k, ``self``.l ``        ``a ``=` `0.0``        ``x ``=` `R``*``((``1``-``k)``*``math.cos(a) ``+` `l``*``k``*``math.cos((``1``-``k)``*``a``/``k)) ``        ``y ``=` `R``*``((``1``-``k)``*``math.sin(a) ``-` `l``*``k``*``math.sin((``1``-``k)``*``a``/``k)) ``        ``self``.t.setpos(``self``.xc ``+` `x, ``self``.yc ``+` `y) ``        ``self``.t.down() `` ` `    ``# draw the whole thing ``    ``def` `draw(``self``): ``        ``# draw rest of points ``        ``R, k, l ``=` `self``.R, ``self``.k, ``self``.l ``        ``for` `i ``in` `range``(``0``, ``360``*``self``.nRot ``+` `1``, ``self``.step): ``            ``a ``=` `math.radians(i) ``            ``x ``=` `R``*``((``1``-``k)``*``math.cos(a) ``+` `l``*``k``*``math.cos((``1``-``k)``*``a``/``k)) ``            ``y ``=` `R``*``((``1``-``k)``*``math.sin(a) ``-` `l``*``k``*``math.sin((``1``-``k)``*``a``/``k)) ``            ``self``.t.setpos(``self``.xc ``+` `x, ``self``.yc ``+` `y) ``        ``# done - hide turtle ``        ``self``.t.hideturtle() ``     ` `    ``# update by one step ``    ``def` `update(``self``): ``        ``# skip if done ``        ``if` `self``.drawingComplete: ``            ``return``        ``# increment angle ``        ``self``.a ``+``=` `self``.step ``        ``# draw step ``        ``R, k, l ``=` `self``.R, ``self``.k, ``self``.l ``        ``# set angle ``        ``a ``=` `math.radians(``self``.a) ``        ``x ``=` `self``.R``*``((``1``-``k)``*``math.cos(a) ``+` `l``*``k``*``math.cos((``1``-``k)``*``a``/``k)) ``        ``y ``=` `self``.R``*``((``1``-``k)``*``math.sin(a) ``-` `l``*``k``*``math.sin((``1``-``k)``*``a``/``k)) ``        ``self``.t.setpos(``self``.xc ``+` `x, ``self``.yc ``+` `y) ``        ``# check if drawing is complete and set flag ``        ``if` `self``.a >``=` `360``*``self``.nRot: ``            ``self``.drawingComplete ``=` `True``            ``# done - hide turtle ``            ``self``.t.hideturtle() `` ` `    ``# clear everything ``    ``def` `clear(``self``): ``        ``self``.t.clear() `` ` `# A class for animating spirographs ``class` `SpiroAnimator: ``    ``# constructor ``    ``def` `__init__(``self``, N): ``        ``# timer value in milliseconds ``        ``self``.deltaT ``=` `10``        ``# get window dimensions ``        ``self``.width ``=` `turtle.window_width() ``        ``self``.height ``=` `turtle.window_height() ``        ``# create spiro objects ``        ``self``.spiros ``=` `[] ``        ``for` `i ``in` `range``(N): ``            ``# generate random parameters ``            ``rparams ``=` `self``.genRandomParams() ``            ``# set spiro params ``            ``spiro ``=` `Spiro(``*``rparams) ``            ``self``.spiros.append(spiro) ``        ``# call timer ``        ``turtle.ontimer(``self``.update, ``self``.deltaT) ``     ` `    ``# restart sprio drawing ``    ``def` `restart(``self``): ``        ``for` `spiro ``in` `self``.spiros: ``            ``# clear ``            ``spiro.clear() ``            ``# generate random parameters ``            ``rparams ``=` `self``.genRandomParams() ``            ``# set spiro params ``            ``spiro.setparams(``*``rparams) ``            ``# restart drawing ``            ``spiro.restart() `` ` `    ``# generate random parameters ``    ``def` `genRandomParams(``self``): ``        ``width, height ``=` `self``.width, ``self``.height ``        ``R ``=` `random.randint(``50``, ``min``(width, height)``/``/``2``) ``        ``r ``=` `random.randint(``10``, ``9``*``R``/``/``10``) ``        ``l ``=` `random.uniform(``0.1``, ``0.9``) ``        ``xc ``=` `random.randint(``-``width``/``/``2``, width``/``/``2``) ``        ``yc ``=` `random.randint(``-``height``/``/``2``, height``/``/``2``) ``        ``col ``=` `(random.random(), ``               ``random.random(), ``               ``random.random()) ``        ``return` `(xc, yc, col, R, r, l) `` ` `    ``def` `update(``self``): ``        ``# update all spiros ``        ``nComplete ``=` `0``        ``for` `spiro ``in` `self``.spiros: ``            ``# update ``            ``spiro.update() ``            ``# count completed ones ``            ``if` `spiro.drawingComplete: ``                ``nComplete``+``=` `1``        ``# if all spiros are complete, restart ``        ``if` `nComplete ``=``=` `len``(``self``.spiros): ``            ``self``.restart() ``        ``# call timer ``        ``turtle.ontimer(``self``.update, ``self``.deltaT) `` ` `    ``# toggle turtle on/off ``    ``def` `toggleTurtles(``self``): ``        ``for` `spiro ``in` `self``.spiros: ``            ``if` `spiro.t.isvisible(): ``                ``spiro.t.hideturtle() ``            ``else``: ``                ``spiro.t.showturtle() ``             ` `# save spiros to image ``def` `saveDrawing(): ``    ``# hide turtle ``    ``turtle.hideturtle() ``    ``# generate unique file name ``    ``dateStr ``=` `(datetime.now()).strftime(``"%d%b%Y-%H%M%S"``) ``    ``fileName ``=` `'spiro-'` `+` `dateStr  ``    ``print``(``'saving drawing to %s.eps/png'` `%` `fileName) ``    ``# get tkinter canvas ``    ``canvas ``=` `turtle.getcanvas() ``    ``# save postscipt image ``    ``canvas.postscript(``file` `=` `fileName ``+` `'.eps'``) ``    ``# use PIL to convert to PNG ``    ``img ``=` `Image.``open``(fileName ``+` `'.eps'``) ``    ``img.save(fileName ``+` `'.png'``, ``'png'``) ``    ``# show turtle ``    ``turtle.showturtle() `` ` `# main() function ``def` `main(): ``    ``# use sys.argv if needed ``    ``print``(``'generating spirograph...'``) ``    ``# create parser ``    ``descStr ``=` `"""This program draws spirographs using the Turtle module.  ``    ``When run with no arguments, this program draws random spirographs. ``     ` `    ``Terminology: `` ` `    ``R: radius of outer circle. ``    ``r: radius of inner circle. ``    ``l: ratio of hole distance to r. ``    ``"""``    ``parser ``=` `argparse.ArgumentParser(description``=``descStr) ``   ` `    ``# add expected arguments ``    ``parser.add_argument(``'--sparams'``, nargs``=``3``, dest``=``'sparams'``, required``=``False``,  ``                        ``help``=``"The three arguments in sparams: R, r, l."``) ``                         ` ` ` `    ``# parse args ``    ``args ``=` `parser.parse_args() `` ` `    ``# set to 80% screen width ``    ``turtle.setup(width``=``0.8``) `` ` `    ``# set cursor shape ``    ``turtle.shape(``'turtle'``) `` ` `    ``# set title ``    ``turtle.title(``"Spirographs!"``) ``    ``# add key handler for saving images ``    ``turtle.onkey(saveDrawing, ``"s"``) ``    ``# start listening  ``    ``turtle.listen() `` ` `    ``# hide main turtle cursor ``    ``turtle.hideturtle() `` ` `    ``# checks args and draw ``    ``if` `args.sparams: ``        ``params ``=` `[``float``(x) ``for` `x ``in` `args.sparams] ``        ``# draw spirograph with given parameters ``        ``# black by default ``        ``col ``=` `(``0.0``, ``0.0``, ``0.0``) ``        ``spiro ``=` `Spiro(``0``, ``0``, col, ``*``params) ``        ``spiro.draw() ``    ``else``: ``        ``# create animator object ``        ``spiroAnim ``=` `SpiroAnimator(``4``) ``        ``# add key handler to toggle turtle cursor ``        ``turtle.onkey(spiroAnim.toggleTurtles, ``"t"``) ``        ``# add key handler to restart animation ``        ``turtle.onkey(spiroAnim.restart, ``"space"``) `` ` `    ``# start turtle main loop ``    ``turtle.mainloop() `` ` `# call main ``if` `__name__ ``=``=` `'__main__'``: ``    ``main() `

Output:
```