Skip to content

Sunflowers have math in them, wtf?

How to pack as many seeds as possible into a sunflower head: Fibonacci

@
Oct 7, 20264 min read

In the middle of a sunflower, if you look hard enough, you'll see two families of spirals, one turning clockwise $arrow.cw$ and the other counterclockwise $arrow.ccw$. Count each one and you usually get two approximate Fibonacci numbers, like 55 or 66. It looks like the plant is calculating it, which can seem a bit absurd. It actually isn't counting anything (duh), it's just following one dumb rule for the sake of efficiency and the numbers appear on their own.

The dumb rule

A sunflower grows new seeds one at a time at the centre and shoves the older ones outwards. Each new seed goes a fixed angle, say $theta$, around from the previous one. The question is now: which angle packs it best?

Think of $theta$ as a fraction of a full turn. If that fraction is a ratio of small integers, say $1/4$ or $2/5$, the seeds stack into a few straight spokes with ugly gaps between them.

#import "@preview/cetz:0.5.2": canvas, draw
#let angle = 360deg * 2 / 5  // 2/5 of a turn
#let arms = 5
#let seeds = 150
#let head-radius = 3.5
#let c = head-radius / calc.sqrt(seeds)  // seed n sits at radius c * sqrt(n)
#let seed = c / 2  // dot radius
#let palette = theme.series.slice(0, 3)
#canvas({
  draw.circle((0, 0), radius: head-radius + seed, stroke: (paint: theme.line, dash: "dashed"))
  for n in range(1, seeds + 1) {
    let r = c * calc.sqrt(n)
    draw.circle(
      (r * calc.cos(n * angle), r * calc.sin(n * angle)),
      radius: seed,
      fill: palette.at(calc.rem(calc.rem(n, arms), palette.len())),
      stroke: none,
    )
  }
})

You want the fraction that stays away from lining up for as long as possible, and that's the golden ratio:

phi=(1+sqrt(5))/2approx1.618phi = (1 + sqrt(5)) / 2 approx 1.618

It's the hardest number to approximate with fractions, because its continued fraction is nothing... but ones.

phi=1+1/(1+1/(1+1/(1+dots.down)))phi = 1 + 1 / (1 + 1 / (1 + 1 / (1 + dots.down)))

The golden angle

Turn a full circle by $phi^(-2)$ and you get the golden angle:

theta=(360degree)/phi2approx137.508degreetheta = (360 degree) / phi^2 approx 137.508 degree

Fibonacci appears because the ratio of consecutive terms of $F_(n+1) = F_n + F_(n-1)$ converges to $phi$:

lim(n−>oo)F(n+1)/Fn=philim_(n -> oo) F_(n+1) / F_n = phi

So the best rational approximations to the golden angle come from Fibonacci numbers, and those are the spiral counts you see in the head.

Placing the seeds

Seed $n$ sits at angle $n theta$. Its distance from the center grows with the square root of $n$, keeping the area per seed constant. A disc of radius $r$ has area $pi r^2$, so if each seed takes area $A$, then $n$ seeds fill

pirn2=nAquad=>quadrn=sqrt(A/pi)sqrt(n)pi r_n^2 = n A quad => quad r_n = sqrt(A / pi) sqrt(n)

With $c = sqrt(A / pi)$, the coordinates are:

(xn,yn)=(csqrt(n)cos(ntheta),csqrt(n)sin(ntheta))(x_n, y_n) = (c sqrt(n) cos(n theta), c sqrt(n) sin(n theta))
#import "@preview/cetz:0.5.2": canvas, draw
#let phi = (1 + calc.sqrt(5)) / 2
#let angle = 360deg / calc.pow(phi, 2)
#let arms = 21
#let seeds = 400
#let head-radius = 3.4
#let c = head-radius / calc.sqrt(seeds)  // seed n sits at radius c * sqrt(n)
#let seed = c / 2  // dot radius
#let palette = theme.series.slice(0, 3)
#canvas({
  for n in range(1, seeds + 1) {
    let r = c * calc.sqrt(n)
    draw.circle(
      (r * calc.cos(n * angle), r * calc.sin(n * angle)),
      radius: seed,
      fill: palette.at(calc.rem(calc.rem(n, arms), palette.len())),
      stroke: none,
    )
  }
})
#import "@preview/cetz:0.5.2": canvas, draw
#let phi = (1 + calc.sqrt(5)) / 2
#let angle = 360deg / calc.pow(phi, 2)
#let arms = 34
#let seeds = 400
#let head-radius = 3.4
#let c = head-radius / calc.sqrt(seeds)  // seed n sits at radius c * sqrt(n)
#let seed = c / 2  // dot radius
#let palette = theme.series.slice(0, 3)
#canvas({
  for n in range(1, seeds + 1) {
    let r = c * calc.sqrt(n)
    draw.circle(
      (r * calc.cos(n * angle), r * calc.sin(n * angle)),
      radius: seed,
      fill: palette.at(calc.rem(calc.rem(n, arms), palette.len())),
      stroke: none,
    )
  }
})

That's pretty much it! If you want to see more, check out this video on the golden ratio by Numberphile :D

Did you enjoy this article?

Recommend it — Standard Reader surfaces well-loved writing to more readers across the network.

Across the AtmosphereDiscussions