Public
Edited
Apr 22
Importers
Insert cell
Insert cell
data = FileAttachment("Sleep_health_and_lifestyle_dataset.csv").csv({ typed: true })
Insert cell
viewof correlationMatrix = correlationMatrixWidget(data)
Insert cell
function correlationMatrixWidget(data, options = {}) {
const { width = 600, height = 600, title = "Correlation Matrix" } = options;

// Create container.
const container = html`<div style="font-family: sans-serif; display: flex; flex-direction: column; gap: 1rem;"></div>`;
// Add title if provided.
if (title) {
container.append(html`<h3>${title}</h3>`);
}

const keys = Object.keys(data[0] || {});
// Filter keys to only those that are numeric for all records.
const numericKeys = keys.filter(key => data.every(d => !isNaN(+d[key])));
if (numericKeys.length < 2) {
container.append(html`<div style="color: red;">Dataset must have at least two numeric columns for a correlation matrix.</div>`);
return container;
}

// Create a multiple-selection dropdown for variables.
const variableSelector = Inputs.select(numericKeys, {
label: "Select variables for correlation",
multiple: true,
value: numericKeys
});
container.append(variableSelector);
// Create a container to hold the plot.
const plotContainer = html`<div></div>`;
container.append(plotContainer);
// Create a container for export buttons.
const exportContainer = html`<div style="display: flex; gap: 1rem;"></div>`;
container.append(exportContainer);
const exportCSVButton = html`<button>Export CSV</button>`;
const exportSVGButton = html`<button>Export SVG</button>`;
exportContainer.append(exportCSVButton, exportSVGButton);
// Helper: Compute Pearson correlation coefficient between two arrays.
function pearson(x, y) {
const n = x.length;
const sumX = d3.sum(x);
const sumY = d3.sum(y);
const sumXY = d3.sum(x.map((d, i) => d * y[i]));
const sumX2 = d3.sum(x.map(d => d * d));
const sumY2 = d3.sum(y.map(d => d * d));
const numerator = n * sumXY - sumX * sumY;
const denominator = Math.sqrt((n * sumX2 - sumX * sumX) * (n * sumY2 - sumY * sumY));
return denominator ? numerator / denominator : 0;
}
// Compute the correlation matrix for selected variables.
function computeCorrelationMatrix(vars) {
const matrix = vars.map(var1 => {
const row = { variable: var1 };
vars.forEach(var2 => {
const col1 = data.map(d => +d[var1]);
const col2 = data.map(d => +d[var2]);
row[var2] = pearson(col1, col2);
});
return row;
});
return { vars, matrix };
}
// Convert correlation matrix to CSV.
function matrixToCSV({vars, matrix}) {
const header = ["variable", ...vars];
const rows = matrix.map(row => header.map(col => row[col]));
return [header.join(","), ...rows.map(r => r.join(","))].join("\n");
}
// Update the correlation matrix plot and export functionality.
function update() {
const selectedVars = variableSelector.value;
const correlationData = computeCorrelationMatrix(selectedVars);
const longData = [];
correlationData.matrix.forEach(row => {
selectedVars.forEach(col => {
longData.push({
x: row.variable,
y: col,
value: row[col]
});
});
});
// heatmap
const plotNode = Plot.plot({
marks: [
// Heatmap rectangles.
Plot.rect(longData, {
x: "x",
y: "y",
fill: "value",
// Include tooltip information.
title: d => `${d.x} vs ${d.y}: ${d.value.toFixed(2)}`,
rx: 2
}),
// Text labels for each cell.
Plot.text(longData, {
x: "x",
y: "y",
text: d => d.value.toFixed(2),
fill: "black",
dy: "0.35em",
textAnchor: "middle"
})
],
color: {
scheme: "Blues",
domain: [-1, 1],
label: "Correlation",
tickCount: 10
},
// Hide axis labels
x: { label: null },
y: { label: null },
width,
height,
marginLeft: 100,
marginBottom: 100
});
// Replace any old plot.
plotContainer.innerHTML = "";
plotContainer.append(plotNode);
// Setup the Export CSV button.
exportCSVButton.onclick = () => {
const csvString = matrixToCSV(correlationData);
const blob = new Blob([csvString], { type: "text/csv" });
const url = URL.createObjectURL(blob);
const a = html`<a href="${url}" download="correlation-matrix.csv"></a>`;
a.click();
URL.revokeObjectURL(url);
};
// Setup the Export SVG button.
exportSVGButton.onclick = () => {
// Check if plotNode is an SVG element; if not, get the contained <svg>.
const svg = plotNode.tagName === "svg" ? plotNode : plotNode.querySelector("svg");
if (svg) {
const serializer = new XMLSerializer();
let svgStr = serializer.serializeToString(svg);
// (Optional) Add XML declaration to the output.
svgStr = `<?xml version="1.0" standalone="no"?>\r\n` + svgStr;
const blob = new Blob([svgStr], { type: "image/svg+xml;charset=utf-8" });
const url = URL.createObjectURL(blob);
const a = html`<a href="${url}" download="correlation-matrix.svg"></a>`;
a.click();
URL.revokeObjectURL(url);
} else {
alert("SVG element not found in the plot.");
}
};
}
// Update the plot whenever the variable selection changes.
variableSelector.addEventListener("input", update);
update();
return container;
}
Insert cell
Insert cell
Insert cell
d3 = require("d3")
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