diff --git a/nupes-elections-front/package-lock.json b/nupes-elections-front/package-lock.json
index 0c46ba4..f1ea476 100644
--- a/nupes-elections-front/package-lock.json
+++ b/nupes-elections-front/package-lock.json
@@ -17,8 +17,10 @@
"@testing-library/user-event": "^13.5.0",
"highcharts": "^11.4.3",
"highcharts-react-official": "^3.2.1",
+ "leaflet": "^1.9.4",
"react": "^18.3.1",
"react-dom": "^18.3.1",
+ "react-leaflet": "^4.2.1",
"react-router-dom": "^6.23.1",
"react-scripts": "5.0.1",
"web-vitals": "^2.1.4"
@@ -4053,6 +4055,17 @@
"url": "https://opencollective.com/popperjs"
}
},
+ "node_modules/@react-leaflet/core": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/@react-leaflet/core/-/core-2.1.0.tgz",
+ "integrity": "sha512-Qk7Pfu8BSarKGqILj4x7bCSZ1pjuAPZ+qmRwH5S7mDS91VSbVVsJSrW4qA+GPrro8t69gFYVMWb1Zc4yFmPiVg==",
+ "license": "Hippocratic-2.1",
+ "peerDependencies": {
+ "leaflet": "^1.9.0",
+ "react": "^18.0.0",
+ "react-dom": "^18.0.0"
+ }
+ },
"node_modules/@remix-run/router": {
"version": "1.16.1",
"resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.16.1.tgz",
@@ -13913,6 +13926,12 @@
"shell-quote": "^1.8.1"
}
},
+ "node_modules/leaflet": {
+ "version": "1.9.4",
+ "resolved": "https://registry.npmjs.org/leaflet/-/leaflet-1.9.4.tgz",
+ "integrity": "sha512-nxS1ynzJOmOlHp+iL3FyWqK89GtNL8U8rvlMOsQdTTssxZwCXh8N2NB3GDQOL+YR3XnWyZAxwQixURb+FA74PA==",
+ "license": "BSD-2-Clause"
+ },
"node_modules/leven": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz",
@@ -16798,6 +16817,20 @@
"integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==",
"license": "MIT"
},
+ "node_modules/react-leaflet": {
+ "version": "4.2.1",
+ "resolved": "https://registry.npmjs.org/react-leaflet/-/react-leaflet-4.2.1.tgz",
+ "integrity": "sha512-p9chkvhcKrWn/H/1FFeVSqLdReGwn2qmiobOQGO3BifX+/vV/39qhY8dGqbdcPh1e6jxh/QHriLXr7a4eLFK4Q==",
+ "license": "Hippocratic-2.1",
+ "dependencies": {
+ "@react-leaflet/core": "^2.1.0"
+ },
+ "peerDependencies": {
+ "leaflet": "^1.9.0",
+ "react": "^18.0.0",
+ "react-dom": "^18.0.0"
+ }
+ },
"node_modules/react-refresh": {
"version": "0.11.0",
"resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.11.0.tgz",
diff --git a/nupes-elections-front/package.json b/nupes-elections-front/package.json
index be6285c..0879248 100644
--- a/nupes-elections-front/package.json
+++ b/nupes-elections-front/package.json
@@ -12,8 +12,10 @@
"@testing-library/user-event": "^13.5.0",
"highcharts": "^11.4.3",
"highcharts-react-official": "^3.2.1",
+ "leaflet": "^1.9.4",
"react": "^18.3.1",
"react-dom": "^18.3.1",
+ "react-leaflet": "^4.2.1",
"react-router-dom": "^6.23.1",
"react-scripts": "5.0.1",
"web-vitals": "^2.1.4"
diff --git a/nupes-elections-front/src/Elections2024.js b/nupes-elections-front/src/Elections2024.js
index 266b0c6..f2adc5b 100644
--- a/nupes-elections-front/src/Elections2024.js
+++ b/nupes-elections-front/src/Elections2024.js
@@ -13,6 +13,9 @@ import * as Highcharts from 'highcharts'
import highchartsItem from 'highcharts/modules/item-series'
import HighchartsReact from 'highcharts-react-official'
import {useEffect, useState} from "react"
+import {GeoJSON, MapContainer, Popup, TileLayer, useMap} from "react-leaflet"
+
+import 'leaflet/dist/leaflet.css'
highchartsItem(Highcharts)
@@ -39,18 +42,7 @@ function ResultatsTable({blocs, nuances, listes, resultats, siegesParListe}) {
{listes_triees.map((liste) => (
-
- {liste.numero}
- {liste.nom}
- nuance.code === liste.nuance)[0].couleur, padding: "0.2em"}}>
- {liste.nuance}
- bloc.nom === liste.bloc)[0].couleur, padding: "0.2em"}}>
- {liste.bloc}
- {voix_listes[liste.numero] || 0}
- {(100 * (voix_listes[liste.numero] || 0) / resultats.inscrits).toFixed(2)} %
- {(100 * (voix_listes[liste.numero] || 0) / resultats.exprimes).toFixed(2)} %
- {siegesParListe[liste.numero]}
-
+
))}
@@ -59,6 +51,25 @@ function ResultatsTable({blocs, nuances, listes, resultats, siegesParListe}) {
}
+function ListeRow({liste, voix, resultats, siegesParListe, blocs, nuances}) {
+ const bloc = blocs.filter(bloc => bloc.nom === liste.bloc)[0]
+ const nuance = nuances.filter(nuance => nuance.code === liste.nuance)[0]
+
+ return
+ {liste.numero}
+ {liste.nom}
+
+ {liste.nuance}
+
+ {liste.bloc}
+ {voix}
+ {(100 * voix / resultats.inscrits).toFixed(2)} %
+ {(100 * voix / resultats.exprimes).toFixed(2)} %
+ {siegesParListe[liste.numero]}
+
+}
+
+
function ParticipationTable({resultats}) {
return <>
@@ -114,6 +125,96 @@ function ParticipationTable({resultats}) {
>
}
+function RegionGeoJSON({resultats_region, listes, blocs, nuances, grouperParBloc = false}) {
+ const voix_listes = resultats_region?.voix_listes ?? {}
+ const listes_triees = listes.toSorted((l1, l2) => {
+ return (voix_listes[l2.numero] || 0) - (voix_listes[l1.numero] || 0)
+ })
+
+ const voixParBloc = {}
+ const voixParNuance = {}
+ for (let bloc of blocs) {
+ voixParBloc[bloc.nom] = 0
+ }
+ for (let nuance of nuances) {
+ voixParNuance[nuance.code] = 0
+ }
+
+ for (let liste of listes) {
+ voixParBloc[liste.bloc] += resultats_region.voix_listes[liste.numero] || 0
+ voixParNuance[liste.nuance] += resultats_region.voix_listes[liste.numero] || 0
+ }
+
+ let couleur = 'grey'
+ if (grouperParBloc) {
+ let maxVoix = 0
+ for (let bloc of blocs) {
+ if (voixParBloc[bloc.nom] > maxVoix) {
+ maxVoix = voixParBloc[bloc.nom]
+ couleur = bloc.couleur
+ }
+ }
+ }
+ else {
+ let maxVoix = 0
+ for (let nuance of nuances) {
+ if (voixParNuance[nuance.code] > maxVoix) {
+ maxVoix = voixParNuance[nuance.code]
+ couleur = nuance.couleur
+ }
+ }
+ }
+
+ return
+
+ {resultats_region.region.nom}
+
+ {listes_triees.slice(0, 5).map(liste =>
+ - {liste.nom} : {voix_listes[liste.numero]} ({(100 * voix_listes[liste.numero] / resultats_region.exprimes).toFixed(2)} %)
)}
+
+
+
+}
+
+function ContenuCarte({typeResultats, resultats, listes, blocs, nuances, grouperParBloc = false}) {
+ const [regions, setRegions] = useState([])
+
+ useEffect(() => {
+ if (!resultats || !resultats.france || !resultats.france.regions)
+ return
+
+ setRegions(regions => [])
+
+ resultats.france.regions.forEach(region_code => {
+ fetch(`/data/resultats/europeennes2024/regions/${region_code}.json`).then(response => response.json())
+ .then(region => setRegions(regions => [...regions, region]))
+ })
+ }, [typeResultats, resultats])
+
+ const map = useMap()
+
+ return <>
+ {regions.map(region => )}
+ >
+}
+
+function Carte({typeResultats, resultats, listes, blocs, nuances, grouperParBloc = false}) {
+ const center = [46.603354, 1.888334]
+
+ return <>
+
+
+
+
+ >
+}
+
export default function Election2024({typeResultats = "france"}) {
const {zoneId} = useParams()
@@ -321,8 +422,10 @@ export default function Election2024({typeResultats = "france"}) {
title: {
text: `Résultats des élections européennes 2024 : ${zoneName}`,
},
- legend: {
- labelFormat: '{name} {x}'
+ tooltip: {
+ formatter: function () {
+ return `${this.x} : ${this.y} voix (${(100 * this.y / resultats.exprimes).toFixed(2)} %)
`
+ }
},
xAxis: {
categories: categoriesVoix,
@@ -355,5 +458,6 @@ export default function Election2024({typeResultats = "france"}) {
/>
+
>
-};
\ No newline at end of file
+}
diff --git a/nupes/scripts/export_resultats_2024.py b/nupes/scripts/export_resultats_2024.py
index aea55cd..54fe926 100644
--- a/nupes/scripts/export_resultats_2024.py
+++ b/nupes/scripts/export_resultats_2024.py
@@ -73,6 +73,11 @@ def exporter_resultats_france(engine: Engine, verbose: bool = False) -> None:
session.add(resultats_france)
resultats_dict = {
+ 'france': {
+ 'regions': [reg.code_insee for reg in session.execute(select(Region)).scalars().all()],
+ 'departements': [dpt.code_insee for dpt in session.execute(select(Departement)).scalars().all()],
+ 'circonscriptions': [circo.id for circo in session.execute(select(Circonscription)).scalars().all()],
+ },
"inscrits": resultats_france.inscrits,
"votants": resultats_france.votants,
"abstentions": resultats_france.abstentions,
@@ -105,7 +110,11 @@ def exporter_resultats_regions(engine: Engine, verbose: bool = False) -> None:
regions_iterator = tqdm(regions, desc="Régions") if verbose else regions
for region in regions_iterator:
region_json = {'code_insee': region.code_insee, 'nom': region.libelle,
- 'departements': [dpt.code_insee for dpt in region.departements]}
+ 'departements': [dpt.code_insee for dpt in region.departements],
+ 'circonscriptions':
+ [circo.id for circo in session.execute(
+ select(Circonscription).join(Departement).filter_by(region_code=region.code_insee))
+ .scalars().all()]}
regions_json.append(region_json)
resultats_region = session.execute(select(ResultatsRegion).filter_by(region_id=region.code_insee)) \
@@ -318,6 +327,7 @@ def exporter_resultats_bureaux_vote(engine: Engine, verbose: bool = False) -> No
iterator = tqdm(bureaux_vote, desc="Bureaux de vote") if verbose else bureaux_vote
for bureau_vote in iterator:
bureau_vote_json = {'id': bureau_vote.id,
+ 'libelle': bureau_vote.libelle,
'commune': bureau_vote.commune_code,
'circonscription': bureau_vote.circo_code}
bureaux_vote_json.append(bureau_vote_json)
diff --git a/nupes/scripts/import_geographie.py b/nupes/scripts/import_geographie.py
index b6de1b0..910da5b 100644
--- a/nupes/scripts/import_geographie.py
+++ b/nupes/scripts/import_geographie.py
@@ -251,7 +251,7 @@ def importer_bureaux_vote(engine: Engine, verbose: bool = False) -> None:
numero_circo = int(bv_dict['codeCirconscription'][len(dpt_code):])
code_circo = f"{dpt_code}-{numero_circo:02d}"
bv_id = bv_dict['id_bv'].split()[0]
- bv_libelle = f"Bureau {code_bv}"
+ bv_libelle = f"Bureau {code_bv} de {bv_dict['nomCommune']}"
if not session.execute(select(Commune).filter_by(code_insee=code_commune)).scalar_one_or_none():
print("Commune non trouvée avec le code", code_commune, "et le nom", bv_dict['nomCommune'])