function scatterPlotWidget(data, options = {}) {
const container = html`<div style="font-family: sans-serif; display: flex; flex-direction: column; gap: 1rem;"></div>`;
if (options.title) {
const titleEl = html`<h3>${options.title}</h3>`;
container.append(titleEl);
}
const keys = Object.keys(data[0] || {});
function isNumericColumn(key) {
return data.every(d => !isNaN(+d[key]));
}
const numericKeys = keys.filter(isNumericColumn);
if (numericKeys.length < 2) {
container.append(html`<div style="color:red;">Dataset must have at least two numeric columns for scatter plot.</div>`);
return container;
}
const xSelect = Inputs.select(numericKeys, {label: "X Axis:", value: numericKeys[0]});
const ySelect = Inputs.select(numericKeys, {label: "Y Axis:", value: numericKeys[1]});
const controls = html`<div style="display: flex; gap: 1rem; align-items: center;"></div>`;
controls.append(xSelect, ySelect);
container.append(controls);
const plotContainer = html`<div></div>`;
container.append(plotContainer);
function updatePlot() {
plotContainer.innerHTML = "";
const xKey = xSelect.value;
const yKey = ySelect.value;
const plotNode = Plot.plot({
marks: [
Plot.dot(data, {x: xKey, y: yKey, r: 3, fill: "#4682b4"})
],
x: {label: xKey, tickCount: 10},
y: {label: yKey, tickCount: 10},
width: options.width || 500,
height: options.height || 400
});
plotContainer.append(plotNode);
}
xSelect.addEventListener("input", updatePlot);
ySelect.addEventListener("input", updatePlot);
updatePlot();
return container;
}