Dashboard interactif de prédiction des résultats des élections municipales françaises (2026), commune par commune, propulsé par un modèle XGBoost entraîné sur les données historiques de 2008 à 2020.
- Carte de France cliquable (GeoJSON + Leaflet) colorée par bloc prédit
- Mode Swing map : visualisation des communes où le résultat pourrait basculer
- Recherche de commune en temps réel
- Probabilités par bloc (Gauche, Centre, Droite, RN, Divers) au premier tour
- Simulation des alliances de second tour : front républicain modélisé (transfert de voix vers le bloc non-RN en tête si RN ≥ 30% au T1)
- Badge de basculement T2 quand le vainqueur change entre les deux tours
- Score de confiance du modèle
- Agrégation des prédictions 2026 pondérée par population communale
- Grille historique 2008 / 2014 / 2020 / 2026 par bloc
- Statistiques globales : couverture, confiance moyenne
- Historique électoral : résultats municipales 2008, 2014, 2020 (graphique barres empilées)
- Panel démographique : CSP, taux de chômage, revenu médian, âge médian (données RP2020 INSEE)
- Indicateurs territoriaux : pauvreté, Gini, accès aux services, prix immobilier, diplômes, motorisation
- Candidats déclarés et sources de sentiment (presse locale, réseaux sociaux)
- Maire sortant avec parti et statut
┌──────────────────────────────────────────────────────┐
│ React + TypeScript + Leaflet + Recharts │ ← Frontend (Vite, port 5174)
│ Dashboard · MapView · CommuneDetail · NationalView │
└──────────────────┬───────────────────────────────────┘
│ HTTP /api (proxy Vite)
┌──────────────────▼───────────────────────────────────┐
│ FastAPI + uvicorn (port 8001, 127.0.0.1 only) │ ← API REST
│ /communes · /map · /national · /candidates │
└──────────────────┬───────────────────────────────────┘
│ aiosqlite (async)
┌──────────────────▼───────────────────────────────────┐
│ SQLite data/elections.db │ ← Base de données
│ communes · election_results · demographic_features │
│ candidates · predictions · territorial_indicators │
└──────────────────────────────────────────────────────┘
▲
┌──────────────────┴───────────────────────────────────┐
│ Pipeline ML (src/) │
│ ingestion.py → features.py → train.py → model.py │
│ XGBoost · 95 features · validation temporelle │
└──────────────────────────────────────────────────────┘
| Couche | Technologie |
|---|---|
| Frontend | React 18, TypeScript, Vite, Leaflet, Recharts, Tailwind CSS |
| API | FastAPI, uvicorn, Pydantic v2 |
| Base de données | SQLite via aiosqlite (entièrement async) |
| Machine Learning | XGBoost, scikit-learn, pandas, numpy |
| IA (analyse de sentiment) | Claude API (Haiku pour classification, Sonnet pour synthèse) |
| Données | data.gouv.fr (résultats électoraux), INSEE RP2020 (démographie), Filosofi (revenus), DVF (immobilier), BPE (équipements) |
Le modèle est un classificateur XGBoost multiclasse (5 blocs : gauche, centre, droite, rn, divers).
Features (95 dimensions) :
- Résultats historiques par bloc (2008, 2014) : part de voix, participation, tendance
- Socio-démographie : 8 CSP, taux de chômage, revenu médian, âge médian, population
- Indicateurs territoriaux : pauvreté, Gini, propriétaires, logements sociaux, services publics, prix immobilier, diplômes, motorisation, vacance
- Dynamique nationale : popularité des partis au moment de l'élection
Validation temporelle :
- Entraînement sur 2008 + 2014
- Test sur 2020 (pas de leakage futur → passé)
- Accuracy holdout : ~56%, gain sur baseline : +14 pts
Post-processing T2 (alliances) : Si RN ≥ 30% au T1, 70% des voix des blocs non-RN se transfèrent vers le bloc non-RN en tête (simulation du front républicain). Les probabilités sont renormalisées.
| Signal | Source |
|---|---|
| Résultats municipales 2008 / 2014 / 2020 | data.gouv.fr |
| Recensement de la population 2020 | INSEE RP2020 |
| Revenus et pauvreté communaux (Filosofi 2020) | INSEE |
| Équipements publics (BPE 2023) | INSEE |
| Transactions immobilières (DVF 2021–2023) | data.gouv.fr |
| GeoJSON communes France | data.gouv.fr |
- Python 3.11+
- Node.js 18+
# Backend
python -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
# Frontend
cd frontend && npm install# Peupler la base avec des données synthétiques réalistes
python scripts/seed_synthetic.py
# Entraîner le modèle
python -m src.train# Terminal 1 — API
uvicorn src.api:app --host 127.0.0.1 --port 8001 --reload
# Terminal 2 — Frontend
cd frontend && npm run dev
# → http://localhost:5174# Ingestion données électorales et démographiques
python scripts/seed_synthetic.py # base synthétique (demo)
python scripts/ingest_filosofi.py # revenus INSEE
python scripts/ingest_bpe.py # équipements publics
python scripts/ingest_dvf.py # prix immobilier
python scripts/ingest_rp.py # recensement complémentairesrc/
├── api.py # API REST FastAPI — tous les endpoints
├── db.py # Dataclasses + accès SQLite (async)
├── features.py # Construction des features ML (95 dim.)
├── model.py # XGBoost — entraînement et prédiction
├── alliances.py # Simulation alliances T2 (pure function)
├── ingestion.py # Import data.gouv.fr + INSEE (async)
└── train.py # Pipeline d'entraînement + génération des prédictions
frontend/src/
├── pages/Dashboard.tsx # Layout principal + modes carte
├── components/
│ ├── MapView.tsx # Carte Leaflet + coloration blocs
│ ├── CommuneDetail.tsx # Panneau latéral détail commune
│ ├── NationalView.tsx # Vue nationale agrégée
│ ├── DemographicPanel.tsx # Indicateurs socio-démo
│ ├── TerritorialPanel.tsx # Indicateurs territoriaux
│ └── HistoryChart.tsx # Historique électoral (Recharts)
├── api/client.ts # Client API typé
└── types/index.ts # Types TypeScript partagés
scripts/
├── seed_synthetic.py # Génération données synthétiques
├── ingest_filosofi.py # Revenus / pauvreté
├── ingest_bpe.py # Équipements publics
├── ingest_dvf.py # Transactions immobilières
└── ingest_rp.py # Recensement complémentaire
pytest tests/ -v- Tout le code I/O est entièrement async (
aiosqlite,aiohttp,asyncio) - L'API écoute exclusivement sur
127.0.0.1(pas d'exposition réseau) - Séparation stricte : features (
features.py) / modèle (model.py) / données (db.py) - Validation temporelle stricte : aucun leakage futur → passé dans l'entraînement
- Les blocs politiques sont résolus par lookup exact (codes RNELP) puis par matching de mots-clés sur le libellé complet de la liste