Cobweb Plots
Cobweb plot visualiser, built in p5.js.
Overview
A cobweb plot is a tool for visualsing the behaviour of discrete 1D iterated functions, functions of the form \(x_{n+1}=f(x_n)\). Going forward we will be using the logistic map as an example, with
\[x_{n+1}=rx_n(1-x_n) \]This implementation uses a brute-force per-pixel approach: for every pixel \((x, y)\), compute the Euclidean distance to each seed and assign the pixel to the nearest one.
Demo
Implementation notes
Complexity
For \(N\) seeds and a \(W \times H\) canvas, the brute-force approach runs in \(O(N \cdot W \cdot H)\). Here (\(N = 24\), \(560 \times 340\)) that is around 4.6 million distance computations per frame. This is fine for a one-shot render but does not scale. Fortune's algorithm constructs the diagram in \(O(N \log N)\).
Edge detection
Edges are detected per-pixel rather than traced geometrically. A pixel at \((x,y)\) is classified as a boundary pixel when the difference between its nearest and second-nearest seed distances falls below a threshold \(\varepsilon\):
\[ \text{edge}(x,y) \iff d_2(x,y) - d_1(x,y) < \varepsilon \]With \(\varepsilon = 2.5\) px this gives clean single-pixel-wide edges without any geometric boundary tracing.
Pixel density
pixelDensity(1) must be called in setup().
On HiDPI displays the default density is 2, so the pixel buffer is
four times larger than expected and index arithmetic silently produces
a corrupted image.
Implementation
Entire code found on Github
The cobweb loop:
let x0 = 0.1;
let y0 = 0;
for (let i = 0; i < n_iters; i++) {
let fx = r * x0 * (1 - x0);
line(cx(x0), cy(y0), cx(x0), cy(fx));
line(cx(x0), cy(fx), cx(fx), cy(fx));
y0 = fx;
x0 = fx;
}