From eba518c49710a01d7ef5ced1eb8e2f1c735f4e7d Mon Sep 17 00:00:00 2001
From: p2312048 <maya.boudjebbour@etu.univ-lyon1.fr>
Date: Thu, 2 Jan 2025 00:23:48 +0100
Subject: [PATCH] Update visualisation sommeil

---
 Visu/index.html |  48 ++++++++++---------
 Visu/script.js  | 121 ++++++++++++++++++++++++++++--------------------
 Visu/style.css  |  53 ++++++++++++++++++---
 3 files changed, 142 insertions(+), 80 deletions(-)

diff --git a/Visu/index.html b/Visu/index.html
index 79b452d..5ca6ba6 100644
--- a/Visu/index.html
+++ b/Visu/index.html
@@ -8,30 +8,34 @@
 </head>
 <body>
     <div class="container">
-        <h1>Comparaison des Cycles de Sommeil</h1>
-        
-        <!-- Sélecteur d'année -->
-        <label for="yearSelect">Choisissez l'année:</label>
-        <select id="yearSelect">
-            <option value="2024">2024</option>
-            <option value="2021">2021</option>
-            <option value="2022">2022</option>
-            <option value="2023">2023</option>
-            <!-- Vous pouvez ajouter d'autres années si nécessaire -->
-        </select>
-        
-        <!-- Sélecteur de membre -->
-        <label for="memberSelect">Choisissez un membre:</label>
-        <select id="memberSelect">
-            <option value="all">Tous les membres</option>
-            <option value="Anis">Anis</option>
-            <option value="Maya">Maya</option>
-            <option value="Corentin">Corentin</option>
-            <option value="Amira">Amira</option>
-        </select>
+        <!-- Conteneur de la partie sélecteurs à gauche -->
+        <div class="selectors">
+            <!-- Sélecteur d'année sous forme de liste déroulante -->
+            <label for="yearSelect">Choisissez l'année:</label>
+            <select id="yearSelect">
+                <option value="2024">2024</option>
+                <option value="2023">2023</option>
+                <option value="2022">2022</option>
+                <option value="2021">2021</option>
+
+            </select>
+            
+            <!-- Sélecteur de membre -->
+            <label for="memberSelect">Choisissez un membre:</label>
+            <select id="memberSelect">
+                <option value="all">Tous les membres</option>
+                <option value="Anis">Anis</option>
+                <option value="Maya">Maya</option>
+                <option value="Corentin">Corentin</option>
+                <option value="Amira">Amira</option>
+            </select>
+        </div>
 
         <!-- Espace pour le graphique -->
-        <svg id="chart"></svg>
+        <svg id="chart">
+            <!-- Titre du graphique à placer dans le SVG -->
+            <text id="chartTitle" x="50%" y="30" text-anchor="middle" font-size="20" fill="#333">Comparaison des Cycles de Sommeil</text>
+        </svg>
     </div>
 
     <script src="https://d3js.org/d3.v7.min.js"></script>
diff --git a/Visu/script.js b/Visu/script.js
index cd5a5c1..bc7f010 100644
--- a/Visu/script.js
+++ b/Visu/script.js
@@ -7,7 +7,7 @@ d3.json("sleep_combined_clean.json").then(function(data) {
     // 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); // Utilisation de d3.timeMonth pour grouper par mois
+        d.month = d3.timeMonth(d.date);
     });
 
     // Création du groupe pour chaque membre
@@ -18,70 +18,81 @@ d3.json("sleep_combined_clean.json").then(function(data) {
         const monthsForYear = getMonthsForYear(selectedYear);
 
         // Filtrage des données par mois
-        var groupedData = d3.group(data, d => d.month); // Utilisation de d3.group pour le groupement 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) || []; // Données filtrées pour le mois
+            const valuesForMonth = groupedData.get(month) || [];
+            const avgMonthSleep = members.map(member => {
+                const memberData = valuesForMonth.filter(d => d[member] !== null);
+                return {
+                    member: member,
+                    value: memberData.length > 0 ? d3.mean(memberData, v => v[member]) : 0
+                };
+            });
 
             return {
                 month: month,
-                values: members.map(member => {
-                    const memberData = valuesForMonth.filter(d => d[member] !== null); 
-                    const avgValue = memberData.length > 0 ? d3.mean(memberData, v => v[member]) : 0;
-                    return {
-                        member: member,
-                        value: avgValue // Valeur calculée pour ce membre
-                    };
-                })
+                values: avgMonthSleep
             };
         });
 
         // Dimensions du graphique
         var width = 800, height = 400;
-        var margin = {top: 20, right: 30, bottom: 60, left: 60}; // Ajuster les marges pour les axes
+        var margin = { top: 20, right: 120, bottom: 60, left: 60 };
 
-        // Création de l'échelle des X et Y
+        // Création des échelles
         var x = d3.scaleBand()
-            .domain(monthsForYear) // Utiliser les mois de l'année sélectionnée
+            .domain(monthsForYear)
             .range([margin.left, width - margin.right])
             .padding(0.1);
-        
+
         var y = d3.scaleLinear()
             .domain([0, d3.max(nestedData, d => d3.max(d.values, v => v.value))])
             .nice()
             .range([height - margin.bottom, margin.top]);
-        
-        // Création de l'échelle des couleurs pour chaque membre
+
         var color = d3.scaleOrdinal()
             .domain(members)
-            .range(["#ff6347", "#4682b4", "#32cd32", "#ff1493"]); // Couleurs différentes pour chaque membre
+            .range(["#ff6347", "#4682b4", "#32cd32", "#ff1493"]);
 
-        // Création du SVG pour le graphique
+        // Création du SVG
         var svg = d3.select("#chart")
             .attr("width", width)
             .attr("height", height);
 
         // Nettoyer le SVG avant de redessiner
-        svg.selectAll("*").remove(); 
+        svg.selectAll("*").remove();
 
-        // Ajouter l'axe X
+        // Ajouter les axes
         svg.append("g")
-            .attr("transform", "translate(0," + (height - margin.bottom) + ")")
-            .call(d3.axisBottom(x).tickFormat(d3.timeFormat("%B"))) // Affichage des mois
+            .attr("transform", `translate(0, ${height - margin.bottom})`)
+            .call(d3.axisBottom(x).tickFormat(d3.timeFormat("%B")))
             .selectAll("text")
             .style("text-anchor", "middle")
-            .style("font-size", "12px")
-            .attr("transform", "rotate(-45)")
-            .attr("dx", "-0.8em")
-            .attr("dy", "0.15em");
+            .style("font-size", "12px");
 
-        // Ajouter l'axe Y
         svg.append("g")
-            .attr("transform", "translate(" + margin.left + ",0)")
+            .attr("transform", `translate(${margin.left}, 0)`)
             .call(d3.axisLeft(y));
 
-        // Créer le tooltip
+        // 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")
@@ -92,58 +103,66 @@ d3.json("sleep_combined_clean.json").then(function(data) {
             .style("border-radius", "5px")
             .style("pointer-events", "none");
 
-        // Dessiner les barres pour chaque mois et chaque membre
+        // Dessiner les barres
         svg.append("g")
             .selectAll("g")
             .data(nestedData)
             .enter().append("g")
-            .attr("transform", d => "translate(" + x(d.month) + ",0)")
+            .attr("transform", d => `translate(${x(d.month)}, 0)`)
             .selectAll("rect")
-            .data(d => {
-                if (selectedMember === "all") {
-                    return d.values; // Affiche tous les membres
-                } else {
-                    return d.values.filter(v => v.member === selectedMember); // Affiche seulement le membre sélectionné
-                }
-            })
+            .data(d => selectedMember === "all" ? d.values : d.values.filter(v => v.member === selectedMember))
             .enter().append("rect")
-            .attr("x", (d, i) => i * (x.bandwidth() / 4)) // Chaque membre reçoit une portion de la bande
+            .attr("x", (d, i) => i * (x.bandwidth() / members.length))
             .attr("y", d => y(d.value))
-            .attr("width", x.bandwidth() / 4) // Largeur des barres
+            .attr("width", x.bandwidth() / members.length)
             .attr("height", d => height - margin.bottom - y(d.value))
             .attr("fill", d => color(d.member))
-            .append("title")
-            .text(d => d.member + ": " + d.value.toFixed(2) + " heures")
             .on("mouseover", function(event, d) {
-                // Afficher le tooltip lors du survol
                 tooltip.style("visibility", "visible")
                     .text(d.member + ": " + d.value.toFixed(2) + " heures");
             })
             .on("mousemove", function(event) {
-                // Déplacer le tooltip avec la souris
                 tooltip.style("top", (event.pageY + 5) + "px")
                     .style("left", (event.pageX + 5) + "px");
             })
             .on("mouseout", function() {
-                // Cacher le tooltip lorsqu'on arrête de survoler
                 tooltip.style("visibility", "hidden");
             });
+
+        // Ajouter la légende
+        var legend = svg.append("g")
+            .attr("transform", `translate(${width - margin.right + 20}, ${margin.top})`);
+
+        members.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);
+        });
     }
 
-    // Initialiser avec 2024 et tous les membres
+    // Initialisation
     updateChart(2024, "all");
 
-    // Mettre à jour le graphique lorsque l'utilisateur change l'année ou le membre
+    // Gestion des changements dans les sélections
     d3.select("#yearSelect").on("change", function() {
         const selectedYear = this.value;
         const selectedMember = d3.select("#memberSelect").node().value;
-        updateChart(selectedYear, selectedMember); // Redessiner le graphique avec la nouvelle année
+        updateChart(selectedYear, selectedMember);
     });
 
-    // Mettre à jour le graphique lorsque l'utilisateur change la sélection du membre
     d3.select("#memberSelect").on("change", function() {
         const selectedMember = this.value;
         const selectedYear = d3.select("#yearSelect").node().value;
-        updateChart(selectedYear, selectedMember); // Redessiner le graphique avec le membre sélectionné
+        updateChart(selectedYear, selectedMember);
     });
 });
diff --git a/Visu/style.css b/Visu/style.css
index 7823d15..f6629cd 100644
--- a/Visu/style.css
+++ b/Visu/style.css
@@ -3,23 +3,63 @@ body {
     margin: 0;
     padding: 0;
     background-color: #f5f5f5;
+    display: flex;
+    justify-content: center;
+    align-items: flex-start;
+    height: 100vh;
 }
 
 .container {
+    display: flex;
+    justify-content: space-between;
     width: 80%;
-    margin: 0 auto;
-    padding-top: 20px;
-    text-align: center;
+    padding: 20px;
+    margin-top: 20px;
+    align-items: flex-start;
 }
 
-h1 {
-    font-size: 24px;
+.selectors {
+    width: 200px;
+    display: flex;
+    flex-direction: column;
+    align-items: flex-start;
+    padding: 10px;
+    background-color: #ffffff;
+    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
+}
+
+label {
+    margin: 10px 0 5px;
+    font-size: 16px;
+}
+
+select {
+    width: 100%;
+    padding: 8px;
     margin-bottom: 20px;
+    font-size: 16px;
+    border-radius: 4px;
+    border: 1px solid #ccc;
+}
+
+#chart-container {
+    display: flex;
+    flex-direction: column;
+    align-items: center; /* Centrer tout le contenu à l'intérieur du conteneur */
+    width: 60%;
+}
+
+#mainTitle {
+    font-size: 24px;
+    margin-bottom: 20px; /* Espacement entre le titre et le graphique */
+    text-align: center; /* Centrer le titre */
 }
 
 #chart {
-    width: 100%;
     height: 500px;
+    width: 70%;
+    background-color: #ffffff;
+    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
 }
 
 .tooltip {
@@ -32,4 +72,3 @@ h1 {
     pointer-events: none;
     font-size: 14px;
 }
-
-- 
GitLab