Published
Edited
Nov 22, 2020
7 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
dodgeData = { // const dodge = (data, radius) => {
const x = d3.scaleLinear() // remove
.domain(d3.extent(data, d => d.value)) // remove
.range([margin.left, width - margin.right]) // remove
const radius2 = 7.5 ** 2; // const radius2 = radius ** 2;
const circles = data.map(d => ({x: x(d.value), data: d})).sort((a, b) => a.x - b.x);
const epsilon = 1e-3;
let head = null, tail = null;
//Returns true if cricle (x,y) intersects with any circle in the queue
function intersects(x,y) {
let a = head;
while(a) {
if (radius2 - epsilon > (a.x - x)**2 + (a.y - y)**2){
return true;
}
a = a.next;
}
return false;
}
//Place each circle sequentially
for(const b of circles) {
//Remove circles from the queue that can't intersect the new circle b
while(head && head.x < b.x - radius2) head = head.next;
//Choose the minimum non-intersecting tangent
if(intersects(b.x, b.y = 0)){
let a = head;
b.y = Infinity;
do {
let y1 = a.y + Math.sqrt(radius2 - (a.x - b.x)**2);
let y2 = a.y - Math.sqrt(radius2 - (a.x - b.x)**2);
if(Math.abs(y1) < Math.abs(b.y) && !intersects(b.x, y1)) b.y = y1;
if(Math.abs(y2) < Math.abs(b.y) && !intersects(b.x, y2)) b.y = y2;
a = a.next;
}while(a);
}
//Add b to queue
b.next = null;
if(head === null) head = tail = b;
else tail = tail.next = b;
}
return circles;
}
Insert cell
data[0]
Insert cell
data = d3.csvParse(await FileAttachment("cars-2.csv").text(), ({Name: name, Weight_in_lbs: value}) => ({name, value: +value}))
Insert cell
Insert cell
Insert cell
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