Published
Edited
May 25, 2022
Importers
3 stars
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
histogramVisualization = {
const x = d3
.scaleLinear()
.domain([0, 256])
.range([0 + margin, width - margin]);
const y = d3
.scaleLinear()
.domain([0, d3.max(histogram.map(x => d3.max(x.data)))])
.range([height - margin, 0 + margin]);

const area = d3
.area()
.x((_, i) => x(i))
.y0(y(0))
.y1((d, _) => y(d))
.curve(d3.curveStepAfter);

const svg = d3
.create("svg")
.attr("width", width)
.attr("height", height)
.attr("class", "histogram")
.style("background-color", "#333")
.style("isolation", "isolate");

for (const channel of histogram) {
svg
.append("path")
.attr("class", channel.name)
// duplicate the last data point so that the right-most step is drawn correctly
.attr("d", area([...channel.data, channel.data.slice(-1)]))
.attr("fill", channel.color)
.attr("stroke", channel.color)
.style("mix-blend-mode", "screen");
}

return svg.node();
}
Insert cell
Insert cell
Insert cell
histogram = {
// dividing the histogram into channels like this is @lemonnish's idea
const histogram = [
{ name: "red", color: "#ff0000", data: new Uint32Array(256) },
{ name: "green", color: "#00ff00", data: new Uint32Array(256) },
{ name: "blue", color: "#0000ff", data: new Uint32Array(256) }
];

const { data } = getImageData(image);

for (let i = 0; i < data.length; i += 4) {
let pixel = data.slice(i, i + 3);
++histogram[0].data[pixel[0]];
++histogram[1].data[pixel[1]];
++histogram[2].data[pixel[2]];
}

return histogram;
}
Insert cell
Insert cell
Insert cell
d3 = require("d3@5")
Insert cell
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