feat: add heatmap to resultat

This commit is contained in:
2025-08-10 06:27:36 +02:00
parent 4f8ab0925b
commit 13f0e69bb0
4 changed files with 1177 additions and 5 deletions

View File

@@ -0,0 +1,380 @@
# 📊 Page des Résultats d'Évaluation
## Vue d'Ensemble
La **page des résultats d'évaluation** (`/assessments/<id>/results`) est une interface d'analyse complète qui présente les performances des élèves sous forme de statistiques, visualisations et heatmaps interactives. Cette page constitue l'aboutissement du processus d'évaluation et offre aux enseignants une vision claire et détaillée des résultats.
## 🎯 Fonctionnalités Principales
### 1. **Statistiques Descriptives**
- **Nombre d'élèves** évalués
- **Moyenne générale** de la classe
- **Médiane** des scores
- **Minimum et Maximum** obtenus
- **Écart-type** de la distribution
- **Total des points** possible pour l'évaluation
### 2. **Histogramme de Distribution**
- **Graphique en barres** des notes avec bins de 1 point
- **Tooltips personnalisés** affichant la liste des élèves pour chaque barre
- **Visualisation Chart.js** responsive et interactive
- **Animation fluide** et design cohérent
### 3. **Heatmaps d'Analyse**
- **Heatmap par compétences** : Performance des élèves par compétence évaluée
- **Heatmap par domaines** : Performance des élèves par domaine mathématique
- **Heatmap par éléments de notation** : Vue détaillée question par question avec couleurs authentiques de la base de données
### 4. **Tableau Détaillé des Résultats**
- **Liste alphabétique** des élèves avec leurs scores
- **Détail par exercice** au format "score/total"
- **Scores totaux** précis avec décimales
- **Navigation intuitive** vers les détails
## 🏗️ Architecture Technique
### Backend - Route `/assessments/<id>/results`
#### Fichier : `routes/assessments.py` (lignes 187-429)
```python
@bp.route('/<int:id>/results')
@handle_db_errors
def results(id):
# 1. Récupération de l'évaluation avec tous ses détails
assessment_repo = AssessmentRepository()
assessment = assessment_repo.get_with_full_details_or_404(id)
# 2. Calculs des scores et statistiques
students_scores, exercise_scores = assessment.calculate_student_scores()
statistics = assessment.get_assessment_statistics()
# 3. Préparation des données heatmaps
# - Collecte des compétences et domaines avec couleurs depuis la BD
# - Calcul des scores agrégés par compétence/domaine
# - Préparation des données pour éléments de notation
# 4. Rendu du template avec toutes les données
return render_template('assessment_results.html', ...)
```
#### Logique de Préparation des Heatmaps
**Compétences et Domaines :**
```python
# Récupération des couleurs depuis la base de données
all_competences = {comp.name: comp.color for comp in Competence.query.all()}
all_domains = {domain.id: {'name': domain.name, 'color': domain.color}
for domain in Domain.query.all()}
# Calcul des pourcentages par élève/compétence
for student_data in sorted_students:
for comp in competences_list:
if comp in student_scores_by_competence:
percentage = (student_scores_by_competence[comp] /
student_totals_by_competence[comp]) * 100
student_row.append(round(percentage, 1))
```
**Éléments de Notation :**
```python
# Couleurs par exercice pour meilleure distinction visuelle
exercise_colors = ['#3b82f6', '#10b981', '#f59e0b', '#8b5cf6', ...]
# Données détaillées avec valeurs originales
for element_key in grading_elements_list:
student_row.append({
'value': grade.value,
'grading_type': element.grading_type,
'max_points': element.max_points
})
```
### Frontend - Template `assessment_results.html`
#### Structure HTML
**Statistiques Générales :**
```html
<div class="bg-white shadow rounded-lg">
<div class="grid grid-cols-2 md:grid-cols-3 lg:grid-cols-6 gap-4">
<div class="text-center">
<div class="text-2xl font-bold text-blue-600">{{ statistics.count }}</div>
<div class="text-sm text-gray-500">Élèves</div>
</div>
<!-- Autres métriques... -->
</div>
</div>
```
**Histogramme Interactif :**
```html
<div class="bg-white shadow rounded-lg">
<div class="px-6 py-4 border-b border-gray-200">
<h2 class="text-lg font-medium text-gray-900">Distribution des notes</h2>
</div>
<div class="px-6 py-4">
<canvas id="scoresChart" width="400" height="200"></canvas>
</div>
</div>
```
#### JavaScript Chart.js avec Tooltips Personnalisés
**Données des Élèves :**
```javascript
const studentsData = [
{% for student_data in students_scores %}
{
name: "{{ student_data.student.last_name }} {{ student_data.student.first_name }}",
score: {{ student_data.total_score }}
}{% if not loop.last %},{% endif %}
{% endfor %}
];
```
**Configuration Chart.js :**
```javascript
new Chart(ctx, {
type: 'bar',
data: {
labels: labels,
datasets: [{
label: 'Nombre d\'élèves',
data: bins,
backgroundColor: 'rgba(59, 130, 246, 0.5)',
borderColor: 'rgba(59, 130, 246, 1)',
borderWidth: 1
}]
},
options: {
plugins: {
tooltip: {
callbacks: {
label: function(tooltipItem) {
const binIndex = tooltipItem.dataIndex;
const count = bins[binIndex];
const students = studentsInBins[binIndex];
if (count === 1) {
return '1 élève : ' + students[0];
} else {
return `${count} élèves : ${students.join(', ')}`;
}
}
},
maxWidth: 400
}
}
}
});
```
### Heatmaps Canvas Personnalisées
#### Fonction `createHeatmap()` pour Compétences/Domaines
```javascript
function createHeatmap(canvasId, data, type) {
// 1. Configuration des dimensions adaptatives
const cellWidth = Math.max(minCellWidth, (canvas.width - padding * 2) / students.length);
const cellHeight = Math.max(minCellHeight, (canvas.height - padding * 2) / categories.length);
// 2. Fonction de couleur avec dégradé HSL continu
function getScoreColor(score) {
const factor = percentage / 100;
return interpolateColorHSL('#ef4444', '#22c55e', factor); // Rouge → Vert
}
// 3. Rendu des cellules avec labels rotatifs
// 4. Légende avec échelle continue 0% → 100%
}
```
#### Fonction `createGradingElementsHeatmap()` pour Éléments
```javascript
function createGradingElementsHeatmap(canvasId, data) {
// 1. Récupération des couleurs authentiques depuis la BD
const scaleColors = data.scale_colors;
// 2. Fonction de couleur selon le type
function getGradeColor(gradeData) {
if (gradeData.grading_type === 'score') {
// Utiliser les couleurs de l'échelle configurée
return scaleColors[gradeData.value].color;
} else if (gradeData.grading_type === 'notes') {
// Dégradé HSL basé sur le pourcentage
const percentage = (parseFloat(gradeData.value) / gradeData.max_points) * 100;
return interpolateColorHSL('#ef4444', '#22c55e', percentage / 100);
}
}
// 3. Labels colorés par exercice pour distinction visuelle
// 4. Légende spécialisée avec échelle complète
}
```
#### Interpolation HSL pour Dégradés Continus
```javascript
function interpolateColorHSL(color1, color2, factor) {
const rgb1 = hexToRgb(color1);
const rgb2 = hexToRgb(color2);
const hsl1 = rgbToHsl(rgb1.r, rgb1.g, rgb1.b);
const hsl2 = rgbToHsl(rgb2.r, rgb2.g, rgb2.b);
// Interpolation en HSL avec gestion des transitions de teinte
let deltaH = hsl2.h - hsl1.h;
if (deltaH > 180) hsl2.h -= 360;
else if (deltaH < -180) hsl2.h += 360;
const h = hsl1.h + (hsl2.h - hsl1.h) * factor;
const s = hsl1.s + (hsl2.s - hsl1.s) * factor;
const l = hsl1.l + (hsl2.l - hsl1.l) * factor;
return rgbToHex(...hslToRgb(normalizedH, s, l));
}
```
## 🎨 Interface Utilisateur
### Design System Cohérent
- **Couleurs** : Palette Tailwind avec bleus, verts, oranges
- **Typographie** : Hiérarchie claire avec font-bold et font-medium
- **Espacement** : Grid system responsive avec gap-4/6
- **Cartes** : `bg-white shadow rounded-lg` pour la consistance
### Responsive Design
- **Mobile** : Scrolling horizontal pour les heatmaps
- **Tablet** : Grilles adaptatives 2-3 colonnes
- **Desktop** : Grilles 6 colonnes pour les statistiques
### Interactions
- **Tooltips Chart.js** : Liste des élèves par tranche de notes
- **Heatmaps hover** : Affichage des scores détaillés
- **Navigation** : Lien retour vers l'évaluation
## 📊 Types de Données Affichées
### 1. **Scores Calculés**
- **Notes numériques** : Sommation directe des valeurs décimales
- **Scores de compétences** : Formule `score * max_points / 3`
- **Valeurs spéciales** : `.` = 0, `d` = dispensé, `a` = absent
### 2. **Agrégations**
- **Par compétence** : Moyenne pondérée des éléments associés
- **Par domaine** : Moyenne pondérée des éléments du domaine
- **Par exercice** : Somme des éléments de l'exercice
### 3. **Métadonnées**
- **Couleurs authentiques** : Récupérées depuis les modèles BD
- **Libellés configurables** : Depuis l'échelle de notation
- **Statuts de correction** : Basés sur la saisie des notes
## 🔧 Gestion des Cas Particuliers
### Données Manquantes
```javascript
if (score === null || score === undefined) {
return '#f3f4f6'; // Gris clair
}
```
### Valeurs Spéciales
```python
# Configuration depuis la base de données
scale_colors = config_manager.get_competence_scale_values()
if scaleColors[value]:
return scaleColors[value].color
```
### Calculs de Pourcentage
```python
if student_totals_by_competence[comp] > 0:
percentage = (student_scores_by_competence[comp] /
student_totals_by_competence[comp]) * 100
student_row.append(round(percentage, 1))
```
## 🚀 Performance et Optimisations
### Backend
- **Requêtes optimisées** : `get_with_full_details_or_404()` avec jointures
- **Calculs unifiés** : Services découplés avec injection de dépendances
- **Cache des couleurs** : Récupération unique depuis la BD
### Frontend
- **Canvas natif** : Rendu des heatmaps sans librairies lourdes
- **Chart.js CDN** : Chargement optimisé des graphiques
- **Responsive dimensions** : Calculs adaptatifs des tailles
### JavaScript
- **Fonctions globales** : Réutilisation des utilitaires HSL
- **Gestion d'erreurs** : Fallbacks pour données manquantes
- **Optimisation DOM** : Mise à jour ciblée des éléments
## 🎯 Cas d'Usage Typiques
### 1. **Analyse de Classe**
L'enseignant consulte la page après correction complète pour :
- **Identifier les difficultés** : Compétences en rouge sur les heatmaps
- **Repérer les réussites** : Domaines bien maîtrisés en vert
- **Analyser la distribution** : Homogénéité/hétérogénéité de la classe
### 2. **Feedback Individuel**
Utilisation du tableau détaillé pour :
- **Scores par exercice** : Performance question par question
- **Comparaison relative** : Position dans la distribution
- **Identification des lacunes** : Éléments non maîtrisés
### 3. **Reporting Pédagogique**
Les statistiques servent à :
- **Évaluer la difficulté** : Moyenne générale vs objectifs
- **Adapter la pédagogie** : Révisions ciblées sur les compétences faibles
- **Communiquer avec les familles** : Résultats contextualisés
## 🔄 Évolutions Récentes (2025)
### ✅ **Améliorations Implementées**
- **Tooltips personnalisés** dans l'histogramme avec liste des élèves
- **Heatmap des éléments de notation** avec couleurs authentiques de la BD
- **Distinction visuelle par exercice** avec palette de couleurs dédiée
- **Interpolation HSL** pour dégradés continus sans sauts de couleur
- **Gestion des erreurs JavaScript** avec fonctions globales structurées
### 🎨 **Améliorations UX**
- **Maxwidth tooltips** : Affichage optimal sur 400px
- **Police adaptative** : 10px pour les éléments, 12px pour les heatmaps classiques
- **Troncature intelligente** : Libellés longs coupés à 22 caractères
- **Légende complète** : Échelle de notation avec explications
## 🔍 Tests et Validation
### Tests d'Intégration
```bash
# Test de la route des résultats
uv run pytest tests/test_routes_assessments.py -k "result"
# Validation des calculs
uv run pytest tests/test_models.py -k "calculate_student_scores"
```
### Tests Frontend
- **Vérification Chart.js** : Présence des tooltips avec noms d'élèves
- **Validation heatmaps** : Rendu correct des couleurs authentiques
- **Test responsive** : Affichage sur différentes tailles d'écran
## 🔗 Navigation et Intégration
### Points d'Entrée
- **Dashboard évaluation** : Bouton "Résultats" sur `/assessments/<id>`
- **Liste des évaluations** : Lien direct depuis la progression
- **Navigation breadcrumb** : Retour vers l'évaluation parente
### Données Partagées
- **Statistiques** : Réutilisées dans d'autres vues analytiques
- **Scores calculés** : Cohérents avec les autres pages de l'application
- **Configuration** : Respect de l'échelle de notation globale
---
**La page des résultats d'évaluation représente l'aboutissement de l'écosystème Notytex, offrant une analyse complète et visuelle des performances avec des outils de diagnostic pédagogique avancés.** 🎓📊

View File

@@ -26,6 +26,7 @@ Cette documentation couvre l'ensemble du **design system Notytex**, ses composan
| -------------------------------------------------- | ---------------------------------------------------------------- | ------ |
| **[CLASSES_PAGE.md](./CLASSES_PAGE.md)** | Page des classes modernisée - Architecture & guide d'utilisation | ✅ |
| **[CLASS_FORM.md](./CLASS_FORM.md)** | Formulaire création/modification classes - Interface & UX | ✅ |
| **[ASSESSMENT_RESULTS_PAGE.md](./ASSESSMENT_RESULTS_PAGE.md)** | **Page résultats évaluation - Heatmaps & analyses avancées** | ✅ |
| [ASSESSMENTS_FILTRES.md](./ASSESSMENTS_FILTRES.md) | Système de filtres des évaluations | ✅ |
| Dashboard Modernization | Page d'accueil & statistiques | 📋 |
| Student Management Page | Interface de gestion des élèves | 📋 |
@@ -118,6 +119,7 @@ xl: 1280px // Large desktop
- Guide des bonnes pratiques générales
- Page des classes (refonte complète)
- **Formulaire de classe (création/modification complet)**
- **Page des résultats d'évaluation (heatmaps & analyses)**
- Composant class_card (documentation technique)
- Filtres des évaluations
- Cartes d'évaluation