Public
Edited
May 16, 2023
1 star
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
algae = {
const variables = ["A", "B"];
const axiom = ["A"];
const rules = {
A: ["A", "B"],
B: ["A"]
};

const system = new LSystem(variables, axiom, rules);
const n = 7;
const result = system.produce(n);

return md`\`\`\`
${result.map((d, i) => `n = ${i} : ${d.join("")}\n`).join("")}
\`\`\``;
}
Insert cell
Insert cell
Insert cell
dragonCurve = {
const variables = ["F", "G", "+", "-"];
const axiom = ["F"];
const rules = {
F: ["F", "+", "G"],
G: ["F", "-", "G"]
};
const angle = 90;

const system = new LSystem(variables, axiom, rules);

const n = 10;

const output = system.produce(n)[n - 1];

return plotDragonCurve(output, angle);
}
Insert cell
Insert cell
// Define an L-system in terms of variables, axioms and rules.
class LSystem {
constructor(variables, axiom, rules) {
this.variables = variables;
this.axiom = axiom;

// 'Rules' are a JS object mapping a variable
// to the list of symbols it should be replaced by
// at each production.
this.rules = rules;

// Add rules for constants/terminals
this.variables.forEach((variable) => {
if (this.rules[variable]) return;
// constants use the identity function
this.rules[variable] = [variable];
});
}

// Run n 'productions' of the system and return the result containing each production.
produce(n) {
// First 'production' is the start/axiom
const result = [this.axiom];
while (result.length < n + 1) {
const next = result[result.length - 1].flatMap(
(item) => this.rules[item]
);
result.push(next);
}
return result;
}
}
Insert cell
Insert cell
Insert cell
// Helper function to plot Dragon Curve data
function plotDragonCurve(data, angle) {
const w = width;
const h = 300;
const center = [w / 2, h * 0.75];
const ctx = DOM.context2d(w, h);
const angleRadians = (angle * Math.PI) / 180;

const unit = 10;

const scaleColor = d3
.scaleSequential(d3.interpolateCool)
.domain([0, data.length]);

let i = 0;
for (let d of data) {
switch (d) {
case "F":
case "G":
ctx.beginPath();
ctx.moveTo(center[0], center[1]);
ctx.lineTo(center[0], center[1] - unit);
ctx.translate(0, -unit);
ctx.strokeStyle = scaleColor(i);
ctx.stroke();
break;
case "+":
// Rotate around center
ctx.translate(...center);
ctx.rotate(angleRadians);
ctx.translate(...center.map((d) => -d));
break;
case "-":
// Negative rotate around center
ctx.translate(...center);
ctx.rotate(-angleRadians);
ctx.translate(...center.map((d) => -d));
break;
}
i++;
}

return ctx.canvas;
}
Insert cell
// Helper function for rendering fractal plants
function plotFractalPlant(ctx, w, h, position, data, angle, scale) {
const center = [Math.floor(w / 2), Math.floor(h / 2)];
const unit = scale;

// Rotate around center
const rot = (radians) => {
ctx.translate(...center);
ctx.rotate(radians);
ctx.translate(...center.map((d) => -d));
};

const scaleColor = d3
.scaleSequential(d3.interpolateGreens)
.domain([-data.length / 2, data.length]);

const angleRadians = (angle * Math.PI) / 180;

const stack = [];

ctx.translate(-center[0] + position[0], h / 2 - position[1]);
// Set the plant at an angle to begin with, more interesting that way
rot(angleRadians);

data.forEach((d, i) => {
switch (d) {
case "F":
ctx.beginPath();
ctx.moveTo(center[0], center[1]);
ctx.lineTo(center[0], center[1] - unit);
ctx.translate(0, -unit);
ctx.strokeStyle = scaleColor(i);
ctx.stroke();
break;
case "[":
stack.push(ctx.getTransform());
break;
case "]":
ctx.setTransform(stack.pop());
break;
case "+":
rot(angleRadians);
break;
case "-":
rot(-angleRadians);
break;
}
});
}
Insert cell
// Helper class for rendering fractal plants
class Planter {
constructor(ctx, w, h) {
this.ctx = ctx;
this.w = w;
this.h = h;
}

plant(position, data, angle = 25, scale = 1) {
this.ctx.resetTransform();
plotFractalPlant(this.ctx, this.w, this.h, position, data, angle, scale);
}
}
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more