plotSchemesAndDeficiencies = ({
data,
width_,
height,
contourStrokeOpacity
}) => {
const none = (t) => culori.formatHex(t);
const protanopia = (t) => culori.formatHex(culori.filterDeficiencyProt()(t));
const deuteranopia = (t) =>
culori.formatHex(culori.filterDeficiencyDeuter()(t));
const tritanopia = (t) => culori.formatHex(culori.filterDeficiencyTrit()(t));
const achromatopsia = (t) => culori.formatHex(culori.filterGrayscale()(t));
const filters = [none, protanopia, deuteranopia, tritanopia, achromatopsia];
const Viridis = (t) => d3.interpolateViridis(t);
const Cividis = (t) => d3.interpolateCividis(t);
const Magma = (t) => d3.interpolateMagma(t);
const Inferno = (t) => d3.interpolateInferno(t);
const Plasma = (t) => d3.interpolatePlasma(t);
const Cubehelix = (t) => d3.interpolateCubehelixDefault(t);
const Warm = (t) => d3.interpolateWarm(t);
const Cool = (t) => d3.interpolateCool(t);
const Sinebow = (t) => d3.interpolateSinebow(1 - t);
const Turbo = (t) => d3.interpolateTurbo(t);
const Rainbow = (t) => d3.interpolateRainbow(t);
const RainbowReversed = (t) => d3.interpolateRainbow(1 - t);
const BuGn = (t) => d3.interpolateBuGn(1 - t);
const BuPu = (t) => d3.interpolateBuPu(1 - t);
const OrRd = (t) => d3.interpolateOrRd(1 - t);
const PuBu = (t) => d3.interpolatePuBu(1 - t);
const PuBuGn = (t) => d3.interpolatePuBuGn(1 - t);
const PuRd = (t) => d3.interpolatePuRd(1 - t);
const RdPu = (t) => d3.interpolateRdPu(1 - t);
const YlGn = (t) => d3.interpolateYlGn(1 - t);
const YlGnBu = (t) => d3.interpolateYlGnBu(1 - t);
const YlOrBr = (t) => d3.interpolateYlOrBr(1 - t);
const YlOrRd = (t) => d3.interpolateYlOrRd(1 - t);
const Blues = (t) => d3.interpolateBlues(1 - t);
const Greens = (t) => d3.interpolateGreens(1 - t);
const Greys = (t) => d3.interpolateGreys(1 - t);
const Purples = (t) => d3.interpolatePurples(1 - t);
const Reds = (t) => d3.interpolateReds(1 - t);
const Oranges = (t) => d3.interpolateOranges(1 - t);
const extras = [
BuGn,
BuPu,
OrRd,
PuBu,
PuBuGn,
PuRd,
RdPu,
YlGn,
YlGnBu,
YlOrBr,
YlOrRd,
Blues,
Greens,
Greys,
Purples,
Reds,
Oranges
];
// match ordering in https://observablehq.com/@mjbo/perceptually-uniform-color-models#schemes
const schemes = [
Viridis,
Cividis,
Magma,
Inferno,
Plasma,
Cubehelix,
Warm,
Cool,
Sinebow,
Rainbow,
RainbowReversed,
Turbo,
...(showMoreSchemes ? extras : [])
];
const fxy = d3.cross(filters, schemes);
return Plot.plot({
color: { type: "identity" },
nice: true,
x: { axis: null },
y: { axis: null },
width,
aspectRatio: 1,
marginLeft: 60,
marginBottom: 50,
fx: {
tickFormat: (f) => f?.name,
domain: filters,
tickRotate: 30,
label: "deficiency"
},
fy: { tickFormat: (f) => f?.name, domain: schemes, label: "scheme" },
marks: [
Plot.raster({
fill: (x, y, { fx, fy }) =>
fx(fy(data[Math.floor(y) * width_ + Math.floor(x)])),
fx: fxy.map((d) => d[0]),
fy: fxy.map((d) => d[1]),
x1: 0,
y1: 0,
x2: width_,
y2: height
}),
contourStrokeOpacity // performance optimisation: if 0, don't render
? Plot.contour({
value: (x, y) => data[Math.floor(y) * width_ + Math.floor(x)],
x1: 0,
y1: 0,
x2: width_,
y2: height,
strokeOpacity: contourStrokeOpacity
})
: undefined
]
});
}