MAKE THE MATHEMATICS YOURSELF

Golden-angle seeds in C

A complete program. Standard C, a compiler, and the rule behind the shape.

Output generated by this C program: Golden-angle seeds
Generated by the C program below Download image ↗
FROM SOURCE TO SHAPE

Run it in three steps.

  1. Save the source.

    Download phyllotaxis.c into a folder on your computer.

  2. Compile it.

    In that folder, run this with GCC or Clang:

    cc -std=c11 -O2 phyllotaxis.c -lm -o phyllotaxis
  3. Make the image.
    ./phyllotaxis

    Open phyllotaxis.svg in a browser to see the result.

On Windows with GCC, name the executable phyllotaxis.exe and run it from the same folder.

THE RULE IN THE PROGRAM

How the picture is built

Place seed n at angle n×ANGLE_DEGREES and radius proportional to √n. The square-root radius makes equal increments in n correspond to equal annular area. A near-golden angular step creates interleaving spiral families.

Make it your own

SEEDS=1600; ANGLE_DEGREES=137.51 matches the atlas default. Try 180×(3−√5) for the exact golden-angle expression, or 144 degrees for a rational comparison.

The default angle is a decimal approximation, so exact irrational-angle claims apply only to the mathematical ideal. The apparent spiral families connect nearby dots in the viewer’s eye; the code draws dots alone. Each run produces one image; use Graphic mode for the interactive animation.

The complete source

phyllotaxis.c · 92 lines · no graphics libraries
/* Arithmos: phyllotaxis
 * Compile: cc -std=c11 -O2 phyllotaxis.c -lm -o phyllotaxis
 * Run:     ./phyllotaxis
 * Output:  phyllotaxis.svg (open this file in a browser)
 * Optional output path: ./phyllotaxis my-image.svg
 * Edit the constants in draw() to explore another case.
 */
#include <math.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

static FILE *nt_out;
#define NT_PI 3.14159265358979323846

/* The small SVG writer keeps this program free of graphics dependencies.
 * Coordinates are pixels on a 1000 x 700 drawing surface.
 * t runs from 0 to 1 through mint, blue, rose, and gold.
 */
static inline void nt_color(double t, char hex[8]) {
    const double stops[4][3] = {
        {91,227,201}, {128,146,240}, {218,138,220}, {244,200,127}
    };
    t = fmax(0.0, fmin(1.0,t)) * 3.0;
    int band = (int)fmin(2.0,floor(t));
    double blend = t - band;
    int r[3];
    for (int k=0;k<3;k++) r[k]=(int)lround(stops[band][k]*(1.0-blend)+stops[band+1][k]*blend);
    snprintf(hex,8,"#%02x%02x%02x",r[0],r[1],r[2]);
}
static inline void nt_line(double x,double y,double X,double Y,double t,double alpha,double width) {
    char color[8];nt_color(t,color);
    fprintf(nt_out,"<path d=\"M%.3f %.3f L%.3f %.3f\" fill=\"none\" stroke=\"%s\" stroke-opacity=\"%.3f\" stroke-width=\"%.3f\"/>\n",x,y,X,Y,color,alpha,width);
}
static inline void nt_dot(double x,double y,double r,double t,double alpha) {
    char color[8];nt_color(t,color);
    fprintf(nt_out,"<circle cx=\"%.3f\" cy=\"%.3f\" r=\"%.3f\" fill=\"%s\" fill-opacity=\"%.3f\"/>\n",x,y,r,color,alpha);
}
static inline void nt_circle(double x,double y,double r,double t,double alpha,double width) {
    char color[8];nt_color(t,color);
    fprintf(nt_out,"<circle cx=\"%.3f\" cy=\"%.3f\" r=\"%.3f\" fill=\"none\" stroke=\"%s\" stroke-opacity=\"%.3f\" stroke-width=\"%.3f\"/>\n",x,y,r,color,alpha,width);
}
static inline void nt_rect(double x,double y,double w,double h,double t,double alpha) {
    char color[8];nt_color(t,color);
    fprintf(nt_out,"<rect x=\"%.3f\" y=\"%.3f\" width=\"%.3f\" height=\"%.3f\" fill=\"%s\" fill-opacity=\"%.3f\"/>\n",x,y,w,h,color,alpha);
}
static inline void nt_text(double x,double y,const char *text) {
    fprintf(nt_out,"<text x=\"%.3f\" y=\"%.3f\" fill=\"#ededf3\" font-family=\"monospace\" font-size=\"16\">",x,y);
    for (;*text;text++) {
        if (*text=='&') fputs("&amp;",nt_out);
        else if (*text=='<') fputs("&lt;",nt_out);
        else if (*text=='>') fputs("&gt;",nt_out);
        else fputc(*text,nt_out);
    }
    fputs("</text>\n",nt_out);
}
static inline int nt_gcd(int a,int b) {a=abs(a);b=abs(b);while(b){int r=a%b;a=b;b=r;}return a;}
static inline int nt_prime(int n) {if(n<2)return 0;for(int d=2;d<=n/d;d++)if(n%d==0)return 0;return 1;}

/* Vogel-style seed model: square-root radius and fixed angular increment.
   ANGLE_DEGREES matches the site's two-decimal slider. For the ideal
   golden angle use 180.0*(3.0-sqrt(5.0)); compare 144.0 for five rays. */
static void draw(void) {
    const int SEEDS=1600;const double ANGLE_DEGREES=137.51,RADIUS=285;
    double angle=ANGLE_DEGREES*NT_PI/180;
    for(int n=1;n<=SEEDS;++n) {
        double r=RADIUS*sqrt(n/(double)SEEDS),theta=n*angle;
        nt_dot(500+r*cos(theta),340-r*sin(theta),2.5,n/(double)SEEDS,.95);
    }
    nt_text(50,675,"r is proportional to sqrt(n); theta advances by 137.51 degrees per seed.");
}

int main(int argc, char **argv) {
    if (argc > 2) {
        fprintf(stderr, "Usage: %s [OUTPUT.svg]\n", argv[0]);
        return EXIT_FAILURE;
    }
    const char *filename = argc == 2 ? argv[1] : "phyllotaxis.svg";
    nt_out = fopen(filename, "wb");
    if (!nt_out) { perror(filename); return EXIT_FAILURE; }
    fputs("<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"1000\" height=\"700\" viewBox=\"0 0 1000 700\">\n"
          "<rect width=\"1000\" height=\"700\" fill=\"#171721\"/>\n", nt_out);
    draw();
    fputs("</svg>\n", nt_out);
    int failed = ferror(nt_out);
    if (fclose(nt_out) != 0) failed = 1;
    if (failed) { fputs("Could not finish writing the image.\n", stderr); return EXIT_FAILURE; }
    printf("Wrote %s\n", filename);
    return EXIT_SUCCESS;
}
All 40 explorations, ready to compile.Download all C examples ↓