Published
Edited
Nov 23, 2020
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 Triangles
Recursive 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
function render(row = false) {
return function(data) {
return html`<div class="table" style="
flex-direction: ${row ? "row" : "column"};
/* font-size: 0.9em; */
">
${type(data, render(!row))}
</div>`;
};
}
Insert cell
function type(data, recur) {
if (data === null || data === undefined) {
return "";
} else if (data instanceof HTMLElement || data instanceof SVGElement) {
return data;
} else if (
Array.isArray(data) &&
!Array.isArray(data[0]) &&
!(data[0] instanceof HTMLElement || data[0] instanceof SVGElement) &&
typeof data[0] === "object"
) {
const keys = Object.keys(data[0]);
return [
keys.map(k => html`<b>${k}</b>`),
...data.map(d => keys.map(k => d[k]))
].map(recur);
} else if (Array.isArray(data)) {
return data.map(recur);
} else if (data instanceof Map) {
return Array.from(data).map(([key, value]) =>
recur([html`<b>${key}</b>`, value])
);
} else if (data instanceof Set) {
return Array.from(data).map(recur);
} else if (typeof data === "object") {
return Object.entries(data).map(([key, value]) =>
recur([html`<b>${key}</b>`, value])
);
} else if (typeof data === "number") {
return html`<div style="text-align: right;">${data.toFixed(2)}</div>`;
} else {
return data;
}
}
Insert cell
html`<style>
.table {
display: flex;
justify-content: space-between;
align-items: stretch;
border: 1px solid #eee;
padding: 1px;
font-size: 0.7rem;
font-family: sans-serif;
}
.table * {
flex: 1 0 0;
}
</style>`
Insert cell
Insert cell
render()([1, 2, 3])
Insert cell
render(true)([1, 2, 3])
Insert cell
render()([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
Insert cell
render(true)([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
Insert cell
render(true)([
[1, 2, 3],
[1, 2, 3, 4],
[1, 2, 3, 4, 5],
[
["alpha", "bravo"],
["charlie", "delta"],
["echo", "foxtrot"],
["golf", "hotel"]
]
])
Insert cell
render()([
{ first: "Toph", last: "Tucker", age: 30 },
{ first: "Willy", last: "Tucker", age: 28 },
{ first: "Toby", last: "Tucker", age: 12 },
{ first: "Grace", last: "Tucker", age: 6 }
])
Insert cell
render()({
name: "Toph",
numbers: new Set([1, 2, 3, 4, 5, 6, 7, 8, 9]),
props: new Map([["alive", true], ["height", `6'2"`], ["eyes", "blue"]]),
circle: svg`<svg width="10" height="10"><circle cx="5" cy="5" r="5" fill="black"/></svg>`
})
Insert cell
render()(await FileAttachment("flare-2.json").json())
Insert cell
render()(getRandomNested(5, 3, Math.random))
Insert cell
render()(
getRandomNested(4, 4, () =>
Math.random() > .5 ? Math.random() : Math.random() > .5 ? [1, 2, 3] : "Toph"
)
)
Insert cell
render()(
getRandomNested(4, 4, () =>
Math.random() > .5
? svg`<svg width="10" height="10"><circle r="5" cx="5" cy="5" fill="${"#" +
(((1 << 24) * Math.random()) | 0).toString(16)}"/></svg>`
: Math.random() > .5
? Array(Math.ceil(Math.random() * 4))
.fill(true)
.map(
() =>
svg`<svg width="20" height="20"><rect width="20" height="20" fill="${"#" +
(((1 << 24) * Math.random()) | 0).toString(16)}"/></svg>`
)
: svg`<svg width="20" height="20"><circle r="10" cx="10" cy="10" fill="${"#" +
(((1 << 24) * Math.random()) | 0).toString(16)}"/></svg>`
)
)
Insert cell
function getRandomNested(n, levels, fn) {
return Array(n)
.fill(true)
.map(levels ? () => getRandomNested(n, levels - 1, fn) : fn);
}
Insert cell
import {president} from "@tophtucker/election-2020-data"
Insert cell
render()(president.data.races[0])
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