{
const data = await FileAttachment("customer_churn_data (4).csv").csv();
const processedData = data
.filter(d => d.InternetService && d.TechSupport && d.Churn)
.map(d => ({
InternetService: d.InternetService || "None",
TechSupport: d.TechSupport || "No",
Churn: d.Churn === "Yes" ? 1 : 0
}));
const internetServiceFilter = Inputs.select(
["All", ...new Set(processedData.map(d => d.InternetService))],
{ label: "Select Internet Service Type", value: "All" }
);
const techSupportFilter = Inputs.select(
["All", ...new Set(processedData.map(d => d.TechSupport))],
{ label: "Select Technical Support", value: "All" }
);
const container = html`<div></div>`;
container.appendChild(internetServiceFilter);
container.appendChild(techSupportFilter);
const renderChart = () => {
const filteredData = processedData.filter(d => {
const matchesInternetService =
internetServiceFilter.value === "All" || d.InternetService === internetServiceFilter.value;
const matchesTechSupport =
techSupportFilter.value === "All" || d.TechSupport === techSupportFilter.value;
return matchesInternetService && matchesTechSupport;
});
// Aggregate churn counts by Internet Service and Technical Support
const aggregatedData = d3.rollups(
filteredData,
group => group.reduce((sum, d) => sum + d.Churn, 0),
d => `${d.InternetService} - Tech Support: ${d.TechSupport}`
).map(([label, count]) => ({
label,
value: count
}));
// Clear the container
container.innerHTML = "";
container.appendChild(internetServiceFilter);
container.appendChild(techSupportFilter);
// If no data is available
if (aggregatedData.length === 0 || aggregatedData.every(d => d.value === 0)) {
container.appendChild(
md`**No data available for the selected filters. Adjust the filters.**`
);
return;
}
// Set up D3 Pie Chart
const width = 800;
const height = 600;
const radius = Math.min(width, height) / 2;
const svg = d3
.create("svg")
.attr("viewBox", `0 0 ${width} ${height}`)
.style("font", "12px sans-serif");
const pie = d3.pie().value(d => d.value)(aggregatedData);
const arc = d3.arc().innerRadius(50).outerRadius(radius - 10);
const color = d3.scaleOrdinal(d3.schemeCategory10);
const g = svg
.append("g")
.attr("transform", `translate(${width / 2}, ${height / 2})`);
g.selectAll("path")
.data(pie)
.join("path")
.attr("d", arc)
.attr("fill", d => color(d.data.label))
.append("title")
.text(d => `${d.data.label}: ${d.data.value}`);
g.selectAll("text")
.data(pie)
.join("text")
.attr("transform", d => `translate(${arc.centroid(d)})`)
.attr("text-anchor", "middle")
.text(d => d.data.label);
container.appendChild(svg.node());
};
// Trigger updates on filter changes
internetServiceFilter.oninput = renderChart;
techSupportFilter.oninput = renderChart;
// Render the initial chart
renderChart();
return container;
}