Published
Edited
Jan 26, 2022
15 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é Picker
Concentration of Measure
Divide SeriesMultiply SeriesMultiplication and Division by Similar TrianglesRecursive typed table (sketch!)Lorenz CurveThe “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
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
// Slider with title and numeric value, to be used with synchronized views
slider = ({ min, max, step, view, title }) =>
html`<form class="sync">
<div>${title}</div>
${view.bind(html`<input
type=range
min="${min}"
max="${max}"
step="${step}"
>`)}
${view.bind(html`<input
type="number"
readonly
class="readonly"
>`)}
</form>`
Insert cell
viewof radius = new View(2)
Insert cell
viewof dimension = new View(1)
Insert cell
Insert cell
w = Math.min(640, width)
Insert cell
color = d3.interpolateRdBu
Insert cell
data = getPoints(dimension, radius)
Insert cell
Insert cell
volumeOverRadius = [
[0, 0],
...d3
.pairs(d3.range(0, radius + 0.11, 0.1))
.map(([r0, r1]) => [
r0 / radius,
(volume(r1, dimension) - volume(r0, dimension)) /
volume(radius, dimension)
])
]
Insert cell
groupedPoints = d3.groups(
data.map(d => distance(d) / radius).filter(d => d <= 1),
d => d
)
Insert cell
Insert cell
// For when you may get very close to 0 and 100%, and the distinction remains important, this shows percentages with just enough precision to distinguish them from those extremes
format = n => {
const f = d3.format(".0%")(n);
const p = n * 100;
const closenessTo1 = Math.abs(Math.floor(Math.log10(100 - p)));
const closenessTo0 = Math.abs(Math.floor(Math.log10(p)));
return n === 0 || n === 1
? f
: f === "100%"
? p.toFixed(Math.min(closenessTo1, 100)) + "%"
: f === "0%"
? p.toFixed(Math.min(closenessTo0, 100)) + "%"
: f;
}
Insert cell
r = d => d * 20
Insert cell
arc = d3.arc()({
innerRadius: r(range[0]),
outerRadius: r(range[1]),
startAngle: 0,
endAngle: 2 * Math.PI
})
Insert cell
circleRange = svg`<svg
width="${r(1) * 2}"
height="${r(1) * 2}"
style="margin: 5px;"
>
<g transform="translate(${r(1)}, ${r(1)})">
<circle r="${r(1)}" fill="hsl(0, 0%, 80%)" />
<path d="${arc}" fill="#3b99fc" stroke="white"/>
</g>
</svg>`
Insert cell
tableData = [...d3.range(1, 10), ...d3.range(10, 101, 10)].map(dim => [
dim,
(volume(range[1], dim) - volume(range[0], dim)) / volume(1, dim)
])
Insert cell
html`<style>
input.readonly {
border: none;
padding: none;
font-family: sans-serif;
font-size: inherit;
width: 2em;
pointer-events: none;
}
form.sync {
font-family: sans-serif;
font-size: 12px;
display: flex;
align-items: center;
}
form.sync div:first-child {
margin-right: 1em;
width: 60px;
}
form.sync div:last-child {
margin-left: 1em;
}
form.sync input {
width: 200px;
}
</style>`
Insert cell
// Header illustration
getIllo = () => {
const w = width + 28,
h = 250;
const context = DOM.context2d(w, h, 1);
const getRandomColor = () => `hsl(${Math.random() * 360},50%,50%)`;

context.canvas.style.margin = "0 -14px 0 -14px";
context.canvas.style.position = "relative";
context.canvas.style.zIndex = "-1";
context.canvas.style.imageRendering = "pixelated";
context.globalCompositeOperation = "xor";

const data = d3.range(3).map(d => ({
cx: d3.randomUniform(w * 0.7, w * 0.9)(),
cy: d3.randomUniform(h * 0.2, h * 0.8)(),
r: (Math.random() * h) / 6,
c: getRandomColor(),
t0: 0
}));

let dr = 4;
d3.timer(t => {
if (t > 2000) return true;
data.forEach(d => {
if (t < d.t0) return;
context.strokeStyle = d.c;
context.beginPath();
context.arc(d.cx, d.cy, d.r, 0, Math.PI * 2);
context.stroke();
d.r += dr;
dr *= 0.95;
});
});

return context.canvas;
}
Insert cell
Insert cell
import {distance, getPoints, volume} from "@tophtucker/theres-plenty-of-room-in-the-corners"
Insert cell
import { View } from "@mbostock/synchronized-views"
Insert cell
import {tweet} from "@mbostock/tweet"
Insert cell
import { legend, ramp } from "@d3/color-legend@704"
Insert cell
import { rangeInput } from "@mootari/range-slider"
Insert cell
d3 = require("d3")
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