mpkhindaJul 17
Football ProjectionsObservable – 17 Jul 26
The Global Game
Heavily derived from Mike Bostock's notebook on Map Projections this notebook projects a standard soccer ball pattern. Appendix
As I’ve been watching the World Cup over the past few weeks I think we’ve all been wondering the same thing: If football is truly the ‘global game,’ then what projection should I use to flatten it?
So, I forked Mike Bostock’s very helpful notebook on the Tissot Indicatrix and replaced the circles with a classic football pattern (truly, his notebook did all of the hard work). Then I picked my 7 favorite projections and turned it into a poster which I printed in fluorescent ink on a Risograph machine.
This was my first time using Observable in a print project but it certainly won’t be the last!
I also posted a little detail shot on Bluesky if you want to see the print close up
1 post - 1 participant
Read full topic
nxrixJul 9
Repeating pattern creatorObservable – 8 Jul 26
Bitmask Fractals
Generated by repeatedly sampling a binary pattern at exponentially increasing scales. Pattern Color
I always had this idea in mind and finally made it easily with Observable, and I like Observable mostly for these reasons:
Everything updates in real time.
You can create and edit notebooks on your phone.
Many useful things are already built in (inputs, imports, …).
2 posts - 2 participants
Read full topic
gorillabiscuitJul 7
Adaptive piecewise scale — keeping outliers on screen without crushing the dataMost real-world financial/count data is lopsided: 80%+ of the values bunch into a narrow band, then a handful of outliers run one or two orders of magnitude past them. Small business loans, property sales, citation counts, earthquake energy — same shape every time. Linear crushes the cluster into a pixel-wide sliver against the outliers. Log fixes the outliers but distorts the cluster’s internal structure and can’t handle zero or negatives.
scaleAdaptive splits the domain into three regions instead: a log tail on each side of a linear “focus window” that holds the dense cluster. The interesting part is the boundary — naively joining a log scale to a linear scale produces a visible kink, because the two scales’ slopes don’t match at the seam. So the tail’s symlog constant is solved numerically (bisection over ~80 iterations) so its slope at the boundary equals the window’s linear slope. The transition ends up C¹-continuous — no kink, no visual seam, even though the underlying math is two completely different scale types.
A few other things it does that I haven’t seen in other outlier-scale approaches:
The window is draggable and pannable, and it’s capped so it can never slide far enough to swallow an outlier tail entirely — that’s a structural guarantee (a pixel-reserve system), not a “please don’t drag too far” heuristic.
Clicking a log tail “travels” the focus window onto it — the data that was compressed becomes the new cluster, and the old cluster becomes the tail. Useful for exploring a dataset that has outliers on both sides at very different scales.
It implements the full d3 continuous-scale contract (domain, range, ticks, tickFormat, nice, clamp, unknown, invert, copy), so it drops into d3.axisBottom like any other scale.
86 tests covering four invariants: monotonicity, invertibility, boundary continuity, and graceful degradation (no outliers → it’s just scaleLinear).
Live notebook: https://observablehq.com/d/ea148faa812f43c9 — try dragging the window or clicking a tail on the real dataset (600 SBA small-business loans, $5k–$5M).
npm install d3-scale-adaptive (npm, source).
If anyone wants the longer story of how this evolved — including a hatch-texture experiment I built and then mostly abandoned, and a few genuinely bad ideas along the way — I wrote it up When Linear and Log Both Fail: An Adaptive D3 Scale — Wouter Schreuders, but everything above is the whole technique.
1 post - 1 participant
Read full topic
tomlarkworthyJul 7
The Plugin Registry PatternWhen building extensible things I want the extenders to be decoupled from the extender, as I do not know how many extensions will be built apriori and I want 3rd parties to be able to extend so its not possible to import all extensions upfront. So far I used to do this with a simple viewof inputs(new Set()) in the extendable which works pretty well. Extenders inject their plugin into the set and trigger a reactive update so now the extendee can reactively trigger a refresh using the new functionality. However, over time I also want to replace the extendee with a new implementation e.g. I have had exporter, exporter-2 and exporter-3 over time. Then it becomes bad that all the extendees have to reference the thing they are extending. Its the same kind of coupling the other way that only bites much later.
My solution is to decouple both sides via a centralized named plugin repository. Bonus is we can provide a nicer API than raw viewof wrangling. The plugin system manages all N x M plugin sets once and forall!
Observable – 6 Jul 26
Plugin Registry
A foundational notebook for decoupled plugin wiring: \`plugins\` maps a name to a set of values.
N providers add values under a name; M consumers read that name's set as a live Generator. Neither side
references the other — they meet only at the...
3 posts - 2 participants
Read full topic