Barnsley’s Fern
Barnsley’s Fern
In 1988, Michael Barnsley published an elegant way to programatically generate ferns. The rules are rather simple: iteratively apply a rotation + translation to a coordinate with certain probabilities, and voilà! A fern appears:
How it works
The fern is generated iteratively. Starting with a seed coordinate, we jump to a new coordinate using an update rule. Given a coordinate vector [x, y], the update is given by:
Which values you use for A and b depend on a probability p. For this specific fern, there are four possible sets of values for A and b, each with it’s associated p:
We plant a seed at [0, 0] and iterate for as many steps as we’d like. At each step, we plot the coordinate. That’s it!
Python Implementation
Let’s code this in python. First, we define our transformations and their associated probabilities:
import numpy as np
A1 = np.array(([0, 0], [0, 0.16]))
b1 = np.array([[0], [0]])
p1 = 0.01
A2 = np.array(([0.85, 0.04], [-0.04, 0.85]))
b2 = np.array([[0], [1.60]])
p2 = 0.85
A3 = np.array(([0.20, -0.26], [0.23, 0.22]))
b3 = np.array([[0], [1.60]])
p3 = 0.07
A4 = np.array(([-0.15, 0.28], [0.26, 0.24]))
b4 = np.array([[0], [0.44]])
p4 = 0.07
Next, we chose given probability p which update rule to apply, and apply it as long as many times as we want:
fern = [] # The collection of all Xs that will make up our Fern
X = np.array(([0], [0])) # Seed
for N in range(100000):
p = np.random.random() # Random value between 0 and 1
if p < p1:
A, b = A1, b1
elif p < p1 + p2:
A, b = A2, b2
elif p < p1 + p2 + p3:
A, b = A3, b3
elif p < p1 + p2 + p3 + p4:
A, b = A4, b4
X = np.matmul(A, X) + b # Update Rule
fern.append(X) # Add our new point to the fern
The last step is simply to scatter plot all our results:
import matplotlib.pyplot as plt
plt.figure(figsize=(10, 10))
plt.scatter(x=[X[0] for X in fern], y=[X[1] for X in fern], c="green", s=0.5)
plt.axis("off")
That’s it! All the code to reproduce this is on Colab:
Comments