Beginner · Times table on a circle

Lesson 2: Loops and remainders

Build the times table on a circle in Python, and learn on the way:

  • a for loop over pairs with zip
  • the remainder % and angles that wrap around
  • a line from two points with plt.plot
  • exploring by changing one parameter

Watch it first

Plays from YouTube after a click.

times-table.py
"""Times table on a circle: N dots, each dot n joined to dot (k * n) mod N.
Run: python times-table.py   (needs: pip install numpy matplotlib)
"""
import numpy as np
import matplotlib.pyplot as plt

plt.style.use("dark_background")

N, k = 200, 2  # the number of dots and the multiplier

start = 2 * np.pi * np.arange(N) / N  # dot n at the angle 2*pi*n/N
end = start * k  # dot k*n: angles wrap around the circle by themselves (that is the "mod N")

plt.figure(figsize=(6, 6))
for a, b in zip(start, end):
    plt.plot([np.cos(a), np.cos(b)], [np.sin(a), np.sin(b)], color="#f5c76b", linewidth=0.6)
plt.axis("equal")
plt.axis("off")
plt.show()

# Try: k = 3 for the nephroid, k = 101 to see it collapse into diameters

No Python on this computer? The notebook runs the same script, the exercises and the answers in your browser, on Google Colab.

Line by line

  1. N, k = 200, 2

    Two names at once: 200 dots and the multiplier 2. These are the two numbers to change.

  2. start = 2 * np.pi * np.arange(N) / N

    The angle of each dot: dot n sits at 2π·n / N, so the 200 dots share the circle evenly.

  3. end = start * k

    The angle of dot k·n. An angle past 2π simply goes round again, and that does the wrapping (k·n mod N) for us.

  4. for a, b in zip(start, end):

    zip pairs the two arrays: each time round, the loop gets one start angle with its end angle.

  5. plt.plot([np.cos(a), np.cos(b)], [np.sin(a), np.sin(b)], color="#f5c76b", linewidth=0.6)

    plt.plot takes the x values, then the y values, of the line’s two ends: one chord of the circle each time round.

Try it yourself

  1. Draw times 3 and times 4. How many cusps (sharp points) does each curve have?

    Hint

    Change k.

    Answer

    Times 3 gives the nephroid with 2 cusps, times 4 a curve with 3: always k − 1.

  2. With 200 dots, which dot does 150 × 2 land on? Work it out with the remainder operator.

    Hint

    In Python, % gives the remainder after dividing.

    Answer

    (150 * 2) % 200 is 100.

  3. Use 20 dots instead of 200. Why is the heart harder to see?

    Hint

    Change N.

    Answer

    With 20 dots there are only 20 lines, too few for the curve they all touch to show.

Quiz

1. What does zip(start, end) give the loop each time round?
2. What is 300 % 200 in Python?
3. Why does the script never use %?
4. In plt.plot([x1, x2], [y1, y2]), what comes first?
5. Which curve does times 2 draw?

Flashcards

Read the front, say the back to yourself, then open the card.

  • zip(a, b)

    Pairs two sequences item by item: (a[0], b[0]), (a[1], b[1]), …

  • x % n

    The remainder of x divided by n: 300 % 200 is 100.

  • plt.plot([x1, x2], [y1, y2])

    A line from (x1, y1) to (x2, y2).

  • Envelope

    The curve that every line of a family just touches: here, the cardioid.

  • Times k on a circle

    A whole multiplier k draws a curve with k − 1 cusps.

These flashcards on their own page →