Public
Edited
Nov 24, 2022
Paused
2 stars
Insert cell
Insert cell
studio(nuggets.cooked) // very very latest 2 3 df
Insert cell
studio(nuggets.raw)
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
palette = d3.schemeCategory10
Insert cell
Insert cell
nuggets = ({ // a Nugget is data plus its accessors

// time needed to execute 1e5 times on a iMac Late 2015 with macOS Monterey 12.6
// cooked is 1.5 times faster than raw
// see later in this notebook
// use palette as is; requires on-the-fly calculations
raw: { // 6400+ ms
data: palette,
fill: (_, i) => palette[i % palette.length],
position: (_, i) => position(i),
},
// turn palette it into a list of objects holding a `Dot`;
cooked: { // 4300+ ms
data: palette.map((color, i) => ({color, position: position(i)})),
fill: point => point.color,
position: point => point.position,
},
})
Insert cell
Insert cell
// const width = 1152;
// interface Aspect {
// wide: number,
// tall: number
// }
// interface Size {
// x: number,
// y: number,
// width: number,
// height: number,
// }
// interface Geometry {
// aspect: Aspect,
// width: number,
// height: number,
// size: Size,
// viewBox: Array<number>,
// }
// const aspect: Aspect = {wide: 16, tall: 9};
// const height = width * aspect.tall / aspect.wide;
// const size: Size = {
// x: -width / 2,
// y: -height / 2,
// width,
// height,
// }
// const geometry: Geometry = {
// aspect: {wide: 16, tall: 9},
// width,
// height,
// size,
// viewBox: Object.values(size),
// }

geometry = {
const aspect = {wide: 16, tall: 3};
const height = width * aspect.tall / aspect.wide;
const size = ({x: -width / 2, y: -height / 2, width, height});
return ({
aspect,
width,
height,
size,
viewBox: Object.values(size),
});
}
Insert cell
Insert cell
artists = [
crosshairs({stroke:"red"}), // must at least contain {}
dotter,
]
Insert cell
Insert cell
Insert cell
position = absolutePosition(palette)(settings)
Insert cell
// yearns for Points, Settings, and index (relative position)
// returns absolute position

absolutePosition =
CURRY(
(
{length}, // from Points
{spacing, shift}, // from Settings
i, // relative position of element
) =>
(
i + // relative position plus…
((shift - 1) / 2) // projects [-1, +1] to [-1, 0] so -1/2 centers the whole
* (length - 1) // total span: number of gaps
)
* spacing // absolute position
)
Insert cell
Insert cell
// takes Geometry, Settings, Artists, and Nugget
// sets up new Pad
// yearns for Nugget
// calls each Artist, passing on Geometry, Settings, and Nugget
// returns Pad’s node

studio =
CURRY(
(
geometry,
settings,
artist,
nugget,
) =>
{

const {width, height, viewBox} = geometry;

const pad = d3
.create("svg")
.attr("width", width)
.attr("height", height)
.attr("viewBox", viewBox)
;

artists.forEach((artist) => pad.call(artist(geometry)(settings)(nugget)));

return pad.node();

}
)(geometry)(settings)(artists)
Insert cell
Insert cell
// type: Artist
// takes Options, Geometry, Settings (unused), Nugget (unused), and Pad
// side effect: draws the axes on Pad

crosshairs =
CURRY(
(
{stroke = "steelblue", strokeWidth = .5, strokeDasharray}, // from Options
{size: {x, y, width, height}}, // from Geometry
settings,
nugget,
pad
) =>
{
pad
.append("path")
.attr("d", `M${x} 0h${width}M0 ${y}v${height}`)
.attr("stroke", stroke)
.attr("stroke-width", strokeWidth)
.attr("stroke-dasharray", strokeDasharray)
;
}
)
Insert cell
// type: Artist
// takes Geometry, Settings, Nugget, and Pad
// side effect: creates a corresponding circle on Pad for Points in Nugget

dotter =
CURRY(
(
geometry, // Geometry unused
{orientation, radius}, // from Settings
{data, fill, position}, // from Nugget
pad
) =>
{
pad
.selectAll("circle")
.data(data)
.join("circle")
.attr("r", radius)
.attr("fill", fill)
.attr(`c${orientation}`, position)
;
}
)
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
ƒ = (name) => `<code>[${name}](#${name})</code>`
Insert cell
R = require("ramda")
Insert cell
CURRY = R.curry
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