Public
Edited
Dec 17, 2024
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
render()
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
function checkAge(age, ageRanges) {
const a = parseFloat(age.split()[0]);
// console.log(`Age ${a}`);
// console.log(`Age Range ${ageRanges}`);
for (const range of ageRanges) {
const rangeObj = ages.find((d) => d.range === range);
// console.log(rangeObj);
// Check if the age falls within the range's min and max
if (
a >= rangeObj.minAge &&
(rangeObj.maxAge === undefined || a <= rangeObj.maxAge)
) {
return true; // Return the matching range object
}
}
return false; // No matching range found
}
Insert cell
case_data = data
.filter((d) => {
const raceList = d["Race / Ethnicity"].split(", ");
if (
(years || parseInt(d.DLC.split("/")[2]) == slider) && // Year
(race.length == 0 || raceList.some((r) => race.includes(r))) && // Race
(sex.length == 0 || sex.includes(d["Biological Sex"])) && // sex
(age.length == 0 || checkAge(d["Missing Age"], age))
) {
return true;
}
return false;
})
.map((d) => {
return {
state: territories.find((s) => s.abbreviation === d.State).name,
county: d.County,
first_name: d["Legal First Name"],
last_name: d["Legal Last Name"],
city: d.City,
sex: d["Biological Sex"],
race: d["Race / Ethnicity"].split(", "),
age_missing: d["Missing Age"],
date_last_contact: d.DLC
};
})
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
map_data = counties_data.map((d) => {
const county = d.county;
const state = d.state;
const cases = case_data.filter(
(c) => c.county === county && c.state === state
);
return { id: d.id, state: state, county: county, cases: cases };
})
Insert cell
Insert cell
{
var total_cases = 0;
map_data.forEach(function sum_cases(county) {
total_cases += county.cases.length;
});
return total_cases;
}
Insert cell
Insert cell
function get_state_data(state) {
const state_cases = case_data.filter((d) => d.state === state);
const race_stats = Object.groupBy(state_cases, (c) => c.race);
const sex_stats = Object.groupBy(state_cases, (c) => c.sex);
return state;
}
Insert cell
stateToCountiesMap = new Map();
Insert cell
countieslist = counties.features; // GeoJSON features for counties
Insert cell
stateslist = states.features; // GeoJSON features for states
Insert cell
countyRaceData = d3.group(case_data, (d) => d.county)
Insert cell
countyRaceDataWithCounts = Array.from(countyRaceData, ([county, counties]) => {
const raceCounts = counties.reduce((acc, row) => {
row.race.forEach(race => {
if (!acc[race]) {
acc[race] = 0;
}
acc[race] += 1;
});
return acc;
}, {});

return { county, raceCounts };
});
Insert cell
tooltip = d3.select("body").append("div")
.style("position", "absolute")
.style("opacity", 0) // Start hidden
.style("background-color", "rgba(0, 0, 0, 0.7)")
.style("color", "white")
.style("padding", "8px")
.style("border-radius", "5px")
.style("font-size", "12px")
.style("pointer-events", "none") // Prevent interaction
.style("box-shadow", "0px 4px 6px rgba(0, 0, 0, 0.3)");

Insert cell
barchartcontainer = d3
.select("#barchartcontainer")
Insert cell
stateslist.forEach((state) => {
const stateCounties = countieslist.filter((county) => {
return county.id.startsWith(state.id); // Example: If county IDs start with state IDs
});

stateToCountiesMap.set(state.properties.name, stateCounties);
});

Insert cell
cases = map_data.map((d) => d.cases.length)
Insert cell
maxcases = Math.max(...cases)
Insert cell
color = d3
.scaleQuantize()
.domain([0, maxcases]) // Set the domain from 0 to max value
.range(d3.schemePurples[9])
Insert cell
projection = d3
.geoAlbersUsa()
.scale(1600) // Adjust the scale to fit your SVG
.translate([780, 430])
Insert cell
path = d3.geoPath(projection)
Insert cell
format = (d) => `${d}%`
Insert cell
valuemap = new Map(map_data.map((d) => [d.id, d.cases.length]))
Insert cell
split_view = d3.select("#split-view")
Insert cell
split_view.style.display = 'flex';
Insert cell
split_view.style.width = '100%';
Insert cell
split_view.on('load', render)
Insert cell
countyRaceGenderAgeData = map_data.map(countyData => {
// Prepare aggregation for this county
const raceCounts = {};
const genderCounts = {};
const ageCounts = {
'0-19': 0,
'20-29': 0,
'30-39': 0,
'40-49': 0,
'50-59': 0,
'60-69': 0,
'70+': 0
};

// Process cases for this county
countyData.cases.forEach(row => {
// Race counting
if (row.race && row.race.length > 0) {
row.race.forEach(race => {
if (!raceCounts[race]) {
raceCounts[race] = 0;
}
raceCounts[race] += 1;
});
}

// Gender counting
if (row.sex) {
if (!genderCounts[row.sex]) {
genderCounts[row.sex] = 0;
}
genderCounts[row.sex] += 1;
}

// Age group counting
if (row.age_missing) {
const age = parseInt(row.age_missing.split(' ')[0]);
let ageGroup;

if (age < 20) ageGroup = '0-19';
else if (age < 30) ageGroup = '20-29';
else if (age < 40) ageGroup = '30-39';
else if (age < 50) ageGroup = '40-49';
else if (age < 60) ageGroup = '50-59';
else if (age < 70) ageGroup = '60-69';
else ageGroup = '70+';

ageCounts[ageGroup] += 1;
}
});

return {
id: countyData.id,
county: countyData.county,
state: countyData.state,
raceCounts,
genderCounts,
ageCounts
};
});
Insert cell
function render() {
const svg = d3.select("#usmap");
// reset map
svg.selectAll(".map-path").remove();
d3.selectAll("#legend > *").remove();
svg.selectAll("path").attr("transform", null);
d3.select("#reset-btn").remove();

svg
.style("width", "100%")
.style("height", "auto")
.attr("viewBox", [0, 0, 1500, 900]);

// Legend
d3.select("#legend")
// .attr("transform", "translate(150, 875)")
.append(() =>
Legend(color, {
title: "Case total",
width: "400",
tickFormat: d3.format("~d"),
labelSize: 200,
titleSize: 50
})
)
.selectAll("text")
.style("font-size", "14px");

d3.select("#legend > svg").attr("width", "100%");

barchartcontainer
.style("display", "flex")
.style("width", "40%")
.style("flexGrow", "0")
.style("flexShrink", "0");
// const title = barchartcontainer
// .append("text")
// .attr("x", 200) // Center the title horizontally
// .attr("y", 20) // Position the title above the chart
// .attr("text-anchor", "middle") // Align text in the center
// .style("font-size", "18px")
// .style("font-weight", "bold")
// .text( "Distribution ".concat(years ? "2010-2024" : slider));

createBarChartAll(years ? "2010-2024" : slider);

d3.select("#title")
.attr("text-anchor", "middle") // Center the title
.style("font-size", "24px") // Increase font size
.style("font-weight", "bold") // Make the title bold
.text(
"Total Missing Cases Per County in ".concat(years ? "2010-2024" : slider)
); // Title text

//NATION MAPPING
svg
.append("path")
.classed("map-path", true)
.datum(topojson.mesh(us, us.objects.nation), { stroke: "black" })
.attr("fill", "none")
.attr("stroke", "black")
.attr("stroke-width", "1px")
.attr("stroke-linejoin", "round")
.attr("d", path);

//STATE MAPPING
svg
.append("path")
.classed("map-path", true)
.datum(topojson.mesh(us, us.objects.states, (a, b) => a !== b))
.attr("fill", "none")
// .attr("stroke-linejoin", "round")
.attr("stroke", "black")
.attr("stroke-width", "1px")
.attr("d", path);

//COUNTY MAPPING
svg
.append("g")
.classed("map-path", true)
.selectAll("path")
.data(counties.features)
.join("path")
.attr("fill", (d) => {
const value = valuemap.get(d.id);
return value ? color(value) : "#ccc"; // Use a gray color if there is no data
})
.attr("stroke", "#333")
.attr("stroke-width", "0.3px")
.attr("d", path)
.on("click", (event, d) => {
// Center and zoom into the clicked state
const state = Array.from(stateToCountiesMap.keys()).find((stateName) => {
const counties = stateToCountiesMap.get(stateName);
return counties.some((county) => county.id === d.id); // Match county ID
});

if (state) {
// Get the state feature corresponding to the state name
const stateFeature = states.features.find(
(s) => s.properties.name === state
);
const stateBounds = path.bounds(stateFeature);
const dx = stateBounds[1][0] - stateBounds[0][0];
const dy = stateBounds[1][1] - stateBounds[0][1];
const x = (stateBounds[0][0] + stateBounds[1][0]) / 2;
const y = (stateBounds[0][1] + stateBounds[1][1]) / 2;

// Increase the zoom scale for more zooming in
const scale = Math.max(2, Math.min(10, 500 / Math.max(dx, dy))); // Allow up to scale 10
const translate = [750 - x * scale, 500 - y * scale];
svg
.transition()
.duration(750)
.call(
zoom.transform,
d3.zoomIdentity.translate(translate[0], translate[1]).scale(scale)
)
.on("end", () => {
barchartcontainer
.style("display", "flex")
.style("width", "40%")
.style("flexGrow", "0")
.style("flexShrink", "0");
const title = barchartcontainer
.append("text")
.attr("x", 200) // Center the title horizontally
.attr("y", 20) // Position the title above the chart
.attr("text-anchor", "middle") // Align text in the center
.style("font-size", "18px")
.style("font-weight", "bold")
.text(`${d.properties.name} - Distribution`);

// barchartcontainer.style("display", "flex");
// barchartcontainer.style("flex-direction", "column");
// barchartcontainer.style("width", "40%");

createBarChart(d.id);

// console.log(`Centered on State: ${state}`);
});
} else {
console.log("No state found for the clicked county.");
}

// Apply the zoom and pan to the clicked state
// console.log(`State: ${d.properties.name}`);
// console.log(`Cases: ${valuemap.get(d.id) || 0}`);
})
.on("mouseover", function (event, d) {
d3.select(this).attr("stroke", "coral").attr("stroke-width", "3px"); // Highlight on hover
// console.log(d.properties.name)
tooltip
.style("opacity", 1)
.html(
`County: ${
d?.properties?.name || "Unknown"
} <br> Cases: ${valuemap.get(d.id)}`
)
.style("left", `${event.pageX + 10}px`) // Position tooltip slightly offset from cursor
.style("top", `${event.pageY + 10}px`);
})
.on("mouseout", function () {
d3.select(this).attr("stroke", "#333").attr("stroke-width", "0.3px"); // Reset after hover
tooltip.style("opacity", 0);
});

// Add zoom and pan functionality
svg.call(
d3.zoom().on("zoom", (event) => {
svg.selectAll("path").attr("transform", event.transform);
})
);
const zoom = d3
.zoom()
.scaleExtent([1, 10]) // Limit zoom scale range
.on("zoom", (event) => {
svg.selectAll("path").attr("transform", event.transform);
});

// Apply the zoom behavior to the SVG
svg.call(zoom);

svg
.append("g")
.selectAll("path")
.data(states.features)
.join("path")
.attr("fill", "none") // No fill
.attr("stroke", "black")
.attr("stroke-width", "1px")
.attr("d", path);

d3.select("body")
.append("div")
.attr("id", "reset-btn")
.style("position", "absolute")
.style("top", "2.4vh")
.style("left", "20px")
.style("z-index", 10) // Ensure it's on top of the map
.append("button")
.text("Reset Zoom")
.style("padding", "10px 20px")
.style("font-size", "14px")
.style("background-color", "#4CAF50") // Green background
.style("color", "white") // White text
.style("border", "none")
.style("border-radius", "5px")
.style("cursor", "pointer")
.on("click", () => {
svg.transition().duration(750).call(zoom.transform, d3.zoomIdentity);
render();
// barchartcontainer.style("display", "none");
});
}
Insert cell
function createBarChart(countyId) {
// Select the bar chart container
const barchartcontainer = d3.select("#barchartcontainer");

// Clear any existing content
barchartcontainer.selectAll("*").remove();

// Set split view to flex
split_view.style("display", "flex");
d3.select("#mapcontainer").style("width", "60%");

// add the button container
const buttonContainer = barchartcontainer.append("div");

// Find the county's data
const countyData = countyRaceGenderAgeData.find((d) => d.id === countyId);

if (!countyData) {
console.log("No data found for this county");
barchartcontainer.style("display", "none");
barchartcontainer.style("width", "0%");
// Set split view to block
split_view.style("display", "block");
d3.select("#mapcontainer").style("width", "100%");
return;
}

// Prepare data for different visualizations
const ageData = Object.entries(countyData.ageCounts).map(([name, value]) => ({
name,
value
}));
const raceData = Object.entries(countyData.raceCounts).map(
([name, value]) => ({ name, value })
);
const genderData = Object.entries(countyData.genderCounts).map(
([name, value]) => ({ name, value })
);
// console.log("........");
// console.log(ageData);
// console.log(raceData);
// console.log(genderData);
// Set up SVG within the container

const margin = { top: 100, right: 40, bottom: 10, left: 50 };

const xtranslate = 50;
const ytranslate = 50;

// Update the width and height of the chart
const width = 450 - margin.left - margin.right;
const height = 400 - margin.top - margin.bottom;
const svg = barchartcontainer
.append("svg")
.attr("width", "100%")
.attr("height", "100%")
.style("margin", "10px")
.style("padding", "15px 10px")
.append("g");

// Function to create a bar chart
function createMultiBarChart(data, title) {
// Clear previous chart
const filteredData = data.filter((d) => d.value > 0);
if (filteredData.length === 0) {
svg
.append("text")
.attr("x", width / 2 + xtranslate)
.attr("y", height / 2 + ytranslate)
.attr("text-anchor", "middle")
.style("font-size", "16px")
.text("No data available to display");
return;
}
// Clear previous chart
svg.selectAll("*").remove();
// console.log("Loading data for: " + title);

// X scale
const x = d3
.scaleBand()
.range([0, width])
.domain(filteredData.map((d) => d.name))
.padding(0.1);

// Y scale
const y = d3
.scaleLinear()
.range([height, 0])
.domain([0, d3.max(filteredData, (d) => d.value)]);

// Color scale
const color = d3
.scaleOrdinal()
.domain(filteredData.map((d) => d.name))
.range(d3.schemeCategory10);

// Create bars
svg
.selectAll(".bar")
.data(filteredData)
.enter()
.append("rect")
.attr("class", "bar")
.attr("x", (d) => x(d.name) + xtranslate)
.attr("width", x.bandwidth())
.attr("y", (d) => y(d.value) + ytranslate)
.attr("height", (d) => height - y(d.value))
.attr("fill", (d) => color(d.name))
.on("mouseover", function (event, d) {
d3.select(this).attr("stroke", "coral").attr("stroke-width", "3px");

// Show tooltip
tooltip
.style("opacity", 1)
.html(`${d.name}: ${d.value}`)
.style("left", `${event.pageX + 10}px`)
.style("top", `${event.pageY + 10}px`);
})
.on("mouseout", function () {
d3.select(this).attr("stroke", "none");
tooltip.style("opacity", 0);
});

// Add X axis
svg
.append("g")
.attr("transform", `translate(${xtranslate},${height + ytranslate})`)
.call(d3.axisBottom(x))
.selectAll("text")
.style("text-anchor", "end")
.attr("dx", ".15em")
.attr("dy", ".5em")
.attr("transform", "rotate(-45)");

// X-axis title
svg
.append("text")
.attr("class", "x-axis-title")
.attr("text-anchor", "middle")
.attr("x", width / 2 + xtranslate)
.attr(
"y",
height + margin.bottom + margin.top + (title.includes("Race") ? 50 : 0)
)
.style("font-size", "12px")
.text(title);

// Add Y axis
svg
.append("g")
.attr("transform", `translate(${xtranslate}, ${ytranslate})`)
.call(d3.axisLeft(y));

// Y-axis title
svg
.append("text")
.attr("class", "y-axis-title")
.attr("text-anchor", "middle")
.attr("transform", "rotate(-90)")
.attr("x", -height / 2 - xtranslate)
.attr("y", margin.left / 2)
.style("font-size", "12px")
.text("Number of Cases");

// Add title
svg
.append("text")
.attr("x", width / 2 + xtranslate)
.attr("y", ytranslate - 25)
.attr("text-anchor", "middle")
.style("font-size", "16px")
.text(
`${countyData.county} County, ${
territories.find((d) => d.name === countyData.state).abbreviation
} - ${title}`
);
}

buttonContainer
// .style("position", "relative")
.style("justify-content", "center")
.style("display", "flex")
.style("flex-direction", "row")
// .style("top", "20px") // Adjust the vertical position
// .style("right", "20px") // Adjust the horizontal position
.style("width", "100%")
.style("background", "rgba(255, 255, 255, 0.8)")
.style("z-index", "10");

// Styling individual buttons
buttonContainer
.append("button")
.text("Age")
.style("padding", "10px 20px")
.style("margin", "5px 10px")
.style("font-size", "12px")
.style("background-color", "#CBC3E3")
.style("color", "#342047")
.style("border", "none") // Remove border
.style("border-radius", "5px") // Rounded corners
.style("cursor", "pointer") // Pointer cursor on hover
.style("transition", "background-color 0.3s") // Smooth background color transition
.on("click", () => createMultiBarChart(ageData, "Age Distribution"))
.on("mouseover", function () {
d3.select(this).style("background-color", "#B8A8D4");
})
.on("mouseout", function () {
d3.select(this).style("background-color", "#CBC3E3"); // Revert back on mouseout
});

buttonContainer
.append("button")
.text("Race")
.style("padding", "10px 20px")
.style("margin", "5px 10px")
.style("font-size", "12px")
.style("background-color", "#CBC3E3")
.style("color", "#342047")
.style("border", "none") // Remove border
.style("border-radius", "5px") // Rounded corners
.style("cursor", "pointer") // Pointer cursor on hover
.style("transition", "background-color 0.3s") // Smooth background color transition
.on("click", () => createMultiBarChart(raceData, "Race Distribution"))
.on("mouseover", function () {
d3.select(this).style("background-color", "#B8A8D4");
})
.on("mouseout", function () {
d3.select(this).style("background-color", "#CBC3E3");
});

buttonContainer
.append("button")
.text("Biological Sex")
.style("padding", "10px 20px")
.style("margin", "5px 10px")
.style("font-size", "12px")
.style("background-color", "#CBC3E3")
.style("color", "#342047")
.style("border", "none") // Remove border
.style("border-radius", "5px") // Rounded corners
.style("cursor", "pointer") // Pointer cursor on hover
.style("transition", "background-color 0.3s") // Smooth background color transition
.on("click", () => createMultiBarChart(genderData, "Biological Sex Distribution"))
.on("mouseover", function () {
d3.select(this).style("background-color", "#B8A8D4");
})
.on("mouseout", function () {
d3.select(this).style("background-color", "#CBC3E3"); // Revert back on mouseout
});

// buttonContainer
// .append("button")
// .text("Close")
// .style("padding", "10px 20px")
// .style("margin", "5px 10px")
// .style("font-size", "12px")
// .style("background-color", "#CBC3E3")
// .style("color", "#342047")
// .style("border", "none") // Remove border
// .style("border-radius", "5px") // Rounded corners
// .style("cursor", "pointer") // Pointer cursor on hover
// .style("transition", "background-color 0.3s") // Smooth background color transition
// .on("click", () => {
// barchartcontainer.style("display", "none");
// buttonContainer.style("display", "none");
// })
// .on("mouseover", function () {
// d3.select(this).style("background-color", "#B8A8D4");
// })
// .on("mouseout", function () {
// d3.select(this).style("background-color", "#CBC3E3"); // Revert back on mouseout
// });

// Initial view (Age Distribution)
createMultiBarChart(ageData, "Age Distribution");

// Make the container visible
barchartcontainer.style("display", "flex");
// buttonContainer.style("display", "block");
}
Insert cell
function createBarChartAll(barcharttitle) {
// Select the bar chart container
const barchartcontainer = d3.select("#barchartcontainer");

// Clear any existing content
barchartcontainer.selectAll("*").remove();

// Set split view to flex
split_view.style("display", "flex");
d3.select("#mapcontainer").style("width", "60%");

// add the button container
const buttonContainer = barchartcontainer.append("div");

const aggregatedData = countyRaceGenderAgeData.reduce(
(acc, county) => {
// Aggregate age counts
for (const [age, count] of Object.entries(county.ageCounts)) {
acc.ageCounts[age] = (acc.ageCounts[age] || 0) + count;
}

// Aggregate race counts
for (const [race, count] of Object.entries(county.raceCounts)) {
acc.raceCounts[race] = (acc.raceCounts[race] || 0) + count;
}

// Aggregate gender counts
for (const [gender, count] of Object.entries(county.genderCounts)) {
acc.genderCounts[gender] = (acc.genderCounts[gender] || 0) + count;
}

return acc;
},
{ ageCounts: {}, raceCounts: {}, genderCounts: {} }
);
// Prepare data for different visualizations
const ageData = Object.entries(aggregatedData.ageCounts).map(
([name, value]) => ({
name,
value
})
);
const raceData = Object.entries(aggregatedData.raceCounts).map(
([name, value]) => ({ name, value })
);
const genderData = Object.entries(aggregatedData.genderCounts).map(
([name, value]) => ({ name, value })
);
// console.log("........");
// console.log(ageData);
// console.log(raceData);
// console.log(genderData);
// Set up SVG within the container

const margin = { top: 100, right: 40, bottom: 10, left: 50 };
// const padding = { top: 50, right: 50, bottom: 50, left: 50 };

const xtranslate = 70;
const ytranslate = 50;

// Update the width and height of the chart
const width = 450 - margin.left - margin.right;
const height = 400 - margin.top - margin.bottom;
const svg = barchartcontainer
.append("svg")
.attr("width", "100%")
.attr("height", "100%")
.style("margin", "10px")
.style("padding", "15px 5px")
.append("g");
// .attr("transform", `translate(${margin.left},${margin.top})`);

// Function to create a bar chart
function createMultiBarChart(data, title) {
// Clear previous chart
const filteredData = data.filter((d) => d.value > 0);
if (filteredData.length === 0) {
svg
.append("text")
.attr("x", width / 2 + xtranslate)
.attr("y", height / 2 + ytranslate)
.attr("text-anchor", "middle")
.style("font-size", "16px")
.text("No data available to display");
return;
}
// Clear previous chart
svg.selectAll("*").remove();
// console.log("Loading data for: " + title);

// X scale
const x = d3
.scaleBand()
.range([0, width])
.domain(filteredData.map((d) => d.name))
.padding(0.1);

// Y scale
const y = d3
.scaleLinear()
.range([height, 0])
.domain([0, d3.max(filteredData, (d) => d.value)]);

// Color scale
const color = d3
.scaleOrdinal()
.domain(filteredData.map((d) => d.name))
.range(d3.schemeCategory10);

// Create bars
svg
.selectAll(".bar")
.data(filteredData)
.enter()
.append("rect")
.attr("class", "bar")
.attr("x", (d) => x(d.name) + xtranslate)
.attr("width", x.bandwidth())
.attr("y", (d) => y(d.value) + ytranslate)
.attr("height", (d) => height - y(d.value))
.attr("fill", (d) => color(d.name))
.on("mouseover", function (event, d) {
d3.select(this).attr("stroke", "coral").attr("stroke-width", "3px");

// Show tooltip
tooltip
.style("opacity", 1)
.html(`${d.name}: ${d.value}`)
.style("left", `${event.pageX + 10}px`)
.style("top", `${event.pageY + 10}px`);
})
.on("mouseout", function () {
d3.select(this).attr("stroke", "none");
tooltip.style("opacity", 0);
});

// Add X axis
svg
.append("g")
.attr("transform", `translate(${xtranslate},${height + ytranslate})`)
.call(d3.axisBottom(x))
.selectAll("text")
.style("text-anchor", "end")
.attr("dx", ".15em")
.attr("dy", ".5em")
.attr("transform", "rotate(-45)");

// X-axis title
svg
.append("text")
.attr("class", "x-axis-title")
.attr("text-anchor", "middle")
.attr("x", width / 2 + xtranslate)
.attr(
"y",
height + margin.bottom + margin.top + (title.includes("Race") ? 50 : 0)
)
.style("font-size", "12px")
.text(title);

// Add Y axis
svg
.append("g")
.attr("transform", `translate(${xtranslate}, ${ytranslate})`)
.call(d3.axisLeft(y));

// Y-axis title
svg
.append("text")
.attr("class", "y-axis-title")
.attr("text-anchor", "middle")
.attr("transform", "rotate(-90)")
.attr("x", -height / 2 - xtranslate)
.attr("y", margin.left / 2)
.style("font-size", "12px")
.text("Number of Cases");

// Chart title
svg
.append("text")
.attr("x", width / 2 + xtranslate)
.attr("y", 30)
.attr("text-anchor", "middle")
.style("font-size", "16px")
.text(`${barcharttitle} - ${title}`);
}

buttonContainer
// .style("position", "relative")
.style("justify-content", "center")
.style("display", "flex")
.style("flex-direction", "row")
// .style("top", "20px") // Adjust the vertical position
// .style("right", "20px") // Adjust the horizontal position
.style("width", "100%")
.style("background", "rgba(255, 255, 255, 0.8)")
.style("z-index", "10");

// Styling individual buttons
buttonContainer
.append("button")
.text("Age")
.style("padding", "10px 20px")
.style("margin", "5px 10px")
.style("font-size", "12px")
.style("background-color", "#CBC3E3")
.style("color", "#342047")
.style("border", "none") // Remove border
.style("border-radius", "5px") // Rounded corners
.style("cursor", "pointer") // Pointer cursor on hover
.style("transition", "background-color 0.3s") // Smooth background color transition
.on("click", () => createMultiBarChart(ageData, "Age Distribution"))
.on("mouseover", function () {
d3.select(this).style("background-color", "#B8A8D4");
})
.on("mouseout", function () {
d3.select(this).style("background-color", "#CBC3E3"); // Revert back on mouseout
});

buttonContainer
.append("button")
.text("Race")
.style("padding", "10px 20px")
.style("margin", "5px 10px")
.style("font-size", "12px")
.style("background-color", "#CBC3E3")
.style("color", "#342047")
.style("border", "none") // Remove border
.style("border-radius", "5px") // Rounded corners
.style("cursor", "pointer") // Pointer cursor on hover
.style("transition", "background-color 0.3s") // Smooth background color transition
.on("click", () => createMultiBarChart(raceData, "Race Distribution"))
.on("mouseover", function () {
d3.select(this).style("background-color", "#B8A8D4");
})
.on("mouseout", function () {
d3.select(this).style("background-color", "#CBC3E3");
});

buttonContainer
.append("button")
.text("Biological Sex")
.style("padding", "10px 20px")
.style("margin", "5px 10px")
.style("font-size", "12px")
.style("background-color", "#CBC3E3")
.style("color", "#342047")
.style("border", "none") // Remove border
.style("border-radius", "5px") // Rounded corners
.style("cursor", "pointer") // Pointer cursor on hover
.style("transition", "background-color 0.3s") // Smooth background color transition
.on("click", () => createMultiBarChart(genderData, "Biological Sex Distribution"))
.on("mouseover", function () {
d3.select(this).style("background-color", "#B8A8D4");
})
.on("mouseout", function () {
d3.select(this).style("background-color", "#CBC3E3"); // Revert back on mouseout
});

// buttonContainer
// .append("button")
// .text("Close")
// .style("padding", "10px 20px")
// .style("margin", "5px 10px")
// .style("font-size", "12px")
// .style("background-color", "#CBC3E3")
// .style("color", "#342047")
// .style("border", "none") // Remove border
// .style("border-radius", "5px") // Rounded corners
// .style("cursor", "pointer") // Pointer cursor on hover
// .style("transition", "background-color 0.3s") // Smooth background color transition
// .on("click", () => {
// barchartcontainer.style("display", "none");
// buttonContainer.style("display", "none");
// })
// .on("mouseover", function () {
// d3.select(this).style("background-color", "#B8A8D4");
// })
// .on("mouseout", function () {
// d3.select(this).style("background-color", "#CBC3E3"); // Revert back on mouseout
// });

// Initial view (Age Distribution)
createMultiBarChart(ageData, "Age Distribution");

// Make the container visible
barchartcontainer.style("display", "flex");
// buttonContainer.style("display", "block");
}
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