--- jupyter: description: 'The golden spiral and the Fibonacci spiral with planex2d: Fibonacci squares tiling a rectangle of F_n F_n+1, the quarter-circle spiral of length π/2 ΣF, the logarithmic spiral that grows by φ per quarter turn, and the quarter circles straying from it by about a hundredth of the radius.' --- # The golden spiral and the Fibonacci spiral Is the spiral drawn through the Fibonacci squares the golden spiral? Squares with the Fibonacci numbers 1, 1, 2, 3, 5, 8, ... as sides tile a rectangle whose sides approach the golden ratio $\varphi = (1 + \sqrt{5})/2$, and a quarter circle in each square makes the well-known Fibonacci spiral. The golden spiral is the logarithmic spiral that grows by $\varphi$ every quarter turn, $$r = r_0 \, \varphi^{2 \theta / \pi} = r_0 \, e^{b \theta}, \qquad b = \frac{2 \ln \varphi}{\pi}.$$ The two look alike but are different curves. The quarter circles change their curvature at every square, while the logarithmic spiral bends evenly, and even in exactly golden squares the circles stray from it. The example tiles the Fibonacci squares and checks their area, draws the Fibonacci spiral with arcs and checks its length, draws the golden spiral with `px.Curve` and checks its length, and measures how far the quarter circles of exactly golden squares run from it. This page is part of a collection of [geometry and design examples](geometry-and-design.md) using planex2d. .. rst-class:: px-example-links `Open this example in the playground `__, the interactive code editor in the browser, to change the code and run it. ![The Fibonacci squares and the spiral of quarter circles through them](../_static/gallery/golden-spiral.png){.result} ```python import math import numpy as np import planex as px ``` ```python nbsphinx="hidden" from docs_figures import Chart, Row ``` ## The Fibonacci squares Starting from a unit square, each new square is added along the long side of the rectangle so far, in turn on the right, at the top, on the left and at the bottom. The squares tile a rectangle of $F_n$ by $F_{n+1}$, so the sum of their areas is $F_1^2 + \dots + F_n^2 = F_n F_{n+1}$, and the ratio of the sides tends to $\varphi$ (Figure 1): ```python phi = (1 + math.sqrt(5)) / 2 F = [1, 1, 2, 3, 5, 8, 13, 21, 34, 55] x0, y0, x1, y1 = 0, 0, 1, 1 squares = [px.QuickSketch().Rectangle(1, 1).Face()] for k, s in enumerate(F[1:], 1): if k % 4 == 1: corner, x1 = (x1, y0), x1 + s elif k % 4 == 2: corner, y1 = (x0, y1), y1 + s elif k % 4 == 3: corner, x0 = (x0 - s, y0), x0 - s else: corner, y0 = (x0, y0 - s), y0 - s squares.append(px.QuickSketch().Move(corner).Rectangle(s, s).Face()) tiling = px.Unify(squares) print("faces", len(tiling.faces), "| area", tiling.mass, "| Σ F²", sum(s * s for s in F), "| F_n F_n+1", 55 * 89) print("sides", tiling.bounding_box, "| ratio", 89 / 55, "| φ", phi) ``` ## The Fibonacci spiral The spiral is a chain of quarter circles, one in each square with the square's side as radius. Drawn as a turtle, it starts at (0, 1) heading down and turns left by 90° along each arc. The arcs are exact, so the length is $\frac{\pi}{2} \sum F_k$ (Figure 1): ```python pen = px.QuickSketch().Move((0, 1), dir=(0, -1)) for s in F: pen = pen.Arc(s, 90) fibonacci = pen.Wires()[0] print("length", fibonacci.mass, "| π/2 Σ F", math.pi / 2 * sum(F)) # px.Plot(px.Compound(squares + [fibonacci])) ``` ```python nbsphinx="hide-input" Row((px.Compound(squares + [fibonacci]), "Ten Fibonacci squares and the spiral", {"lw": 1.2}), caption="The Fibonacci squares and their spiral of quarter circles") ``` At every joint, the radius jumps from one Fibonacci number to the next, by a factor that tends to $\varphi$. The golden spiral has no such jumps, since its radius of curvature, $r \sqrt{1 + b^2}$, grows evenly with $r$. ## The golden spiral Drawn in exactly golden squares, with the sides $\varphi^k$, the same chain of quarter circles has its joints on a logarithmic spiral. Each joint is reached from the one before by $r_k (1 + i) h_k$, as complex numbers with the heading $h_k$, and these steps shrink by $\varphi$ and turn back a quarter turn going inward. Their sum to infinity is a geometric series, and it gives the pole the spiral winds into: ```python radii = [phi**k for k in range(-6, 7)] start, heading = complex(0, 1), complex(0, -1) pole = start - radii[0] * (1 + 1j) * heading * (-1j / phi) / (1 + 1j / phi) pen = px.QuickSketch().Move((0, 1), dir=(0, -1)) joints = [start] for r in radii: pen = pen.Arc(r, 90) joints.append(joints[-1] + r * (1 + 1j) * heading) heading *= 1j golden_arcs = pen.Wires()[0] print("distances of the joints from the pole grow by", [abs(joints[k + 1] - pole) / abs(joints[k] - pole) for k in range(3)]) ``` The golden spiral through the first joint is drawn with `px.Curve` from a Python function. A logarithmic spiral has a finite length from its pole, and between two radii it is $(r_1 - r_0) \sqrt{1 + 1/b^2}$ long: ```python b = 2 * math.log(phi) / math.pi r0, theta0 = abs(start - pole), math.atan2((start - pole).imag, (start - pole).real) turns = len(radii) * math.pi / 2 def golden(t): """the golden spiral t radians on from the first joint""" r = r0 * math.exp(b * t) return (pole.real + r * math.cos(theta0 + t), pole.imag + r * math.sin(theta0 + t)) spiral = px.Curve(golden, (0, turns)) print("length", spiral.mass, "| (r1 - r0) √(1 + 1/b²)", (r0 * math.exp(b * turns) - r0) * math.sqrt(1 + 1 / b**2)) ``` ## How far apart Along the chain of quarter circles, its distance from the pole is compared with the golden spiral's at the same angle. Between the joints, where they meet the spiral, the circles first run inside it and then outside, by up to about a hundredth of the radius either way. Every quarter circle does the same, and Figure 2 shows the last one: ```python points = np.array(golden_arcs.Polylines(1e-5)[0]) z = points[:, 0] + 1j * points[:, 1] - pole theta = np.unwrap(np.angle(z)) deviation = np.abs(z) / (r0 * np.exp(b * (theta - theta[0]))) - 1 print("largest", deviation.max(), "| smallest", deviation.min()) print("Hausdorff distance", golden_arcs.Hausdorff(spiral), "| the largest radius", radii[-1]) # plt.plot((theta - theta[0]) / (math.pi / 2), 100 * deviation); plt.show() ``` ```python nbsphinx="hide-input" quarters = (theta - theta[0]) / (math.pi / 2) last = quarters >= len(radii) - 1 Chart("Angle along the quarter circle in degrees", "Distance from the golden spiral in %", curves={"The last quarter circle": (90 * (quarters[last] - len(radii) + 1), 100 * deviation[last])}, title="How far a quarter circle runs from the golden spiral") ``` See [Curves from equations](../core/basics/curves.md) for `px.Curve` and [Sunflower seeds and the golden angle](sunflower-golden-angle.md) for $\varphi$ in nature. ```python nbsphinx="hidden" import sys import matplotlib.pyplot as plt sys.path.insert(0, "..") from docs_figures import FACE, INK, PLANEX from gallery import save_figure fig, ax = plt.subplots(figsize=(6, 4)) for square in squares: square.Plot(ax=ax, face_col=FACE, line_col=INK, legend=False) for artist in ax.lines + ax.collections + ax.patches: artist.set_linewidth(0.8) before = len(ax.lines), len(ax.collections) fibonacci.Plot(ax=ax, face_col=None, line_col=PLANEX, arc_col=PLANEX, legend=False) for artist in ax.lines[before[0]:] + ax.collections[before[1]:]: artist.set_linewidth(2.4) ax.set_xlim(-24 - 1.5, 65 + 1.5) ax.set_ylim(-39 - 4.4, 16 + 4.4) ax.set_aspect("equal") ax.axis("off") save_figure(fig, "golden-spiral") plt.close(fig) ```