Published unlisted
Edited
Sep 25, 2021
1 star
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
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
function showExamples(plots, scales = ["x", "color"], properties) {
return html`<details><summary>Example${plots.length > 1 ? "s":""}</summary>
${plots.map(([title, plot]) => showExample(title, plot, scales, properties))}`
}
Insert cell
function showExample(title, plot, scales = ["x", "color"], properties) {
return html`<h5>${title}</h5>
${scales.map((scale) => props(plot.scale(scale), properties))}
${plot}
<hr>`;

function props(obj, properties) {
return Inputs.table(
(properties == null ? Object.keys(obj) : properties).map((p) => ({
property: p,
value:
obj[p] === undefined
? "undefined"
: typeof obj[p] === "string"
? obj[p]
: JSON.stringify(obj[p])
})), {width: 300}
);
}
}
Insert cell
Insert cell
//import {Plot} from "8baa87efd6b4f30d"
Plot = FileAttachment("plot@18.umd.js").url().then(require)
Insert cell
Insert cell
Insert cell
labelI = Plot.dotX(data, {x: "body_mass"}).plot()
Insert cell
labelI.scale("x")
Insert cell
Insert cell
Insert cell
labelE = Plot.dotX(data, {x: "body_mass"}).plot({x: {label: "Body mass", type:"linear"}})
Insert cell
labelE.scale("x").label
Insert cell
labelE.scale("x").interpolate(0,100)(.5)
Insert cell
labelNull = Plot.dotX(data, {x: "body_mass"}).plot({x: {label: null}})
Insert cell
labelNull.scale("x").label
Insert cell
Plot.dotX(data, {x: "body_mass"}).plot({x: {label: null}}).scale("x").label === null
Insert cell
Plot.plot({
marks: [Plot.dotX(data, { x: "body_mass" }), Plot.dotX(data, { x: "island" })]
}).scale("x").label === undefined
Insert cell
Plot.dotX(data, { x: d => d.body_mass }).plot().scale("x").label === undefined
Insert cell
Insert cell
Insert cell
Insert cell
labelE.scale("x").domain // [2700, 6300]
Insert cell
Insert cell
domainE = Plot.dotX(data, {x: "body_mass"}).plot({x: {domain: [3500, 4000]}})
Insert cell
domainE.scale("x").domain // [3500, 4000]
Insert cell
Insert cell
nice = Plot.dot(data, {x: "body_mass"}).plot({x: {nice: true}})
Insert cell
nice.scale("x").domain // [2500, 6500]
Insert cell
nice.scale("x").nice // undefined : the nice property is subsumed in the domain
Insert cell
Insert cell
Insert cell
Inputs.table(data)
Insert cell
clamp = Plot.dotX(data, {x: "body_mass", fill:"black", fillOpacity: .01}).plot({x: {domain: [3500, 4000], clamp: true}})
Insert cell
clamp.scale("x").clamp // true
Insert cell
nice.scale("x").clamp // false
Insert cell
Insert cell
round = Plot.dotX(data, {x: "body_mass"}).plot({x: {domain: [3500, 4000], round: true}})
Insert cell
round.scale("x")
Insert cell
round.scale("x").interpolate(0,100)(1/3) // interpolateRound
Insert cell
round.scale("x").round // undefined, subsumed by the interpolator
Insert cell
Plot.dotX(data, {x: "body_mass"}).plot({x: round.scale("x")}).scale("x").interpolate(0,100)(1/3) // stays round
Insert cell
Insert cell
Insert cell
custominterpolate = Plot.dotX(data, { x: "body_mass" }).plot({
x: { interpolate: (a, b) => (t) => +(t * (b - a) + a).toFixed(1) }
})
Insert cell
custominterpolate.scale("x").interpolate(0,100)(1/3)
Insert cell
colorinterpolate = Plot.dotX(data, { x: "body_mass", fill: "body_mass" }).plot({
color: { scheme: "warm", reverse: true }
})
Insert cell
colorinterpolate.scale("color").scheme // :( , scheme becomes an interpolator.
Insert cell
html`<div style="background:${colorinterpolate.scale("color").interpolate(0,1)(1/3)}">should be orange`
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Plot.dotX(data, { x: "body_mass", fill: "island" }).plot().scale("color")
Insert cell
Plot.dotX(data, { x: "body_mass", fill: "island" }).plot().scale("color").range // d3.schemeTableau10
Insert cell
Plot.dotX(data, { x: "body_mass", fill: "island" })
.plot({ color: { scheme: "reds" } })
.scale("color").range // d3.schemeReds[3]
Insert cell
Insert cell
Insert cell
doubleCheck({
x: { zero: true },
color: { zero: true }
})
Insert cell
Insert cell
doubleCheck({
x: { transform: d => 1 / d }
})
Insert cell
Insert cell
Plot.dotX(data, { x: "body_mass" })
.plot({ x: { type: "sqrt" } })
.scale("x")
Insert cell
Plot.dotX(data, { x: "body_mass" })
.plot({ x: { type: "pow", exponent: 1.7 } }) // note: exponent is passed as-is, "a" becomes "a".
.scale("x")
Insert cell
Plot.dotX(data, { x: "body_mass" })
.plot({ x: { type: "symlog", constant: 1.7 } }) // note: constant is passed as-is, "a" becomes "a".
.scale("x")
Insert cell
Plot.dotX(data, { x: "body_mass" })
.plot({ x: { type: "log", base: 2 } }) // note: base is passed as-is, "a" becomes "a".
.scale("x")
Insert cell
Insert cell
Insert cell
range = d3.range(-19, 50)
Insert cell
A = Plot.dotX(range).plot({ x: {} }) // { domain: [-19, 49], range: … }
Insert cell
test("All the expected scales are returned; non-instantiated scales are undefined; non-existing scales throw an error", (t) => {
const p = Plot.dotX(data, { fill: "island" }).plot();
t.assert(p.scale("x"));
t.equal(p.scale("y"), undefined);
t.equal(p.scale("fx"), undefined);
t.equal(p.scale("fy"), undefined);
t.equal(p.scale("r"), undefined);
t.assert(p.scale("color"));
t.equal(p.scale("opacity"), undefined);
t.throws(() => p.scale("nonexistent"));
t.end();
})
Insert cell
Ax = A.scale("x")
Insert cell
A.scale("y")
Insert cell
A.scale("z") // Error: unknown scale: z
Insert cell
Insert cell
opacity = Plot.rectX(
data,
Plot.binX({ fillOpacity: "count" }, { x: "body_mass", thresholds: 20 })
).plot({
opacity: { percent: true }
})
Insert cell
opacity.scale("opacity").label // "body_mass (%)"
Insert cell
opacity.scale("opacity").domain
Insert cell
test("An opacity scale has the expected defaults", (t) => {
const p = Plot.rectX(
data,
Plot.binX({ fillOpacity: "count" }, { x: "body_mass", thresholds: 20 })
).plot({
opacity: { percent: true }
});
const x = p.scale("opacity");
t.deepEqual(x.domain, [0, 4000])
t.deepEqual(x.range, [0, 1])
t.equal(x.interpolate(0, 10)(.15), 1.5),
t.equal(x.clamp, false)
t.equal(x.type, "linear")
t.equal(x.percent, true)
t.equal(x.label, "Frequency (%)")
t.end();
})
Insert cell
Plot.dot(range, { x: (d) => d, y: d3.randomLcg(42) }).plot({ x: {} }) // { domain: [-19, 49], range: … }
Insert cell
Plot.dotX(range).plot({ x: { nice: true } }) // { domain: [-2, 50], range: … }
Insert cell
Plot.dotX(range).plot({ x: { domain: [0, 60] } }) // { domain: [0, 60], range: … }
Insert cell
Plot.dotX(range).plot({ x: { domain: [0, 60], clamp: true } }) // { domain: [0, 60], range: …, clamp: true }
Insert cell
Plot.dotX(range).plot({ x: { round: true } }) // { domain: [-20, 49], range: …, round: true }
Insert cell
Plot.dotX(range).plot({
x: {
interpolate: (a, b) => (t) => Math.sqrt(a * a * (1 - t) + b * b * t)
}
})
Insert cell
// piecewise domains
Plot.dotX(range).plot({
x: {
domain: [-20, 0, 50, 200],
type: "linear"
}
}) // returns same domain + type, as well as domain+type+range?? (tbd)
Insert cell
Plot.dotX(range).plot({
x: {
domain: [-20, 0, 50, 200],
type: "linear"
}
}).scale("x")
Insert cell
Insert cell
doubleCheck({
color: {
type: "diverging-log",
domain: [-6000, -3000],
pivot: -4500,
constant: 3,
symmetric: true,
scheme: "cool"
}
}, Plot.dotX(data, { fill: d => -d.body_mass, x: "body_mass", r: 9 }))
Insert cell
Insert cell
Insert cell
dsymlog = c.scale("color")
Insert cell
ramp(c.scale("color").interpolate)
Insert cell
ramp(d3.interpolateWarm)
Insert cell
Insert cell
Insert cell
revdyn = Plot.dotX(data, { fill: "body_mass", x: "body_mass", r: 9 })
.plot({
color: {
type: "diverging", pivot: 4500
}
})
.scale("color")
Insert cell
ramp(revdyn.interpolate)
Insert cell
Insert cell
Insert cell
eranged.scale("color") // interpolate is now interpolateHsl
Insert cell
doubleCheck({
color: {
type: "diverging-log",
pivot: 3200
}
})
Insert cell
Insert cell
Insert cell
doubleCheck({
color: {
type: "cyclical",
domain: [1000, 6000]
}})
Insert cell
doubleCheck({
color: {
type: "cyclical", // superseded by scheme and interpolate
scheme: "blues",
domain: [0, 10000]
}
})
Insert cell
doubleCheck({
color: {
type: "cyclical", // superseded by scheme and interpolate
scheme: "blues", // superseded by interpolate
interpolate: d3.interpolateWarm,
}})
Insert cell
Insert cell
doubleCheck({
color: {
type: "sequential",
reverse: true
}
})
Insert cell
doubleCheck({
color: {
type: "sequential", // superseded by scheme and interpolate
scheme: "blues"
}
})
Insert cell
doubleCheck({
color: {
type: "sequential", // superseded by scheme and interpolate
scheme: "blues", // superseded by interpolate
interpolate: d3.interpolateWarm
}
})
Insert cell
Insert cell
doubleCheck({
color: {
type: "threshold",
domain: d3.range(2000, 7000, 500)
}
})
Insert cell
Insert cell
qu = doubleCheck({
color: {
type: "quantile",
quantiles: 10,
scheme: "warm"
}
})
Insert cell
quc = qu.scale("color")
Insert cell
Insert cell
doubleCheck({
color: {
type: "quantile",
quantiles: 3,
scheme: "sinebow"
}
})
Insert cell
doubleCheck({
color: {
type: "quantile",
range: ["red", "yellow", "blue", "green"] // the range determines the number of quantiles
}
})
Insert cell
quantil = Plot.dotX(data, { fill: "body_mass", x: "body_mass", r: 9 }).plot({
color: {
type: "quantile",
scheme: "warm" // reds, rdbu…
}
})
Insert cell
doubleCheck({
color: {
type: "quantile",
scheme: "warm"
}
})
Insert cell
doubleCheck({
color: {
type: "quantile",
scheme: "reds"
}
})
Insert cell
qu2 = doubleCheck({
color: {
type: "quantile",
scheme: "rdbu",
quantiles: 12,
reverse: true
}
})
Insert cell
qu2.scale("color")
Insert cell
doubleCheck({
color: {
type: "quantile",
scheme: "rdylgn",
quantiles: 10
}
})
Insert cell
doubleCheck = (
scales,
pl = Plot.dotX(data, { fill: "body_mass", x: "body_mass", r: 9 })
) => {
const plot = pl.plot(scales);
const plot2 = pl.plot({
fx: plot.scale("fx"),
fy: plot.scale("fy"),
x: plot.scale("x"),
y: plot.scale("y"),
color: plot.scale("color"),
r: plot.scale("r"),
opacity: plot.scale("opacity")
});
const plot3 = pl.plot({
fx: plot2.scale("fx"),
fy: plot2.scale("fy"),
x: plot2.scale("x"),
y: plot2.scale("y"),
color: plot2.scale("color"),
r: plot2.scale("r"),
opacity: plot2.scale("opacity")
});

if (plot3.innerHTML != plot.innerHTML)
return Object.assign(
html`<div style="border: solid brown 2px">${plot}${plot2}${plot3}`,
{ scale: plot.scale }
);

// now test with reverse
if (scales.color) {
scales.color.reverse = !scales.color.reverse;
{
const plot = pl.plot(scales);
const plot2 = pl.plot({
fx: plot.scale("fx"),
fy: plot.scale("fy"),
x: plot.scale("x"),
y: plot.scale("y"),
color: plot.scale("color"),
r: plot.scale("r"),
opacity: plot.scale("opacity")
});
const plot3 = pl.plot({
fx: plot2.scale("fx"),
fy: plot2.scale("fy"),
x: plot2.scale("x"),
y: plot2.scale("y"),
color: plot2.scale("color"),
r: plot2.scale("r"),
opacity: plot2.scale("opacity")
});

if (plot3.innerHTML != plot.innerHTML)
return Object.assign(
html`<div style="border: solid brown 2px">${plot}${plot2}${plot3}<div><em>Error on color {reverse: ${JSON.stringify(
scales.color.reverse
)}}</em>`,
{ scale: plot.scale }
);
}
}
return html`${plot}`; // <div>${JSON.stringify(plot.scale("color"), null, 2)}`
}
Insert cell
Insert cell
doubleCheck(
{ color: { type: "categorical" } },
Plot.dotX(data, { fill: "island", x: "body_mass", r: 9 })
)
Insert cell
doubleCheck({}, Plot.dotX(data, { fill: "island", x: "body_mass", r: 9 }))
Insert cell
Insert cell
doubleCheck({
color: {type: "ordinal", reverse: true}
}, Plot.dotX(data, { fill: "island", x: "body_mass", r: 9 }))
Insert cell
doubleCheck(
{
color: { range: ["yellow", "lime", "grey"] }
},
Plot.dotX(data, { fill: "island", x: "body_mass", r: 9 })
)
Insert cell
doubleCheck({
color: {range: ["yellow", "lime", "black", "red"]}
}, Plot.dotX(data, { fill: "island", x: "body_mass", r: 9 }))
Insert cell
doubleCheck({
x: { reverse: false, type: "band" },
y: { reverse: true },
color: { type: "categorical" },
}, Plot.barY("ABCDEF".split("").map(d => ({d})), {x: "d", y2: "d", fill: "d"}))
Insert cell
Insert cell
doubleCheck(
{
x: { type: "point", align: 0 },
r: { range: [2, 13] }
},
Plot.dotX(data, Plot.groupX({ r: "count" }, { fill: "island", x: "island" }))
)
Insert cell
doubleCheck(
{
x: { type: "point", align: 0.7 },
r: { range: [2, 13] }
},
Plot.dotX(data, Plot.groupX({ r: "count" }, { fill: "island", x: "island" }))
)
Insert cell
doubleCheck(
{
x: { type: "point" },
r: { range: [2, 13] }
},
Plot.dotX(data, Plot.groupX({ r: "count" }, { fill: "island", x: "island" }))
)
Insert cell
Insert cell
doubleCheck({
x: {type: "band"}
}, Plot.cellX(data, Plot.groupX({fillOpacity: "count"}, { fill: "island", x: "island" })))
Insert cell
doubleCheck({
x: {type: "band", align: 0}
}, Plot.cellX(data, Plot.groupX({fillOpacity: "count"}, { fill: "island", x: "island" })))
Insert cell
doubleCheck({
x: {type: "band", align: 1}
}, Plot.cellX(data, Plot.groupX({fillOpacity: "count"}, { fill: "island", x: "island" })))
Insert cell
doubleCheck({
x: {type: "band", paddingInner: 0.4}
}, Plot.cellX(data, Plot.groupX({fillOpacity: "count"}, { fill: "island", x: "island" })))
Insert cell
doubleCheck({
x: {type: "band", paddingOuter: 0.4}
}, Plot.cellX(data, Plot.groupX({fillOpacity: "count"}, { fill: "island", x: "island" })))
Insert cell
Insert cell
dates = ["2002-01-07", "2003-06-09", "2004-01-01"].map(d3.isoParse)
Insert cell
doubleCheck({
x: {type: "utc"}
}, Plot.tickX(dates, { x: d => d }))
Insert cell
doubleCheck({
x: {type: "time"}
}, Plot.tickX(dates, { x: d => d }))
Insert cell
iden = Plot.tickX(dates, { x: d => d, stroke: () => "red" }).plot({
x: {type: "point"},
color: {type: "identity"},
})
Insert cell
iden.scale("color")
Insert cell
iden2 = doubleCheck({
x: {type: "identity"},
color: {type: "identity"},
}, Plot.tickX([100, 200, 300, 400], { x: d => d, stroke: ["red", "blue", "lime", "grey"] }))
Insert cell
iden2.scale("color")
Insert cell
Insert cell
doubleCheck(
{
x: { type: "linear", domain: [0, 100, 400] },
color: { type: "pow", exponent: 3.1, domain: [0, 200, 350] }
},
Plot.tickX(d3.range(400), {
x: (d) => d,
stroke: (d) => d
})
)
Insert cell
Insert cell
Insert cell
import { toc } from "@mbostock/toc"
Insert cell
import {data} from "@observablehq/plot-exploration-penguins"
Insert cell
import {test} from "d6eed8a5da2c6923"
Insert cell
import {ramp} from "@mbostock/color-ramp"
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