Public
Edited
Jan 4, 2024
Insert cell
Insert cell
Insert cell
Insert cell
{
const app = cm.app({
width: 640,
height: 640
});

app
.data(cm.range(120))
.process(cm.map, (_, i, data) => (i * Math.PI) / data.length)
.append(cm.circle, {
x: (t) => Math.cos(t) * Math.cos(t * 3),
y: (t) => Math.sin(t) * Math.cos(t * 3),
r: (t) => t,
fill: "black"
})
.transform(cm.mapPosition, { padding: 30 })
.transform(cm.mapAttrs, { r: { range: [8, 15] } });

return app.render().node();
}
Insert cell
Insert cell
Insert cell
Insert cell
{
const width = 700,
height = 700,
scale = 300,
theta = cm.range(count, 0, cm.TWO_PI);

function update(app) {
const time = app.prop("frameCount") / 50;

app.append(cm.clear, { fill: "black" });

app
.data(theta) // Bind Data.
.append(cm.circle, {
// Define some glsl attributes and interpolate some values.
position: cm.glsl`vec2 position(float theta) {
vec2 xy = vec2(
cos(theta),
sin(theta)) * (0.6 + 0.2 * cos(theta * 6.0 + cos(theta * 8.0 + ${time}))
);
return xy * ${scale} + vec2(${width / 2}, ${height / 2});
}`,
r: cm.glsl`float r(float theta) {
float d = 0.2 + 0.12 * cos(theta * 9.0 - ${time} * 2.0);
return d * ${scale};
}`,
stroke: cm.glsl`vec4 stroke(float theta) {
float th = 8.0 * theta + ${time} * 2.0;
vec3 rgb = 0.6 + 0.4 * vec3(
cos(th - ${Math.PI} * 2.0 / 3.0),
cos(th),
cos(th - ${Math.PI} * 5.0 / 3.0)
);
return vec4(rgb, 0.0);
}`,
strokeOpacity: cm.glsl`float strokeOpacity(float theta) {
return 0.15 * 2000.0 / ${count};
}`
});
}

// Diposes app when rerunning cell.
function dispose(app) {
invalidation.then(() => app.dispose());
}

return cm
.app({
width,
height,
renderer: cm.webgl() // Uses WebGL renderer.
})
.on("update", update)
.call(stats)
.call(dispose)
.start()
.node();
}
Insert cell
Insert cell
{
const width = 640;
const height = 360;
const palette = cm.glsl`vec3 palette(float t) {
vec3 a = vec3(0.5, 0.5, 0.5);
vec3 b = vec3(0.5, 0.5, 0.5);
vec3 c = vec3(1.0, 1.0, 1.0);
vec3 d = vec3(0.263, 0.416, 0.557);
return a + b * cos(3.1415926 * 2.0 * (c * t + d));
}`;

function update(app) {
const time = app.prop("frameCount") / 50;
const fill = cm.glsl`vec4 fill(vec2 coord, vec4 color) {
vec2 uv = (coord - vec2(${width}, ${height})) / ${height};
vec2 uv0 = uv;
vec3 rgb = vec3(0.0);
for (float i = 0.0; i < 4.0; i++) {
uv = fract(uv * 1.5) - 0.5;
float d = length(uv) * exp(-length(uv0));
vec3 col = ${palette}(length(uv0) + i * 0.4 + ${time} * 0.4);
d = sin(d * 8.0 + ${time}) / 8.0;
d = abs(d);
d = pow(0.01 / d, 1.2);
rgb += col * d;
}
return vec4(rgb, 1.0);
}`;
app.append(cm.rect, { x: 0, y: 0, width, height, fill });
}

function dispose(app) {
invalidation.then(() => app.dispose());
}

return cm
.app({
renderer: cm.webgl(),
width,
height
})
.on("update", update)
.call(dispose)
.start()
.node();
}
Insert cell
Insert cell
{
let fire = null;

function update(app) {
const width = app.prop("width");
const height = app.prop("height");
if (!fire) fire = createFire(width, height);
updateFire(fire);
drawFire(app, fire);
}

function dispose(app) {
invalidation.then(() => app.dispose());
}

const app = cm.app({
renderer: await cm.terminal(),
frameRate: 15
});

return app.on("update", update).call(dispose).start().node();
}
Insert cell
Insert cell
function arrow(flow, { length, x, y, rotate, angle, ...options }) {
const group = flow.append(cm.group, { x, y, rotate });
const l1 = length.map((d) => d / 2);
const l2 = length.map((d) => -d / 2);
group.append(cm.link, { x: l2, y: 0, x1: l1, y1: 0, ...options });
group.append(cm.link, {
x: 0,
y: 0,
x1: l1,
y1: 0,
rotate: angle,
transformOrigin: "end",
...options
});
group.append(cm.link, {
x: 0,
y: 0,
x1: l1,
y1: 0,
rotate: -angle,
transformOrigin: "end",
...options
});
}
Insert cell
Insert cell
{
const width = 640,
height = 240,
size = 16,
cols = width / size,
rows = height / size,
noise = cm.randomNoise(),
fields = cm
.cross(cm.range(cols), cm.range(rows))
.map(([x, y]) => ({ x, y, value: noise(y * 0.1, x * 0.1) }));

const app = cm.app({ width, height });

app
.data(fields)
.append(arrow, {
x: (d) => d.x * size + size / 2,
y: (d) => d.y * size + size / 2,
rotate: (d) => d.value,
angle: cm.constant(Math.PI / 6),
rotate: (d) => d.value,
stroke: (d) => d.value,
length: (d) => d.value
})
.transform(cm.mapAttrs, {
rotate: { range: [0, cm.TWO_PI] },
length: { range: [size * 0.3, size * 0.9] },
stroke: { interpolate: d3.interpolateViridis }
});

return app.render().node();
}
Insert cell
Insert cell
{
const app = cm.app({ width: 928, height: 500 });

app.data(alphabet).append(barY, {
x: (d) => d.letter,
y: (d) => d.frequency
});

return app.render().node();
}
Insert cell
Insert cell
Insert cell
{
const app = cm.app();
for (let i = 0; i < 500; i++) {
const x = cm.random(app.prop("width"));
const y = cm.random(app.prop("height"));
const radius = cm.randomInt(30);
const r = cm.randomInt(255);
const g = cm.randomInt(255);
const b = cm.randomInt(255);
app.append(cm.circle, {
x,
y,
r: radius,
fill: `rgb(${r}, ${g}, ${b})`
});
}
return app.render().node();
}
Insert cell
Insert cell
Insert cell
Insert cell
function createFire(width, height) {
return cm.range(height).map(() => cm.range(width).map(() => 0));
}
Insert cell
function updateFire(fire) {
const h = fire.length;
const w = fire[0].length;
const max = h;
const noise = cm.randomNoise(0, max);

for (let y = 0; y < h - 1; y++) {
for (let x = 0; x < w; x++) {
const decay = cm.randomInt(0, 3);
const spread = cm.randomInt(-1, 1);
const index = Math.min(Math.max(0, x - spread), w - 1);
const target = fire[y + 1][index];
fire[y][x] = Math.max(0, target - decay);
}
}

for (let x = 0; x < w; x++) {
fire[h - 1][x] = noise(x / 10) | 0;
}
}
Insert cell
function drawFire(app, fire) {
const max = fire.length;

app.append(cm.clear, { fill: "black" });

app
.data(fire)
.append(cm.group, { x: 0, y: (_, i) => i })
.data((d) => d)
.append(cm.point, {
y: 0,
x: (_, i) => i,
stroke0: (d) => (d === 0 ? " " : cm.randomChar()),
stroke2: (d) => (d === 0 ? null : d)
})
.transform(cm.mapAttrs, {
stroke2: {
domain: [0, max],
interpolate: d3.interpolateCool
}
});
}
Insert cell
Insert cell
Insert cell
Insert cell
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