## Animating a rotating spiral

With a couple of loops and a bit of maths you can create a rotating spiral.

# Animating a rotating spiral

Following up on the concepts covered in my previous article “Animations from first principles in 5 minutes” and “More animations from first principles in 5 minutes”, in this article we will create the animation you can see above.

We start by modifying the parametrisation of the circle to create a spiral:

SIDE = 600

def spiral(percentage):
return (
SIDE // 2
* percentage
* cos(10 * pi * percentage),
SIDE // 2
* percentage
* sin(10 * pi * percentage),
)

The 10 inside cos/sin dictate how many turns the spiral does, all you have to do is divide that number by 2, so a 10 means we do 5 turns around the centre of the spiral.

You can “easily” put the spiral on the screen:

from itertools import product
from math import sin, cos, pi

import pygame

SIDE = 600
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)

screen = pygame.display.set_mode((SIDE, SIDE))
screen.fill(WHITE)

def draw_pixel(screen, x, y, colour):
x, y = round(x), round(y)
for dx, dy in product(range(-1, 2), repeat=2):
screen.set_at((x + dx, y + dy), colour)

def spiral(percentage):
return (
SIDE // 2 * percentage * cos(10 * pi * percentage),
SIDE // 2 * percentage * sin(10 * pi * percentage),
)

STEPS = 3000
for step in range(STEPS + 1):
percentage = step / STEPS
x, y = rotating_spiral(percentage, tick / 10)
draw_pixel(screen, x, y, BLACK)
pygame.display.flip()
input()

By modifying the function spiral to accept an argument that represents time and by creating an outer loop that emulates ticking of time, we can rotate this spiral:

# ...

def spiral(percentage, time):
return (
SIDE // 2 * percentage * cos(10 * pi * percentage + time),
SIDE // 2 * percentage * sin(10 * pi * percentage + time),
)

# ...

STEPS = 3000
for tick in count():
screen.fill(WHITE)
for step in range(STEPS + 1):
percentage = step / STEPS
x, y = rotating_spiral(percentage, tick / 10)
draw_pixel(screen, x, y, BLACK)
pygame.display.flip()

To make the spiral expand and contract, we must make it so that the radius has to change as time ticks:

def rotating_spiral(percentage, time):
return (
SIDE // 2
+ (1 + sin(time) / 10)  # <-- new
* percentage * (SIDE // 3) * cos(10 * pi * percentage + time),
SIDE // 2
+ (1 + sin(time) / 10)  # <-- new
* percentage * (SIDE // 3) * sin(10 * pi * percentage + time),
)

Finally, to add colour, we create two functions that generate the background and foreground colours for each frame instead of using the constants WHITE / BLACK:

# ...

def bg(time):
return (
40 + int(abs(30 * sin(0.05 * time))),
40 + int(abs(30 * sin(0.05 * time))),
40 + int(abs(30 * sin(0.05 * time))),
)

def fg(time):
return (
255 - int(abs(15 * sin(0.1 * time))),
85 + int(abs(160 * sin(0.1 * time))),
85 + int(abs(60 * sin(0.1 * time))),
)

STEPS = 3000
for tick in count(step=0.1):  # <-- smaller tick
screen.fill(bg(tick))
clr = fg(tick)
for step in range(STEPS + 1):
percentage = step / STEPS
x, y = rotating_spiral(percentage, tick)
draw_pixel(screen, x, y, clr)
pygame.display.flip()

Running the code above should produce the following animation:

## Become a better Python 🐍 developer 🚀

+35 chapters. +400 pages. Hundreds of examples. Over 30,000 readers!

My book “Pydon'ts” teaches you how to write elegant, expressive, and Pythonic code, to help you become a better developer. >>> Download it here 🐍🚀.