Skip to content
Snippets Groups Projects
Commit a541e07e authored by BOUDJEBBOUR MAYA p2312048's avatar BOUDJEBBOUR MAYA p2312048
Browse files

V1 visualisations calories+pas

parent 116adfe4
No related branches found
No related tags found
No related merge requests found
This diff is collapsed.
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Calories Brûlées par Mois</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<div id="visualization"></div>
<script src="https://d3js.org/d3.v7.min.js"></script>
<script src="script.js"></script>
</body>
</html>
fetch('final_combined_with_all_data.json')
.then((response) => response.json())
.then((data) => {
const parseDate = d3.timeParse("%Y-%m-%d");
const formatYear = d3.timeFormat("%Y");
const formatMonth = d3.timeFormat("%Y-%m");
const members = ["Corentin", "Maya", "Anis", "Amira"];
data.forEach(d => d.date = parseDate(d.date));
// Dimensions et marges
const margin = { top: 50, right: 230, bottom: 150, left: 70 };
const width = 1000 - margin.left - margin.right;
const height = 500 - margin.top - margin.bottom;
// Créer le conteneur SVG principal
const svg = d3.select("#visualization")
.append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", `translate(${margin.left},${margin.top})`);
// Créer un conteneur pour le graphique détaillé
const detailContainer = d3.select("#visualization")
.append("div")
.attr("id", "detail-container")
.style("margin-top", "20px");
// Définir les années et la plage d'affichage
const years = [2022, 2023, 2024];
// Créer le slider
const sliderContainer = d3.select("#visualization")
.append("div")
.attr("id", "slider-container")
.style("display", "flex")
.style("align-items", "center")
.style("justify-content", "space-between");
const rangeSlider = sliderContainer.append("input")
.attr("type", "range")
.attr("min", 0)
.attr("max", years.length - 1)
.attr("value", 0)
.style("width", "30%")
.style("margin-left", "50px");
const yearDisplay = sliderContainer.append("span")
.text(years[0]);
// Tooltip
const tooltip = d3.select("body").append("div")
.attr("class", "tooltip")
.style("opacity", 0);
// Fonction de mise à jour de la visualisation
function updateVisualization(selectedYear) {
const filteredData = data.filter(d => formatYear(d.date) === selectedYear.toString());
if (filteredData.length === 0) {
console.log(`Aucune donnée pour l'année ${selectedYear}`);
return;
}
const groupedData = d3.groups(filteredData, d => formatMonth(d.date));
const aggregatedData = groupedData.map(([month, records]) => {
const aggregated = { month };
members.forEach(member => {
aggregated[`Calories_${member}`] = d3.mean(records, d => d[`Calories_${member}`] || 0);
});
return aggregated;
});
svg.selectAll("*").remove();
svg.append("text")
.attr("x", width / 2) // Centrer horizontalement
.attr("y", margin.top - 60) // Positionner légèrement au-dessus du graphique
.attr("text-anchor", "middle") // Centrer le texte
.style("font-size", "16px") // Taille de police
.style("font-weight", "bold") // Gras
.text("Analyse des calories brûlées par mois");
const xScale = d3.scaleBand()
.domain(aggregatedData.map(d => d.month))
.range([0, width])
.padding(0.2);
const yScale = d3.scaleLinear()
.domain([0, d3.max(aggregatedData, d => Math.max(...members.map(member => d[`Calories_${member}`])))]).nice()
.range([height, 0]);
// Définir une palette de couleurs avec des couleurs plus distinctes
const colorScale = d3.scaleOrdinal()
.domain(members)
.range([
"#1d38e3", // corentin
"#0f7e06", // maya
"#d6bff4", // anis
"#7e09bd" // amira
]);
// Axe X
svg.append("g")
.attr("transform", `translate(0, ${height})`)
.call(d3.axisBottom(xScale))
.selectAll("text")
.attr("transform", "rotate(-45)")
.style("text-anchor", "end");
// Légende de l'axe X
svg.append("text")
.attr("x", width / 2)
.attr("y", height + 40)
.attr("text-anchor", "middle")
.style("font-size", "14px")
.text("Mois");
// Axe Y
svg.append("g").call(d3.axisLeft(yScale));
// Légende de l'axe Y
svg.append("text")
.attr("transform", "rotate(-90)")
.attr("x", -height / 2)
.attr("y", -50)
.attr("text-anchor", "middle")
.style("font-size", "14px")
.text("Calories brûlées");
// Légende des membres (rectangles colorés)
const legend = svg.append("g")
.attr("transform", `translate(${width + 10}, 20)`);
members.forEach((member, i) => {
legend.append("rect")
.attr("x", 0)
.attr("y", i * 20)
.attr("width", 15)
.attr("height", 15)
.attr("fill", colorScale(member));
legend.append("text")
.attr("x", 20)
.attr("y", i * 20 + 12)
.text(member)
.style("font-size", "12px")
.attr("text-anchor", "start");
});
// Création des aires pour chaque membre
members.forEach((member, i) => {
const areaData = aggregatedData.map(d => {
let calories = d[`Calories_${member}`] === -1.0 ? 0 : d[`Calories_${member}`]; // Remplacer -1.0 par 0
return {
month: d.month,
calories: calories
};
});
const area = d3.area()
.x(d => xScale(d.month) + xScale.bandwidth() / 2)
.y0(yScale(0))
.y1(d => yScale(d.calories))
.defined(d => d.calories !== 0); // Ne pas tracer si les données sont manquantes
svg.append("path")
.data([areaData])
.attr("class", `area-${member}`)
.attr("d", area)
.attr("fill", colorScale(member))
.attr("opacity", 0.8) // Opacité augmentée pour plus de visibilité
//.attr("stroke", "white") // Bordure blanche
// .attr("stroke-width", 2) // Épaisseur de la bordure
});
}
// Initialisation de la visualisation avec la première année
updateVisualization(years[0]);
// Écouter les changements du slider
rangeSlider.on("input", function() {
const selectedYear = years[this.value];
yearDisplay.text(selectedYear);
updateVisualization(selectedYear);
});
})
.catch((error) => console.error('Erreur de chargement des données:', error));
body {
font-family: Arial, sans-serif;
margin: 0;
padding: 0;
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
background-color: #f4f4f4;
}
#visualization {
margin-top: 20px;
width: 80%;
max-width: 1000px;
}
#slider-container {
margin-top: 20px;
display: flex;
justify-content: space-between;
align-items: center;
}
This diff is collapsed.
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Analyse des Pas des Utilisateurs</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<div id="visualization"></div>
<div id="detail-container"></div>
<script src="https://d3js.org/d3.v7.min.js"></script>
<script src="script.js"></script>
</body>
</html>
fetch('final_combined_with_all_data.json')
.then((response) => response.json())
.then((data) => {
const parseDate = d3.timeParse("%Y-%m-%d");
const formatYear = d3.timeFormat("%Y");
const formatMonth = d3.timeFormat("%Y-%m");
const members = ["Corentin", "Maya", "Anis", "Amira"];
data.forEach(d => d.date = parseDate(d.date));
// Dimensions et marges
const margin = { top: 50, right: 230, bottom: 150, left: 70 };
const width = 1000 - margin.left - margin.right;
const height = 500 - margin.top - margin.bottom;
// Créer le conteneur SVG principal
const svg = d3.select("#visualization")
.append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", `translate(${margin.left},${margin.top})`);
// Créer un conteneur pour le graphique détaillé
const detailContainer = d3.select("#visualization")
.append("div")
.attr("id", "detail-container")
.style("margin-top", "20px");
// Définir les années et la plage d'affichage
const years = [2021, 2022, 2023, 2024];
// Créer le slider
const sliderContainer = d3.select("#visualization")
.append("div")
.attr("id", "slider-container")
.style("display", "flex")
.style("align-items", "center")
.style("justify-content", "space-between");
const rangeSlider = sliderContainer.append("input")
.attr("type", "range")
.attr("min", 0)
.attr("max", years.length - 1)
.attr("value", 0)
.style("width", "60%");
const yearDisplay = sliderContainer.append("span")
.text(years[0]);
// Tooltip
const tooltip = d3.select("body").append("div")
.attr("class", "tooltip")
.style("opacity", 0);
// Fonction de mise à jour de la visualisation
function updateVisualization(selectedYear) {
const filteredData = data.filter(d => formatYear(d.date) === selectedYear.toString());
if (filteredData.length === 0) {
console.log(`Aucune donnée pour l'année ${selectedYear}`);
return;
}
const groupedData = d3.groups(filteredData, d => formatMonth(d.date));
const aggregatedData = groupedData.map(([month, records]) => {
const aggregated = { month };
members.forEach(member => {
aggregated[`Steps_${member}`] = d3.mean(records, d => d[`Steps_${member}`] || 0);
});
return aggregated;
});
svg.selectAll("*").remove();
svg.append("text")
.attr("x", width / 2) // Centrer horizontalement
.attr("y", margin.top - 60) // Positionner légèrement au-dessus du graphique
.attr("text-anchor", "middle") // Centrer le texte
.style("font-size", "16px") // Taille de police
.style("font-weight", "bold") // Gras
.text("Analyse du nombre de pas par mois");
const xScale = d3.scaleBand()
.domain(aggregatedData.map(d => d.month))
.range([0, width])
.padding(0.2);
const yScale = d3.scaleLinear()
.domain([0, d3.max(aggregatedData, d => Math.max(...members.map(member => d[`Steps_${member}`])))]).nice()
.range([height, 0]);
const colorScale = d3.scaleOrdinal(d3.schemeCategory10).domain(members);
// Axe X
svg.append("g")
.attr("transform", `translate(0, ${height})`)
.call(d3.axisBottom(xScale))
.selectAll("text")
.attr("transform", "rotate(-45)")
.style("text-anchor", "end");
// Légende de l'axe X
svg.append("text")
.attr("x", width / 2)
.attr("y", height + 40)
.attr("text-anchor", "middle")
.style("font-size", "14px")
.text("Mois");
// Axe Y
svg.append("g").call(d3.axisLeft(yScale));
// Légende de l'axe Y
svg.append("text")
.attr("transform", "rotate(-90)")
.attr("x", -height / 2)
.attr("y", -50)
.attr("text-anchor", "middle")
.style("font-size", "14px")
.text("Nombre de pas");
// Légende des membres (rectangles colorés)
const legend = svg.append("g")
.attr("transform", `translate(${width + 10}, 20)`);
members.forEach((member, i) => {
legend.append("rect")
.attr("x", 0)
.attr("y", i * 20)
.attr("width", 15)
.attr("height", 15)
.attr("fill", colorScale(member));
legend.append("text")
.attr("x", 20)
.attr("y", i * 20 + 12)
.text(member)
.style("font-size", "12px")
.attr("text-anchor", "start");
});
// Lignes pour chaque membre
members.forEach((member, i) => {
const lineData = aggregatedData.map(d => {
let steps = d[`Steps_${member}`] === -1.0 ? 0 : d[`Steps_${member}`]; // Remplacer -1.0 par 0
return {
month: d.month,
steps: steps
};
});
// Vérifier si toutes les données d'un mois sont à 0 (indiquant qu'il n'y a pas de données pour ce mois)
const isAllZero = lineData.every(d => d.steps === 0);
const line = d3.line()
.x(d => xScale(d.month) + xScale.bandwidth() / 2)
.y(d => yScale(d.steps))
.defined(d => d.steps !== 0); // Ne pas tracer pour les valeurs égales à 0 (données manquantes)
svg.append("path")
.data([lineData])
.attr("class", `line-${member}`)
.attr("d", line)
.attr("fill", "none")
.attr("stroke", colorScale(member))
.attr("stroke-width", 2)
.style("stroke-dasharray", isAllZero ? "5,5" : "none") // Ajouter des pointillés si toutes les données sont manquantes
.on("mouseover", function(event, d) {
tooltip.transition().duration(200).style("opacity", .9);
tooltip.html(`${member} : Nombre de pas par mois`)
.style("left", (event.pageX + 5) + "px")
.style("top", (event.pageY - 28) + "px");
})
.on("mouseout", function() {
tooltip.transition().duration(500).style("opacity", 0);
});
});
}
// Initialisation de la visualisation avec la première année
updateVisualization(years[0]);
// Mettre à jour la visualisation lorsque le slider est déplacé
rangeSlider.on("input", function() {
const selectedYear = years[this.value];
yearDisplay.text(selectedYear);
updateVisualization(selectedYear);
});
});
/* Style général de la page */
body {
font-family: Arial, sans-serif;
background-color: #f4f4f4;
margin: 0;
padding: 20px;
}
/* Style pour la zone de la visualisation */
#visualization {
width: 60%;
height: 600px;
background-color: white;
margin-bottom: 40px;
}
/* Style pour le slider et l'année */
#slider-container {
display: flex;
justify-content: space-between;
align-items: center;
width: 25%;
margin-bottom: 10px;
margin-left: 80px;
}
#range-slider {
width: 60%;
margin: 0 10px;
}
/* Conteneur des détails */
#detail-container {
margin-top: 40px;
width: 100%;
}
/* Style du tooltip */
.tooltip {
position: absolute;
background-color: rgba(0, 0, 0, 0.7);
color: white;
padding: 8px;
border-radius: 4px;
pointer-events: none;
font-size: 14px;
opacity: 0;
}
This diff is collapsed.
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment