Public
Edited
May 13, 2024
1 fork
Importers
Insert cell
Insert cell
data = FileAttachment("allModelScores@2.csv").csv({typed: true})
Insert cell
viewof options = Inputs.radio(new Map([["Mean square error (MSE)", "mse"], ["Root mean square error (RMSE)", "rmse"], ["Mean absolute error (MAE)", "mae"]]), {
value: "mae",
label: "Performance metrics"
})
Insert cell
chart = {
const svg = d3.select(DOM.svg(width, height));

const g = svg
.append("g")
.selectAll("g")
.data(boxes)
.join("g");

g.append("path")
.attr("stroke", "currentColor")
.attr(
"d",
(d, i) => `
M${x(i) + x.bandwidth() / 2},${y(d.range[1])}
V${y(d.range[0])}
`
);

g.append("path")
.attr("fill", "#ddd")
.attr(
"d",
(d, i) => `
M${x(i)},${y(d.quartiles[2])}
H${x(i) + x.bandwidth()}
V${y(d.quartiles[0])}
H${x(i)}
Z
`
);

g.append("path")
.attr("stroke", "currentColor")
.attr("stroke-width", 2)
.attr(
"d",
(d, i) => `
M${x(i)},${y(d.quartiles[1])}
H${x(i) + x.bandwidth()}
`
);

g.append("g")
.attr("fill", "currentColor")
.attr("fill-opacity", 0.2)
.attr("stroke", "none")
.attr("transform", (d, i) => `translate(${x(i) + x.bandwidth() / 2},0)`)
.selectAll("circle")
.data(d => d.outliers)
.join("circle")
.attr("r", 3)
.attr("cx", () => (Math.random() - 0.5) * 4)
.attr("cy", d => y(d));

svg.append("g").call(xAxis);

svg.append("g").call(yAxis);

return svg.node();
}
Insert cell
boxes = {
let arrMap = Array.from(d3.group(data, d => d.model), ([key, value]) => ({
key,
value
}));
arrMap.map(o => {
const values = o.value.map(d => d[options]);
const min = d3.min(values);
const max = d3.max(values);
const q1 = d3.quantile(values, .25);
const q2 = d3.quantile(values, .5);
const q3 = d3.quantile(values, .75);
const iqr = q3 - q1;
const r0 = Math.max(min, q1 - iqr * 1.5);
const r1 = Math.min(max, q3 + iqr * 1.5);
o.quartiles = [q1, q2, q3];
o.range = [r0, r1];
o.outliers = values.filter(v => v < r0 || v > r1);
return o;
});

return arrMap.sort((a, b) => keys.indexOf(a.key) - keys.indexOf(b.key));
}
Insert cell
keys = [...new Set(data.map(x => x.model))]
Insert cell
x = d3
.scaleBand()
.domain(d3.range(boxes.length))
.range([margin.left, width - margin.right])
.padding(0.1)
Insert cell
y = d3
.scaleLinear()
.domain([d3.min(boxes, d => d.range[0]), d3.max(boxes, d => d.range[1])])
.nice()
.range([height - margin.bottom, margin.top])
Insert cell
xAxis = g =>
g.attr("transform", `translate(0,${height - margin.bottom})`).call(
d3
.axisBottom(x)
.tickFormat(i => boxes[i].key)
.tickSizeOuter(0)
)
Insert cell
yAxis = g =>
g
.attr("transform", `translate(${margin.left},0)`)
.call(d3.axisLeft(y).ticks(null, "s"))
.call(g => g.select(".domain").remove())
Insert cell
width = 800
Insert cell
height = 500
Insert cell
margin = ({ top: 20, right: 20, bottom: 30, left: 40 })
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