Skip to content
Sample of Mathematical Rose (Rhodonea) Patterns

openprocessing_p5js · PolarCurves

Mathematical Rose (Rhodonea) Patterns

Overlay of multiple rose (rhodonea) curves in the canonical polar form r = a * cos((n/d) * theta + phase), parametrised by the rational multiplier k = n/d. Several curves with different (n, d, scale, phase) are layered onto the same canvas, each in its own hue. step(n) advances the per-curve phase, slowly rotating the petals.

Original: https://thecodingtrain.com/challenges/55-mathematical-rose-patterns/

▶ Try the live demo (JS port) ▶ Run reference.py via Pyodide 10 formulas have instant JS ports. The Pyodide path runs the actual Python in your browser — first load is ~6 MB, then instant.

Family
openprocessing_p5js
Source
openprocessing · p5.js
Evolution
curve
Render
overlay_polyline
Complexity
low
Agents
9
Year
2018
Author
Daniel Shiffman (Coding Train #55) / community (OpenProcessing)

Math essence

x = scale * cos(n/d * theta + phase) * cos(theta); y = scale * sin(n/d * theta + phase) * sin(theta). Ploidy: k odd -> k petals, k even -> 2k petals. With irrational k the curve is dense in the disk and never closes (Wikipedia, Rhodonea curve).

Parameters

Name Type Default Range Description
dim int 512 200–1200 Square canvas side length.
num_curves int 9 1–24 Number of overlaid rose curves.
samples int 1200 200–6000 Sample count per curve (closed polyline vertices).
radius float 215 30–600 Base radius in pixels.
phase_step float 0.012 0–0.2 Per-tick phase increment (radians) per curve.
bg_color tuple 8,10,24 — Background canvas color.
seed int null 0–999999

Reference

First 60 lines of reference.py. Full source: library_external/openprocessing_p5js/PolarCurves/reference.py

from __future__ import annotations

from typing import ClassVar

import numpy as np


def _rose_xy(
    theta: np.ndarray, n: int, d: int, scale: float, phase: float
) -> tuple[np.ndarray, np.ndarray]:
    """Rhodonea / rose curve sampled at ``theta``.

    x = scale * cos(n/d * theta + phase) * cos(theta)
    y = scale * sin(n/d * theta + phase) * sin(theta)

    Petal count:
        n/d = k rational:
            - k odd     -> k petals
            - k even    -> 2*k petals
            - k integer -> 2*k petals (closes after one revolution)
    """
    k = n / d
    r = np.cos(k * theta + phase)
    x = scale * r * np.cos(theta)
    y = scale * r * np.sin(theta)
    return x, y


class PolarCurves:
    """Overlay of multiple rose (rhodonea) curves in the canonical polar form.

    This is the classic *Coding Train* Mathematical Rose Patterns sketch
    (challenge #55, <https://thecodingtrain.com/challenges/55-mathematical-rose-patterns/>)
    and a long-running OpenProcessing favourite. The signature identity is the
    polar equation ``r = a + b * cos((n/d) * theta + phase)``, parametrised by
    a slider-controlled ``k = n / d`` and rendered as a closed polyline.

    Several curves with different ``(n, d, scale, phase)`` are layered onto the
    same canvas, each in its own hue. ``step(n)`` advances the per-curve phase
    by ``phase_step`` ticks, slowly rotating the petals. ``reset()`` re-seeds
    the phase schedule. ``render()`` rasterises all curves into the running
    canvas and returns it as ``H x W x 3`` uint8.
    """

    family: ClassVar[str] = "openprocessing_p5js"
    sketch: ClassVar[str] = "polarCurves"

    def __init__(
        self,
        dim: int = 512,
        num_curves: int = 9,
        samples: int = 1200,
        radius: float | None = None,
        phase_step: float = 0.012,
        bg_color: tuple[int, int, int] = (8, 10, 24),
        seed: int | None = None,
    ) -> None:
        self.dim = dim
        self.num_curves = num_curves
        self.samples = samples

Try running it locally

The reference implementation is self-contained Python with numpy. Install the package and run:

python library_external/openprocessing_p5js/PolarCurves/reference.py

Need help? See Learn for the standard environment setup, or Playground for an in-browser sketchbook.

More from openprocessing · p5.js

See all openprocessing_p5js artworks →