Public
Edited
Oct 9
44 forks
219 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

One platform to build and deploy the best data apps

Experiment and prototype by building visualizations in live JavaScript notebooks. Collaborate with your team and decide which concepts to build out.
Use Observable Framework to build data apps locally. Use data loaders to build in any language or library, including Python, SQL, and R.
Seamlessly deploy to Observable. Test before you ship, use automatic deploy-on-commit, and ensure your projects are always up-to-date.
Learn more