Published
Edited
Apr 11, 2022
1 fork
Importers
3 stars
Food clockDisambiguating selection in a 2D treePerceptually more-uniform diverging color scatterplotDays since a U.S. President was last shotSingle-serving sitesDo you feel old?Dynamic scales deprive dashboards of institutional memoryNesting chevron pillsColumnar group byDe Moivre by generatorsShowing ESPN Receiver Tracking Metrics using weighted radar chartsCombine consecutive stringsDollar spectrumThe Feedback BathtubIs Visnu’s hex random?Dual axes are a great way to show correlation 🔥Promise.raceHealthcare plan payoff curvePlot image beeswarmGenerations on Google TrendsFor i of myriadChatterjee correlationChecking invariance of round trip-0 and 0Norms and central tendencyDisordering ULsData-driven table sort iconPlot: weather with sunrise and sunsetRecreating Östling’s regression visualizationsMixing knowledge and random guessesHow many five digit numbers are prime?Warping gridspaceSampling moodLow IDsTesting for OmicronAll Too WellDistance from square root to nearest factorSuper BogosortParrots of Telegraph HillNudibranch sightingsDecimal watershedsFirst Ladies of the United StatesEval-in-PlaceClassic Research in Data VisualizationResponsive PrettierObsv, obvsGenerating All Natural NumbersDaily Café PickerConcentration of MeasureDivide SeriesMultiply SeriesMultiplication and Division by Similar TrianglesRecursive typed table (sketch!)
Lorenz Curve
The “Select cells” buttonRecursive viewof testBubble Map RaceSensitivity and Specificity (sketch)Reactive transition sketchHow to crash ObservableSpilhaus World TourSimpson’s paradox: CalendarsThe Cauchy DistributionEmoji frequenciesThe Man Comes AroundNot what I meant to doSVG numeral sketchesRSAMandelbrot’s binomial time bending??Re: “Can Moons Have Moons?”Continuous cursorParenthesis matching with vertical offsetsA filter icon that shows filtering instead of funnelingFlag of the Popular VoteFlag of the Popular VoteFlag of the Popular VoteTrailing zeroes in factorialsBitcoin fractal bubbles (animated)Bitcoin fractal bubbles
Insert cell
Insert cell
Insert cell
chart = {
const svg = d3.create("svg").attr("viewBox", [0, 0, width, height]);

svg.append("g").call(xAxis);

svg.append("g").call(yAxis);

svg
.append("path")
.attr("d", `M ${x(0)} ${y(0)} L ${x(1)} ${y(1)}`)
.attr("stroke", "#ccc")
.attr("stroke-dasharray", "3 4");

svg
.append("g")
.attr("fill", "none")
.selectAll("path")
.data(groups)
.join("path")
.attr("d", d => line(d[1].curve))
.attr("stroke", d => color(d[1].gini))
.call(halo);

return svg.node();
}
Insert cell
gini = arr =>
d3.sum(d3.cross(arr, arr, (a, b) => Math.abs(a - b))) /
(2 * arr.length ** 2 * d3.mean(arr))
Insert cell
// Table A4, “Mean Household Income of Quintiles” from
// https://www.census.gov/data/tables/2019/demo/income-poverty/p60-266.html
data = {
const csv = d3.csvParse(
await FileAttachment("usa gini - table a4.csv").text(),
d3.autoType
);
const [variable, ...rest] = csv.columns;
return csv.flatMap(quintile =>
rest.map(year => ({
group: year,
item: quintile[variable],
value: quintile[year]
}))
);
}
Insert cell
groups = d3.rollups(
data,
d => {
const sorted = d.map(d => d.value).sort(d3.ascending);
return {
curve: [0, ...d3.cumsum(sorted)].map((d, i, arr) => [
i / (arr.length - 1),
d / arr[arr.length - 1]
]),
gini: gini(sorted)
};
},
d => d.group
)
Insert cell
xTitle = "Percentage of items"
Insert cell
yTitle = "Percentage of total value"
Insert cell
x = d3.scaleLinear().range([margin.left, width - margin.right])
Insert cell
y = d3.scaleLinear().range([height - margin.bottom, margin.top])
Insert cell
// You could smooth with `.curve(d3.curveMonotoneX)`
// but it may mislead, making coarse data look too fine.
line = d3
.line()
.x(d => x(d[0]))
.y(d => y(d[1]))
// .curve(d3.curveMonotoneX)
Insert cell
xAxis = g =>
g
.attr("transform", `translate(0,${height - margin.bottom})`)
.call(
d3
.axisBottom(x)
.ticks(width / 80)
.tickFormat(pct)
)
.call(g => g.select(".domain").remove())
.call(g =>
g
.append("text")
.attr("x", width)
.attr("y", margin.bottom - 4)
.attr("fill", "currentColor")
.attr("font-weight", "bold")
.attr("text-anchor", "end")
.text(xTitle)
)
Insert cell
yAxis = g =>
g
.attr("transform", `translate(${margin.left},0)`)
.call(d3.axisLeft(y).tickFormat(pct))
.call(g => g.select(".domain").remove())
.call(g =>
g
.append("text")
.attr("x", -margin.left)
.attr("y", 10)
.attr("fill", "currentColor")
.attr("text-anchor", "start")
.attr("font-weight", "bold")
.text(yTitle)
)
Insert cell
color = d3.scaleSequential(
d3.extent(groups.map(d => d[1].gini)),
d3.interpolateWarm
)
Insert cell
margin = ({top: 25, right: 20, bottom: 35, left: 40})
Insert cell
height = width
Insert cell
pct = d3.format(".0%")
Insert cell
// from https://observablehq.com/@d3/connected-scatterplot
// notice that this introduces a distortion: lines drawn later are more prominent
function halo(path) {
path
.select(function() {
return this.parentNode.insertBefore(this.cloneNode(true), this);
})
.attr("fill", "none")
.attr("stroke", "white")
.attr("stroke-width", 4)
.attr("stroke-linejoin", "round");
}
Insert cell
d3 = require("d3@5", "d3-array@2")
Insert cell
import { legend } from "@d3/color-legend"
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