d3.json("sleep_combined_clean.json").then(function(data) { // Fonction pour filtrer les mois en fonction de l'année sélectionnée function getMonthsForYear(year) { return d3.timeMonths(new Date(year + "-01-01"), new Date(year + "-12-31")); } // Parsing des dates et tri des données par mois data.forEach(d => { d.date = d3.timeParse("%Y-%m-%d")(d.date); d.month = d3.timeMonth(d.date); }); // Création du groupe pour chaque membre var members = ["Anis", "Maya", "Corentin", "Amira"]; // Fonction de mise à jour du graphique en fonction de l'année et des membres sélectionnés function updateChart(selectedYear, selectedMembers) { const monthsForYear = getMonthsForYear(selectedYear); // Filtrage des données par mois var groupedData = d3.group(data, d => d.month); // Transformation des données en format plus approprié pour la visualisation var nestedData = monthsForYear.map(month => { const valuesForMonth = groupedData.get(month) || []; const avgMonthSleep = selectedMembers.map(member => { const memberData = valuesForMonth.filter(d => d[member] !== null); return { member: member, value: memberData.length > 0 ? d3.mean(memberData, v => v[member]) : null // Utiliser null pour les données manquantes }; }); return { month: month, values: avgMonthSleep }; }); // Dimensions du graphique var width = 800, height = 400; var margin = { top: 20, right: 120, bottom: 60, left: 60 }; // Création des échelles var x = d3.scaleBand() .domain(monthsForYear) .range([margin.left, width - margin.right]) .padding(0.05); // Réduire l'espacement entre les mois var y = d3.scaleLinear() .domain([0, d3.max(nestedData, d => d3.max(d.values, v => v.value))]) .nice() .range([height - margin.bottom, margin.top]); var color = d3.scaleOrdinal() .domain(selectedMembers) .range(["#ff6347", "#4682b4", "#32cd32", "#ff1493"]); // Création du SVG var svg = d3.select("#chart") .attr("width", width) .attr("height", height); // Nettoyer le SVG avant de redessiner svg.selectAll("*").remove(); // Ajouter les axes svg.append("g") .attr("transform", `translate(0, ${height - margin.bottom})`) .call(d3.axisBottom(x) .tickFormat(d3.timeFormat("%B")) // Utilisation du format du mois pour l'axe X .ticks(d3.timeMonth.every(1)) // Affichage de chaque mois ) .selectAll("text") .style("text-anchor", "middle") .style("font-size", "12px"); svg.append("g") .attr("transform", `translate(${margin.left}, 0)`) .call(d3.axisLeft(y)); // Ajouter les titres des axes svg.append("text") .attr("x", width / 2) .attr("y", height - 5) .attr("text-anchor", "middle") .style("font-size", "16px") .text("Mois"); svg.append("text") .attr("transform", "rotate(-90)") .attr("x", -height / 2) .attr("y", 20) .attr("text-anchor", "middle") .style("font-size", "16px") .text("Heures de sommeil"); // Création du tooltip var tooltip = d3.select("body").append("div") .attr("class", "tooltip") .style("position", "absolute") .style("visibility", "hidden") .style("background-color", "rgba(0, 0, 0, 0.7)") .style("color", "white") .style("padding", "5px") .style("border-radius", "5px") .style("pointer-events", "none"); // Dessiner les barres svg.append("g") .selectAll("g") .data(nestedData) .enter().append("g") .attr("transform", d => `translate(${x(d.month)}, 0)`) .selectAll("rect") .data(d => d.values.filter(v => selectedMembers.includes(v.member) && v.value !== null)) // Filtrer les données null .enter().append("rect") .attr("x", (d, i) => i * (x.bandwidth() / selectedMembers.length)) // Coller les barres .attr("y", d => y(d.value)) .attr("width", x.bandwidth() / selectedMembers.length - 1) // Ajuster la largeur des barres .attr("height", d => height - margin.bottom - y(d.value)) .attr("fill", d => color(d.member)) .on("mouseover", function(event, d) { tooltip.style("visibility", "visible") .text(d.member + ": " + d.value.toFixed(2) + " heures"); }) .on("mousemove", function(event) { tooltip.style("top", (event.pageY + 5) + "px") .style("left", (event.pageX + 5) + "px"); }) .on("mouseout", function() { tooltip.style("visibility", "hidden"); }); // Ajouter la légende var legend = svg.append("g") .attr("transform", `translate(${width - margin.right + 20}, ${margin.top})`); selectedMembers.forEach((member, i) => { var legendRow = legend.append("g") .attr("transform", `translate(0, ${i * 20})`); legendRow.append("rect") .attr("width", 15) .attr("height", 15) .attr("fill", color(member)); legendRow.append("text") .attr("x", 20) .attr("y", 12) .style("font-size", "12px") .text(member); }); } // Initialisation avec tous les membres updateChart(2024, ["Anis", "Maya", "Corentin", "Amira"]); // Gestion des changements dans les sélections d3.select("#yearSelect").on("change", function() { const selectedYear = this.value; const selectedMembers = Array.from(document.querySelectorAll("#memberSelect input:checked")).map(input => input.value); updateChart(selectedYear, selectedMembers); }); d3.select("#memberSelect").on("change", function() { const selectedYear = d3.select("#yearSelect").node().value; const selectedMembers = Array.from(document.querySelectorAll("#memberSelect input:checked")).map(input => input.value); updateChart(selectedYear, selectedMembers); }); });