Public
Edited
Sep 29, 2024
Insert cell
Insert cell
Plotly = require("https://cdn.plot.ly/plotly-2.35.2.min.js")
Insert cell
Insert cell
data
Type Table, then Shift-Enter. Ctrl-space for more options.

Insert cell
data2 = [
{ model: "GPT-4o", agreementWithGoldStandard: 96.7, costPerReport: 0.44 },
{
model: "GPT-4o mini",
agreementWithGoldStandard: 88.3,
costPerReport: 0.01
},
{
model: "Llama 3.1 405B",
agreementWithGoldStandard: 95.0,
costPerReport: 0.35
},
{
model: "Llama 3.1 70B",
agreementWithGoldStandard: 92.0,
costPerReport: 0.15
},
{
model: "Llama 3.1 8B",
agreementWithGoldStandard: 75.3,
costPerReport: 0.02
}
]
Insert cell
viewof chart = {
// Set up dimensions and margins
const margin = { top: 40, right: 170, bottom: 80, left: 60 };
const width = 800 - margin.left - margin.right;
const height = 500 - margin.top - margin.bottom;

// Create SVG
const svg = d3
.create("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom);

const g = svg
.append("g")
.attr("transform", `translate(${margin.left},${margin.top})`);

// Set up scales with increased padding
const x = d3
.scaleBand()
.domain(data2.map((d) => d.model))
.range([0, width])
.padding(0.3); // Increased padding between model groups

const xSubgroup = d3
.scaleBand()
.domain(["agreement", "cost"])
.range([0, x.bandwidth()])
.padding(0.1); // Added padding between bars within each group

const yLeft = d3.scaleLinear().domain([50, 100]).range([height, 0]);

const yRight = d3.scaleLinear().domain([0, 0.5]).range([height, 0]);

// Add X axis
g.append("g")
.attr("transform", `translate(0,${height})`)
.call(d3.axisBottom(x))
.selectAll("text")
.attr("transform", "rotate(-45)")
.style("text-anchor", "end")
.style("font-size", "12px");

// Add Y axis left
g.append("g")
.call(d3.axisLeft(yLeft))
.style("font-size", "12px")
.append("text")
.attr("fill", "#000")
.attr("transform", "rotate(-90)")
.attr("y", -40)
.attr("x", -height / 2)
.attr("text-anchor", "middle")
.style("font-size", "14px")
.text("Agreement with gold standard (%)");

// Add Y axis right
g.append("g")
.attr("transform", `translate(${width},0)`)
.call(d3.axisRight(yRight))
.style("font-size", "12px")
.append("text")
.attr("fill", "#000")
.attr("transform", "rotate(-90)")
.attr("y", 60)
.attr("x", -height / 2)
.attr("text-anchor", "middle")
.style("font-size", "14px")
.text("Average cost per report (USD)");

// Add the bars for agreement
g.selectAll(".bar-agreement")
.data(data2)
.join("rect")
.attr("class", "bar-agreement")
.attr("x", (d) => x(d.model) + xSubgroup("agreement"))
.attr("y", (d) => yLeft(d.agreementWithGoldStandard))
.attr("width", xSubgroup.bandwidth())
.attr("height", (d) => height - yLeft(d.agreementWithGoldStandard))
.attr("fill", "#006400");

// Add the bars for cost
g.selectAll(".bar-cost")
.data(data2)
.join("rect")
.attr("class", "bar-cost")
.attr("x", (d) => x(d.model) + xSubgroup("cost"))
.attr("y", (d) => yRight(d.costPerReport))
.attr("width", xSubgroup.bandwidth())
.attr("height", (d) => height - yRight(d.costPerReport))
.attr("fill", "#EEBC1D");

// Add grid lines
g.append("g")
.attr("class", "grid")
.call(d3.axisLeft(yLeft).tickSize(-width).tickFormat(""))
.style("stroke-dasharray", "3,3")
.style("opacity", 0.3);

// Add title
svg
.append("text")
.attr("x", (width + margin.left) / 2 + 30)
.attr("y", margin.top / 2)
.attr("text-anchor", "middle")
.style("font-size", "20px")
.style("font-weight", "bold")
.text("Agreement with gold standard vs average cost per report");

// Add legend
const legendData = [
{
name: "Agreement with gold standard",
lines: ["Agreement with", "gold standard"],
color: "#006400"
},
{ name: "Cost", lines: ["Cost"], color: "#EEBC1D" }
];

const legend = svg
.append("g")
.attr("font-family", "sans-serif")
.attr("font-size", 12)
.attr("text-anchor", "start");

let legendOffsetY = 10;

legendData.forEach((d, i) => {
const legendItem = legend
.append("g")
.attr(
"transform",
`translate(${margin.left + width + 50}, ${margin.top + legendOffsetY})`
);

legendItem
.append("rect")
.attr("x", 0)
.attr("y", 0)
.attr("width", 19)
.attr("height", 19)
.attr("fill", d.color);

const text = legendItem
.append("text")
.attr("x", 24)
.attr("y", 9.5)
.attr("dy", "0");

d.lines.forEach((line, index) => {
text
.append("tspan")
.attr("x", 24)
.attr("dy", index === 0 ? 0 : "1.2em")
.text(line);
});

legendOffsetY += d.lines.length * 18;
});

return svg.node();
}
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