Published
Edited
Mar 25, 2021
2 stars
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
background_textures = regl.texture(await textures.image())
Insert cell
rolled
Insert cell
html`Countries of origin for A-files in the National Archives`
Insert cell
Hilbert_Curve
Insert cell
import { Hilbert_Curve} from '@bmschmidt/hilbert-curve-layout-for-webgl'
Insert cell
import { viewof regl, H_Curve, glsl } from '@bmschmidt/webgl-h-curve'
Insert cell
Insert cell
vertex_shader = glsl`
precision highp float;

attribute float ix;
uniform float u_texture_num;
uniform float u_time;
uniform float u_max_ix;
uniform float tick;
uniform vec3 u_color;
uniform sampler2D u_color_buffer;
uniform float u_separation;
varying vec4 fill;
varying vec2 uv;

${H_Curve.value}
${Hilbert_Curve.value}

void main() {
vec2 p_null = vec2(0., 0.);
gl_PointSize = 1.8;
float relative_pos = ix - floor(u_max_ix/2.);
${curve === "Hilbert Curve" ? " vec2 pos = (Hilbert_Curve(ix) * vec2(1., -1.) - p_null)/ sqrt(u_max_ix) * 2.7 - vec2(.99, -0.99);" : "vec2 pos = (H_Curve(relative_pos) - p_null)/ sqrt(u_max_ix) * 3.2 - vec2(.99, -.99);"}

gl_Position = vec4(pos.x, pos.y, 0., 1.);
float prop_through = ix / u_max_ix;
float offset = -fract(u_time / 5.);
fill = vec4(u_color.rgb, 1.);

uv = (pos + 1.) / 2.;
float a = floor(mod(u_texture_num, 4.)) / 4.;
float b = floor(u_texture_num / 4.) / 4.;
uv = uv / 4. + vec2(a, b);
}
`
Insert cell
colorscheme = regl.texture(canvas)
Insert cell
canvas = {
// This actual canvas is shunted to regl to use as the colorscale texture, which is kinda nifty.
// const width = 512
const canvas = DOM.canvas(width, 20)
const ctx = canvas.getContext("2d")
for (let i = 0; i < width; i++) {
ctx.fillStyle = d3.interpolateSinebow(i/width)

ctx.fillRect(i, 0, 1, 20)
}
return canvas
}
Insert cell
drawPoints = {
const regl_params = {

depth: { enable: false },
stencil: { enable: false },
blend: {
enable: true,
func: {
srcRGB: 'one',
srcAlpha: 'one',
dstRGB: 'one minus src alpha',
dstAlpha: 'one minus src alpha',
},
},
frag: fragment_shader.value,
vert: vertex_shader.value,
attributes: {
ix: {
buffer: points,
stride: 4,
offset: (_, {offset}) => offset * 4
},
},
uniforms: {
// tick: ({ tick }) => tick,
u_max_ix: n_points,
u_boust: 1, // Left older from previous version
u_time: regl.context("time"),
u_aspect_ratio: 1,
u_color_buffer: colorscheme,
u_color: regl.prop("color"),
u_separation: 0,
u_texture_map: background_textures,
u_texture_num: regl.prop("texture_num"),
},
// specify the number of points to draw from the buffer.
count: (_, {count}) => {return count},
primitive: regl.prop("primitive")
}

return regl(regl_params)
}
Insert cell
points = {
const floats = new Float32Array(d3.sum(data.map(d => d.count)))
for (let i = 0; i <= floats.length; i++) {
floats[i] = i;
}
return regl.buffer(floats)
}
Insert cell
data = FileAttachment("data.json").json()
Insert cell
n_points = d3.sum(data, d => d.count)
Insert cell
rolled = {
data.sort((a, b) => b.count - a.count)
const field = "country"
const entries = -1
let i = 0
let start = 0
let current
let rolled = []
while (i < N) {
current = data[i]
const html_color = colors(current[field])
const {r, g, b} = d3.rgb(html_color)
const color = [r/255, g/255, b/255];
rolled.push({
label: current[field],
count: current.count,
start: start,
color,
html_color
})
start += current.count
i++
}
let other_count = 0
while (i < data.length) {
other_count += data[i].count
i++
}
const html_color = colors("Other")
const {r, g, b} = d3.rgb(html_color)
const color = [r/255, g/255, b/255];
rolled.push({
label: "Other",
count: other_count,
start: start,
color,
html_color
})
return rolled
}
Insert cell
colors = d3.scaleOrdinal(d3.schemeSet1)

Insert cell
Type JavaScript, then Shift-Enter. Ctrl-space for more options. Arrow ↑/↓ to switch modes.

Insert cell
draw_tick = {
const tick = regl.frame(({time}) => {
// clear contents of the drawing buffer
let i = 0
regl.clear({
color: [0, 0, 0, 0],
depth: 1
})
for (let d of rolled) {
// console.log(d.count)
// Use only some of the textures; 13 is prime.
drawPoints({count: d.count, color: d.color, offset: d.start, primitive: "points", texture_num: i++ % 13})
}
/*
fbo.use( () => {
regl.clear({
color: [0, 0, 0, 0],
depth: 1
})
drawPoints({points: z.points, rounded_points: Math.round(z.points), primitive: z.primitive})
})
drawPoints({points: z.points, rounded_points: Math.round(z.points), primitive: z.primitive})

copy_from_fbo(fbo)
})
*/
})
invalidation.then(() => tick.cancel())
}
Insert cell
import { Range, Radio } from '@observablehq/inputs'
Insert cell
import {aq, op, repr } from '@bmschmidt/a-files'
Insert cell
d3 = require("d3@v6")
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