Published
Edited
May 15, 2020
2 stars
Insert cell
Insert cell
chart = {
const svg = d3.create("svg")
.attr("viewBox", [-width/4, 0, width, height]);
svg.selectAll("rect")
.data(bins)
.join("rect")
.attr("class", d => d.correct ? "rect-correct" : "rect-incorrect")
.attr("transform", "translate(50,0)")
.attr("height", d => yScale(d.x0) - yScale(d.x1))
.attr("x", halfBandwidth)
.attr("y", d => yScale(d.x1))
.style("fill", "#f2cc37")
.style("fill-opacity", d => d.correct ? 1 : 0.5)
.transition()
.duration(500)
.delay((d, i) => i % binThresholds.length * 100)
.attr("width", d => d.correct ?
correctDist.scale(d.length) - halfBandwidth + offset :
halfBandwidth - (incorrectDist.scale(-d.length) + offset))
.attr("x", d => d.correct ? halfBandwidth : incorrectDist.scale(-d.length) + offset);
svg.append("g")
.call(yAxis);
return svg.node();
}
Insert cell
bins = d3.merge([
correctDist.bins.map(d => ({x0: d.x0, x1: d.x1, length: d.length, correct: true})),
incorrectDist.bins.map(d => ({x0: d.x0, x1: d.x1, length: d.length, correct: false}))
])
Insert cell
incorrectDist = createHistogram(data.filter(d => !d.correct).map(d => d.score), binThresholds, xScale, yScale);
Insert cell
correctDist = createHistogram(data.filter(d => d.correct).map(d => d.score), binThresholds, xScale, yScale);
Insert cell
function createHistogram(data, binThresholds, xScale, yScale) {
// general histogram
const histogram = d3.histogram()
.domain(yScale.domain())
.thresholds(binThresholds);
const bins = histogram(data);

// create scale
const maxBinLength = d3.max(bins.map(d => d.length));
const violinScale = d3.scaleLinear()
.range([0, xScale.bandwidth()])
.domain([-maxBinLength, maxBinLength]);

return {
bins: bins,
scale: violinScale
}
}
Insert cell
binThresholds = yScale.ticks(50)
Insert cell
halfBandwidth = xScale.bandwidth() / 2 + offset
Insert cell
offset = 0.05 * xScale.bandwidth();
Insert cell
yAxis = g => g
.attr("transform", `translate(${margin.left},0)`)
.call(d3.axisLeft(yScale))
Insert cell
xScale = d3.scaleBand()
.range([0, width - 600])
.domain(["pseudo"])
.padding(0.05)
Insert cell
yScale = d3.scaleLinear()
.domain(d3.extent(data, d => d.score)).nice()
.range([height - margin.bottom, margin.top])
Insert cell
data = FileAttachment("scores.json").json()
Insert cell
margin = ({top: 20, right: 20, bottom: 20, left: 20})
Insert cell
height = 350
Insert cell
d3 = require("d3@5")
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