Public
Edited
Oct 9, 2024
45 forks
220 stars
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
margin = ({
left: 20,
bottom: 20,
right: 60,
top: 10
});
Insert cell
height = width * .5;
Insert cell
chartWidth = width - margin.left - margin.right;
Insert cell
chartHeight = height - margin.top - margin.bottom;
Insert cell
Insert cell
xScale = d3.scaleTime()
.domain([new Date(2010, 0, 1), new Date(2010, 3, 1)])
.range([0, chartWidth]);
Insert cell
yScale = d3.scaleLinear()
.domain([0, 20])
.range([chartHeight, 0]);
Insert cell
Insert cell
xAxisGenerator = d3.axisBottom(xScale)
.tickValues(d3.range(0, 4).map(d => new Date(2010, d, 1)));
Insert cell
yAxisGenerator = d3.axisLeft(yScale)
.tickValues(d3.range(0, 30, 5));
Insert cell
lineGenerator = d3.line()
.x(d => xScale(d.date))
.y(d => yScale(d.value));
Insert cell
Insert cell
Insert cell
fruits = d3.csv("https://gist.githubusercontent.com/HarryStevens/2ca674b53b0ea1ab806a3e704386c4c9/raw/3828df9890fbe0ff8b5259e2e3f9ebd1d38984bc/fruits.csv");
Insert cell
data = parseData(fruits)
Insert cell
lineData = parseLineData(data)
Insert cell
flatData = parseFlatData(data)
Insert cell
voronoiData = {
const v = [...new d3.Delaunay((flatData.map(d => [xScale(d.date), yScale(d.value)])).flat()).voronoi([0, 0, chartWidth, chartHeight]).cellPolygons()];
for (let i = 0, l = v.length; i < l; i++){
v[i].data = flatData[i];
}
return v;
}
Insert cell
largestVoronoiData = parseLargestVoronoi(flatData, voronoiData)
Insert cell
colors = ({
Apples: {
light: "#fb9a99",
dark: "#e31a1c"
},
Blueberries: {
light: "#a6cee3",
dark: "#1f78b4"
},
Carrots: {
light: "#fdbf6f",
dark: "#ff7f00"
},
})
Insert cell
Insert cell
parseData = data => {
const output = [];
for (let i = 0, l = data.length; i < l; i++){
let d = data[i],
o = {},
s = d.Date.split("/"),
yyyy = +("20" + s[2]),
mm = s[0] - 1,
dd = +s[1];

o.date = new Date(yyyy, mm, dd);

for (let col in d){
if (col !== "Date"){
o[col] = +d[col];
}
}
output.push(o);
}
return output;
}
Insert cell
parseLineData = data => {
const output = [];
let i = 0;
for (let col in data[0]){
if (i > 0) {
let o = {
key: col,
light: colors[col].light,
dark: colors[col].dark,
data: []
};
for (let i0 = 0, l0 = data.length; i0 < l0; i0++){
let d0 = data[i0];
o.data.push({
date: d0.date,
value: d0[col]
});
}
output.push(o);
}
i++;
}
return output;
}
Insert cell
parseFlatData = data => {
const output = [],
columns = [];
let i = 0;
for (let col in data[0]){
columns.push(col);
if (i > 0) {
for (let i0 = 0, l0 = data.length; i0 < l0; i0++){
let d0 = data[i0];
output.push({
date: d0.date,
value: d0[col],
key: col,
colors: colors[col]
});
}

}
i++;
}
output.columns = columns;
return output;
}
Insert cell
parseLargestVoronoi = (flatData, voronoiData) => {
let output = {};
for (let i = 1, l = flatData.columns.length; i < l; i++){
output[flatData.columns[i]] = {area: 0}
}
for (let i = 0, l = voronoiData.length; i < l; i++){
let o = {},
cell = voronoiData[i],
area = geometric.polygonArea(cell),
key = cell.data.key;
if (area > output[key].area){
output[key].centroid = geometric.polygonCentroid(cell);
output[key].point = [xScale(cell.data.date), yScale(cell.data.value)];
output[key].angle = geometric.lineAngle([output[key].point, output[key].centroid]);
output[key].area = area;
output[key].polygon = cell;
output[key].colors = colors[key];
}
}
let output2 = [];
for (let key in output){
output[key].key = key;
output2.push(output[key]);
}
return output2;
}
Insert cell
last = array => array[array.length - 1]
Insert cell
Insert cell
import {toc} from "@harrystevens/toc@129"
Insert cell
geometric = require("geometric@2");
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