Public
Edited
Oct 24, 2023
7 forks
Importers
68 stars
Insert cell
Insert cell
Insert cell
population2radius = d3.scaleSqrt() // instead of scaleLinear()
.domain([0, 2e9])
.range([0, 300])
Insert cell
population2radius(1.386e9) // China’s 1.386 billion citizens are represented by a circle of radius = 250px
Insert cell
population2radius(127e6) // Japan’s population of 127 millions is represented by a circle of radius = 76px
Insert cell
population2radius(427e3) // Brunei shows up as a small circle
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
{
const color = d3.scaleOrdinal(d3.schemePaired.slice(7));

const strokeWidth = 8;

const population2radius = d3.scaleSqrt()
.domain([0, 2e9])
.range([0 + strokeWidth / 2, 300 + strokeWidth / 2]); // 🌶

return svg`<svg width=${width} height=200px stroke-width=${strokeWidth} stroke=#ddd>
<g transform="translate(50,100)" style="text-anchor: middle; font-family: sans-serif; font-weight: bold;">
<circle r=${population2radius(427e3)} cx=20 fill="${color("Brunei")}" />
<text dx=20 dy=${-10 - strokeWidth / 2} stroke=none fill=#555>Brunei</text>
<circle r=${population2radius(56.72e6)} cx=220 fill="${color("China")}" />
<text dx=220 fill="white" stroke=none>S. Africa</text>
<circle r=${population2radius(127e6)} cx=500 fill="${color("Japan")}" />
<text dx=500 fill="white" stroke=none>Japan</text>
</g>
</svg>`;
}
Insert cell
Insert cell
Insert cell
{
const values = [5, 20, 50, 100]; // hint: add 0 in this array…

const scale = d3.scaleSqrt()
.domain([0, d3.max(values)])
.range([1, 100]); // … then change 1 to 0

return svg`<svg width=${width} height=230px><g transform="translate(200,10)">
${values.map(
v =>
svg`<g><circle cy="${200 - scale(v)}"
r="${scale(v)}" stroke=black fill=none />
<text y="${200 - 2 * scale(v) + 3}"
style="dominant-baseline: hanging; text-anchor: middle;"
>${v}</text>
</g>`
)}</g></svg>`;
}
Insert cell
Insert cell
visualizeScale(d3.scaleSqrt())
Insert cell
Insert cell
Insert cell
Insert cell
visualizeScale(d3.scaleSqrt().domain([-1, 1]))
Insert cell
Insert cell
visualizeScale(
d3.scaleSqrt()
.domain([-400, -100, 0, 400])
.range([0, 1, 10, 15])
)
Insert cell
Insert cell
visualizeScale(
d3.scaleSqrt()
.domain([-100, 100])
.rangeRound([-10, 10])
)
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
paint = d3.scalePow()
.exponent(k)
.range(["yellow", "red"])
Insert cell
Insert cell
Insert cell
visualizeScale(d3.scalePow().exponent(1 / 3))
Insert cell
Insert cell
visualizeScale(
d3.scalePow()
.exponent(1.2)
.range([0.0999, 1])
)
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
// adapted from http://lasp.colorado.edu/~bagenal/MATH/math0.html#tables
objects = [
{ name: "Milky Way Galaxy", size: 1e18 }, // sizes in km
{ name: "Nearest Star", size: 1e13 },
{ name: "The Solar System", size: 1e9 },
{ name: "The Sun", size: 1e6 },
{ name: "The Earth", size: 1e3 },
{ name: "A Mountain", size: 75 },
{ name: "A Human", size: 1e-3 },
{ name: "A Cell", size: 1e-8 },
{ name: "An Atom", size: 1e-12 },
{ name: "A Proton", size: 1e-15 }
]
Insert cell
scaleUniverse = d3.scaleLog().domain([1e-15, 1e20])
Insert cell
Insert cell
Insert cell
Insert cell
scaleBinary = d3.scaleLog()
.base(2)
.domain([16, 2 ** 20])
Insert cell
Insert cell
Insert cell
d3.scaleLog().domain([-100, -1])(-10)
Insert cell
Insert cell
powers = d3.scaleLog().domain([0.01, 100000])
Insert cell
// by default, ticks are displayed in scientific notation (SI)...
visualizeTicks(powers)
Insert cell
// ... but you can pass explicit format to ticks
// see https://d3js.org/d3-format#locale_format
visualizeTicks(powers, [5, "~g"])
Insert cell
Insert cell
Insert cell
binaryScale = d3.scaleLog()
.base(2)
.domain([1, 32])
Insert cell
visualizeTicks(
binaryScale,
[10, "b"] // 💡 see https://d3js.org/d3-axis#axis_ticks
)
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
days = [
// l: label ; v: value
{ l: "The Big Bang", v: -13.8e9 * 365.24 },
{ l: "Dinosaur extinction", v: -65e6 * 365.24 },
{ l: "The founding of Rome", v: -(800 + 2019) * 365.24 },
{ l: "Last year", v: -365 },
{ l: "Yesterday", v: -1 },
{ l: "Now", v: +0 },
// { l: "In 2 hours", v: +2 / 24 },
{ l: "Tomorrow", v: +1 },
{ l: "Next year", v: +365 },
{ l: "2100", v: +365.24 * 91 },
{ l: "Asimov’s Foundation", v: +12000 * 365.24 },
{ l: "Sun dies", v: 6e9 * 365 }
]
Insert cell
{
const scale = d3.scaleSymlog()
.domain(d3.extent(days, d => d.v))
.constant(0.1) // try 0.01 to leave room for "in 2 hours"
.range([width * 0.05, width * 0.95]);

const svg = d3.create("svg")
.attr("width", width)
.attr("height", 100)
.attr("style", "text-anchor:middle; font-family: sans-serif; font-size:12px");

svg.append("line")
.attr("x1", scale.range()[0])
.attr("x2", scale.range()[1])
.attr("y1", 50)
.attr("y2", 50)
.attr("stroke", "#999");
const g = svg.selectAll("g")
.data(days)
.join("g")
.attr("transform", d => `translate(${scale(d.v)}, 50)`);

g.append("circle")
.attr("r", 4)
.attr("fill", d => (d.l === "Now" ? "red" : "black"));
g.append("text")
.attr("y", (_, i) => -8 + 30 * (i % 2))
.attr("dx", 3)
.text(d => d.l);

return svg.node();
}
Insert cell
Insert cell
paintRgb = d3.scaleSqrt()
.range(["blue", "red"])
.interpolate(d3.interpolateHsl)
Insert cell
paintHsl = paintRgb.copy()
.interpolate(d3.interpolateHslLong)
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
radius = d3.scaleSqrt([0, 100], [0, 30])
Insert cell
radius(-1e-6) // 🕷 if this is used as a circle’s radius, it might create a bug
Insert cell
{
const clamped = d3.scaleSqrt([0, 100], [0, 30]).clamp(true);
return clamped(-1e-6); // 👍 fixed !
}
Insert cell
radius.clamp() // read the clamping state.
Insert cell
Insert cell
x = d3.scaleLinear([0, 1], [60, width * 0.95]).unknown(10)
Insert cell
values = Array.from({ length: 100 }, (_, i) => i % 10 === 0 ? NaN : Math.random())
Insert cell
Insert cell
Insert cell
function visualizeScale(scale) {
const w = Math.min(600, width),
h = 300,
m = width > 599 ? 30 : 10;
const x = d3.scaleLinear()
.domain(d3.extent(scale.domain()))
.nice()
.range([m, w - m]),
y = d3.scaleLinear()
.domain(d3.extent(scale.range()))
.nice()
.range([h - m, m]),
svg = d3.create("svg")
.attr("width", width + 20)
.attr("height", h + 20),
g = svg.append("g"),
line = [];

for (let i = m + 1e-6; i < w - m; i += 1) {
const X = x.invert(i),
Y = scale(X),
j = y(Y);
line.push([i, j]);
}

g.append("path")
.attr("d", "M" + line.join("L"))
.style("stroke", "black")
.style("fill", "none");

g.append("g")
.attr("transform", `translate(${m},0)`)
.call(d3.axisLeft(y));
g.append("g")
.attr("transform", `translate(0,${y(0)})`)
.call(d3.axisBottom(x));

return svg.node();
}
Insert cell
function visualizeTicks(scale, tickArguments) {
const height = 20, m = width > 599 ? 90 : 10;

if (tickArguments === undefined) tickArguments = [];

scale.range([m, width - m]);

const svg = d3.create("svg")
.attr("width", width)
.attr("height", height);

svg.append("g").call(d3.axisBottom(scale).ticks(...tickArguments));

return svg.node();
}
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