Example slinky.py

This image is based on rotated ellipses.

Code slinky-1-tk.py

We will start by looking at the simplified code slinky-1-tk.py, which creates this image:

The image is simply an ellipse which has been rotated through 90 degrees. The ellipse is drawn at various angles as it rotates.

import sympl.tkcanvas
from sympl.range import crange
from math import sin, cos, pi
 
width = 500
height = 500
a = 200
b = 100
steps = 100
 
def ellipse(a, b, cx, cy, theta, steps):
    points = []
    for t in crange(0, 2*pi, steps):
        x = cx + a*cos(t)*cos(theta) - b*sin(t)*sin(theta)
        y = cy + a*cos(t)*sin(theta) + b*sin(t)*cos(theta)
        points.append((x, y))
    return points
 
def draw(canvas):
    cx = 250
    cy = 250
    for i, theta in enumerate(crange(0, pi/2, 40, closed=True)):
        points = ellipse(a, b, cx, cy, theta, steps)
        p = points[-1]
        for p1 in points:
            canvas.create_line(p, p1, width=1)
            p = p1
 
 
sympl.tkcanvas.tk_image(width, height, draw)

Since Tkinter canvas does not support rotation, we draw the ellipse as a many-sided polygon using the ellipse function. The ellipse has major and minor axes length a and b, and centre (cx, cy). It is rotated by theta radians clockwise. steps gives the number of sides, 100 gives a reasonably smooth result.

In the draw function we just create and draw an ellipse 40 times at angles 0 to pi/2. Notice we use a closed crange, so that it actually includes both 0 and pi/2, as well as the values in between.

Code slinky-tk.py

In the final code, we simply translate each ellipse by a small amount in the x direction as we rotate. This stretches the image for a more interesting effect. We also change the colour of each ellipse.

import sympl.tkcanvas
from sympl.range import crange
from math import sin, cos, pi
from colour import Color
 
width = 600
height = 500
a = 200
b = 100
steps = 100
colors = list(Color('red').range_to(Color('blue'), 40))
 
def ellipse(a, b, cx, cy, theta, steps):
    points = []
    for t in crange(0, 2*pi, steps):
        x = cx + a*cos(t)*cos(theta) - b*sin(t)*sin(theta)
        y = cy + a*cos(t)*sin(theta) + b*sin(t)*cos(theta)
        points.append((x, y))
    return points
 
def draw(canvas):
    cx = 250
    cy = 250
    for i, theta in enumerate(crange(0, pi/2, 40, closed=True)):
        points = ellipse(a, b, cx, cy, theta, steps)
        p = points[-1]
        for p1 in points:
            canvas.create_line(p, p1, width=1, fill=colors[i])
            p = p1
        cx += 5
 
sympl.tkcanvas.tk_image(width, height, draw)

This code generates a list of colours:

colors = list(Color('red').range_to(Color('blue'), 40))

The colours change gradually from red to blue. They take the scenic route around the colour wheel, from red to yellow to green to cyan to blue (rather than simply red to magenta to blue).

In the draw loop, each ellipse is drawn ina different colour. Notice that we also increment cx, the centre of the ellipse, by 5 each time to create the translation.