chartGrid = {
const margin = { top: 50, right: 20, bottom: 60, left: 60 };
const width = 250 - margin.left - margin.right;
const height = 250 - margin.top - margin.bottom;
const svg = d3.create("svg")
.attr("width", 800)
.attr("height", 300);
const diseases = Object.keys(sleepData);
const barColors = { Yes: "#e63946", No: "#457b9d" };
diseases.forEach((disease, i) => {
const group = svg.append("g")
.attr("transform", `translate(${(i % 3) * 260 + margin.left}, ${margin.top})`);
const data = Object.entries(sleepData[disease]).map(([group, value]) => ({
group, value
}));
const x = d3.scaleBand()
.domain(data.map(d => d.group))
.range([0, width])
.padding(0.4);
const y = d3.scaleLinear()
.domain([0, d3.max(data, d => d.value) + 1])
.range([height, 0]);
group.append("text")
.attr("x", width / 2)
.attr("y", -20)
.attr("text-anchor", "middle")
.style("font-size", "16px")
.style("font-weight", "bold")
.text(disease.replace(/([A-Z])/g, ' $1').trim());
// Axes
group.append("g")
.attr("transform", `translate(0,${height})`)
.call(d3.axisBottom(x));
group.append("g")
.call(d3.axisLeft(y).ticks(5));
// Axis labels
group.append("text")
.attr("x", width / 2)
.attr("y", height + 40)
.attr("text-anchor", "middle")
.style("font-size", "12px")
.text("Has Disease?");
group.append("text")
.attr("transform", "rotate(-90)")
.attr("y", -40)
.attr("x", -height / 2)
.attr("text-anchor", "middle")
.style("font-size", "12px")
.text("Sleep Time (hours)");
// Tooltip
const tooltip = d3.select(DOM.element("div"))
.style("position", "absolute")
.style("pointer-events", "none")
.style("background", "#fff")
.style("padding", "6px 10px")
.style("font", "13px sans-serif")
.style("border", "1px solid #ccc")
.style("box-shadow", "0px 0px 6px rgba(0,0,0,0.1)")
.style("border-radius", "4px")
.style("opacity", 0);
svg.node().appendChild(tooltip.node());
// Bars
group.selectAll(".bar")
.data(data)
.join("rect")
.attr("x", d => x(d.group))
.attr("y", d => y(d.value))
.attr("width", x.bandwidth())
.attr("height", d => height - y(d.value))
.attr("fill", d => barColors[d.group])
.on("mouseover", function(event, d) {
tooltip.style("opacity", 1)
.html(`<strong>${d.group}</strong>: ${d.value.toFixed(2)} hrs`);
})
.on("mousemove", function(event) {
tooltip
.style("left", (event.pageX + 10) + "px")
.style("top", (event.pageY - 30) + "px");
})
.on("mouseout", function() {
tooltip.style("opacity", 0);
});
// Stats summary (t and p)
const stats = statsData[disease];
group.append("text")
.attr("x", width / 2)
.attr("y", height + 55)
.attr("text-anchor", "middle")
.style("font-size", "11px")
.style("fill", "#555")
.text(`t = ${stats.t_stat}, p = ${stats.p_value}`);
});
return svg.node();
}