function plotFPXY(data, {
summarize = v=>v.length,
locationKey = "LOCATION",
clipFraction = 0.025,
xyRange = 420,
colorMap = "plasma",
w = 0.7 * width,
showMissing = true,
showHistogram = false,
nbins = 25,
}={}) {
const summary = d3.rollups(data, summarize, d => d[locationKey]);
const zlo = d3.quantile(summary, clipFraction, ([loc,z]) => z);
const zhi = d3.quantile(summary, 1 - clipFraction, ([loc,z]) => z);
const zprec = d3.precisionFixed((zhi - zlo) / 100);
const zfmt = d3.format("." + zprec + "f");
const allLocs = summary.map(d => d[locationKey]);
const missingLocs = !showMissing ? [] : (
[...fpNominalCoords.entries()]
.filter(([loc, {type}]) => (type == "POS") && !allLocs.includes(loc))
.map(([loc,_]) => loc));
const radius = w / 165;
const xyPlot = Plot.plot({
width: w,
height: w,
marginTop:0,
marginLeft:0,
marginRight:0,
marginBottom:0,
x:{ticks:false, domain:[-xyRange, xyRange]},
y:{ticks:false, domain:[-xyRange, xyRange]},
color:{domain: [zlo,zhi], scheme: colorMap},
color: {scheme: colorMap},
marks: [
Plot.dot(summary, {
x: ([loc,z]) => fpNominalCoords.get(loc).x,
y: ([loc,z]) => fpNominalCoords.get(loc).y,
fill: ([loc,z]) => z,
title: ([loc,z]) => `LOC[${loc}]=${zfmt(z)}`,
r: radius,
}),
Plot.dot(missingLocs, {
x: loc => fpNominalCoords.get(loc).x,
y: loc => fpNominalCoords.get(loc).y,
stroke: "lightgray",
strokeWidth: 1,
r: radius,
}),
]
});
if(showHistogram) {
const bins = d3.range(nbins + 1).map(i => zlo + (zhi - zlo) * i / nbins);
const histPlot = Plot.plot({
width: w,
height: 200,
marginTop:0,
marginLeft:0,
marginRight:0,
x:{domain:[zlo, zhi], label:null},
y:{ticks:0, label:null},
color:{domain:[zlo, zhi], scheme: colorMap},
marks:[
Plot.frame(),
Plot.rectY(
summary.filter(([loc,z]) => (z >= zlo) && (z < zhi)),
Plot.binX(
{y:"proportion", fill:"median"},
{x:{value: ([loc,z]) => z, thresholds: bins}, fill: ([loc,z]) => z}
)
),
],
});
return html`<div>${xyPlot}${histPlot}</div>`;
}
else {
return xyPlot;
}
}