Public
Edited
Apr 14, 2021
Insert cell
md`# Copper Diamond`
Insert cell
chart = {
const svg = d3.create('svg')
.attr('viewBox', [0, 0, width, height]);
buildCircles(svg, topData, topY);
buildCircles(svg, bottomData, bottomY);
return svg.node();
}
Insert cell
function buildCircles(svg, data, y) {
let x = deltaX / 2;
for(let i = 0; i < data.length; i++) {
let g = svg.append('g');
let simulation = d3.forceSimulation(data[i])
.force('charge', d3.forceManyBody().strength(0))
.force('collision', d3.forceCollide().radius(radius + spacing))
.force('x', d3.forceX().x( x ))
.force('y', d3.forceY().y( (d) => y(d['Happiness Score']) ))
simulation.on('tick', () => {
let item = g
.selectAll('circle')
.data(data[i])

item.join('circle')
.attr('r', radius)
.style('opacity', 0.5)
.merge(item)
.attr('cx', d => d.x)
.attr('cy', d => d.y)
})
x += deltaX;
}
}
Insert cell
deltaX = (width - margin.left - margin.right) / data.length;
Insert cell
bottomY = d3.scaleLinear()
.domain(d3.extent(bottomData.flat(), d => d['Happiness Score']))
.range([height - margin.bottom, (height / 2) + halfMiddleSize]);
Insert cell
topY = d3.scaleLinear()
.domain(d3.extent(topData.flat(), d => d['Happiness Score']))
.range([(height / 2) - halfMiddleSize, margin.top]);
Insert cell
bottomData = data.map(d => d.filter(d2 => d2['Happiness Score'] < 5))
Insert cell
topData = data.map(d => d.filter(d2 => d2['Happiness Score'] > 5))
Insert cell
data = await FileAttachment("alice-in-wonderland-hedonometer.json").json()
Insert cell
halfMiddleSize = (height * middlePercent) / 2
Insert cell
middlePercent = 0.1
Insert cell
spacing = 2
Insert cell
radius = 3
Insert cell
height = 800
Insert cell
margin = ({top: 10, right: 10, bottom: 10, left: 10})
Insert cell
d3 = require('d3@6')
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