Public
Edited
Mar 9, 2023
Insert cell
Insert cell
Insert cell
Plot.plot({
marks: grid(settings)([1, settings.minor, settings.micro]),
x: noAxesOrTicks, y: noAxesOrTicks,
marginRight: 0, marginLeft: 0, marginBottom: 0, marginTop: 0,
width, height: width * settings.tall / settings.wide,
style: {backgroundColor: "snow"}
})
Insert cell
grid =
(settings = {}) =>
(divisions) =>
R.pipe(
R.map(lines(settings)),
R.map(hatch(settings)(divisions))
)
(["tall", "wide"])
Insert cell
g =
(settings) =>
divisions =>
R.pipe(
R.map(R.partialRight(lines, [settings])),
R.map(R.partial(hatch, [settings, divisions]))
)
Insert cell
// generate mark for either horizontal or vertical grid lines
hatch =
(settings) =>
(divisions) =>
(lines) =>
R.map(linker(settings)(lines))
(divisions)
Insert cell
// create Plot.link function for list of lines
linker =
({stroke = "lightgrey", strokeWidth = 1}) =>
(lines) =>
(divisions) =>
Plot.link(
[
xy(settings)("tall")(settings.minor)(line),
xy(settings)("wide")(settings.minor)(line),
xy(settings)("tall")(settings.micro)(line),
xy(settings)("wide")(settings.micro)(line),
].flat(),
{
x1: "x1", y1: "y1", x2: "x2", y2: "y2",
stroke, strokeWidth, opacity: 1 / divisions,
}
)
Insert cell
// generate list of grid lines, either horizontal or vertical according to orientation
lines =
({wide = 16, tall = 9} = {}) =>
(orientation = "tall") =>
(divisions = 2) =>
{
const aspect = ({wide, tall});
const height = width * tall / wide;
const lineCount = aspect[orientation] * divisions + 1;
const stepSize = ({wide: width, tall: height}[orientation]) / divisions / aspect[orientation];
// take stepSize; return function that takes (_, i) and returns line coordinates,
// according to orientation
const line = ((stepSize) => ({
tall: (_, i) => ({y1: i * stepSize, y2: i * stepSize, x1: 0, x2: width}),
wide: (_, i) => ({x1: i * stepSize, x2: i * stepSize, y1: 0, y2: height}),
})[orientation])(stepSize);

return d3.range(lineCount).map(line);
}
Insert cell
xy =
({wide = 16, tall = 9} = {}) =>
(orientation = "wide") =>
(divisions = 2) =>
(transform = ((x) => x)) =>
{
const aspect = ({wide, tall});
const height = width * tall / wide;
const stepSize = ({wide: width, tall: height}[orientation]) / divisions / aspect[orientation];
const size = ({wide: height, tall: width})[orientation];
const objectify = transform(width, height, orientation);
return d3
.range(0, size, stepSize) // generate start positions for lines
.concat(size) // include closing line
.map(objectify) // convert to line objects for plot
;
}
Insert cell
line =
(width, height, orientation) =>
(p) =>
({
wide: ({x1: 0, y1: p, x2: width, y2: p}),
tall: ({x1: p, y1: 0, x2: p, y2: height}),
})
[orientation] // return proper object for Plot.link
Insert cell
noAxesOrTicks = ({label: null, tickFormat: null, tickSize: null})
Insert cell
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