v3.2.0 — Phase D population, soir d'élection, scénarios URL, fiches enrichies, favicon/og
- PHASE D : feature store démographique depuis le classeur OFFICIEL Élections
Québec (Recensement 2021 × 127 circonscriptions 2026, codes stables, source
parfaite — aucune interpolation) : population, 65+, langue à la maison,
universitaire, locataires, immigrants, revenu 100k+, autochtones,
appartements, minorités visibles + z-scores + SIMILARITÉ top-10 (validée :
Gouin≈Mercier/SMSJ, Westmount≈NDG/MRO, Ungava profil nordique).
API /api/demographics/{nom}; démographie + semblables intégrés aux fiches
- MODÈLE DU SOIR D'ÉLECTION (modeling/election_night.py, dormant) : prior =
forecast final; décomposition hiérarchique des résidus rapportés (national
~N(0,σ_ind²) → régional → local, pondérés par dépouillement propre — garde
anti-biais des premiers bureaux); resimulation à variances réduites; calling
conservateur (P≥99,5 % ET ≥40 % dépouillé). /api/election-night +
POST /api/admin/election-night. Test synthétique : décalage national +3 pp
retrouvé, zéro invention à décalage nul
- LABO DE SCÉNARIOS partageables par URL (?s=base64) : encodage/décodage
complet, bouton copier, presets appliqués aux contrôles, étiquetage strict
« conditionnel — pas le forecast officiel »
- FICHES ENRICHIES : sensibilité au swing (marge attendue, chemin de bascule
minimal, stabilité vs IC) + démographie officielle
- FAVICON (SVG+PNG 64/180/512, fleur QC Signal) + OG:IMAGE 1200×630 (hémicycle)
+ balises og/twitter sur les 11 pages
- COMPAS-PROGRAMMES.md : mandat complet du compas électoral IA inscrit à la
feuille de route (règles de neutralité/preuve, ordre d'exécution, actifs
réutilisables) — prochaine grande phase
- 37/37 tests (slug, bornes démographiques, soir d'élection)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
156 changed files +1,304 −14
added
COMPAS-PROGRAMMES.md
+72 −0
@@ -0,0 +1,72 @@ | ||
| 1 | +<!-- QC Élection Forecast — Plateforme de prévision électorale du Québec 2026 --> | |
| 2 | +<!-- Auteur : Simon-Pierre Boucher --> | |
| 3 | +<!-- Contact : contact@spboucher.ai --> | |
| 4 | +<!-- https://www.qc-election.com --> | |
| 5 | + | |
| 6 | +# FEUILLE DE ROUTE — Programmes officiels et compas électoral IA | |
| 7 | + | |
| 8 | +Mandat reçu le 2026-08-31 (spécification complète conservée ici). Statut : | |
| 9 | +**PLANIFIÉ — prochaine grande phase après la consolidation du forecast.** | |
| 10 | +Règle finale : ne jamais sacrifier la neutralité et la preuve pour le spectaculaire. | |
| 11 | + | |
| 12 | +## Vision | |
| 13 | +Module d'analyse des programmes des 5 partis : documentation officielle | |
| 14 | +collectée/versionnée, engagements atomiques structurés et CITÉS, comparaison | |
| 15 | +équitable thème par thème, compas électoral multidimensionnel (6 axes + sous-axes) | |
| 16 | +alimenté par l'IA mais audité, questionnaire adaptatif, proximités avec | |
| 17 | +incertitude — jamais « vous êtes ce parti ». | |
| 18 | + | |
| 19 | +## Règles absolues (résumé de la spécification) | |
| 20 | +1. **Aucune invention** : chaque affirmation ↔ preuve textuelle officielle + | |
| 21 | + version; « position officielle non trouvée » plutôt qu'une position supposée; | |
| 22 | + séparation engagement explicite / orientation / chiffré / continuité / | |
| 23 | + position historique non reconfirmée / inférence IA (marquée, confiance, | |
| 24 | + exclue du score principal) / absence. | |
| 25 | +2. **Hiérarchie d'autorité** : plateforme finale > cadre financier > engagement | |
| 26 | + de campagne > communiqué > page thématique > congrès > déclaration | |
| 27 | + transcrite > social officiel. Contradiction → afficher les deux, jamais écraser. | |
| 28 | +3. **Neutralité testée** : double classification indépendante + arbitre, | |
| 29 | + permutation des noms de partis, symétrie des formulations, calibration sur | |
| 30 | + corpus annoté, reproductibilité à température nulle, versions modèle/prompt. | |
| 31 | +4. **Vie privée** : aucune réponse du compas enregistrée sans consentement. | |
| 32 | + | |
| 33 | +## Actifs déjà en place (réutiliser) | |
| 34 | +- Sites officiels vérifiés + registre : `config/social_seeds.json` | |
| 35 | + (caq/pq/plq/qs/pcq + fiches DGEQ `data/partis_autorises.json`). | |
| 36 | +- Pipeline Firecrawl (scrape/archivage/hash) : `ingest/firecrawl_watch.py`, | |
| 37 | + patterns d'archivage `data/raw/…`. | |
| 38 | +- File de révision : pattern `excluded=True` + WebSignal (rapports primaires). | |
| 39 | +- RAG maison : `modeling/explain.py` (à étendre au corpus des programmes). | |
| 40 | +- Design system QC Signal + composants (tabs, tables, cartes). | |
| 41 | + | |
| 42 | +## Ordre d'exécution (spécification §Ordre) | |
| 43 | +1. Schéma canonique : tables `party_documents` (versionnées, hash, autorité, | |
| 44 | + statut actif/remplacé), `claims` (engagement atomique : thème, verbatim, | |
| 45 | + citation URL+section, instrument, statut, coûts, compétence, confiance, | |
| 46 | + validation humaine), `taxonomy` versionnée (18 thèmes), `axes` (6+6). | |
| 47 | +2. Connecteurs des 5 sites (découverte PDF/pages, diff « Ce qui a changé dans | |
| 48 | + les programmes », respect robots.txt, file de blocage humaine). | |
| 49 | +3. Extraction d'engagements (règles + LLM avec confiance, JAMAIS silencieux) | |
| 50 | + + interface de révision (admin). | |
| 51 | +4. Comparateur thématique (matrice 5 partis × 18 thèmes, indices documentaires : | |
| 52 | + couverture, précision, chiffrage, financement, cohérence, traçabilité, | |
| 53 | + faisabilité juridictionnelle, stabilité — méthodologie publique, pas de | |
| 54 | + « meilleur programme »). | |
| 55 | +5. Axes + corpus annoté + calibration IA (scores -5..+5 par engagement, | |
| 56 | + pondération autorité/récence/précision/budget, incertitude, preuves listées). | |
| 57 | +6. Questionnaire 25-35 propositions + mode adaptatif (gain d'information, | |
| 58 | + importance déclarée, « cela dépend », axes désactivables). | |
| 59 | +7. Moteur de proximité (par axe, accords/désaccords forts, robustesse, | |
| 60 | + sensibilité, 3 pondérations, intervalles) — jamais un verdict unique. | |
| 61 | +8. Pages : /programmes (matrice, recherche sémantique, citations ouvrables, | |
| 62 | + chronologie, « différences essentielles », « positions non documentées »), | |
| 63 | + /compas (interactif, accessible, partage sans réponses privées), | |
| 64 | + explorateur RAG cité, mode chercheur (exports CSV/JSON, API, snapshots | |
| 65 | + immuables reproductibles). | |
| 66 | +9. Contrôles automatiques (§Étape 10 au complet) + tests de biais. | |
| 67 | + | |
| 68 | +## Définition de terminé (spécification) | |
| 69 | +Un citoyen comprend les différences réelles, vérifie chaque affirmation dans un | |
| 70 | +document officiel, obtient une proximité multidimensionnelle sans manipulation, | |
| 71 | +explore pourquoi le résultat change, et reproduit le même résultat depuis le | |
| 72 | +même snapshot. | |
modified
METHODOLOGY.md
+27 −1
@@ -5,7 +5,7 @@ | ||
| 5 | 5 | |
| 6 | 6 | # Méthodologie — QC Élection Forecast |
| 7 | 7 | |
| 8 | −Version du modèle : **2.0.0 « Au-delà des sondages »** · Élection cible : générale | |
| 8 | +Version du modèle : **3.2.0 « 127 »** · Élection cible : générale | |
| 9 | 9 | québécoise du 5 octobre 2026 (127 circonscriptions, majorité à 64). |
| 10 | 10 | |
| 11 | 11 | Ce document est la référence auditable du système. La version grand public est servie sur |
@@ -269,6 +269,32 @@ données futures dans les replays. | ||
| 269 | 269 | chantier suivant : innovations à queues lourdes (Student-t) testées par le |
| 270 | 270 | même replay. |
| 271 | 271 | |
| 272 | + | |
| 273 | +## 9 quater. v3.2 — Phase D (population), soir d'élection, scénarios, connecteurs | |
| 274 | + | |
| 275 | +- **Feature store démographique (Phase D)** : classeur OFFICIEL d'Élections | |
| 276 | + Québec « Statistiques du Recensement 2021 par circonscription 2026 » | |
| 277 | + (2 917 variables × 127 circonscriptions, codes stables — source parfaite, | |
| 278 | + aucune interpolation) → `data/population/riding_2026_demographics.csv` | |
| 279 | + (population, 65+, langue à la maison, universitaire, locataires, immigrants, | |
| 280 | + revenu 100 k$+, autochtones, appartements, minorités visibles; z-scores) et | |
| 281 | + **graphe de similarité** top-10 (cosinus) — validation qualitative : Gouin ≈ | |
| 282 | + Mercier/Ste-Marie–St-Jacques; Westmount ≈ NDG/Mont-Royal–Outremont; Ungava | |
| 283 | + profil nordique. Base du MRP (cellules) et du transfert du soir d'élection. | |
| 284 | + Exposé par fiche (`/api/demographics/{nom}`). | |
| 285 | +- **Modèle du soir d'élection** (dormant jusqu'au 5 octobre) : prior = forecast | |
| 286 | + final; résidus des circonscriptions rapportées décomposés hiérarchiquement | |
| 287 | + (national ~N(0, σ_industrie²) → régional → local), pondérés par leur propre | |
| 288 | + dépouillement (garde anti-biais des premiers bureaux); resimulation avec | |
| 289 | + variances réduites; **déclarations conservatrices** (P ≥ 99,5 % ET ≥ 40 % | |
| 290 | + dépouillé). `/api/election-night`, alimenté par l'admin depuis le DGEQ. | |
| 291 | +- **Laboratoire de scénarios** : chaque scénario du simulateur est encodé dans | |
| 292 | + l'URL (partage exact), presets reproductibles, étiquetage strict | |
| 293 | + « conditionnel — pas le forecast officiel ». | |
| 294 | +- **Fiches locales** : sensibilité au swing (marge attendue, chemin de bascule | |
| 295 | + minimal vers le challenger, stabilité vs largeur d'IC) + démographie officielle | |
| 296 | + + circonscriptions semblables. | |
| 297 | + | |
| 272 | 298 | ## 10. Limites connues |
| 273 | 299 | |
| 274 | 300 | 1. Pas de sondages régionaux publics structurés — la variation régionale vient de la |
modified
V3_MODEL_ARCHITECTURE.md
+6 −0
@@ -28,3 +28,9 @@ prédictive du prochain sondage → 10 modèle du soir d'élection. | ||
| 28 | 28 | |
| 29 | 29 | Règles : shadow/champion-challenger avant production; version bump à tout |
| 30 | 30 | changement de distribution; no silent model change (backtest+ablation+changelog). |
| 31 | + | |
| 32 | +## Phase suivante planifiée — Programmes & Compas électoral IA | |
| 33 | +Mandat complet : `COMPAS-PROGRAMMES.md` (documents officiels versionnés des 5 | |
| 34 | +partis, engagements atomiques cités, comparateur thématique, compas 6 axes, | |
| 35 | +questionnaire adaptatif, RAG cité, exports chercheurs) — neutralité et preuve | |
| 36 | +avant spectaculaire. | |
modified
backend/app/api/admin.py
+23 −0
@@ -191,6 +191,29 @@ def _ablation_job(): | ||
| 191 | 191 | db.close() |
| 192 | 192 | |
| 193 | 193 | |
| 194 | +class ReportedDistrict(BaseModel): | |
| 195 | + district: str | |
| 196 | + pct_reported: float = Field(ge=0, le=100) | |
| 197 | + results: dict[str, float] # {party: % des votes dépouillés} | |
| 198 | + | |
| 199 | + | |
| 200 | +class ElectionNightIn(BaseModel): | |
| 201 | + reported: list[ReportedDistrict] | |
| 202 | + n_sims: int = Field(15000, ge=2000, le=50000) | |
| 203 | + | |
| 204 | + | |
| 205 | +@router.post("/election-night", dependencies=[Depends(require_admin)]) | |
| 206 | +def election_night_update(body: ElectionNightIn, db: Session = Depends(get_db)): | |
| 207 | + """Soir d'élection : injecte les résultats partiels DGEQ → forecast en direct.""" | |
| 208 | + from ..modeling.election_night import update | |
| 209 | + reported = [r.model_dump() for r in body.reported] | |
| 210 | + for r in reported: | |
| 211 | + s = sum(r["results"].values()) | |
| 212 | + if r["results"] and not (60 <= s <= 105): | |
| 213 | + raise HTTPException(422, f"{r['district']}: somme implausible ({s:.0f})") | |
| 214 | + return update(db, reported, n_sims=body.n_sims) | |
| 215 | + | |
| 216 | + | |
| 194 | 217 | def _replay_job(): |
| 195 | 218 | from ..modeling.validation.historical_replay import run_replay |
| 196 | 219 | run_replay() |
modified
backend/app/api/public.py
+27 −0
@@ -278,6 +278,33 @@ def ablation_report(): | ||
| 278 | 278 | return json.loads(f.read_text()) |
| 279 | 279 | |
| 280 | 280 | |
| 281 | +@router.get("/demographics/{name}") | |
| 282 | +def demographics(name: str): | |
| 283 | + """Démographie officielle de la circonscription (Recensement 2021 sur les | |
| 284 | + limites 2026, classeur Élections Québec) + circonscriptions semblables.""" | |
| 285 | + from ..ingest.eq_socioeconomic import POP_DIR, slug_of | |
| 286 | + f = POP_DIR / "portraits" / f"{slug_of(name)}.json" | |
| 287 | + if not f.exists(): | |
| 288 | + raise HTTPException(404, "Démographie non disponible") | |
| 289 | + data = json.loads(f.read_text()) | |
| 290 | + simf = POP_DIR / "riding_similarity.json" | |
| 291 | + if simf.exists(): | |
| 292 | + data["similar"] = json.loads(simf.read_text()).get(data["district"], [])[:6] | |
| 293 | + return data | |
| 294 | + | |
| 295 | + | |
| 296 | +@router.get("/election-night") | |
| 297 | +def election_night(): | |
| 298 | + """État du modèle du soir d'élection (dormant avant le 5 octobre 2026).""" | |
| 299 | + from ..modeling.election_night import latest_state | |
| 300 | + state = latest_state() | |
| 301 | + if state is None: | |
| 302 | + raise HTTPException(404, "Le soir d'élection n'a pas commencé — le " | |
| 303 | + "modèle s'activera avec les premiers résultats " | |
| 304 | + "officiels du DGEQ le 5 octobre 2026.") | |
| 305 | + return state | |
| 306 | + | |
| 307 | + | |
| 281 | 308 | @router.get("/replay") |
| 282 | 309 | def replay_report(): |
| 283 | 310 | """Replay historique multi-élections (2007-2022, LOEO strict, §52-54).""" |
modified
backend/app/config.py
+1 −1
@@ -36,7 +36,7 @@ _load_env_file(BASE_DIR / ".env") | ||
| 36 | 36 | class Settings(BaseSettings): |
| 37 | 37 | # --- Général --- |
| 38 | 38 | app_name: str = "QC Élection Forecast" |
| 39 | − model_version: str = "3.1.0" | |
| 39 | + model_version: str = "3.2.0" | |
| 40 | 40 | database_url: str = f"sqlite:///{BASE_DIR / 'qc_election.db'}" |
| 41 | 41 | admin_token: str = os.environ.get("ADMIN_TOKEN", "change-me") |
| 42 | 42 | port: int = 8140 |
added
backend/app/ingest/eq_socioeconomic.py
+329 −0
@@ -0,0 +1,329 @@ | ||
| 1 | +# QC Élection Forecast — Plateforme de prévision électorale du Québec 2026 | |
| 2 | +# Auteur : Simon-Pierre Boucher | |
| 3 | +# Contact : contact@spboucher.ai | |
| 4 | +# https://www.qc-election.com | |
| 5 | +"""Feature store démographique des 127 circonscriptions (Phase D). | |
| 6 | + | |
| 7 | +SOURCE TIER 1 IDÉALE : Élections Québec publie, pour chacune des 127 | |
| 8 | +circonscriptions 2026, un « Portrait socioéconomique » — produits personnalisés | |
| 9 | +du Recensement 2021 de Statistique Canada calculés SUR LES LIMITES 2026 | |
| 10 | +(aucune interpolation d'aires de diffusion requise) : | |
| 11 | +âge × genre, langue parlée à la maison, diplomation, revenu des ménages, | |
| 12 | +immigration, identité autochtone, minorités visibles, type de logement. | |
| 13 | + | |
| 14 | +Sorties : | |
| 15 | + * data/population/riding_2026_demographics.csv — 1 ligne / circonscription | |
| 16 | + (variables clés + z-scores standardisés sur les 127) avec provenance; | |
| 17 | + * data/population/riding_similarity.json — top 10 de circonscriptions | |
| 18 | + SEMBLABLES par distance cosinus sur les features standardisées (§29 : | |
| 19 | + partial pooling, transferts du soir d'élection, comparaisons); | |
| 20 | + * data/population/portraits/{slug}.json — détail complet par circonscription | |
| 21 | + (fiches locales, cellules MRP marginales âge×genre×langue). | |
| 22 | +""" | |
| 23 | +from __future__ import annotations | |
| 24 | + | |
| 25 | +import json | |
| 26 | +import logging | |
| 27 | +import re | |
| 28 | +import unicodedata | |
| 29 | +from concurrent.futures import ThreadPoolExecutor | |
| 30 | +from datetime import date | |
| 31 | + | |
| 32 | +import numpy as np | |
| 33 | +from sqlalchemy.orm import Session | |
| 34 | + | |
| 35 | +from ..config import DATA_DIR, settings | |
| 36 | +from .. import models as Mo | |
| 37 | + | |
| 38 | +log = logging.getLogger("eq-socio") | |
| 39 | + | |
| 40 | +POP_DIR = DATA_DIR / "population" | |
| 41 | +PORTRAIT_URL = ("https://www.electionsquebec.qc.ca/cartes-electorales/" | |
| 42 | + "circonscriptions-provinciales/portrait-socioeconomique/{slug}/") | |
| 43 | + | |
| 44 | +AGE_GROUPS = ["0 à 9", "10 à 19", "20 à 29", "30 à 39", "40 à 49", | |
| 45 | + "50 à 59", "60 à 69", "70 à 79", "80 ans et plus"] | |
| 46 | + | |
| 47 | +# variables retenues pour la standardisation / similarité | |
| 48 | +Z_FEATURES = ["pct_60_plus", "pct_locataires", "pct_francais", "pct_anglais", | |
| 49 | + "pct_universitaire", "pct_revenu_100k_plus", "pct_immigrants", | |
| 50 | + "pct_autochtone", "pct_appartements"] | |
| 51 | + | |
| 52 | + | |
| 53 | +def slug_of(name: str) -> str: | |
| 54 | + s = re.sub(r"[–—]", "-", name) # tirets cadratins AVANT l'ascii-fold | |
| 55 | + s = unicodedata.normalize("NFKD", s).encode("ascii", "ignore").decode() | |
| 56 | + s = s.replace("'", "").replace("’", "") | |
| 57 | + s = re.sub(r"[\s-]+", "-", s).lower() | |
| 58 | + return re.sub(r"[^a-z0-9-]", "", s) | |
| 59 | + | |
| 60 | + | |
| 61 | +def _table_after(md: str, header_kw: str, span: int = 2600) -> dict[str, float]: | |
| 62 | + """Première table markdown après un titre contenant `header_kw` → | |
| 63 | + {libellé: valeur de la circonscription (1re colonne de données)}.""" | |
| 64 | + i = md.lower().find(header_kw.lower()) | |
| 65 | + if i < 0: | |
| 66 | + return {} | |
| 67 | + window = md[i:i + span] | |
| 68 | + out = {} | |
| 69 | + for m in re.finditer(r"^\|\s*([^|]{2,80}?)\s*\|\s*([\d\s ,.$%]+?)\s*\|", window, re.M): | |
| 70 | + label = m.group(1).strip().strip("*") | |
| 71 | + raw = m.group(2).replace("%", "").replace("$", "") | |
| 72 | + raw = re.sub(r"[\s ]", "", raw).replace(",", ".") | |
| 73 | + try: | |
| 74 | + v = float(raw) | |
| 75 | + except ValueError: | |
| 76 | + continue | |
| 77 | + # les tables successives réutilisent les mêmes libellés (âge en %, | |
| 78 | + # puis effectifs Hommes/Femmes, puis Province) : la PREMIÈRE table | |
| 79 | + # après le titre fait foi — jamais d'écrasement. | |
| 80 | + if label not in out: | |
| 81 | + out[label] = v | |
| 82 | + return out | |
| 83 | + | |
| 84 | + | |
| 85 | +def _riding_population(md: str, name: str) -> float | None: | |
| 86 | + """Population = total Hommes + Femmes du bloc de LA circonscription | |
| 87 | + (le bloc « Province » suit — on s'arrête avant).""" | |
| 88 | + i = md.find("Répartition des femmes et des hommes selon l'âge") | |
| 89 | + if i < 0: | |
| 90 | + return None | |
| 91 | + block = md[i:i + 2600] | |
| 92 | + j = block.find("**Province**") | |
| 93 | + if j > 0: | |
| 94 | + block = block[:j] | |
| 95 | + m = re.search(r"\|\s*\*\*Total\*\*\s*\|\s*([\d\s , ]+)\|\s*([\d\s , ]+)\|", | |
| 96 | + block) | |
| 97 | + if not m: | |
| 98 | + return None | |
| 99 | + def n(s): | |
| 100 | + return float(re.sub(r"[^\d]", "", s) or 0) | |
| 101 | + return n(m.group(1)) + n(m.group(2)) | |
| 102 | + | |
| 103 | + | |
| 104 | +def parse_portrait(md: str, name: str = "") -> dict | None: | |
| 105 | + """Markdown du portrait → variables clés (avec les tables brutes utiles).""" | |
| 106 | + ages = _table_after(md, "Population totale selon les groupes d'âge", 1000) | |
| 107 | + ages = {k: v for k, v in ages.items() | |
| 108 | + if any(k.startswith(g) for g in AGE_GROUPS) and v <= 100} | |
| 109 | + if len(ages) < 7: | |
| 110 | + return None | |
| 111 | + pop_total = _riding_population(md, name) | |
| 112 | + langue = _table_after(md, "langue la plus souvent parlée", 900) | |
| 113 | + diplo = _table_after(md, "plus haut diplôme ou grade", 2200) | |
| 114 | + revenu = _table_after(md, "Revenu des ménages", 2600) | |
| 115 | + immig = _table_after(md, "Citoyenneté et immigration", 1600) | |
| 116 | + autoch = _table_after(md, "identité autochtone", 700) | |
| 117 | + logement = _table_after(md, "type de construction résidentielle", 1800) | |
| 118 | + minor = _table_after(md, "Minorités visibles", 900) | |
| 119 | + | |
| 120 | + def find(d, *kws): | |
| 121 | + for k, v in d.items(): | |
| 122 | + if all(kw.lower() in k.lower() for kw in kws): | |
| 123 | + return v | |
| 124 | + return None | |
| 125 | + | |
| 126 | + g60 = sum(v for k, v in ages.items() | |
| 127 | + if k.startswith(("60 à 69", "70 à 79", "80 ans"))) | |
| 128 | + g2039 = sum(v for k, v in ages.items() if k.startswith(("20 à 29", "30 à 39"))) | |
| 129 | + uni = find(diplo, "universitaire") or find(diplo, "baccalauréat") | |
| 130 | + rev100 = sum(v for k, v in revenu.items() | |
| 131 | + if re.match(r"(100 000|125 000|150 000|200 000)", k)) | |
| 132 | + return { | |
| 133 | + "population": pop_total, | |
| 134 | + "age_groups_pct": ages, | |
| 135 | + "pct_60_plus": round(g60, 1), | |
| 136 | + "pct_20_39": round(g2039, 1), | |
| 137 | + "pct_francais": find(langue, "français"), | |
| 138 | + "pct_anglais": find(langue, "anglais"), | |
| 139 | + "pct_universitaire": uni, | |
| 140 | + "pct_revenu_100k_plus": round(rev100, 1) if revenu else None, | |
| 141 | + "pct_immigrants": find(immig, "immigrant"), | |
| 142 | + "pct_autochtone": find(autoch, "autochtone"), | |
| 143 | + "pct_minorites_visibles": find(minor, "minorit") or find(minor, "total"), | |
| 144 | + "pct_appartements": find(logement, "appartement") or | |
| 145 | + find(logement, "cinq étages"), | |
| 146 | + "tables": {"langue": langue, "revenu": revenu, "diplome": diplo, | |
| 147 | + "logement": logement}, | |
| 148 | + } | |
| 149 | + | |
| 150 | + | |
| 151 | +XLS_URL = ("https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/" | |
| 152 | + "statistiques-recensement-2021-CEP2026.xls") | |
| 153 | +XLS_PATH = POP_DIR / "statistiques-recensement-2021-CEP2026.xls" | |
| 154 | + | |
| 155 | +# Codes de variables stables du classeur officiel (feuille « 127 CEP 2026 ») | |
| 156 | +XLS_CODES = { | |
| 157 | + "population": "TAB1CH_0", | |
| 158 | + "pct_65_plus": "TAB1CH_20b", | |
| 159 | + "pct_revenu_100k_plus": "TAB2C2247_REV", | |
| 160 | + "pct_autochtone": "TAB1CH_lan_N_9", | |
| 161 | + "pct_locataires": "TAB2C2515a", | |
| 162 | + "n_immigrants": "TAB2C18", | |
| 163 | + "n_immigration_total": "TAB2C16", | |
| 164 | + "n_uni_bacc_plus": "TAB3C706", | |
| 165 | + "pct_fr_maison": "TAB1CH_580a", # langue la plus parlée à la MAISON | |
| 166 | + "pct_en_maison": "TAB1CH_579a", | |
| 167 | + "n_app_duplex": "TAB1CH_209", | |
| 168 | + "n_app_moins5": "TAB1CH_210", | |
| 169 | + "n_app_5plus": "TAB1CH_211", | |
| 170 | + "n_logements_occ": "TAB1CH_0b", | |
| 171 | +} | |
| 172 | + | |
| 173 | + | |
| 174 | +def build_from_xls(db: Session) -> dict: | |
| 175 | + """SOURCE PRINCIPALE : le classeur officiel d'Élections Québec | |
| 176 | + (Recensement 2021, 2 917 variables × 127 circonscriptions 2026, codes | |
| 177 | + stables) — déterministe, complet, sans scraping.""" | |
| 178 | + import httpx | |
| 179 | + import pandas as pd | |
| 180 | + POP_DIR.mkdir(parents=True, exist_ok=True) | |
| 181 | + if not XLS_PATH.exists(): | |
| 182 | + r = httpx.get(XLS_URL, timeout=180, follow_redirects=True) | |
| 183 | + r.raise_for_status() | |
| 184 | + XLS_PATH.write_bytes(r.content) | |
| 185 | + raw = pd.ExcelFile(XLS_PATH).parse("127 CEP 2026 ", header=None) | |
| 186 | + # noms de circonscription sur deux lignes (L1 + L2) | |
| 187 | + names = [] | |
| 188 | + for c in range(3, raw.shape[1]): | |
| 189 | + l1 = str(raw.iat[1, c]) if pd.notna(raw.iat[1, c]) else "" | |
| 190 | + l2 = str(raw.iat[2, c]) if pd.notna(raw.iat[2, c]) else "" | |
| 191 | + names.append((l1 + l2).strip()) | |
| 192 | + code_row = {str(raw.iat[i, 0]).strip(): i for i in range(raw.shape[0]) | |
| 193 | + if pd.notna(raw.iat[i, 0])} | |
| 194 | + # % minorités visibles : repérée par libellé (code variable selon éditions) | |
| 195 | + minor_row = next((i for i in range(raw.shape[0]) | |
| 196 | + if pd.notna(raw.iat[i, 1]) and "total des minorités visibles" | |
| 197 | + in str(raw.iat[i, 1]).lower() | |
| 198 | + and "pourcentage" in str(raw.iat[i, 1]).lower()), None) | |
| 199 | + uni_denom_row = next((i for i in range(raw.shape[0]) | |
| 200 | + if pd.notna(raw.iat[i, 1]) and | |
| 201 | + "15 ans et plus dans les ménages privés selon le plus haut" | |
| 202 | + in str(raw.iat[i, 1])), None) | |
| 203 | + | |
| 204 | + def val(code_or_row, col): | |
| 205 | + i = code_row.get(code_or_row) if isinstance(code_or_row, str) else code_or_row | |
| 206 | + if i is None: | |
| 207 | + return None | |
| 208 | + v = raw.iat[i, col] | |
| 209 | + try: | |
| 210 | + return float(v) | |
| 211 | + except (TypeError, ValueError): | |
| 212 | + return None | |
| 213 | + | |
| 214 | + # alignement noms XLS ↔ noms de la base (accents/tirets) | |
| 215 | + db_names = {slug_of(d.name): d.name for d in db.query(Mo.District).all()} | |
| 216 | + rows = [] | |
| 217 | + for k, xls_name in enumerate(names): | |
| 218 | + col = 3 + k | |
| 219 | + name = db_names.get(slug_of(xls_name)) | |
| 220 | + if name is None: | |
| 221 | + log.warning("circonscription XLS non appariée: %s", xls_name) | |
| 222 | + continue | |
| 223 | + cv = lambda k: val(XLS_CODES[k], col) | |
| 224 | + pop = cv("population") | |
| 225 | + apps = sum((cv(k2) or 0.0) | |
| 226 | + for k2 in ("n_app_duplex", "n_app_moins5", "n_app_5plus")) | |
| 227 | + log_tot = cv("n_logements_occ") or 1.0 | |
| 228 | + imm_tot = cv("n_immigration_total") or 1.0 | |
| 229 | + uni_den = val(uni_denom_row, col) or 1.0 | |
| 230 | + pct = lambda x: round(x * 100, 1) if x is not None else None | |
| 231 | + rows.append({ | |
| 232 | + "district": name, "population": pop, | |
| 233 | + "pct_60_plus": pct(cv("pct_65_plus")), # 65+ (libellé officiel) | |
| 234 | + "pct_francais": pct(cv("pct_fr_maison")), | |
| 235 | + "pct_anglais": pct(cv("pct_en_maison")), | |
| 236 | + "pct_universitaire": round((cv("n_uni_bacc_plus") or 0) | |
| 237 | + / uni_den * 100, 1), | |
| 238 | + "pct_revenu_100k_plus": pct(cv("pct_revenu_100k_plus")), | |
| 239 | + "pct_immigrants": round((cv("n_immigrants") or 0) | |
| 240 | + / imm_tot * 100, 1), | |
| 241 | + "pct_autochtone": pct(cv("pct_autochtone")), | |
| 242 | + "pct_locataires": pct(cv("pct_locataires")), | |
| 243 | + "pct_appartements": round(apps / log_tot * 100, 1), | |
| 244 | + "pct_minorites_visibles": pct(val(minor_row, col)), | |
| 245 | + "source_url": XLS_URL, | |
| 246 | + "source": ("Élections Québec — Statistiques du Recensement 2021 " | |
| 247 | + "par circonscription 2026 (classeur officiel)"), | |
| 248 | + "harvested": date.today().isoformat(), | |
| 249 | + }) | |
| 250 | + (POP_DIR / "portraits").mkdir(parents=True, exist_ok=True) | |
| 251 | + for r in rows: | |
| 252 | + (POP_DIR / "portraits" / f"{slug_of(r['district'])}.json").write_text( | |
| 253 | + json.dumps(r, ensure_ascii=False)) | |
| 254 | + out = build_feature_store(db) | |
| 255 | + return {"circonscriptions_xls": len(rows), **out} | |
| 256 | + | |
| 257 | + | |
| 258 | +def harvest(db: Session, max_workers: int = 4, | |
| 259 | + refresh: bool = False) -> dict: | |
| 260 | + """Moissonne les 127 portraits (idempotent : saute les JSON déjà présents).""" | |
| 261 | + from .firecrawl_watch import _enabled, _post | |
| 262 | + if not _enabled(): | |
| 263 | + return {"skipped": "Firecrawl requis"} | |
| 264 | + (POP_DIR / "portraits").mkdir(parents=True, exist_ok=True) | |
| 265 | + names = [d.name for d in db.query(Mo.District).all()] | |
| 266 | + | |
| 267 | + def one(name: str) -> tuple[str, str]: | |
| 268 | + slug = slug_of(name) | |
| 269 | + f = POP_DIR / "portraits" / f"{slug}.json" | |
| 270 | + if f.exists() and not refresh: | |
| 271 | + return name, "cache" | |
| 272 | + data = _post("/scrape", {"url": PORTRAIT_URL.format(slug=slug), | |
| 273 | + "formats": ["markdown"]}, timeout=90.0) | |
| 274 | + md = ((data or {}).get("data") or {}).get("markdown") or "" | |
| 275 | + parsed = parse_portrait(md, name) if md else None | |
| 276 | + if parsed is None: | |
| 277 | + return name, "échec" | |
| 278 | + parsed["markdown"] = md[:60000] # conservé pour re-parse sans réseau | |
| 279 | + parsed["district"] = name | |
| 280 | + parsed["source_url"] = PORTRAIT_URL.format(slug=slug) | |
| 281 | + parsed["source"] = ("Élections Québec — portrait socioéconomique " | |
| 282 | + "(Recensement 2021, limites 2026)") | |
| 283 | + parsed["harvested"] = date.today().isoformat() | |
| 284 | + f.write_text(json.dumps(parsed, ensure_ascii=False)) | |
| 285 | + return name, "ok" | |
| 286 | + | |
| 287 | + results: dict[str, int] = {"ok": 0, "cache": 0, "échec": 0} | |
| 288 | + failed = [] | |
| 289 | + with ThreadPoolExecutor(max_workers=max_workers) as ex: | |
| 290 | + for name, status in ex.map(one, names): | |
| 291 | + results[status] += 1 | |
| 292 | + if status == "échec": | |
| 293 | + failed.append(name) | |
| 294 | + build_feature_store(db) | |
| 295 | + return {**results, "échecs": failed[:10]} | |
| 296 | + | |
| 297 | + | |
| 298 | +def build_feature_store(db: Session) -> dict: | |
| 299 | + """Portraits JSON → CSV standardisé + graphe de similarité (top 10).""" | |
| 300 | + import pandas as pd | |
| 301 | + rows = [] | |
| 302 | + for f in sorted((POP_DIR / "portraits").glob("*.json")): | |
| 303 | + d = json.loads(f.read_text()) | |
| 304 | + rows.append({k: d.get(k) for k in | |
| 305 | + ["district", "population", *Z_FEATURES, | |
| 306 | + "pct_minorites_visibles", "source_url", "harvested"]}) | |
| 307 | + if len(rows) < 60: | |
| 308 | + return {"skipped": f"seulement {len(rows)} portraits"} | |
| 309 | + df = pd.DataFrame(rows) | |
| 310 | + for c in Z_FEATURES: | |
| 311 | + col = pd.to_numeric(df[c], errors="coerce") | |
| 312 | + mu, sd = col.mean(), col.std() or 1.0 | |
| 313 | + df[f"z_{c}"] = ((col - mu) / sd).round(3) | |
| 314 | + POP_DIR.mkdir(parents=True, exist_ok=True) | |
| 315 | + df.to_csv(POP_DIR / "riding_2026_demographics.csv", index=False) | |
| 316 | + # similarité cosinus sur les z-features (valeurs manquantes → 0) | |
| 317 | + Z = df[[f"z_{c}" for c in Z_FEATURES]].fillna(0.0).to_numpy() | |
| 318 | + norms = np.linalg.norm(Z, axis=1, keepdims=True) | |
| 319 | + norms[norms == 0] = 1.0 | |
| 320 | + S = (Z / norms) @ (Z / norms).T | |
| 321 | + sim = {} | |
| 322 | + names = df["district"].tolist() | |
| 323 | + for i, n in enumerate(names): | |
| 324 | + order = np.argsort(-S[i]) | |
| 325 | + sim[n] = [{"district": names[j], "similarity": round(float(S[i, j]), 3)} | |
| 326 | + for j in order[1:11]] | |
| 327 | + (POP_DIR / "riding_similarity.json").write_text( | |
| 328 | + json.dumps(sim, ensure_ascii=False)) | |
| 329 | + return {"circonscriptions": len(df)} | |
added
backend/app/modeling/election_night.py
+187 −0
@@ -0,0 +1,187 @@ | ||
| 1 | +# QC Élection Forecast — Plateforme de prévision électorale du Québec 2026 | |
| 2 | +# Auteur : Simon-Pierre Boucher | |
| 3 | +# Contact : contact@spboucher.ai | |
| 4 | +# https://www.qc-election.com | |
| 5 | +"""Modèle du SOIR D'ÉLECTION (§89-93) — prêt avant le 5 octobre, dormant d'ici là. | |
| 6 | + | |
| 7 | +Principe : le forecast pré-électoral est le PRIOR. À mesure que le DGEQ publie | |
| 8 | +des résultats partiels : | |
| 9 | + | |
| 10 | + 1. chaque circonscription rapportée fournit un résidu | |
| 11 | + `alr(observé) − alr(attendu)`; | |
| 12 | + 2. le résidu est décomposé hiérarchiquement — erreur NATIONALE partagée | |
| 13 | + (prior N(0, σ_industrie²)), erreur RÉGIONALE (prior N(0, σ_rég²)), | |
| 14 | + reste local — par pondération de précision, chaque observation pesée par | |
| 15 | + sa fraction dépouillée; | |
| 16 | + 3. les circonscriptions NON rapportées sont mises à jour par les erreurs | |
| 17 | + nationale et régionale inférées (transfert hiérarchique, jamais | |
| 18 | + d'extrapolation naïve des premiers bureaux); | |
| 19 | + 4. la simulation est relancée avec les variances RÉDUITES par l'information | |
| 20 | + accumulée → P(victoire) en direct; | |
| 21 | + 5. **calling conservateur** : un siège n'est « déclaré » que si | |
| 22 | + P ≥ 99,5 % ET ≥ 40 % dépouillé (ou P ≥ 99,99 %). | |
| 23 | + | |
| 24 | +Garde anti-biais de dépouillement (§90) : les premiers bureaux ne sont pas | |
| 25 | +aléatoires (vote par anticipation, urbain/rural). Chaque circonscription n'est | |
| 26 | +comparée qu'à SA propre attente et pèse au prorata de son propre dépouillement; | |
| 27 | +un plancher de variance de comptage 1/dépouillé protège les débuts de soirée. | |
| 28 | +""" | |
| 29 | +from __future__ import annotations | |
| 30 | + | |
| 31 | +import json | |
| 32 | +from dataclasses import dataclass | |
| 33 | +from datetime import datetime, timezone | |
| 34 | + | |
| 35 | +import numpy as np | |
| 36 | +from sqlalchemy.orm import Session | |
| 37 | + | |
| 38 | +from ..config import DATA_DIR, settings | |
| 39 | +from .compositions import alr, close, inv_alr | |
| 40 | +from .simulate import SimulationInput, run_simulation | |
| 41 | + | |
| 42 | +STATE_FILE = DATA_DIR / "election_night_state.json" | |
| 43 | +MIN_REPORT = 0.05 # < 5 % dépouillé : la circonscription n'informe pas | |
| 44 | +CALL_PROB = 0.995 | |
| 45 | +CALL_MIN_REPORTED = 0.40 | |
| 46 | +COUNT_NOISE_BASE = 0.06 # sd alr du bruit de comptage à 100 % dépouillé | |
| 47 | + | |
| 48 | + | |
| 49 | +@dataclass | |
| 50 | +class NightUpdate: | |
| 51 | + national_shift: np.ndarray # alr (M,) | |
| 52 | + national_var: float | |
| 53 | + regional_shift: dict[str, np.ndarray] | |
| 54 | + n_informative: int | |
| 55 | + | |
| 56 | + | |
| 57 | +def _expected_district_alr(inp: SimulationInput) -> np.ndarray: | |
| 58 | + """Attente pré-électorale par circonscription (base 2022 + swing national).""" | |
| 59 | + delta_nat = inp.x_mean - alr(inp.baseline_national) | |
| 60 | + return alr(inp.district_baselines) + delta_nat[None, :] | |
| 61 | + | |
| 62 | + | |
| 63 | +def infer_shifts(inp: SimulationInput, reported: list[dict], | |
| 64 | + industry_sd: float) -> NightUpdate: | |
| 65 | + """Décomposition hiérarchique des résidus des circonscriptions rapportées.""" | |
| 66 | + M = len(inp.x_mean) | |
| 67 | + exp_alr = _expected_district_alr(inp) | |
| 68 | + name_idx = {n: i for i, n in enumerate(inp.district_names)} | |
| 69 | + resids, weights, regions = [], [], [] | |
| 70 | + for r in reported: | |
| 71 | + i = name_idx.get(r["district"]) | |
| 72 | + frac = float(r.get("pct_reported", 0)) / 100.0 | |
| 73 | + if i is None or frac < MIN_REPORT: | |
| 74 | + continue | |
| 75 | + obs = close(np.array([r["results"].get(p, 0.3) | |
| 76 | + for p in settings.parties]) / 100.0) | |
| 77 | + resid = alr(obs) - exp_alr[i] | |
| 78 | + # variance de l'observation : local + comptage partiel | |
| 79 | + var = (settings.riding_error_sd ** 2 | |
| 80 | + + settings.regional_error_sd ** 2 | |
| 81 | + + (COUNT_NOISE_BASE ** 2) / max(frac, MIN_REPORT)) | |
| 82 | + resids.append(resid) | |
| 83 | + weights.append(1.0 / var) | |
| 84 | + regions.append(inp.district_regions[i]) | |
| 85 | + if not resids: | |
| 86 | + return NightUpdate(np.zeros(M), industry_sd ** 2, {}, 0) | |
| 87 | + R = np.array(resids); W = np.array(weights) | |
| 88 | + # national : posterior N — prior N(0, σ_ind²), vraisemblance moyenne pondérée | |
| 89 | + prior_prec = 1.0 / industry_sd ** 2 | |
| 90 | + like_prec = W.sum() | |
| 91 | + nat_var = 1.0 / (prior_prec + like_prec) | |
| 92 | + nat_shift = nat_var * (R * W[:, None]).sum(axis=0) | |
| 93 | + # régional : sur les résidus nets, par région, prior N(0, σ_rég²) | |
| 94 | + reg_shift: dict[str, np.ndarray] = {} | |
| 95 | + for reg in set(regions): | |
| 96 | + mask = np.array([g == reg for g in regions]) | |
| 97 | + Rr, Wr = R[mask] - nat_shift[None, :], W[mask] | |
| 98 | + rp = 1.0 / settings.regional_error_sd ** 2 | |
| 99 | + rv = 1.0 / (rp + Wr.sum()) | |
| 100 | + reg_shift[reg] = rv * (Rr * Wr[:, None]).sum(axis=0) | |
| 101 | + return NightUpdate(nat_shift, nat_var, reg_shift, len(resids)) | |
| 102 | + | |
| 103 | + | |
| 104 | +def update(db: Session, reported: list[dict], n_sims: int = 15000) -> dict: | |
| 105 | + """Résultats partiels → forecast en direct + déclarations conservatrices.""" | |
| 106 | + from ..pipeline import _district_inputs | |
| 107 | + from .. import models as Mo | |
| 108 | + run = (db.query(Mo.ForecastRun).filter(Mo.ForecastRun.is_backtest.is_(False)) | |
| 109 | + .order_by(Mo.ForecastRun.as_of.desc(), Mo.ForecastRun.id.desc()).first()) | |
| 110 | + if run is None: | |
| 111 | + raise RuntimeError("Aucun forecast pré-électoral (prior manquant)") | |
| 112 | + result_ref = run.national.get("baseline_national") | |
| 113 | + inp = _district_inputs(db, result_ref) | |
| 114 | + inp.x_mean = np.array(run.national["x_forecast"]) | |
| 115 | + inp.P = np.array(run.national["P_forecast"]) | |
| 116 | + industry_sd = float(run.diagnostics.get("industry_sd", | |
| 117 | + settings.industry_error_sd)) | |
| 118 | + | |
| 119 | + upd = infer_shifts(inp, reported, industry_sd) | |
| 120 | + | |
| 121 | + # état national mis à jour : moyenne décalée, incertitude nationale réduite | |
| 122 | + inp.x_mean = inp.x_mean + upd.national_shift | |
| 123 | + M = len(inp.x_mean) | |
| 124 | + # remplace la part « erreur systémique » du P par la variance posterior | |
| 125 | + inp.P = inp.P + (upd.national_var - industry_sd ** 2) * np.eye(M) | |
| 126 | + inp.P = 0.5 * (inp.P + inp.P.T) | |
| 127 | + ev = np.linalg.eigvalsh(inp.P) | |
| 128 | + if ev.min() < 1e-8: # PSD après réduction | |
| 129 | + inp.P += (1e-8 - ev.min()) * np.eye(M) | |
| 130 | + | |
| 131 | + # chocs régionaux inférés injectés comme scénario régional (moyennes) | |
| 132 | + reg_pp: dict[str, dict[str, float]] = {} | |
| 133 | + for reg, shift in upd.regional_shift.items(): | |
| 134 | + base = close(np.array( | |
| 135 | + [result_ref[p] for p in settings.parties]) / 100.0) | |
| 136 | + delta = (inv_alr(alr(base) + shift) - base) * 100.0 | |
| 137 | + reg_pp[reg] = {p: round(float(delta[i]), 2) | |
| 138 | + for i, p in enumerate(settings.parties) | |
| 139 | + if abs(delta[i]) >= 0.1} | |
| 140 | + sim = run_simulation(inp, n_sims=n_sims, | |
| 141 | + scenario={"regional_pp": reg_pp} if reg_pp else None, | |
| 142 | + rng=np.random.default_rng(20261005)) | |
| 143 | + | |
| 144 | + by_name = {r["district"]: r for r in reported} | |
| 145 | + districts, called = [], 0 | |
| 146 | + for d in sim.districts: | |
| 147 | + rep = by_name.get(d["district"]) | |
| 148 | + frac = float((rep or {}).get("pct_reported", 0)) / 100.0 | |
| 149 | + wp = dict(d["win_probs"]) | |
| 150 | + leader = max(wp, key=wp.get) | |
| 151 | + if rep and frac >= 0.99: # dépouillement complet = décidé | |
| 152 | + obs = rep["results"] | |
| 153 | + leader = max(obs, key=obs.get) | |
| 154 | + wp = {p: (1.0 if p == leader else 0.0) for p in settings.parties} | |
| 155 | + is_called = (wp[leader] >= CALL_PROB and | |
| 156 | + (frac >= CALL_MIN_REPORTED or wp[leader] >= 0.9999)) | |
| 157 | + called += is_called | |
| 158 | + districts.append({"district": d["district"], "region": d["region"], | |
| 159 | + "leader": leader, "win_probs": wp, | |
| 160 | + "pct_reported": round(frac * 100, 1), | |
| 161 | + "called": is_called, | |
| 162 | + "reported_results": (rep or {}).get("results")}) | |
| 163 | + state = { | |
| 164 | + "at": datetime.now(timezone.utc).isoformat(), | |
| 165 | + "prior_run_id": run.id, | |
| 166 | + "n_reported": len(reported), "n_informative": upd.n_informative, | |
| 167 | + "national_shift_pp": {p: round(float( | |
| 168 | + (inv_alr(inp.x_mean)[i] - inv_alr(np.array( | |
| 169 | + run.national["x_forecast"]))[i]) * 100), 2) | |
| 170 | + for i, p in enumerate(settings.parties)}, | |
| 171 | + "regional_shift_pp": reg_pp, | |
| 172 | + "seats": sim.seats, "summary": sim.seat_matrix_summary, | |
| 173 | + "national_vote": sim.national_vote, | |
| 174 | + "districts": districts, "seats_called": called, | |
| 175 | + "method": ("Prior = forecast pré-électoral; erreurs nationale/régionales " | |
| 176 | + "inférées hiérarchiquement des circonscriptions rapportées " | |
| 177 | + "(pondérées par leur dépouillement); déclarations à " | |
| 178 | + f"P ≥ {CALL_PROB:.1%} et ≥ {CALL_MIN_REPORTED:.0%} dépouillé."), | |
| 179 | + } | |
| 180 | + STATE_FILE.write_text(json.dumps(state, ensure_ascii=False)) | |
| 181 | + return state | |
| 182 | + | |
| 183 | + | |
| 184 | +def latest_state() -> dict | None: | |
| 185 | + if STATE_FILE.exists(): | |
| 186 | + return json.loads(STATE_FILE.read_text()) | |
| 187 | + return None | |
modified
backend/app/seed.py
+11 −0
@@ -225,6 +225,17 @@ def seed_all(db: Session | None = None) -> dict: | ||
| 225 | 225 | "83 % vs 76,5 %, EAM inchangée. Cœur alr paramétré par ères de " |
| 226 | 226 | "partis (ADQ 2007-2008). Audits : METHODOLOGY_AUDIT, " |
| 227 | 227 | "STATISTICAL_DEBT, V3_MODEL_ARCHITECTURE, HISTORICAL_REPLAY_PLAN."))) |
| 228 | + get_or_create(db, Mo.ModelVersion, version="3.2.0", | |
| 229 | + defaults=dict(changelog=( | |
| 230 | + "Release produit (distribution du forecast INCHANGÉE) : feature " | |
| 231 | + "store démographique officiel (classeur Élections Québec, " | |
| 232 | + "Recensement 2021 × 127 circ. 2026, similarité top-10), modèle du " | |
| 233 | + "soir d'élection (mise à jour bayésienne hiérarchique, calling " | |
| 234 | + "conservateur, dormant), scénarios partageables par URL, fiches " | |
| 235 | + "enrichies (sensibilité au swing, chemin de bascule, démographie), " | |
| 236 | + "baselines dans le replay, Course à 64, connecteurs primaires 7 " | |
| 237 | + "firmes avec file de révision, favicon + og:image, feuille de " | |
| 238 | + "route Compas électoral (COMPAS-PROGRAMMES.md)."))) | |
| 228 | 239 | # Sources |
| 229 | 240 | for name, url, kind in [ |
| 230 | 241 | ("Wikipédia — sondages 2026", "https://en.wikipedia.org/wiki/2026_Quebec_general_election", "polls"), |
added
backend/data/population/portraits/abitibi-est.json
+1 −0
@@ -0,0 +1 @@ | ||
| 1 | +{"district": "Abitibi-Est", "population": 44055.0, "pct_60_plus": 19.6, "pct_francais": 96.7, "pct_anglais": 2.3, "pct_universitaire": 12.6, "pct_revenu_100k_plus": 11.7, "pct_immigrants": 2.0, "pct_autochtone": 0.2, "pct_locataires": 36.4, "pct_appartements": 36.9, "pct_minorites_visibles": null, "source_url": "https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls", "source": "Élections Québec — Statistiques du Recensement 2021 par circonscription 2026 (classeur officiel)", "harvested": "2026-08-31"} | |
| \ No newline at end of file | ||
added
backend/data/population/portraits/abitibi-ouest.json
+1 −0
@@ -0,0 +1 @@ | ||
| 1 | +{"district": "Abitibi-Ouest", "population": 45290.0, "pct_60_plus": 22.0, "pct_francais": 98.9, "pct_anglais": 0.8, "pct_universitaire": 10.0, "pct_revenu_100k_plus": 9.1, "pct_immigrants": 1.0, "pct_autochtone": 0.0, "pct_locataires": 26.7, "pct_appartements": 22.9, "pct_minorites_visibles": null, "source_url": "https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls", "source": "Élections Québec — Statistiques du Recensement 2021 par circonscription 2026 (classeur officiel)", "harvested": "2026-08-31"} | |
| \ No newline at end of file | ||
added
backend/data/population/portraits/acadie.json
+1 −0
@@ -0,0 +1 @@ | ||
| 1 | +{"district": "Acadie", "population": 82340.0, "pct_60_plus": 18.6, "pct_francais": 45.4, "pct_anglais": 16.8, "pct_universitaire": 34.4, "pct_revenu_100k_plus": 6.5, "pct_immigrants": 51.2, "pct_autochtone": 0.0, "pct_locataires": 61.3, "pct_appartements": 85.9, "pct_minorites_visibles": null, "source_url": "https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls", "source": "Élections Québec — Statistiques du Recensement 2021 par circonscription 2026 (classeur officiel)", "harvested": "2026-08-31"} | |
| \ No newline at end of file | ||
added
backend/data/population/portraits/anjou-louis-riel.json
+1 −0
@@ -0,0 +1 @@ | ||
| 1 | +{"district": "Anjou-Louis-Riel", "population": 63611.0, "pct_60_plus": 20.8, "pct_francais": 72.0, "pct_anglais": 8.8, "pct_universitaire": 26.6, "pct_revenu_100k_plus": 6.8, "pct_immigrants": 35.9, "pct_autochtone": 0.0, "pct_locataires": 59.1, "pct_appartements": 82.1, "pct_minorites_visibles": null, "source_url": "https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls", "source": "Élections Québec — Statistiques du Recensement 2021 par circonscription 2026 (classeur officiel)", "harvested": "2026-08-31"} | |
| \ No newline at end of file | ||
added
backend/data/population/portraits/argenteuil.json
+1 −0
@@ -0,0 +1 @@ | ||
| 1 | +{"district": "Argenteuil", "population": 48180.0, "pct_60_plus": 27.2, "pct_francais": 83.0, "pct_anglais": 16.2, "pct_universitaire": 13.9, "pct_revenu_100k_plus": 6.4, "pct_immigrants": 4.6, "pct_autochtone": 0.0, "pct_locataires": 26.9, "pct_appartements": 19.3, "pct_minorites_visibles": null, "source_url": "https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls", "source": "Élections Québec — Statistiques du Recensement 2021 par circonscription 2026 (classeur officiel)", "harvested": "2026-08-31"} | |
| \ No newline at end of file | ||
added
backend/data/population/portraits/arthabaska-lerable.json
+1 −0
@@ -0,0 +1 @@ | ||
| 1 | +{"district": "Arthabaska–L'Érable", "population": 77225.0, "pct_60_plus": 25.8, "pct_francais": 97.9, "pct_anglais": 0.5, "pct_universitaire": 12.3, "pct_revenu_100k_plus": 4.4, "pct_immigrants": 2.5, "pct_autochtone": 0.0, "pct_locataires": 34.8, "pct_appartements": 32.9, "pct_minorites_visibles": null, "source_url": "https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls", "source": "Élections Québec — Statistiques du Recensement 2021 par circonscription 2026 (classeur officiel)", "harvested": "2026-08-31"} | |
| \ No newline at end of file | ||
added
backend/data/population/portraits/beauce-nord.json
+1 −0
@@ -0,0 +1 @@ | ||
| 1 | +{"district": "Beauce-Nord", "population": 57245.0, "pct_60_plus": 20.7, "pct_francais": 98.8, "pct_anglais": 0.4, "pct_universitaire": 12.7, "pct_revenu_100k_plus": 5.2, "pct_immigrants": 1.5, "pct_autochtone": 0.0, "pct_locataires": 22.4, "pct_appartements": 14.4, "pct_minorites_visibles": null, "source_url": "https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls", "source": "Élections Québec — Statistiques du Recensement 2021 par circonscription 2026 (classeur officiel)", "harvested": "2026-08-31"} | |
| \ No newline at end of file | ||
added
backend/data/population/portraits/beauce-sud.json
+1 −0
@@ -0,0 +1 @@ | ||
| 1 | +{"district": "Beauce-Sud", "population": 63595.0, "pct_60_plus": 22.5, "pct_francais": 98.4, "pct_anglais": 0.6, "pct_universitaire": 10.4, "pct_revenu_100k_plus": 4.3, "pct_immigrants": 1.5, "pct_autochtone": 0.0, "pct_locataires": 29.8, "pct_appartements": 22.4, "pct_minorites_visibles": null, "source_url": "https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls", "source": "Élections Québec — Statistiques du Recensement 2021 par circonscription 2026 (classeur officiel)", "harvested": "2026-08-31"} | |
| \ No newline at end of file | ||
added
backend/data/population/portraits/beauharnois.json
+1 −0
@@ -0,0 +1 @@ | ||
| 1 | +{"district": "Beauharnois", "population": 68800.0, "pct_60_plus": 23.1, "pct_francais": 94.9, "pct_anglais": 4.1, "pct_universitaire": 11.0, "pct_revenu_100k_plus": 5.3, "pct_immigrants": 3.3, "pct_autochtone": 0.0, "pct_locataires": 39.8, "pct_appartements": 40.7, "pct_minorites_visibles": null, "source_url": "https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls", "source": "Élections Québec — Statistiques du Recensement 2021 par circonscription 2026 (classeur officiel)", "harvested": "2026-08-31"} | |
| \ No newline at end of file | ||
added
backend/data/population/portraits/bellechasse.json
+1 −0
@@ -0,0 +1 @@ | ||
| 1 | +{"district": "Bellechasse", "population": 57020.0, "pct_60_plus": 23.1, "pct_francais": 98.8, "pct_anglais": 0.5, "pct_universitaire": 12.3, "pct_revenu_100k_plus": 4.7, "pct_immigrants": 1.8, "pct_autochtone": 0.0, "pct_locataires": 22.4, "pct_appartements": 15.3, "pct_minorites_visibles": null, "source_url": "https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls", "source": "Élections Québec — Statistiques du Recensement 2021 par circonscription 2026 (classeur officiel)", "harvested": "2026-08-31"} | |
| \ No newline at end of file | ||
added
backend/data/population/portraits/bellefeuille.json
+1 −0
@@ -0,0 +1 @@ | ||
| 1 | +{"district": "Bellefeuille", "population": 55275.0, "pct_60_plus": 12.5, "pct_francais": 96.3, "pct_anglais": 2.4, "pct_universitaire": 14.2, "pct_revenu_100k_plus": 8.6, "pct_immigrants": 5.1, "pct_autochtone": 0.0, "pct_locataires": 25.3, "pct_appartements": 27.1, "pct_minorites_visibles": null, "source_url": "https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls", "source": "Élections Québec — Statistiques du Recensement 2021 par circonscription 2026 (classeur officiel)", "harvested": "2026-08-31"} | |
| \ No newline at end of file | ||
added
backend/data/population/portraits/berthier.json
+1 −0
@@ -0,0 +1 @@ | ||
| 1 | +{"district": "Berthier", "population": 61440.0, "pct_60_plus": 26.4, "pct_francais": 95.6, "pct_anglais": 1.1, "pct_universitaire": 10.2, "pct_revenu_100k_plus": 4.4, "pct_immigrants": 1.9, "pct_autochtone": 1.3, "pct_locataires": 24.4, "pct_appartements": 14.1, "pct_minorites_visibles": null, "source_url": "https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls", "source": "Élections Québec — Statistiques du Recensement 2021 par circonscription 2026 (classeur officiel)", "harvested": "2026-08-31"} | |
| \ No newline at end of file | ||
added
backend/data/population/portraits/bertrand.json
+1 −0
@@ -0,0 +1 @@ | ||
| 1 | +{"district": "Bertrand", "population": 64730.0, "pct_60_plus": 28.0, "pct_francais": 93.2, "pct_anglais": 5.9, "pct_universitaire": 17.7, "pct_revenu_100k_plus": 6.2, "pct_immigrants": 5.2, "pct_autochtone": 0.0, "pct_locataires": 27.2, "pct_appartements": 21.2, "pct_minorites_visibles": null, "source_url": "https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls", "source": "Élections Québec — Statistiques du Recensement 2021 par circonscription 2026 (classeur officiel)", "harvested": "2026-08-31"} | |
| \ No newline at end of file | ||
added
backend/data/population/portraits/blainville.json
+1 −0
@@ -0,0 +1 @@ | ||
| 1 | +{"district": "Blainville", "population": 79480.0, "pct_60_plus": 15.1, "pct_francais": 88.7, "pct_anglais": 6.5, "pct_universitaire": 25.1, "pct_revenu_100k_plus": 14.1, "pct_immigrants": 12.0, "pct_autochtone": 0.0, "pct_locataires": 20.4, "pct_appartements": 27.1, "pct_minorites_visibles": null, "source_url": "https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls", "source": "Élections Québec — Statistiques du Recensement 2021 par circonscription 2026 (classeur officiel)", "harvested": "2026-08-31"} | |
| \ No newline at end of file | ||
added
backend/data/population/portraits/bonaventure.json
+1 −0
@@ -0,0 +1 @@ | ||
| 1 | +{"district": "Bonaventure", "population": 40733.0, "pct_60_plus": 28.8, "pct_francais": 89.4, "pct_anglais": 10.3, "pct_universitaire": 11.6, "pct_revenu_100k_plus": 4.3, "pct_immigrants": 1.1, "pct_autochtone": 0.1, "pct_locataires": 27.2, "pct_appartements": 13.7, "pct_minorites_visibles": null, "source_url": "https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls", "source": "Élections Québec — Statistiques du Recensement 2021 par circonscription 2026 (classeur officiel)", "harvested": "2026-08-31"} | |
| \ No newline at end of file | ||
added
backend/data/population/portraits/borduas.json
+1 −0
@@ -0,0 +1 @@ | ||
| 1 | +{"district": "Borduas", "population": 71565.0, "pct_60_plus": 20.9, "pct_francais": 95.8, "pct_anglais": 2.9, "pct_universitaire": 24.2, "pct_revenu_100k_plus": 12.4, "pct_immigrants": 4.9, "pct_autochtone": 0.0, "pct_locataires": 22.5, "pct_appartements": 25.8, "pct_minorites_visibles": null, "source_url": "https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls", "source": "Élections Québec — Statistiques du Recensement 2021 par circonscription 2026 (classeur officiel)", "harvested": "2026-08-31"} | |
| \ No newline at end of file | ||
added
backend/data/population/portraits/bourassa-sauve.json
+1 −0
@@ -0,0 +1 @@ | ||
| 1 | +{"district": "Bourassa-Sauvé", "population": 81450.0, "pct_60_plus": 18.1, "pct_francais": 64.2, "pct_anglais": 9.0, "pct_universitaire": 13.3, "pct_revenu_100k_plus": 2.2, "pct_immigrants": 39.8, "pct_autochtone": 0.0, "pct_locataires": 70.7, "pct_appartements": 87.2, "pct_minorites_visibles": null, "source_url": "https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls", "source": "Élections Québec — Statistiques du Recensement 2021 par circonscription 2026 (classeur officiel)", "harvested": "2026-08-31"} | |
| \ No newline at end of file | ||
added
backend/data/population/portraits/brome-missisquoi.json
+1 −0
@@ -0,0 +1 @@ | ||
| 1 | +{"district": "Brome-Missisquoi", "population": 64785.0, "pct_60_plus": 26.3, "pct_francais": 82.1, "pct_anglais": 17.2, "pct_universitaire": 21.1, "pct_revenu_100k_plus": 8.2, "pct_immigrants": 4.7, "pct_autochtone": 0.0, "pct_locataires": 31.4, "pct_appartements": 30.9, "pct_minorites_visibles": null, "source_url": "https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls", "source": "Élections Québec — Statistiques du Recensement 2021 par circonscription 2026 (classeur officiel)", "harvested": "2026-08-31"} | |
| \ No newline at end of file | ||
added
backend/data/population/portraits/camille-laurin.json
+1 −0
@@ -0,0 +1 @@ | ||
| 1 | +{"district": "Camille-Laurin", "population": 71858.0, "pct_60_plus": 15.9, "pct_francais": 83.2, "pct_anglais": 5.0, "pct_universitaire": 24.6, "pct_revenu_100k_plus": 6.0, "pct_immigrants": 23.0, "pct_autochtone": 0.0, "pct_locataires": 60.6, "pct_appartements": 79.4, "pct_minorites_visibles": null, "source_url": "https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls", "source": "Élections Québec — Statistiques du Recensement 2021 par circonscription 2026 (classeur officiel)", "harvested": "2026-08-31"} | |
| \ No newline at end of file | ||
added
backend/data/population/portraits/chambly.json
+1 −0
@@ -0,0 +1 @@ | ||
| 1 | +{"district": "Chambly", "population": 70525.0, "pct_60_plus": 15.1, "pct_francais": 92.4, "pct_anglais": 4.5, "pct_universitaire": 24.8, "pct_revenu_100k_plus": 13.6, "pct_immigrants": 8.1, "pct_autochtone": 0.0, "pct_locataires": 21.0, "pct_appartements": 27.7, "pct_minorites_visibles": null, "source_url": "https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls", "source": "Élections Québec — Statistiques du Recensement 2021 par circonscription 2026 (classeur officiel)", "harvested": "2026-08-31"} | |
| \ No newline at end of file | ||
added
backend/data/population/portraits/champlain.json
+1 −0
@@ -0,0 +1 @@ | ||
| 1 | +{"district": "Champlain", "population": 73250.0, "pct_60_plus": 27.5, "pct_francais": 98.5, "pct_anglais": 0.7, "pct_universitaire": 13.8, "pct_revenu_100k_plus": 5.0, "pct_immigrants": 2.5, "pct_autochtone": 0.0, "pct_locataires": 33.9, "pct_appartements": 32.6, "pct_minorites_visibles": null, "source_url": "https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls", "source": "Élections Québec — Statistiques du Recensement 2021 par circonscription 2026 (classeur officiel)", "harvested": "2026-08-31"} | |
| \ No newline at end of file | ||
added
backend/data/population/portraits/chapleau.json
+1 −0
@@ -0,0 +1 @@ | ||
| 1 | +{"district": "Chapleau", "population": 80435.0, "pct_60_plus": 19.5, "pct_francais": 85.4, "pct_anglais": 9.4, "pct_universitaire": 18.0, "pct_revenu_100k_plus": 6.9, "pct_immigrants": 12.2, "pct_autochtone": 0.0, "pct_locataires": 39.0, "pct_appartements": 41.8, "pct_minorites_visibles": null, "source_url": "https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls", "source": "Élections Québec — Statistiques du Recensement 2021 par circonscription 2026 (classeur officiel)", "harvested": "2026-08-31"} | |
| \ No newline at end of file | ||
added
backend/data/population/portraits/charlesbourg.json
+1 −0
@@ -0,0 +1 @@ | ||
| 1 | +{"district": "Charlesbourg", "population": 74350.0, "pct_60_plus": 24.7, "pct_francais": 96.7, "pct_anglais": 0.9, "pct_universitaire": 22.4, "pct_revenu_100k_plus": 6.7, "pct_immigrants": 8.0, "pct_autochtone": 0.0, "pct_locataires": 41.6, "pct_appartements": 52.7, "pct_minorites_visibles": null, "source_url": "https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls", "source": "Élections Québec — Statistiques du Recensement 2021 par circonscription 2026 (classeur officiel)", "harvested": "2026-08-31"} | |
| \ No newline at end of file | ||
added
backend/data/population/portraits/charlevoix-cote-de-beaupre.json
+1 −0
@@ -0,0 +1 @@ | ||
| 1 | +{"district": "Charlevoix-Côte-de-Beaupré", "population": 65840.0, "pct_60_plus": 26.7, "pct_francais": 99.0, "pct_anglais": 0.6, "pct_universitaire": 17.2, "pct_revenu_100k_plus": 7.6, "pct_immigrants": 2.2, "pct_autochtone": 0.0, "pct_locataires": 23.1, "pct_appartements": 20.8, "pct_minorites_visibles": null, "source_url": "https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls", "source": "Élections Québec — Statistiques du Recensement 2021 par circonscription 2026 (classeur officiel)", "harvested": "2026-08-31"} | |
| \ No newline at end of file | ||
added
backend/data/population/portraits/chateauguay.json
+1 −0
@@ -0,0 +1 @@ | ||
| 1 | +{"district": "Châteauguay", "population": 70595.0, "pct_60_plus": 18.3, "pct_francais": 67.4, "pct_anglais": 24.7, "pct_universitaire": 16.6, "pct_revenu_100k_plus": 6.7, "pct_immigrants": 17.8, "pct_autochtone": 0.0, "pct_locataires": 25.8, "pct_appartements": 26.1, "pct_minorites_visibles": null, "source_url": "https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls", "source": "Élections Québec — Statistiques du Recensement 2021 par circonscription 2026 (classeur officiel)", "harvested": "2026-08-31"} | |
| \ No newline at end of file | ||
added
backend/data/population/portraits/chauveau.json
+1 −0
@@ -0,0 +1 @@ | ||
| 1 | +{"district": "Chauveau", "population": 76350.0, "pct_60_plus": 15.9, "pct_francais": 97.9, "pct_anglais": 1.1, "pct_universitaire": 21.1, "pct_revenu_100k_plus": 9.3, "pct_immigrants": 4.1, "pct_autochtone": 0.1, "pct_locataires": 22.4, "pct_appartements": 23.6, "pct_minorites_visibles": null, "source_url": "https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls", "source": "Élections Québec — Statistiques du Recensement 2021 par circonscription 2026 (classeur officiel)", "harvested": "2026-08-31"} | |
| \ No newline at end of file | ||
added
backend/data/population/portraits/chicoutimi.json
+1 −0
@@ -0,0 +1 @@ | ||
| 1 | +{"district": "Chicoutimi", "population": 57895.0, "pct_60_plus": 26.5, "pct_francais": 98.5, "pct_anglais": 0.6, "pct_universitaire": 21.4, "pct_revenu_100k_plus": 8.0, "pct_immigrants": 2.0, "pct_autochtone": 0.1, "pct_locataires": 43.2, "pct_appartements": 46.2, "pct_minorites_visibles": null, "source_url": "https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls", "source": "Élections Québec — Statistiques du Recensement 2021 par circonscription 2026 (classeur officiel)", "harvested": "2026-08-31"} | |
| \ No newline at end of file | ||
added
backend/data/population/portraits/chomedey.json
+1 −0
@@ -0,0 +1 @@ | ||
| 1 | +{"district": "Chomedey", "population": 77470.0, "pct_60_plus": 23.8, "pct_francais": 41.8, "pct_anglais": 22.3, "pct_universitaire": 21.3, "pct_revenu_100k_plus": 4.7, "pct_immigrants": 46.3, "pct_autochtone": 0.0, "pct_locataires": 46.1, "pct_appartements": 62.4, "pct_minorites_visibles": null, "source_url": "https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls", "source": "Élections Québec — Statistiques du Recensement 2021 par circonscription 2026 (classeur officiel)", "harvested": "2026-08-31"} | |
| \ No newline at end of file | ||
added
backend/data/population/portraits/chutes-de-la-chaudiere.json
+1 −0
@@ -0,0 +1 @@ | ||
| 1 | +{"district": "Chutes-de-la-Chaudière", "population": 77200.0, "pct_60_plus": 17.2, "pct_francais": 98.4, "pct_anglais": 0.8, "pct_universitaire": 26.3, "pct_revenu_100k_plus": 11.5, "pct_immigrants": 3.0, "pct_autochtone": 0.0, "pct_locataires": 23.0, "pct_appartements": 23.9, "pct_minorites_visibles": null, "source_url": "https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls", "source": "Élections Québec — Statistiques du Recensement 2021 par circonscription 2026 (classeur officiel)", "harvested": "2026-08-31"} | |
| \ No newline at end of file | ||
added
backend/data/population/portraits/cote-du-sud.json
+1 −0
@@ -0,0 +1 @@ | ||
| 1 | +{"district": "Côte-du-Sud", "population": 61385.0, "pct_60_plus": 29.4, "pct_francais": 99.2, "pct_anglais": 0.4, "pct_universitaire": 11.2, "pct_revenu_100k_plus": 3.4, "pct_immigrants": 1.2, "pct_autochtone": 0.0, "pct_locataires": 26.4, "pct_appartements": 20.1, "pct_minorites_visibles": null, "source_url": "https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls", "source": "Élections Québec — Statistiques du Recensement 2021 par circonscription 2026 (classeur officiel)", "harvested": "2026-08-31"} | |
| \ No newline at end of file | ||
added
backend/data/population/portraits/daniel-johnson.json
+1 −0
@@ -0,0 +1 @@ | ||
| 1 | +{"district": "Daniel-Johnson", "population": 58030.0, "pct_60_plus": 19.5, "pct_francais": 96.6, "pct_anglais": 2.8, "pct_universitaire": 11.0, "pct_revenu_100k_plus": 5.1, "pct_immigrants": 2.4, "pct_autochtone": 0.0, "pct_locataires": 24.5, "pct_appartements": 17.6, "pct_minorites_visibles": null, "source_url": "https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls", "source": "Élections Québec — Statistiques du Recensement 2021 par circonscription 2026 (classeur officiel)", "harvested": "2026-08-31"} | |
| \ No newline at end of file | ||
added
backend/data/population/portraits/darcy-mcgee.json
+1 −0
@@ -0,0 +1 @@ | ||
| 1 | +{"district": "D'Arcy-McGee", "population": 92930.0, "pct_60_plus": 19.9, "pct_francais": 21.4, "pct_anglais": 50.5, "pct_universitaire": 41.9, "pct_revenu_100k_plus": 9.8, "pct_immigrants": 46.4, "pct_autochtone": 0.0, "pct_locataires": 66.0, "pct_appartements": 83.2, "pct_minorites_visibles": null, "source_url": "https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls", "source": "Élections Québec — Statistiques du Recensement 2021 par circonscription 2026 (classeur officiel)", "harvested": "2026-08-31"} | |
| \ No newline at end of file | ||
added
backend/data/population/portraits/deux-montagnes.json
+1 −0
@@ -0,0 +1 @@ | ||
| 1 | +{"district": "Deux-Montagnes", "population": 63190.0, "pct_60_plus": 20.2, "pct_francais": 87.3, "pct_anglais": 8.0, "pct_universitaire": 16.9, "pct_revenu_100k_plus": 7.4, "pct_immigrants": 10.7, "pct_autochtone": 0.0, "pct_locataires": 30.2, "pct_appartements": 35.6, "pct_minorites_visibles": null, "source_url": "https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls", "source": "Élections Québec — Statistiques du Recensement 2021 par circonscription 2026 (classeur officiel)", "harvested": "2026-08-31"} | |
| \ No newline at end of file | ||
added
backend/data/population/portraits/drummond-bois-francs.json
+1 −0
@@ -0,0 +1 @@ | ||
| 1 | +{"district": "Drummond-Bois-Francs", "population": 65520.0, "pct_60_plus": 24.5, "pct_francais": 97.6, "pct_anglais": 1.0, "pct_universitaire": 13.1, "pct_revenu_100k_plus": 5.3, "pct_immigrants": 3.2, "pct_autochtone": 0.0, "pct_locataires": 37.7, "pct_appartements": 33.6, "pct_minorites_visibles": null, "source_url": "https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls", "source": "Élections Québec — Statistiques du Recensement 2021 par circonscription 2026 (classeur officiel)", "harvested": "2026-08-31"} | |
| \ No newline at end of file | ||
added
backend/data/population/portraits/dubuc.json
+1 −0
@@ -0,0 +1 @@ | ||
| 1 | +{"district": "Dubuc", "population": 52015.0, "pct_60_plus": 22.0, "pct_francais": 99.0, "pct_anglais": 0.8, "pct_universitaire": 12.2, "pct_revenu_100k_plus": 7.7, "pct_immigrants": 0.8, "pct_autochtone": 0.0, "pct_locataires": 24.3, "pct_appartements": 22.5, "pct_minorites_visibles": null, "source_url": "https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls", "source": "Élections Québec — Statistiques du Recensement 2021 par circonscription 2026 (classeur officiel)", "harvested": "2026-08-31"} | |
| \ No newline at end of file | ||
added
backend/data/population/portraits/duplessis.json
+1 −0
@@ -0,0 +1 @@ | ||
| 1 | +{"district": "Duplessis", "population": 48090.0, "pct_60_plus": 18.9, "pct_francais": 82.7, "pct_anglais": 8.4, "pct_universitaire": 10.8, "pct_revenu_100k_plus": 15.5, "pct_immigrants": 1.7, "pct_autochtone": 5.5, "pct_locataires": 28.8, "pct_appartements": 23.2, "pct_minorites_visibles": null, "source_url": "https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls", "source": "Élections Québec — Statistiques du Recensement 2021 par circonscription 2026 (classeur officiel)", "harvested": "2026-08-31"} | |
| \ No newline at end of file | ||
added
backend/data/population/portraits/fabre.json
+1 −0
@@ -0,0 +1 @@ | ||
| 1 | +{"district": "Fabre", "population": 78795.0, "pct_60_plus": 14.5, "pct_francais": 58.0, "pct_anglais": 21.6, "pct_universitaire": 26.8, "pct_revenu_100k_plus": 12.1, "pct_immigrants": 30.5, "pct_autochtone": 0.0, "pct_locataires": 21.1, "pct_appartements": 25.9, "pct_minorites_visibles": null, "source_url": "https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls", "source": "Élections Québec — Statistiques du Recensement 2021 par circonscription 2026 (classeur officiel)", "harvested": "2026-08-31"} | |
| \ No newline at end of file | ||
added
backend/data/population/portraits/gaspe.json
+1 −0
@@ -0,0 +1 @@ | ||
| 1 | +{"district": "Gaspé", "population": 35955.0, "pct_60_plus": 28.2, "pct_francais": 93.3, "pct_anglais": 6.3, "pct_universitaire": 11.7, "pct_revenu_100k_plus": 4.1, "pct_immigrants": 1.9, "pct_autochtone": 0.0, "pct_locataires": 27.1, "pct_appartements": 15.5, "pct_minorites_visibles": null, "source_url": "https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls", "source": "Élections Québec — Statistiques du Recensement 2021 par circonscription 2026 (classeur officiel)", "harvested": "2026-08-31"} | |
| \ No newline at end of file | ||
added
backend/data/population/portraits/gatineau.json
+1 −0
@@ -0,0 +1 @@ | ||
| 1 | +{"district": "Gatineau", "population": 76855.0, "pct_60_plus": 18.3, "pct_francais": 77.3, "pct_anglais": 21.1, "pct_universitaire": 23.3, "pct_revenu_100k_plus": 13.1, "pct_immigrants": 5.3, "pct_autochtone": 0.0, "pct_locataires": 14.8, "pct_appartements": 10.3, "pct_minorites_visibles": null, "source_url": "https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls", "source": "Élections Québec — Statistiques du Recensement 2021 par circonscription 2026 (classeur officiel)", "harvested": "2026-08-31"} | |
| \ No newline at end of file | ||
added
backend/data/population/portraits/gouin.json
+1 −0
@@ -0,0 +1 @@ | ||
| 1 | +{"district": "Gouin", "population": 61460.0, "pct_60_plus": 11.4, "pct_francais": 83.4, "pct_anglais": 9.9, "pct_universitaire": 49.9, "pct_revenu_100k_plus": 10.5, "pct_immigrants": 18.3, "pct_autochtone": 0.0, "pct_locataires": 69.4, "pct_appartements": 97.6, "pct_minorites_visibles": null, "source_url": "https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls", "source": "Élections Québec — Statistiques du Recensement 2021 par circonscription 2026 (classeur officiel)", "harvested": "2026-08-31"} | |
| \ No newline at end of file | ||
added
backend/data/population/portraits/granby.json
+1 −0
@@ -0,0 +1 @@ | ||
| 1 | +{"district": "Granby", "population": 72365.0, "pct_60_plus": 25.1, "pct_francais": 95.6, "pct_anglais": 1.8, "pct_universitaire": 13.1, "pct_revenu_100k_plus": 4.9, "pct_immigrants": 5.2, "pct_autochtone": 0.0, "pct_locataires": 44.4, "pct_appartements": 47.1, "pct_minorites_visibles": null, "source_url": "https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls", "source": "Élections Québec — Statistiques du Recensement 2021 par circonscription 2026 (classeur officiel)", "harvested": "2026-08-31"} | |
| \ No newline at end of file | ||
added
backend/data/population/portraits/groulx.json
+1 −0
@@ -0,0 +1 @@ | ||
| 1 | +{"district": "Groulx", "population": 68930.0, "pct_60_plus": 20.7, "pct_francais": 84.0, "pct_anglais": 8.2, "pct_universitaire": 22.0, "pct_revenu_100k_plus": 10.3, "pct_immigrants": 10.6, "pct_autochtone": 0.0, "pct_locataires": 39.0, "pct_appartements": 47.2, "pct_minorites_visibles": null, "source_url": "https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls", "source": "Élections Québec — Statistiques du Recensement 2021 par circonscription 2026 (classeur officiel)", "harvested": "2026-08-31"} | |
| \ No newline at end of file | ||
added
backend/data/population/portraits/hochelaga-maisonneuve.json
+1 −0
@@ -0,0 +1 @@ | ||
| 1 | +{"district": "Hochelaga-Maisonneuve", "population": 59448.0, "pct_60_plus": 10.8, "pct_francais": 86.2, "pct_anglais": 7.0, "pct_universitaire": 36.6, "pct_revenu_100k_plus": 5.7, "pct_immigrants": 18.0, "pct_autochtone": 0.0, "pct_locataires": 73.0, "pct_appartements": 91.7, "pct_minorites_visibles": null, "source_url": "https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls", "source": "Élections Québec — Statistiques du Recensement 2021 par circonscription 2026 (classeur officiel)", "harvested": "2026-08-31"} | |
| \ No newline at end of file | ||
added
backend/data/population/portraits/hull.json
+1 −0
@@ -0,0 +1 @@ | ||
| 1 | +{"district": "Hull", "population": 94660.0, "pct_60_plus": 15.6, "pct_francais": 70.8, "pct_anglais": 19.0, "pct_universitaire": 38.3, "pct_revenu_100k_plus": 11.7, "pct_immigrants": 22.6, "pct_autochtone": 0.0, "pct_locataires": 54.4, "pct_appartements": 61.1, "pct_minorites_visibles": null, "source_url": "https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls", "source": "Élections Québec — Statistiques du Recensement 2021 par circonscription 2026 (classeur officiel)", "harvested": "2026-08-31"} | |
| \ No newline at end of file | ||
added
backend/data/population/portraits/huntingdon.json
+1 −0
@@ -0,0 +1 @@ | ||
| 1 | +{"district": "Huntingdon", "population": 57950.0, "pct_60_plus": 20.7, "pct_francais": 83.1, "pct_anglais": 16.0, "pct_universitaire": 10.2, "pct_revenu_100k_plus": 5.1, "pct_immigrants": 3.6, "pct_autochtone": 0.0, "pct_locataires": 22.9, "pct_appartements": 12.7, "pct_minorites_visibles": null, "source_url": "https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls", "source": "Élections Québec — Statistiques du Recensement 2021 par circonscription 2026 (classeur officiel)", "harvested": "2026-08-31"} | |
| \ No newline at end of file | ||
added
backend/data/population/portraits/iberville.json
+1 −0
@@ -0,0 +1 @@ | ||
| 1 | +{"district": "Iberville", "population": 64145.0, "pct_60_plus": 19.2, "pct_francais": 96.3, "pct_anglais": 2.7, "pct_universitaire": 12.4, "pct_revenu_100k_plus": 5.8, "pct_immigrants": 3.4, "pct_autochtone": 0.0, "pct_locataires": 28.0, "pct_appartements": 23.4, "pct_minorites_visibles": null, "source_url": "https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls", "source": "Élections Québec — Statistiques du Recensement 2021 par circonscription 2026 (classeur officiel)", "harvested": "2026-08-31"} | |
| \ No newline at end of file | ||
added
backend/data/population/portraits/iles-de-la-madeleine.json
+1 −0
@@ -0,0 +1 @@ | ||
| 1 | +{"district": "Îles-de-la-Madeleine", "population": 12650.0, "pct_60_plus": 28.3, "pct_francais": 94.9, "pct_anglais": 5.0, "pct_universitaire": 13.2, "pct_revenu_100k_plus": 7.6, "pct_immigrants": 0.8, "pct_autochtone": 0.0, "pct_locataires": 24.4, "pct_appartements": 8.8, "pct_minorites_visibles": null, "source_url": "https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls", "source": "Élections Québec — Statistiques du Recensement 2021 par circonscription 2026 (classeur officiel)", "harvested": "2026-08-31"} | |
| \ No newline at end of file | ||
added
backend/data/population/portraits/jacques-cartier.json
+1 −0
@@ -0,0 +1 @@ | ||
| 1 | +{"district": "Jacques-Cartier", "population": 62510.0, "pct_60_plus": 24.7, "pct_francais": 18.4, "pct_anglais": 68.1, "pct_universitaire": 44.4, "pct_revenu_100k_plus": 18.6, "pct_immigrants": 25.5, "pct_autochtone": 0.0, "pct_locataires": 24.6, "pct_appartements": 23.5, "pct_minorites_visibles": null, "source_url": "https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls", "source": "Élections Québec — Statistiques du Recensement 2021 par circonscription 2026 (classeur officiel)", "harvested": "2026-08-31"} | |
| \ No newline at end of file | ||
added
backend/data/population/portraits/jean-lesage.json
+1 −0
@@ -0,0 +1 @@ | ||
| 1 | +{"district": "Jean-Lesage", "population": 59745.0, "pct_60_plus": 23.5, "pct_francais": 94.8, "pct_anglais": 1.1, "pct_universitaire": 22.4, "pct_revenu_100k_plus": 3.0, "pct_immigrants": 10.7, "pct_autochtone": 0.0, "pct_locataires": 75.0, "pct_appartements": 90.0, "pct_minorites_visibles": null, "source_url": "https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls", "source": "Élections Québec — Statistiques du Recensement 2021 par circonscription 2026 (classeur officiel)", "harvested": "2026-08-31"} | |
| \ No newline at end of file | ||
added
backend/data/population/portraits/jean-talon.json
+1 −0
@@ -0,0 +1 @@ | ||
| 1 | +{"district": "Jean-Talon", "population": 69815.0, "pct_60_plus": 23.2, "pct_francais": 90.3, "pct_anglais": 2.2, "pct_universitaire": 47.6, "pct_revenu_100k_plus": 11.6, "pct_immigrants": 15.2, "pct_autochtone": 0.0, "pct_locataires": 58.4, "pct_appartements": 68.7, "pct_minorites_visibles": null, "source_url": "https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls", "source": "Élections Québec — Statistiques du Recensement 2021 par circonscription 2026 (classeur officiel)", "harvested": "2026-08-31"} | |
| \ No newline at end of file | ||
added
backend/data/population/portraits/jeanne-mance-viger.json
+1 −0
@@ -0,0 +1 @@ | ||
| 1 | +{"district": "Jeanne-Mance-Viger", "population": 79340.0, "pct_60_plus": 20.9, "pct_francais": 46.2, "pct_anglais": 21.8, "pct_universitaire": 21.8, "pct_revenu_100k_plus": 4.5, "pct_immigrants": 47.0, "pct_autochtone": 0.0, "pct_locataires": 64.9, "pct_appartements": 90.5, "pct_minorites_visibles": null, "source_url": "https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls", "source": "Élections Québec — Statistiques du Recensement 2021 par circonscription 2026 (classeur officiel)", "harvested": "2026-08-31"} | |
| \ No newline at end of file | ||
added
backend/data/population/portraits/joliette.json
+1 −0
@@ -0,0 +1 @@ | ||
| 1 | +{"district": "Joliette", "population": 71115.0, "pct_60_plus": 26.5, "pct_francais": 97.9, "pct_anglais": 0.7, "pct_universitaire": 13.9, "pct_revenu_100k_plus": 5.3, "pct_immigrants": 3.5, "pct_autochtone": 0.1, "pct_locataires": 44.3, "pct_appartements": 41.2, "pct_minorites_visibles": null, "source_url": "https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls", "source": "Élections Québec — Statistiques du Recensement 2021 par circonscription 2026 (classeur officiel)", "harvested": "2026-08-31"} | |
| \ No newline at end of file | ||
added
backend/data/population/portraits/jonquiere.json
+1 −0
@@ -0,0 +1 @@ | ||
| 1 | +{"district": "Jonquière", "population": 56325.0, "pct_60_plus": 24.7, "pct_francais": 99.3, "pct_anglais": 0.5, "pct_universitaire": 15.7, "pct_revenu_100k_plus": 7.9, "pct_immigrants": 1.1, "pct_autochtone": 0.0, "pct_locataires": 37.1, "pct_appartements": 40.2, "pct_minorites_visibles": null, "source_url": "https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls", "source": "Élections Québec — Statistiques du Recensement 2021 par circonscription 2026 (classeur officiel)", "harvested": "2026-08-31"} | |
| \ No newline at end of file | ||
added
backend/data/population/portraits/la-peltrie.json
+1 −0
@@ -0,0 +1 @@ | ||
| 1 | +{"district": "La Peltrie", "population": 77880.0, "pct_60_plus": 17.3, "pct_francais": 96.8, "pct_anglais": 1.7, "pct_universitaire": 20.9, "pct_revenu_100k_plus": 7.9, "pct_immigrants": 4.9, "pct_autochtone": 0.0, "pct_locataires": 31.0, "pct_appartements": 32.1, "pct_minorites_visibles": null, "source_url": "https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls", "source": "Élections Québec — Statistiques du Recensement 2021 par circonscription 2026 (classeur officiel)", "harvested": "2026-08-31"} | |
| \ No newline at end of file | ||
added
backend/data/population/portraits/la-piniere.json
+1 −0
@@ -0,0 +1 @@ | ||
| 1 | +{"district": "La Pinière", "population": 81625.0, "pct_60_plus": 21.1, "pct_francais": 48.3, "pct_anglais": 19.7, "pct_universitaire": 37.5, "pct_revenu_100k_plus": 11.1, "pct_immigrants": 40.8, "pct_autochtone": 0.0, "pct_locataires": 29.3, "pct_appartements": 45.6, "pct_minorites_visibles": null, "source_url": "https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls", "source": "Élections Québec — Statistiques du Recensement 2021 par circonscription 2026 (classeur officiel)", "harvested": "2026-08-31"} | |
| \ No newline at end of file | ||
added
backend/data/population/portraits/la-prairie.json
+1 −0
@@ -0,0 +1 @@ | ||
| 1 | +{"district": "La Prairie", "population": 65325.0, "pct_60_plus": 16.3, "pct_francais": 81.5, "pct_anglais": 8.8, "pct_universitaire": 30.9, "pct_revenu_100k_plus": 15.3, "pct_immigrants": 15.1, "pct_autochtone": 0.0, "pct_locataires": 24.4, "pct_appartements": 32.4, "pct_minorites_visibles": null, "source_url": "https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls", "source": "Élections Québec — Statistiques du Recensement 2021 par circonscription 2026 (classeur officiel)", "harvested": "2026-08-31"} | |
| \ No newline at end of file | ||
added
backend/data/population/portraits/labelle.json
+1 −0
@@ -0,0 +1 @@ | ||
| 1 | +{"district": "Labelle", "population": 62590.0, "pct_60_plus": 29.0, "pct_francais": 96.4, "pct_anglais": 3.2, "pct_universitaire": 12.7, "pct_revenu_100k_plus": 5.3, "pct_immigrants": 2.5, "pct_autochtone": 0.0, "pct_locataires": 27.9, "pct_appartements": 21.8, "pct_minorites_visibles": null, "source_url": "https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls", "source": "Élections Québec — Statistiques du Recensement 2021 par circonscription 2026 (classeur officiel)", "harvested": "2026-08-31"} | |
| \ No newline at end of file | ||
added
backend/data/population/portraits/lac-saint-jean.json
+1 −0
@@ -0,0 +1 @@ | ||
| 1 | +{"district": "Lac-Saint-Jean", "population": 54090.0, "pct_60_plus": 24.2, "pct_francais": 99.5, "pct_anglais": 0.2, "pct_universitaire": 12.5, "pct_revenu_100k_plus": 7.1, "pct_immigrants": 0.7, "pct_autochtone": 0.0, "pct_locataires": 27.5, "pct_appartements": 28.8, "pct_minorites_visibles": null, "source_url": "https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls", "source": "Élections Québec — Statistiques du Recensement 2021 par circonscription 2026 (classeur officiel)", "harvested": "2026-08-31"} | |
| \ No newline at end of file | ||
added
backend/data/population/portraits/lafontaine.json
+1 −0
@@ -0,0 +1 @@ | ||
| 1 | +{"district": "LaFontaine", "population": 58066.0, "pct_60_plus": 18.7, "pct_francais": 51.2, "pct_anglais": 30.1, "pct_universitaire": 16.6, "pct_revenu_100k_plus": 6.3, "pct_immigrants": 34.9, "pct_autochtone": 0.0, "pct_locataires": 31.9, "pct_appartements": 41.4, "pct_minorites_visibles": null, "source_url": "https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls", "source": "Élections Québec — Statistiques du Recensement 2021 par circonscription 2026 (classeur officiel)", "harvested": "2026-08-31"} | |
| \ No newline at end of file | ||
added
backend/data/population/portraits/lassomption.json
+1 −0
@@ -0,0 +1 @@ | ||
| 1 | +{"district": "L'Assomption", "population": 71795.0, "pct_60_plus": 16.2, "pct_francais": 97.2, "pct_anglais": 1.0, "pct_universitaire": 13.2, "pct_revenu_100k_plus": 7.0, "pct_immigrants": 6.8, "pct_autochtone": 0.0, "pct_locataires": 24.7, "pct_appartements": 24.5, "pct_minorites_visibles": null, "source_url": "https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls", "source": "Élections Québec — Statistiques du Recensement 2021 par circonscription 2026 (classeur officiel)", "harvested": "2026-08-31"} | |
| \ No newline at end of file | ||
added
backend/data/population/portraits/laurier-dorion.json
+1 −0
@@ -0,0 +1 @@ | ||
| 1 | +{"district": "Laurier-Dorion", "population": 74674.0, "pct_60_plus": 12.7, "pct_francais": 56.9, "pct_anglais": 14.4, "pct_universitaire": 38.5, "pct_revenu_100k_plus": 6.3, "pct_immigrants": 31.9, "pct_autochtone": 0.0, "pct_locataires": 73.0, "pct_appartements": 90.0, "pct_minorites_visibles": null, "source_url": "https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls", "source": "Élections Québec — Statistiques du Recensement 2021 par circonscription 2026 (classeur officiel)", "harvested": "2026-08-31"} | |
| \ No newline at end of file | ||
added
backend/data/population/portraits/laval-des-rapides.json
+1 −0
@@ -0,0 +1 @@ | ||
| 1 | +{"district": "Laval-des-Rapides", "population": 80150.0, "pct_60_plus": 21.9, "pct_francais": 72.0, "pct_anglais": 8.4, "pct_universitaire": 25.9, "pct_revenu_100k_plus": 5.7, "pct_immigrants": 33.2, "pct_autochtone": 0.0, "pct_locataires": 57.2, "pct_appartements": 73.0, "pct_minorites_visibles": null, "source_url": "https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls", "source": "Élections Québec — Statistiques du Recensement 2021 par circonscription 2026 (classeur officiel)", "harvested": "2026-08-31"} | |
| \ No newline at end of file | ||
added
backend/data/population/portraits/laviolette-saint-maurice.json
+1 −0
@@ -0,0 +1 @@ | ||
| 1 | +{"district": "Laviolette-Saint-Maurice", "population": 72160.0, "pct_60_plus": 28.3, "pct_francais": 95.2, "pct_anglais": 0.9, "pct_universitaire": 10.8, "pct_revenu_100k_plus": 4.0, "pct_immigrants": 1.8, "pct_autochtone": 1.8, "pct_locataires": 37.8, "pct_appartements": 38.5, "pct_minorites_visibles": null, "source_url": "https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls", "source": "Élections Québec — Statistiques du Recensement 2021 par circonscription 2026 (classeur officiel)", "harvested": "2026-08-31"} | |
| \ No newline at end of file | ||
added
backend/data/population/portraits/les-plaines.json
+1 −0
@@ -0,0 +1 @@ | ||
| 1 | +{"district": "Les Plaines", "population": 65615.0, "pct_60_plus": 12.8, "pct_francais": 94.8, "pct_anglais": 2.4, "pct_universitaire": 10.2, "pct_revenu_100k_plus": 6.0, "pct_immigrants": 9.0, "pct_autochtone": 0.0, "pct_locataires": 26.7, "pct_appartements": 29.2, "pct_minorites_visibles": null, "source_url": "https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls", "source": "Élections Québec — Statistiques du Recensement 2021 par circonscription 2026 (classeur officiel)", "harvested": "2026-08-31"} | |
| \ No newline at end of file | ||
added
backend/data/population/portraits/levis.json
+1 −0
@@ -0,0 +1 @@ | ||
| 1 | +{"district": "Lévis", "population": 63160.0, "pct_60_plus": 26.9, "pct_francais": 97.7, "pct_anglais": 0.9, "pct_universitaire": 23.7, "pct_revenu_100k_plus": 7.9, "pct_immigrants": 4.5, "pct_autochtone": 0.0, "pct_locataires": 46.4, "pct_appartements": 51.4, "pct_minorites_visibles": null, "source_url": "https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls", "source": "Élections Québec — Statistiques du Recensement 2021 par circonscription 2026 (classeur officiel)", "harvested": "2026-08-31"} | |
| \ No newline at end of file | ||
added
backend/data/population/portraits/lotbiniere-frontenac.json
+1 −0
@@ -0,0 +1 @@ | ||
| 1 | +{"district": "Lotbinière-Frontenac", "population": 72630.0, "pct_60_plus": 25.8, "pct_francais": 98.4, "pct_anglais": 0.8, "pct_universitaire": 10.8, "pct_revenu_100k_plus": 4.0, "pct_immigrants": 1.6, "pct_autochtone": 0.0, "pct_locataires": 25.4, "pct_appartements": 21.0, "pct_minorites_visibles": null, "source_url": "https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls", "source": "Élections Québec — Statistiques du Recensement 2021 par circonscription 2026 (classeur officiel)", "harvested": "2026-08-31"} | |
| \ No newline at end of file | ||
added
backend/data/population/portraits/louis-hebert.json
+1 −0
@@ -0,0 +1 @@ | ||
| 1 | +{"district": "Louis-Hébert", "population": 58585.0, "pct_60_plus": 26.7, "pct_francais": 95.9, "pct_anglais": 1.4, "pct_universitaire": 41.8, "pct_revenu_100k_plus": 15.6, "pct_immigrants": 6.7, "pct_autochtone": 0.0, "pct_locataires": 22.8, "pct_appartements": 36.2, "pct_minorites_visibles": null, "source_url": "https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls", "source": "Élections Québec — Statistiques du Recensement 2021 par circonscription 2026 (classeur officiel)", "harvested": "2026-08-31"} | |
| \ No newline at end of file | ||
added
backend/data/population/portraits/marguerite-bourgeoys.json
+1 −0
@@ -0,0 +1 @@ | ||
| 1 | +{"district": "Marguerite-Bourgeoys", "population": 82235.0, "pct_60_plus": 20.3, "pct_francais": 38.5, "pct_anglais": 36.8, "pct_universitaire": 24.5, "pct_revenu_100k_plus": 5.3, "pct_immigrants": 35.3, "pct_autochtone": 0.0, "pct_locataires": 60.7, "pct_appartements": 89.0, "pct_minorites_visibles": null, "source_url": "https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls", "source": "Élections Québec — Statistiques du Recensement 2021 par circonscription 2026 (classeur officiel)", "harvested": "2026-08-31"} | |
| \ No newline at end of file | ||
added
backend/data/population/portraits/marie-lacoste-gerin-lajoie.json
+1 −0
@@ -0,0 +1 @@ | ||
| 1 | +{"district": "Marie-Lacoste-Gérin-Lajoie", "population": 58305.0, "pct_60_plus": 19.0, "pct_francais": 97.0, "pct_anglais": 1.0, "pct_universitaire": 11.6, "pct_revenu_100k_plus": 3.9, "pct_immigrants": 3.8, "pct_autochtone": 0.0, "pct_locataires": 37.9, "pct_appartements": 34.5, "pct_minorites_visibles": null, "source_url": "https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls", "source": "Élections Québec — Statistiques du Recensement 2021 par circonscription 2026 (classeur officiel)", "harvested": "2026-08-31"} | |
| \ No newline at end of file | ||
added
backend/data/population/portraits/marie-victorin.json
+1 −0
@@ -0,0 +1 @@ | ||
| 1 | +{"district": "Marie-Victorin", "population": 66315.0, "pct_60_plus": 18.3, "pct_francais": 84.9, "pct_anglais": 5.0, "pct_universitaire": 24.5, "pct_revenu_100k_plus": 5.2, "pct_immigrants": 21.1, "pct_autochtone": 0.0, "pct_locataires": 66.1, "pct_appartements": 76.9, "pct_minorites_visibles": null, "source_url": "https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls", "source": "Élections Québec — Statistiques du Recensement 2021 par circonscription 2026 (classeur officiel)", "harvested": "2026-08-31"} | |
| \ No newline at end of file | ||
added
backend/data/population/portraits/marquette.json
+1 −0
@@ -0,0 +1 @@ | ||
| 1 | +{"district": "Marquette", "population": 65760.0, "pct_60_plus": 19.2, "pct_francais": 46.3, "pct_anglais": 40.3, "pct_universitaire": 29.8, "pct_revenu_100k_plus": 9.1, "pct_immigrants": 24.6, "pct_autochtone": 0.0, "pct_locataires": 53.0, "pct_appartements": 67.8, "pct_minorites_visibles": null, "source_url": "https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls", "source": "Élections Québec — Statistiques du Recensement 2021 par circonscription 2026 (classeur officiel)", "harvested": "2026-08-31"} | |
| \ No newline at end of file | ||
added
backend/data/population/portraits/maskinonge.json
+1 −0
@@ -0,0 +1 @@ | ||
| 1 | +{"district": "Maskinongé", "population": 56775.0, "pct_60_plus": 24.5, "pct_francais": 98.7, "pct_anglais": 0.7, "pct_universitaire": 14.7, "pct_revenu_100k_plus": 6.5, "pct_immigrants": 1.8, "pct_autochtone": 0.0, "pct_locataires": 24.4, "pct_appartements": 18.9, "pct_minorites_visibles": null, "source_url": "https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls", "source": "Élections Québec — Statistiques du Recensement 2021 par circonscription 2026 (classeur officiel)", "harvested": "2026-08-31"} | |
| \ No newline at end of file | ||
added
backend/data/population/portraits/masson.json
+1 −0
@@ -0,0 +1 @@ | ||
| 1 | +{"district": "Masson", "population": 65810.0, "pct_60_plus": 16.9, "pct_francais": 93.5, "pct_anglais": 3.5, "pct_universitaire": 16.9, "pct_revenu_100k_plus": 10.4, "pct_immigrants": 9.3, "pct_autochtone": 0.0, "pct_locataires": 22.8, "pct_appartements": 32.5, "pct_minorites_visibles": null, "source_url": "https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls", "source": "Élections Québec — Statistiques du Recensement 2021 par circonscription 2026 (classeur officiel)", "harvested": "2026-08-31"} | |
| \ No newline at end of file | ||
added
backend/data/population/portraits/matane-matapedia-mitis.json
+1 −0
@@ -0,0 +1 @@ | ||
| 1 | +{"district": "Matane-Matapédia-Mitis", "population": 56838.0, "pct_60_plus": 26.1, "pct_francais": 99.4, "pct_anglais": 0.5, "pct_universitaire": 10.1, "pct_revenu_100k_plus": 3.8, "pct_immigrants": 0.8, "pct_autochtone": 0.0, "pct_locataires": 28.4, "pct_appartements": 19.5, "pct_minorites_visibles": null, "source_url": "https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls", "source": "Élections Québec — Statistiques du Recensement 2021 par circonscription 2026 (classeur officiel)", "harvested": "2026-08-31"} | |
| \ No newline at end of file | ||
added
backend/data/population/portraits/maurice-richard.json
+1 −0
@@ -0,0 +1 @@ | ||
| 1 | +{"district": "Maurice-Richard", "population": 68210.0, "pct_60_plus": 21.3, "pct_francais": 78.1, "pct_anglais": 6.8, "pct_universitaire": 36.6, "pct_revenu_100k_plus": 8.6, "pct_immigrants": 28.5, "pct_autochtone": 0.0, "pct_locataires": 65.1, "pct_appartements": 90.6, "pct_minorites_visibles": null, "source_url": "https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls", "source": "Élections Québec — Statistiques du Recensement 2021 par circonscription 2026 (classeur officiel)", "harvested": "2026-08-31"} | |
| \ No newline at end of file | ||
added
backend/data/population/portraits/megantic.json
+1 −0
@@ -0,0 +1 @@ | ||
| 1 | +{"district": "Mégantic", "population": 61885.0, "pct_60_plus": 27.0, "pct_francais": 95.0, "pct_anglais": 4.6, "pct_universitaire": 9.8, "pct_revenu_100k_plus": 3.6, "pct_immigrants": 1.9, "pct_autochtone": 0.0, "pct_locataires": 25.5, "pct_appartements": 21.0, "pct_minorites_visibles": null, "source_url": "https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls", "source": "Élections Québec — Statistiques du Recensement 2021 par circonscription 2026 (classeur officiel)", "harvested": "2026-08-31"} | |
| \ No newline at end of file | ||
added
backend/data/population/portraits/mercier.json
+1 −0
@@ -0,0 +1 @@ | ||
| 1 | +{"district": "Mercier", "population": 69895.0, "pct_60_plus": 10.3, "pct_francais": 71.0, "pct_anglais": 20.3, "pct_universitaire": 56.8, "pct_revenu_100k_plus": 13.0, "pct_immigrants": 22.3, "pct_autochtone": 0.0, "pct_locataires": 67.9, "pct_appartements": 97.2, "pct_minorites_visibles": null, "source_url": "https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls", "source": "Élections Québec — Statistiques du Recensement 2021 par circonscription 2026 (classeur officiel)", "harvested": "2026-08-31"} | |
| \ No newline at end of file | ||
added
backend/data/population/portraits/mille-iles.json
+1 −0
@@ -0,0 +1 @@ | ||
| 1 | +{"district": "Mille-Îles", "population": 66660.0, "pct_60_plus": 18.1, "pct_francais": 71.9, "pct_anglais": 15.6, "pct_universitaire": 24.8, "pct_revenu_100k_plus": 10.0, "pct_immigrants": 26.1, "pct_autochtone": 0.0, "pct_locataires": 22.6, "pct_appartements": 30.4, "pct_minorites_visibles": null, "source_url": "https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls", "source": "Élections Québec — Statistiques du Recensement 2021 par circonscription 2026 (classeur officiel)", "harvested": "2026-08-31"} | |
| \ No newline at end of file | ||
added
backend/data/population/portraits/mirabel.json
+1 −0
@@ -0,0 +1 @@ | ||
| 1 | +{"district": "Mirabel", "population": 68370.0, "pct_60_plus": 13.1, "pct_francais": 92.9, "pct_anglais": 4.1, "pct_universitaire": 16.7, "pct_revenu_100k_plus": 9.4, "pct_immigrants": 7.5, "pct_autochtone": 0.0, "pct_locataires": 21.7, "pct_appartements": 26.0, "pct_minorites_visibles": null, "source_url": "https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls", "source": "Élections Québec — Statistiques du Recensement 2021 par circonscription 2026 (classeur officiel)", "harvested": "2026-08-31"} | |
| \ No newline at end of file | ||
added
backend/data/population/portraits/mont-royal-outremont.json
+1 −0
@@ -0,0 +1 @@ | ||
| 1 | +{"district": "Mont-Royal-Outremont", "population": 96625.0, "pct_60_plus": 17.0, "pct_francais": 49.4, "pct_anglais": 25.3, "pct_universitaire": 53.4, "pct_revenu_100k_plus": 16.0, "pct_immigrants": 36.8, "pct_autochtone": 0.0, "pct_locataires": 64.4, "pct_appartements": 83.5, "pct_minorites_visibles": null, "source_url": "https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls", "source": "Élections Québec — Statistiques du Recensement 2021 par circonscription 2026 (classeur officiel)", "harvested": "2026-08-31"} | |
| \ No newline at end of file | ||
added
backend/data/population/portraits/montarville.json
+1 −0
@@ -0,0 +1 @@ | ||
| 1 | +{"district": "Montarville", "population": 68015.0, "pct_60_plus": 24.2, "pct_francais": 90.7, "pct_anglais": 5.8, "pct_universitaire": 40.6, "pct_revenu_100k_plus": 19.8, "pct_immigrants": 9.8, "pct_autochtone": 0.0, "pct_locataires": 15.2, "pct_appartements": 26.1, "pct_minorites_visibles": null, "source_url": "https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls", "source": "Élections Québec — Statistiques du Recensement 2021 par circonscription 2026 (classeur officiel)", "harvested": "2026-08-31"} | |
| \ No newline at end of file | ||
added
backend/data/population/portraits/montmorency.json
+1 −0
@@ -0,0 +1 @@ | ||
| 1 | +{"district": "Montmorency", "population": 74740.0, "pct_60_plus": 19.0, "pct_francais": 98.2, "pct_anglais": 0.5, "pct_universitaire": 19.7, "pct_revenu_100k_plus": 7.0, "pct_immigrants": 5.0, "pct_autochtone": 0.0, "pct_locataires": 30.0, "pct_appartements": 37.3, "pct_minorites_visibles": null, "source_url": "https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls", "source": "Élections Québec — Statistiques du Recensement 2021 par circonscription 2026 (classeur officiel)", "harvested": "2026-08-31"} | |
| \ No newline at end of file | ||
added
backend/data/population/portraits/nelligan.json
+1 −0
@@ -0,0 +1 @@ | ||
| 1 | +{"district": "Nelligan", "population": 79805.0, "pct_60_plus": 18.1, "pct_francais": 26.9, "pct_anglais": 51.1, "pct_universitaire": 35.1, "pct_revenu_100k_plus": 12.8, "pct_immigrants": 35.7, "pct_autochtone": 0.0, "pct_locataires": 21.3, "pct_appartements": 23.8, "pct_minorites_visibles": null, "source_url": "https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls", "source": "Élections Québec — Statistiques du Recensement 2021 par circonscription 2026 (classeur officiel)", "harvested": "2026-08-31"} | |
| \ No newline at end of file | ||
added
backend/data/population/portraits/nicolet-becancour.json
+1 −0
@@ -0,0 +1 @@ | ||
| 1 | +{"district": "Nicolet-Bécancour", "population": 49390.0, "pct_60_plus": 24.7, "pct_francais": 98.8, "pct_anglais": 0.6, "pct_universitaire": 13.0, "pct_revenu_100k_plus": 5.1, "pct_immigrants": 1.6, "pct_autochtone": 0.0, "pct_locataires": 24.7, "pct_appartements": 18.1, "pct_minorites_visibles": null, "source_url": "https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls", "source": "Élections Québec — Statistiques du Recensement 2021 par circonscription 2026 (classeur officiel)", "harvested": "2026-08-31"} | |
| \ No newline at end of file | ||
added
backend/data/population/portraits/notre-dame-de-grace.json
+1 −0
@@ -0,0 +1 @@ | ||
| 1 | +{"district": "Notre-Dame-de-Grâce", "population": 73265.0, "pct_60_plus": 17.3, "pct_francais": 25.7, "pct_anglais": 54.1, "pct_universitaire": 48.0, "pct_revenu_100k_plus": 12.9, "pct_immigrants": 34.8, "pct_autochtone": 0.0, "pct_locataires": 63.0, "pct_appartements": 82.0, "pct_minorites_visibles": null, "source_url": "https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls", "source": "Élections Québec — Statistiques du Recensement 2021 par circonscription 2026 (classeur officiel)", "harvested": "2026-08-31"} | |
| \ No newline at end of file | ||
added
backend/data/population/portraits/orford.json
+1 −0
@@ -0,0 +1 @@ | ||
| 1 | +{"district": "Orford", "population": 54795.0, "pct_60_plus": 29.9, "pct_francais": 85.4, "pct_anglais": 14.0, "pct_universitaire": 24.0, "pct_revenu_100k_plus": 8.8, "pct_immigrants": 5.1, "pct_autochtone": 0.0, "pct_locataires": 26.3, "pct_appartements": 25.3, "pct_minorites_visibles": null, "source_url": "https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls", "source": "Élections Québec — Statistiques du Recensement 2021 par circonscription 2026 (classeur officiel)", "harvested": "2026-08-31"} | |
| \ No newline at end of file | ||
added
backend/data/population/portraits/papineau.json
+1 −0
@@ -0,0 +1 @@ | ||
| 1 | +{"district": "Papineau", "population": 74845.0, "pct_60_plus": 18.7, "pct_francais": 92.2, "pct_anglais": 6.8, "pct_universitaire": 12.6, "pct_revenu_100k_plus": 6.2, "pct_immigrants": 4.0, "pct_autochtone": 0.0, "pct_locataires": 26.8, "pct_appartements": 18.9, "pct_minorites_visibles": null, "source_url": "https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls", "source": "Élections Québec — Statistiques du Recensement 2021 par circonscription 2026 (classeur officiel)", "harvested": "2026-08-31"} | |
| \ No newline at end of file | ||
added
backend/data/population/portraits/pierre-laporte.json
+1 −0
@@ -0,0 +1 @@ | ||
| 1 | +{"district": "Pierre-Laporte", "population": 74615.0, "pct_60_plus": 22.1, "pct_francais": 68.6, "pct_anglais": 17.9, "pct_universitaire": 31.1, "pct_revenu_100k_plus": 10.6, "pct_immigrants": 23.5, "pct_autochtone": 0.0, "pct_locataires": 46.8, "pct_appartements": 56.8, "pct_minorites_visibles": null, "source_url": "https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls", "source": "Élections Québec — Statistiques du Recensement 2021 par circonscription 2026 (classeur officiel)", "harvested": "2026-08-31"} | |
| \ No newline at end of file | ||
added
backend/data/population/portraits/pointe-aux-trembles.json
+1 −0
@@ -0,0 +1 @@ | ||
| 1 | +{"district": "Pointe-aux-Trembles", "population": 54262.0, "pct_60_plus": 17.7, "pct_francais": 90.1, "pct_anglais": 3.2, "pct_universitaire": 14.8, "pct_revenu_100k_plus": 5.1, "pct_immigrants": 16.2, "pct_autochtone": 0.0, "pct_locataires": 45.4, "pct_appartements": 58.5, "pct_minorites_visibles": null, "source_url": "https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls", "source": "Élections Québec — Statistiques du Recensement 2021 par circonscription 2026 (classeur officiel)", "harvested": "2026-08-31"} | |
| \ No newline at end of file | ||
added
backend/data/population/portraits/pontiac.json
+1 −0
@@ -0,0 +1 @@ | ||
| 1 | +{"district": "Pontiac", "population": 78350.0, "pct_60_plus": 17.0, "pct_francais": 52.3, "pct_anglais": 41.8, "pct_universitaire": 28.7, "pct_revenu_100k_plus": 13.1, "pct_immigrants": 13.6, "pct_autochtone": 0.0, "pct_locataires": 23.8, "pct_appartements": 20.5, "pct_minorites_visibles": null, "source_url": "https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls", "source": "Élections Québec — Statistiques du Recensement 2021 par circonscription 2026 (classeur officiel)", "harvested": "2026-08-31"} | |
| \ No newline at end of file | ||
added
backend/data/population/portraits/portneuf.json
+1 −0
@@ -0,0 +1 @@ | ||
| 1 | +{"district": "Portneuf", "population": 66595.0, "pct_60_plus": 21.9, "pct_francais": 98.6, "pct_anglais": 1.0, "pct_universitaire": 14.3, "pct_revenu_100k_plus": 6.8, "pct_immigrants": 1.6, "pct_autochtone": 0.0, "pct_locataires": 20.8, "pct_appartements": 15.9, "pct_minorites_visibles": null, "source_url": "https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls", "source": "Élections Québec — Statistiques du Recensement 2021 par circonscription 2026 (classeur officiel)", "harvested": "2026-08-31"} | |
| \ No newline at end of file | ||
added
backend/data/population/portraits/prevost.json
+1 −0
@@ -0,0 +1 @@ | ||
| 1 | +{"district": "Prévost", "population": 61360.0, "pct_60_plus": 20.5, "pct_francais": 95.0, "pct_anglais": 4.2, "pct_universitaire": 18.4, "pct_revenu_100k_plus": 9.2, "pct_immigrants": 4.4, "pct_autochtone": 0.0, "pct_locataires": 20.7, "pct_appartements": 19.1, "pct_minorites_visibles": null, "source_url": "https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls", "source": "Élections Québec — Statistiques du Recensement 2021 par circonscription 2026 (classeur officiel)", "harvested": "2026-08-31"} | |
| \ No newline at end of file | ||
added
backend/data/population/portraits/rene-levesque.json
+1 −0
@@ -0,0 +1 @@ | ||
| 1 | +{"district": "René-Lévesque", "population": 40435.0, "pct_60_plus": 24.2, "pct_francais": 95.0, "pct_anglais": 0.4, "pct_universitaire": 10.6, "pct_revenu_100k_plus": 8.0, "pct_immigrants": 1.1, "pct_autochtone": 2.2, "pct_locataires": 25.6, "pct_appartements": 19.0, "pct_minorites_visibles": null, "source_url": "https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls", "source": "Élections Québec — Statistiques du Recensement 2021 par circonscription 2026 (classeur officiel)", "harvested": "2026-08-31"} | |
| \ No newline at end of file | ||
added
backend/data/population/portraits/repentigny.json
+1 −0
@@ -0,0 +1 @@ | ||
| 1 | +{"district": "Repentigny", "population": 70715.0, "pct_60_plus": 22.4, "pct_francais": 94.0, "pct_anglais": 2.1, "pct_universitaire": 17.9, "pct_revenu_100k_plus": 9.3, "pct_immigrants": 12.0, "pct_autochtone": 0.0, "pct_locataires": 26.3, "pct_appartements": 37.3, "pct_minorites_visibles": null, "source_url": "https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls", "source": "Élections Québec — Statistiques du Recensement 2021 par circonscription 2026 (classeur officiel)", "harvested": "2026-08-31"} | |
| \ No newline at end of file | ||
added
backend/data/population/portraits/richelieu.json
+1 −0
@@ -0,0 +1 @@ | ||
| 1 | +{"district": "Richelieu", "population": 64515.0, "pct_60_plus": 26.5, "pct_francais": 98.5, "pct_anglais": 0.8, "pct_universitaire": 10.6, "pct_revenu_100k_plus": 6.3, "pct_immigrants": 2.9, "pct_autochtone": 0.0, "pct_locataires": 32.4, "pct_appartements": 29.9, "pct_minorites_visibles": null, "source_url": "https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls", "source": "Élections Québec — Statistiques du Recensement 2021 par circonscription 2026 (classeur officiel)", "harvested": "2026-08-31"} | |
| \ No newline at end of file | ||
added
backend/data/population/portraits/richmond.json
+1 −0
@@ -0,0 +1 @@ | ||
| 1 | +{"district": "Richmond", "population": 72780.0, "pct_60_plus": 18.2, "pct_francais": 94.9, "pct_anglais": 3.8, "pct_universitaire": 20.2, "pct_revenu_100k_plus": 7.7, "pct_immigrants": 3.7, "pct_autochtone": 0.0, "pct_locataires": 24.7, "pct_appartements": 23.7, "pct_minorites_visibles": null, "source_url": "https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls", "source": "Élections Québec — Statistiques du Recensement 2021 par circonscription 2026 (classeur officiel)", "harvested": "2026-08-31"} | |
| \ No newline at end of file | ||
added
backend/data/population/portraits/rimouski.json
+1 −0
@@ -0,0 +1 @@ | ||
| 1 | +{"district": "Rimouski", "population": 57191.0, "pct_60_plus": 23.3, "pct_francais": 99.0, "pct_anglais": 0.4, "pct_universitaire": 21.9, "pct_revenu_100k_plus": 6.2, "pct_immigrants": 2.2, "pct_autochtone": 0.0, "pct_locataires": 35.3, "pct_appartements": 31.1, "pct_minorites_visibles": null, "source_url": "https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls", "source": "Élections Québec — Statistiques du Recensement 2021 par circonscription 2026 (classeur officiel)", "harvested": "2026-08-31"} | |
| \ No newline at end of file | ||
added
backend/data/population/portraits/riviere-du-loup-temiscouata-les-basques.json
+1 −0
@@ -0,0 +1 @@ | ||
| 1 | +{"district": "Rivière-du-Loup–Témiscouata–Les Basques", "population": 63705.0, "pct_60_plus": 28.2, "pct_francais": 99.2, "pct_anglais": 0.4, "pct_universitaire": 12.7, "pct_revenu_100k_plus": 4.5, "pct_immigrants": 1.2, "pct_autochtone": 0.0, "pct_locataires": 30.0, "pct_appartements": 26.1, "pct_minorites_visibles": null, "source_url": "https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls", "source": "Élections Québec — Statistiques du Recensement 2021 par circonscription 2026 (classeur officiel)", "harvested": "2026-08-31"} | |
| \ No newline at end of file | ||
added
backend/data/population/portraits/robert-baldwin.json
+1 −0
@@ -0,0 +1 @@ | ||
| 1 | +{"district": "Robert-Baldwin", "population": 77275.0, "pct_60_plus": 19.7, "pct_francais": 21.3, "pct_anglais": 53.3, "pct_universitaire": 33.3, "pct_revenu_100k_plus": 9.9, "pct_immigrants": 41.2, "pct_autochtone": 0.0, "pct_locataires": 31.0, "pct_appartements": 33.4, "pct_minorites_visibles": null, "source_url": "https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls", "source": "Élections Québec — Statistiques du Recensement 2021 par circonscription 2026 (classeur officiel)", "harvested": "2026-08-31"} | |
| \ No newline at end of file | ||
added
backend/data/population/portraits/roberval.json
+1 −0
@@ -0,0 +1 @@ | ||
| 1 | +{"district": "Roberval", "population": 55230.0, "pct_60_plus": 26.6, "pct_francais": 99.5, "pct_anglais": 0.2, "pct_universitaire": 11.0, "pct_revenu_100k_plus": 4.4, "pct_immigrants": 0.9, "pct_autochtone": 0.1, "pct_locataires": 26.4, "pct_appartements": 23.9, "pct_minorites_visibles": null, "source_url": "https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls", "source": "Élections Québec — Statistiques du Recensement 2021 par circonscription 2026 (classeur officiel)", "harvested": "2026-08-31"} | |
| \ No newline at end of file | ||
added
backend/data/population/portraits/rosemont.json
+1 −0
@@ -0,0 +1 @@ | ||
| 1 | +{"district": "Rosemont", "population": 76870.0, "pct_60_plus": 19.5, "pct_francais": 81.6, "pct_anglais": 6.1, "pct_universitaire": 36.9, "pct_revenu_100k_plus": 8.9, "pct_immigrants": 24.2, "pct_autochtone": 0.0, "pct_locataires": 67.4, "pct_appartements": 92.7, "pct_minorites_visibles": null, "source_url": "https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls", "source": "Élections Québec — Statistiques du Recensement 2021 par circonscription 2026 (classeur officiel)", "harvested": "2026-08-31"} | |
| \ No newline at end of file | ||
added
backend/data/population/portraits/rousseau.json
+1 −0
@@ -0,0 +1 @@ | ||
| 1 | +{"district": "Rousseau", "population": 58430.0, "pct_60_plus": 15.7, "pct_francais": 98.0, "pct_anglais": 1.2, "pct_universitaire": 7.2, "pct_revenu_100k_plus": 4.0, "pct_immigrants": 2.9, "pct_autochtone": 0.0, "pct_locataires": 24.8, "pct_appartements": 16.1, "pct_minorites_visibles": null, "source_url": "https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls", "source": "Élections Québec — Statistiques du Recensement 2021 par circonscription 2026 (classeur officiel)", "harvested": "2026-08-31"} | |
| \ No newline at end of file | ||
added
backend/data/population/portraits/rouyn-noranda-temiscamingue.json
+1 −0
@@ -0,0 +1 @@ | ||
| 1 | +{"district": "Rouyn-Noranda-Témiscamingue", "population": 57735.0, "pct_60_plus": 21.0, "pct_francais": 93.5, "pct_anglais": 5.9, "pct_universitaire": 14.9, "pct_revenu_100k_plus": 9.8, "pct_immigrants": 1.9, "pct_autochtone": 0.0, "pct_locataires": 33.3, "pct_appartements": 32.2, "pct_minorites_visibles": null, "source_url": "https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls", "source": "Élections Québec — Statistiques du Recensement 2021 par circonscription 2026 (classeur officiel)", "harvested": "2026-08-31"} | |
| \ No newline at end of file | ||
added
backend/data/population/portraits/saint-francois.json
+1 −0
@@ -0,0 +1 @@ | ||
| 1 | +{"district": "Saint-François", "population": 71350.0, "pct_60_plus": 22.7, "pct_francais": 88.3, "pct_anglais": 8.2, "pct_universitaire": 17.3, "pct_revenu_100k_plus": 3.9, "pct_immigrants": 7.2, "pct_autochtone": 0.0, "pct_locataires": 47.5, "pct_appartements": 48.4, "pct_minorites_visibles": null, "source_url": "https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls", "source": "Élections Québec — Statistiques du Recensement 2021 par circonscription 2026 (classeur officiel)", "harvested": "2026-08-31"} | |
| \ No newline at end of file | ||
added
backend/data/population/portraits/saint-henri-sainte-anne.json
+1 −0
@@ -0,0 +1 @@ | ||
| 1 | +{"district": "Saint-Henri-Sainte-Anne", "population": 84550.0, "pct_60_plus": 13.2, "pct_francais": 55.9, "pct_anglais": 30.4, "pct_universitaire": 42.3, "pct_revenu_100k_plus": 11.2, "pct_immigrants": 26.0, "pct_autochtone": 0.0, "pct_locataires": 65.2, "pct_appartements": 91.4, "pct_minorites_visibles": null, "source_url": "https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls", "source": "Élections Québec — Statistiques du Recensement 2021 par circonscription 2026 (classeur officiel)", "harvested": "2026-08-31"} | |
| \ No newline at end of file | ||
added
backend/data/population/portraits/saint-hyacinthe.json
+1 −0
@@ -0,0 +1 @@ | ||
| 1 | +{"district": "Saint-Hyacinthe", "population": 71160.0, "pct_60_plus": 24.2, "pct_francais": 96.0, "pct_anglais": 0.7, "pct_universitaire": 13.3, "pct_revenu_100k_plus": 5.6, "pct_immigrants": 6.5, "pct_autochtone": 0.0, "pct_locataires": 46.6, "pct_appartements": 49.3, "pct_minorites_visibles": null, "source_url": "https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls", "source": "Élections Québec — Statistiques du Recensement 2021 par circonscription 2026 (classeur officiel)", "harvested": "2026-08-31"} | |
| \ No newline at end of file | ||
added
backend/data/population/portraits/saint-jean.json
+1 −0
@@ -0,0 +1 @@ | ||
| 1 | +{"district": "Saint-Jean", "population": 77380.0, "pct_60_plus": 21.6, "pct_francais": 95.8, "pct_anglais": 2.7, "pct_universitaire": 15.6, "pct_revenu_100k_plus": 7.7, "pct_immigrants": 4.7, "pct_autochtone": 0.0, "pct_locataires": 41.5, "pct_appartements": 44.0, "pct_minorites_visibles": null, "source_url": "https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls", "source": "Élections Québec — Statistiques du Recensement 2021 par circonscription 2026 (classeur officiel)", "harvested": "2026-08-31"} | |
| \ No newline at end of file | ||
added
backend/data/population/portraits/saint-jerome.json
+1 −0
@@ -0,0 +1 @@ | ||
| 1 | +{"district": "Saint-Jérôme", "population": 56330.0, "pct_60_plus": 27.3, "pct_francais": 96.3, "pct_anglais": 1.4, "pct_universitaire": 10.1, "pct_revenu_100k_plus": 3.3, "pct_immigrants": 5.5, "pct_autochtone": 0.0, "pct_locataires": 57.0, "pct_appartements": 65.8, "pct_minorites_visibles": null, "source_url": "https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls", "source": "Élections Québec — Statistiques du Recensement 2021 par circonscription 2026 (classeur officiel)", "harvested": "2026-08-31"} | |
| \ No newline at end of file | ||
added
backend/data/population/portraits/saint-laurent.json
+1 −0
@@ -0,0 +1 @@ | ||
| 1 | +{"district": "Saint-Laurent", "population": 93910.0, "pct_60_plus": 16.1, "pct_francais": 38.7, "pct_anglais": 28.1, "pct_universitaire": 38.3, "pct_revenu_100k_plus": 11.2, "pct_immigrants": 48.4, "pct_autochtone": 0.0, "pct_locataires": 50.2, "pct_appartements": 70.5, "pct_minorites_visibles": null, "source_url": "https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls", "source": "Élections Québec — Statistiques du Recensement 2021 par circonscription 2026 (classeur officiel)", "harvested": "2026-08-31"} | |
| \ No newline at end of file | ||
added
backend/data/population/portraits/sainte-marie-saint-jacques.json
+1 −0
@@ -0,0 +1 @@ | ||
| 1 | +{"district": "Sainte-Marie-Saint-Jacques", "population": 66864.0, "pct_60_plus": 11.7, "pct_francais": 69.1, "pct_anglais": 20.1, "pct_universitaire": 50.7, "pct_revenu_100k_plus": 10.8, "pct_immigrants": 25.9, "pct_autochtone": 0.0, "pct_locataires": 71.3, "pct_appartements": 86.4, "pct_minorites_visibles": null, "source_url": "https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls", "source": "Élections Québec — Statistiques du Recensement 2021 par circonscription 2026 (classeur officiel)", "harvested": "2026-08-31"} | |
| \ No newline at end of file | ||
added
backend/data/population/portraits/sainte-rose.json
+1 −0
@@ -0,0 +1 @@ | ||
| 1 | +{"district": "Sainte-Rose", "population": 74990.0, "pct_60_plus": 15.3, "pct_francais": 74.3, "pct_anglais": 11.1, "pct_universitaire": 26.3, "pct_revenu_100k_plus": 11.1, "pct_immigrants": 26.3, "pct_autochtone": 0.0, "pct_locataires": 20.9, "pct_appartements": 23.8, "pct_minorites_visibles": null, "source_url": "https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls", "source": "Élections Québec — Statistiques du Recensement 2021 par circonscription 2026 (classeur officiel)", "harvested": "2026-08-31"} | |
| \ No newline at end of file | ||
added
backend/data/population/portraits/sanguinet.json
+1 −0
@@ -0,0 +1 @@ | ||
| 1 | +{"district": "Sanguinet", "population": 58600.0, "pct_60_plus": 16.1, "pct_francais": 87.4, "pct_anglais": 6.0, "pct_universitaire": 16.6, "pct_revenu_100k_plus": 8.6, "pct_immigrants": 10.9, "pct_autochtone": 0.0, "pct_locataires": 25.6, "pct_appartements": 30.4, "pct_minorites_visibles": null, "source_url": "https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls", "source": "Élections Québec — Statistiques du Recensement 2021 par circonscription 2026 (classeur officiel)", "harvested": "2026-08-31"} | |
| \ No newline at end of file | ||
added
backend/data/population/portraits/sherbrooke.json
+1 −0
@@ -0,0 +1 @@ | ||
| 1 | +{"district": "Sherbrooke", "population": 72420.0, "pct_60_plus": 23.5, "pct_francais": 90.0, "pct_anglais": 3.6, "pct_universitaire": 30.1, "pct_revenu_100k_plus": 6.0, "pct_immigrants": 11.7, "pct_autochtone": 0.0, "pct_locataires": 62.5, "pct_appartements": 69.1, "pct_minorites_visibles": null, "source_url": "https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls", "source": "Élections Québec — Statistiques du Recensement 2021 par circonscription 2026 (classeur officiel)", "harvested": "2026-08-31"} | |
| \ No newline at end of file | ||
added
backend/data/population/portraits/soulanges.json
+1 −0
@@ -0,0 +1 @@ | ||
| 1 | +{"district": "Soulanges", "population": 73010.0, "pct_60_plus": 17.0, "pct_francais": 67.9, "pct_anglais": 29.4, "pct_universitaire": 20.2, "pct_revenu_100k_plus": 11.1, "pct_immigrants": 8.4, "pct_autochtone": 0.0, "pct_locataires": 16.6, "pct_appartements": 14.0, "pct_minorites_visibles": null, "source_url": "https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls", "source": "Élections Québec — Statistiques du Recensement 2021 par circonscription 2026 (classeur officiel)", "harvested": "2026-08-31"} | |
| \ No newline at end of file | ||
added
backend/data/population/portraits/taillon.json
+1 −0
@@ -0,0 +1 @@ | ||
| 1 | +{"district": "Taillon", "population": 74570.0, "pct_60_plus": 21.2, "pct_francais": 86.2, "pct_anglais": 4.2, "pct_universitaire": 29.2, "pct_revenu_100k_plus": 9.5, "pct_immigrants": 20.1, "pct_autochtone": 0.0, "pct_locataires": 48.0, "pct_appartements": 63.3, "pct_minorites_visibles": null, "source_url": "https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls", "source": "Élections Québec — Statistiques du Recensement 2021 par circonscription 2026 (classeur officiel)", "harvested": "2026-08-31"} | |
| \ No newline at end of file | ||
added
backend/data/population/portraits/taschereau.json
+1 −0
@@ -0,0 +1 @@ | ||
| 1 | +{"district": "Taschereau", "population": 64045.0, "pct_60_plus": 26.0, "pct_francais": 93.9, "pct_anglais": 2.4, "pct_universitaire": 44.4, "pct_revenu_100k_plus": 8.1, "pct_immigrants": 10.2, "pct_autochtone": 0.0, "pct_locataires": 69.8, "pct_appartements": 94.1, "pct_minorites_visibles": null, "source_url": "https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls", "source": "Élections Québec — Statistiques du Recensement 2021 par circonscription 2026 (classeur officiel)", "harvested": "2026-08-31"} | |
| \ No newline at end of file | ||
added
backend/data/population/portraits/terrebonne.json
+1 −0
@@ -0,0 +1 @@ | ||
| 1 | +{"district": "Terrebonne", "population": 71340.0, "pct_60_plus": 17.3, "pct_francais": 92.7, "pct_anglais": 3.3, "pct_universitaire": 17.8, "pct_revenu_100k_plus": 10.0, "pct_immigrants": 11.5, "pct_autochtone": 0.0, "pct_locataires": 27.9, "pct_appartements": 32.6, "pct_minorites_visibles": null, "source_url": "https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls", "source": "Élections Québec — Statistiques du Recensement 2021 par circonscription 2026 (classeur officiel)", "harvested": "2026-08-31"} | |
| \ No newline at end of file | ||
added
backend/data/population/portraits/trois-rivieres.json
+1 −0
@@ -0,0 +1 @@ | ||
| 1 | +{"district": "Trois-Rivières", "population": 70875.0, "pct_60_plus": 28.0, "pct_francais": 96.1, "pct_anglais": 1.0, "pct_universitaire": 22.6, "pct_revenu_100k_plus": 6.1, "pct_immigrants": 6.0, "pct_autochtone": 0.1, "pct_locataires": 54.8, "pct_appartements": 58.5, "pct_minorites_visibles": null, "source_url": "https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls", "source": "Élections Québec — Statistiques du Recensement 2021 par circonscription 2026 (classeur officiel)", "harvested": "2026-08-31"} | |
| \ No newline at end of file | ||
added
backend/data/population/portraits/ungava.json
+1 −0
@@ -0,0 +1 @@ | ||
| 1 | +{"district": "Ungava", "population": 45740.0, "pct_60_plus": 9.1, "pct_francais": 32.1, "pct_anglais": 12.7, "pct_universitaire": 7.4, "pct_revenu_100k_plus": 9.8, "pct_immigrants": 1.2, "pct_autochtone": 37.0, "pct_locataires": 44.4, "pct_appartements": 15.3, "pct_minorites_visibles": null, "source_url": "https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls", "source": "Élections Québec — Statistiques du Recensement 2021 par circonscription 2026 (classeur officiel)", "harvested": "2026-08-31"} | |
| \ No newline at end of file | ||
added
backend/data/population/portraits/vachon.json
+1 −0
@@ -0,0 +1 @@ | ||
| 1 | +{"district": "Vachon", "population": 71640.0, "pct_60_plus": 17.7, "pct_francais": 79.9, "pct_anglais": 8.6, "pct_universitaire": 22.8, "pct_revenu_100k_plus": 8.2, "pct_immigrants": 21.2, "pct_autochtone": 0.0, "pct_locataires": 23.2, "pct_appartements": 34.1, "pct_minorites_visibles": null, "source_url": "https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls", "source": "Élections Québec — Statistiques du Recensement 2021 par circonscription 2026 (classeur officiel)", "harvested": "2026-08-31"} | |
| \ No newline at end of file | ||
added
backend/data/population/portraits/vanier-les-rivieres.json
+1 −0
@@ -0,0 +1 @@ | ||
| 1 | +{"district": "Vanier-Les Rivières", "population": 70015.0, "pct_60_plus": 25.4, "pct_francais": 95.4, "pct_anglais": 0.9, "pct_universitaire": 25.2, "pct_revenu_100k_plus": 8.0, "pct_immigrants": 7.9, "pct_autochtone": 0.0, "pct_locataires": 49.5, "pct_appartements": 61.5, "pct_minorites_visibles": null, "source_url": "https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls", "source": "Élections Québec — Statistiques du Recensement 2021 par circonscription 2026 (classeur officiel)", "harvested": "2026-08-31"} | |
| \ No newline at end of file | ||
added
backend/data/population/portraits/vaudreuil.json
+1 −0
@@ -0,0 +1 @@ | ||
| 1 | +{"district": "Vaudreuil", "population": 82115.0, "pct_60_plus": 17.0, "pct_francais": 52.7, "pct_anglais": 35.7, "pct_universitaire": 24.4, "pct_revenu_100k_plus": 9.9, "pct_immigrants": 20.6, "pct_autochtone": 0.0, "pct_locataires": 22.8, "pct_appartements": 29.2, "pct_minorites_visibles": null, "source_url": "https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls", "source": "Élections Québec — Statistiques du Recensement 2021 par circonscription 2026 (classeur officiel)", "harvested": "2026-08-31"} | |
| \ No newline at end of file | ||
added
backend/data/population/portraits/vercheres.json
+1 −0
@@ -0,0 +1 @@ | ||
| 1 | +{"district": "Verchères", "population": 70835.0, "pct_60_plus": 16.2, "pct_francais": 96.9, "pct_anglais": 1.6, "pct_universitaire": 21.6, "pct_revenu_100k_plus": 12.6, "pct_immigrants": 5.2, "pct_autochtone": 0.0, "pct_locataires": 20.7, "pct_appartements": 25.2, "pct_minorites_visibles": null, "source_url": "https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls", "source": "Élections Québec — Statistiques du Recensement 2021 par circonscription 2026 (classeur officiel)", "harvested": "2026-08-31"} | |
| \ No newline at end of file | ||
added
backend/data/population/portraits/verdun.json
+1 −0
@@ -0,0 +1 @@ | ||
| 1 | +{"district": "Verdun", "population": 70375.0, "pct_60_plus": 17.7, "pct_francais": 61.8, "pct_anglais": 23.8, "pct_universitaire": 45.5, "pct_revenu_100k_plus": 12.8, "pct_immigrants": 24.6, "pct_autochtone": 0.0, "pct_locataires": 62.4, "pct_appartements": 90.0, "pct_minorites_visibles": null, "source_url": "https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls", "source": "Élections Québec — Statistiques du Recensement 2021 par circonscription 2026 (classeur officiel)", "harvested": "2026-08-31"} | |
| \ No newline at end of file | ||
added
backend/data/population/portraits/viau.json
+1 −0
@@ -0,0 +1 @@ | ||
| 1 | +{"district": "Viau", "population": 70417.0, "pct_60_plus": 13.7, "pct_francais": 57.5, "pct_anglais": 7.9, "pct_universitaire": 21.4, "pct_revenu_100k_plus": 2.4, "pct_immigrants": 44.2, "pct_autochtone": 0.0, "pct_locataires": 71.7, "pct_appartements": 86.3, "pct_minorites_visibles": null, "source_url": "https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls", "source": "Élections Québec — Statistiques du Recensement 2021 par circonscription 2026 (classeur officiel)", "harvested": "2026-08-31"} | |
| \ No newline at end of file | ||
added
backend/data/population/portraits/vimont-auteuil.json
+1 −0
@@ -0,0 +1 @@ | ||
| 1 | +{"district": "Vimont-Auteuil", "population": 60305.0, "pct_60_plus": 18.2, "pct_francais": 69.8, "pct_anglais": 18.3, "pct_universitaire": 23.9, "pct_revenu_100k_plus": 9.8, "pct_immigrants": 24.1, "pct_autochtone": 0.0, "pct_locataires": 21.2, "pct_appartements": 28.5, "pct_minorites_visibles": null, "source_url": "https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls", "source": "Élections Québec — Statistiques du Recensement 2021 par circonscription 2026 (classeur officiel)", "harvested": "2026-08-31"} | |
| \ No newline at end of file | ||
added
backend/data/population/portraits/westmount-saint-louis.json
+1 −0
@@ -0,0 +1 @@ | ||
| 1 | +{"district": "Westmount-Saint-Louis", "population": 86250.0, "pct_60_plus": 17.2, "pct_francais": 26.2, "pct_anglais": 49.6, "pct_universitaire": 60.5, "pct_revenu_100k_plus": 16.8, "pct_immigrants": 33.2, "pct_autochtone": 0.0, "pct_locataires": 71.4, "pct_appartements": 90.3, "pct_minorites_visibles": null, "source_url": "https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls", "source": "Élections Québec — Statistiques du Recensement 2021 par circonscription 2026 (classeur officiel)", "harvested": "2026-08-31"} | |
| \ No newline at end of file | ||
added
backend/data/population/riding_2026_demographics.csv
+128 −0
@@ -0,0 +1,128 @@ | ||
| 1 | +district,population,pct_60_plus,pct_locataires,pct_francais,pct_anglais,pct_universitaire,pct_revenu_100k_plus,pct_immigrants,pct_autochtone,pct_appartements,pct_minorites_visibles,source_url,harvested,z_pct_60_plus,z_pct_locataires,z_pct_francais,z_pct_anglais,z_pct_universitaire,z_pct_revenu_100k_plus,z_pct_immigrants,z_pct_autochtone,z_pct_appartements | |
| 2 | +Abitibi-Est,44055.0,19.6,36.4,96.7,2.3,12.6,11.7,2.0,0.2,36.9,,https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls,2026-08-31,-0.247,-0.087,0.696,-0.582,-0.825,1.014,-0.828,-0.055,-0.222 | |
| 3 | +Abitibi-Ouest,45290.0,22.0,26.7,98.9,0.8,10.0,9.1,1.0,0.0,22.9,,https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls,2026-08-31,0.252,-0.66,0.799,-0.692,-1.044,0.276,-0.902,-0.115,-0.766 | |
| 4 | +Acadie,82340.0,18.6,61.3,45.4,16.8,34.4,6.5,51.2,0.0,85.9,,https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls,2026-08-31,-0.456,1.383,-1.714,0.474,1.013,-0.461,2.815,-0.115,1.682 | |
| 5 | +Anjou-Louis-Riel,63611.0,20.8,59.1,72.0,8.8,26.6,6.8,35.9,0.0,82.1,,https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls,2026-08-31,0.002,1.253,-0.464,-0.109,0.356,-0.376,1.682,-0.115,1.535 | |
| 6 | +Argenteuil,48180.0,27.2,26.9,83.0,16.2,13.9,6.4,4.6,0.0,19.3,,https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls,2026-08-31,1.335,-0.648,0.052,0.43,-0.715,-0.49,-0.635,-0.115,-0.906 | |
| 7 | +Arthabaska–L'Érable,77225.0,25.8,34.8,97.9,0.5,12.3,4.4,2.5,0.0,32.9,,https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls,2026-08-31,1.044,-0.182,0.752,-0.713,-0.85,-1.057,-0.791,-0.115,-0.377 | |
| 8 | +Beauce-Nord,57245.0,20.7,22.4,98.8,0.4,12.7,5.2,1.5,0.0,14.4,,https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls,2026-08-31,-0.018,-0.914,0.795,-0.721,-0.817,-0.83,-0.865,-0.115,-1.096 | |
| 9 | +Beauce-Sud,63595.0,22.5,29.8,98.4,0.6,10.4,4.3,1.5,0.0,22.4,,https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls,2026-08-31,0.356,-0.477,0.776,-0.706,-1.011,-1.086,-0.865,-0.115,-0.785 | |
| 10 | +Beauharnois,68800.0,23.1,39.8,94.9,4.1,11.0,5.3,3.3,0.0,40.7,,https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls,2026-08-31,0.481,0.114,0.612,-0.451,-0.96,-0.802,-0.732,-0.115,-0.074 | |
| 11 | +Bellechasse,57020.0,23.1,22.4,98.8,0.5,12.3,4.7,1.8,0.0,15.3,,https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls,2026-08-31,0.481,-0.914,0.795,-0.713,-0.85,-0.972,-0.843,-0.115,-1.061 | |
| 12 | +Bellefeuille,55275.0,12.5,25.3,96.3,2.4,14.2,8.6,5.1,0.0,27.1,,https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls,2026-08-31,-1.726,-0.742,0.677,-0.575,-0.69,0.135,-0.598,-0.115,-0.603 | |
| 13 | +Berthier,61440.0,26.4,24.4,95.6,1.1,10.2,4.4,1.9,1.3,14.1,,https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls,2026-08-31,1.168,-0.796,0.644,-0.67,-1.028,-1.057,-0.835,0.276,-1.108 | |
| 14 | +Bertrand,64730.0,28.0,27.2,93.2,5.9,17.7,6.2,5.2,0.0,21.2,,https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls,2026-08-31,1.502,-0.63,0.532,-0.32,-0.395,-0.547,-0.591,-0.115,-0.832 | |
| 15 | +Blainville,79480.0,15.1,20.4,88.7,6.5,25.1,14.1,12.0,0.0,27.1,,https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls,2026-08-31,-1.184,-1.032,0.32,-0.276,0.229,1.695,-0.087,-0.115,-0.603 | |
| 16 | +Bonaventure,40733.0,28.8,27.2,89.4,10.3,11.6,4.3,1.1,0.1,13.7,,https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls,2026-08-31,1.668,-0.63,0.353,0.0,-0.909,-1.086,-0.894,-0.085,-1.124 | |
| 17 | +Borduas,71565.0,20.9,22.5,95.8,2.9,24.2,12.4,4.9,0.0,25.8,,https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls,2026-08-31,0.023,-0.908,0.654,-0.539,0.153,1.213,-0.613,-0.115,-0.653 | |
| 18 | +Bourassa-Sauvé,81450.0,18.1,70.7,64.2,9.0,13.3,2.2,39.8,0.0,87.2,,https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls,2026-08-31,-0.56,1.938,-0.831,-0.094,-0.766,-1.682,1.971,-0.115,1.733 | |
| 19 | +Brome-Missisquoi,64785.0,26.3,31.4,82.1,17.2,21.1,8.2,4.7,0.0,30.9,,https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls,2026-08-31,1.148,-0.382,0.01,0.503,-0.108,0.021,-0.628,-0.115,-0.455 | |
| 20 | +Camille-Laurin,71858.0,15.9,60.6,83.2,5.0,24.6,6.0,23.0,0.0,79.4,,https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls,2026-08-31,-1.018,1.342,0.062,-0.386,0.187,-0.603,0.727,-0.115,1.43 | |
| 21 | +Chambly,70525.0,15.1,21.0,92.4,4.5,24.8,13.6,8.1,0.0,27.7,,https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls,2026-08-31,-1.184,-0.996,0.494,-0.422,0.204,1.553,-0.376,-0.115,-0.58 | |
| 22 | +Champlain,73250.0,27.5,33.9,98.5,0.7,13.8,5.0,2.5,0.0,32.6,,https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls,2026-08-31,1.398,-0.235,0.781,-0.699,-0.724,-0.887,-0.791,-0.115,-0.389 | |
| 23 | +Chapleau,80435.0,19.5,39.0,85.4,9.4,18.0,6.9,12.2,0.0,41.8,,https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls,2026-08-31,-0.268,0.066,0.165,-0.065,-0.37,-0.348,-0.073,-0.115,-0.032 | |
| 24 | +Charlesbourg,74350.0,24.7,41.6,96.7,0.9,22.4,6.7,8.0,0.0,52.7,,https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls,2026-08-31,0.815,0.22,0.696,-0.684,0.001,-0.405,-0.384,-0.115,0.392 | |
| 25 | +Charlevoix-Côte-de-Beaupré,65840.0,26.7,23.1,99.0,0.6,17.2,7.6,2.2,0.0,20.8,,https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls,2026-08-31,1.231,-0.872,0.804,-0.706,-0.437,-0.149,-0.813,-0.115,-0.848 | |
| 26 | +Châteauguay,70595.0,18.3,25.8,67.4,24.7,16.6,6.7,17.8,0.0,26.1,,https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls,2026-08-31,-0.518,-0.713,-0.68,1.049,-0.488,-0.405,0.342,-0.115,-0.642 | |
| 27 | +Chauveau,76350.0,15.9,22.4,97.9,1.1,21.1,9.3,4.1,0.1,23.6,,https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls,2026-08-31,-1.018,-0.914,0.752,-0.67,-0.108,0.333,-0.672,-0.085,-0.739 | |
| 28 | +Chicoutimi,57895.0,26.5,43.2,98.5,0.6,21.4,8.0,2.0,0.1,46.2,,https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls,2026-08-31,1.189,0.314,0.781,-0.706,-0.083,-0.036,-0.828,-0.085,0.139 | |
| 29 | +Chomedey,77470.0,23.8,46.1,41.8,22.3,21.3,4.7,46.3,0.0,62.4,,https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls,2026-08-31,0.627,0.486,-1.883,0.874,-0.091,-0.972,2.452,-0.115,0.769 | |
| 30 | +Chutes-de-la-Chaudière,77200.0,17.2,23.0,98.4,0.8,26.3,11.5,3.0,0.0,23.9,,https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls,2026-08-31,-0.747,-0.878,0.776,-0.692,0.33,0.957,-0.754,-0.115,-0.727 | |
| 31 | +Côte-du-Sud,61385.0,29.4,26.4,99.2,0.4,11.2,3.4,1.2,0.0,20.1,,https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls,2026-08-31,1.793,-0.678,0.814,-0.721,-0.943,-1.341,-0.887,-0.115,-0.875 | |
| 32 | +Daniel-Johnson,58030.0,19.5,24.5,96.6,2.8,11.0,5.1,2.4,0.0,17.6,,https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls,2026-08-31,-0.268,-0.79,0.691,-0.546,-0.96,-0.859,-0.798,-0.115,-0.972 | |
| 33 | +D'Arcy-McGee,92930.0,19.9,66.0,21.4,50.5,41.9,9.8,46.4,0.0,83.2,,https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls,2026-08-31,-0.185,1.66,-2.842,2.928,1.646,0.475,2.46,-0.115,1.577 | |
| 34 | +Deux-Montagnes,63190.0,20.2,30.2,87.3,8.0,16.9,7.4,10.7,0.0,35.6,,https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls,2026-08-31,-0.122,-0.453,0.254,-0.167,-0.462,-0.206,-0.184,-0.115,-0.272 | |
| 35 | +Drummond-Bois-Francs,65520.0,24.5,37.7,97.6,1.0,13.1,5.3,3.2,0.0,33.6,,https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls,2026-08-31,0.773,-0.01,0.738,-0.677,-0.783,-0.802,-0.739,-0.115,-0.35 | |
| 36 | +Dubuc,52015.0,22.0,24.3,99.0,0.8,12.2,7.7,0.8,0.0,22.5,,https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls,2026-08-31,0.252,-0.802,0.804,-0.692,-0.859,-0.121,-0.917,-0.115,-0.782 | |
| 37 | +Duplessis,48090.0,18.9,28.8,82.7,8.4,10.8,15.5,1.7,5.5,23.2,,https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls,2026-08-31,-0.393,-0.536,0.038,-0.138,-0.977,2.092,-0.85,1.54,-0.754 | |
| 38 | +Fabre,78795.0,14.5,21.1,58.0,21.6,26.8,12.1,30.5,0.0,25.9,,https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls,2026-08-31,-1.309,-0.99,-1.122,0.823,0.372,1.128,1.282,-0.115,-0.649 | |
| 39 | +Gaspé,35955.0,28.2,27.1,93.3,6.3,11.7,4.1,1.9,0.0,15.5,,https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls,2026-08-31,1.543,-0.636,0.536,-0.291,-0.901,-1.142,-0.835,-0.115,-1.054 | |
| 40 | +Gatineau,76855.0,18.3,14.8,77.3,21.1,23.3,13.1,5.3,0.0,10.3,,https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls,2026-08-31,-0.518,-1.362,-0.215,0.787,0.077,1.411,-0.584,-0.115,-1.256 | |
| 41 | +Gouin,61460.0,11.4,69.4,83.4,9.9,49.9,10.5,18.3,0.0,97.6,,https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls,2026-08-31,-1.955,1.861,0.071,-0.029,2.321,0.674,0.379,-0.115,2.137 | |
| 42 | +Granby,72365.0,25.1,44.4,95.6,1.8,13.1,4.9,5.2,0.0,47.1,,https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls,2026-08-31,0.898,0.385,0.644,-0.619,-0.783,-0.915,-0.591,-0.115,0.174 | |
| 43 | +Groulx,68930.0,20.7,39.0,84.0,8.2,22.0,10.3,10.6,0.0,47.2,,https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls,2026-08-31,-0.018,0.066,0.099,-0.153,-0.032,0.617,-0.191,-0.115,0.178 | |
| 44 | +Hochelaga-Maisonneuve,59448.0,10.8,73.0,86.2,7.0,36.6,5.7,18.0,0.0,91.7,,https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls,2026-08-31,-2.08,2.074,0.203,-0.24,1.199,-0.688,0.357,-0.115,1.908 | |
| 45 | +Hull,94660.0,15.6,54.4,70.8,19.0,38.3,11.7,22.6,0.0,61.1,,https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls,2026-08-31,-1.08,0.976,-0.521,0.634,1.342,1.014,0.697,-0.115,0.718 | |
| 46 | +Huntingdon,57950.0,20.7,22.9,83.1,16.0,10.2,5.1,3.6,0.0,12.7,,https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls,2026-08-31,-0.018,-0.884,0.057,0.415,-1.028,-0.859,-0.709,-0.115,-1.162 | |
| 47 | +Iberville,64145.0,19.2,28.0,96.3,2.7,12.4,5.8,3.4,0.0,23.4,,https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls,2026-08-31,-0.331,-0.583,0.677,-0.553,-0.842,-0.66,-0.724,-0.115,-0.747 | |
| 48 | +Îles-de-la-Madeleine,12650.0,28.3,24.4,94.9,5.0,13.2,7.6,0.8,0.0,8.8,,https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls,2026-08-31,1.564,-0.796,0.612,-0.386,-0.775,-0.149,-0.917,-0.115,-1.314 | |
| 49 | +Jacques-Cartier,62510.0,24.7,24.6,18.4,68.1,44.4,18.6,25.5,0.0,23.5,,https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls,2026-08-31,0.815,-0.784,-2.983,4.21,1.857,2.972,0.912,-0.115,-0.743 | |
| 50 | +Jean-Lesage,59745.0,23.5,75.0,94.8,1.1,22.4,3.0,10.7,0.0,90.0,,https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls,2026-08-31,0.565,2.192,0.607,-0.67,0.001,-1.455,-0.184,-0.115,1.842 | |
| 51 | +Jean-Talon,69815.0,23.2,58.4,90.3,2.2,47.6,11.6,15.2,0.0,68.7,,https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls,2026-08-31,0.502,1.212,0.395,-0.59,2.127,0.986,0.149,-0.115,1.014 | |
| 52 | +Jeanne-Mance-Viger,79340.0,20.9,64.9,46.2,21.8,21.8,4.5,47.0,0.0,90.5,,https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls,2026-08-31,0.023,1.595,-1.677,0.838,-0.049,-1.029,2.504,-0.115,1.861 | |
| 53 | +Joliette,71115.0,26.5,44.3,97.9,0.7,13.9,5.3,3.5,0.1,41.2,,https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls,2026-08-31,1.189,0.379,0.752,-0.699,-0.715,-0.802,-0.717,-0.085,-0.055 | |
| 54 | +Jonquière,56325.0,24.7,37.1,99.3,0.5,15.7,7.9,1.1,0.0,40.2,,https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls,2026-08-31,0.815,-0.046,0.818,-0.713,-0.564,-0.064,-0.894,-0.115,-0.094 | |
| 55 | +La Peltrie,77880.0,17.3,31.0,96.8,1.7,20.9,7.9,4.9,0.0,32.1,,https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls,2026-08-31,-0.726,-0.406,0.701,-0.626,-0.125,-0.064,-0.613,-0.115,-0.409 | |
| 56 | +La Pinière,81625.0,21.1,29.3,48.3,19.7,37.5,11.1,40.8,0.0,45.6,,https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls,2026-08-31,0.065,-0.506,-1.578,0.685,1.275,0.844,2.045,-0.115,0.116 | |
| 57 | +La Prairie,65325.0,16.3,24.4,81.5,8.8,30.9,15.3,15.1,0.0,32.4,,https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls,2026-08-31,-0.935,-0.796,-0.018,-0.109,0.718,2.036,0.142,-0.115,-0.397 | |
| 58 | +Labelle,62590.0,29.0,27.9,96.4,3.2,12.7,5.3,2.5,0.0,21.8,,https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls,2026-08-31,1.71,-0.589,0.682,-0.517,-0.817,-0.802,-0.791,-0.115,-0.809 | |
| 59 | +Lac-Saint-Jean,54090.0,24.2,27.5,99.5,0.2,12.5,7.1,0.7,0.0,28.8,,https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls,2026-08-31,0.71,-0.613,0.828,-0.735,-0.834,-0.291,-0.924,-0.115,-0.537 | |
| 60 | +LaFontaine,58066.0,18.7,31.9,51.2,30.1,16.6,6.3,34.9,0.0,41.4,,https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls,2026-08-31,-0.435,-0.353,-1.442,1.442,-0.488,-0.518,1.608,-0.115,-0.047 | |
| 61 | +L'Assomption,71795.0,16.2,24.7,97.2,1.0,13.2,7.0,6.8,0.0,24.5,,https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls,2026-08-31,-0.955,-0.778,0.72,-0.677,-0.775,-0.32,-0.472,-0.115,-0.704 | |
| 62 | +Laurier-Dorion,74674.0,12.7,73.0,56.9,14.4,38.5,6.3,31.9,0.0,90.0,,https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls,2026-08-31,-1.684,2.074,-1.174,0.299,1.359,-0.518,1.386,-0.115,1.842 | |
| 63 | +Laval-des-Rapides,80150.0,21.9,57.2,72.0,8.4,25.9,5.7,33.2,0.0,73.0,,https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls,2026-08-31,0.232,1.141,-0.464,-0.138,0.297,-0.688,1.482,-0.115,1.181 | |
| 64 | +Laviolette-Saint-Maurice,72160.0,28.3,37.8,95.2,0.9,10.8,4.0,1.8,1.8,38.5,,https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls,2026-08-31,1.564,-0.005,0.626,-0.684,-0.977,-1.171,-0.843,0.427,-0.16 | |
| 65 | +Les Plaines,65615.0,12.8,26.7,94.8,2.4,10.2,6.0,9.0,0.0,29.2,,https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls,2026-08-31,-1.663,-0.66,0.607,-0.575,-1.028,-0.603,-0.31,-0.115,-0.521 | |
| 66 | +Lévis,63160.0,26.9,46.4,97.7,0.9,23.7,7.9,4.5,0.0,51.4,,https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls,2026-08-31,1.273,0.503,0.743,-0.684,0.111,-0.064,-0.643,-0.115,0.342 | |
| 67 | +Lotbinière-Frontenac,72630.0,25.8,25.4,98.4,0.8,10.8,4.0,1.6,0.0,21.0,,https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls,2026-08-31,1.044,-0.737,0.776,-0.692,-0.977,-1.171,-0.857,-0.115,-0.84 | |
| 68 | +Louis-Hébert,58585.0,26.7,22.8,95.9,1.4,41.8,15.6,6.7,0.0,36.2,,https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls,2026-08-31,1.231,-0.89,0.659,-0.648,1.638,2.121,-0.48,-0.115,-0.249 | |
| 69 | +Marguerite-Bourgeoys,82235.0,20.3,60.7,38.5,36.8,24.5,5.3,35.3,0.0,89.0,,https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls,2026-08-31,-0.102,1.347,-2.038,1.93,0.179,-0.802,1.638,-0.115,1.803 | |
| 70 | +Marie-Lacoste-Gérin-Lajoie,58305.0,19.0,37.9,97.0,1.0,11.6,3.9,3.8,0.0,34.5,,https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls,2026-08-31,-0.372,0.001,0.71,-0.677,-0.909,-1.199,-0.695,-0.115,-0.315 | |
| 71 | +Marie-Victorin,66315.0,18.3,66.1,84.9,5.0,24.5,5.2,21.1,0.0,76.9,,https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls,2026-08-31,-0.518,1.666,0.142,-0.386,0.179,-0.83,0.586,-0.115,1.333 | |
| 72 | +Marquette,65760.0,19.2,53.0,46.3,40.3,29.8,9.1,24.6,0.0,67.8,,https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls,2026-08-31,-0.331,0.893,-1.672,2.185,0.625,0.276,0.845,-0.115,0.979 | |
| 73 | +Maskinongé,56775.0,24.5,24.4,98.7,0.7,14.7,6.5,1.8,0.0,18.9,,https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls,2026-08-31,0.773,-0.796,0.79,-0.699,-0.648,-0.461,-0.843,-0.115,-0.921 | |
| 74 | +Masson,65810.0,16.9,22.8,93.5,3.5,16.9,10.4,9.3,0.0,32.5,,https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls,2026-08-31,-0.81,-0.89,0.546,-0.495,-0.462,0.645,-0.287,-0.115,-0.393 | |
| 75 | +Matane-Matapédia-Mitis,56838.0,26.1,28.4,99.4,0.5,10.1,3.8,0.8,0.0,19.5,,https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls,2026-08-31,1.106,-0.559,0.823,-0.713,-1.036,-1.228,-0.917,-0.115,-0.898 | |
| 76 | +Maurice-Richard,68210.0,21.3,65.1,78.1,6.8,36.6,8.6,28.5,0.0,90.6,,https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls,2026-08-31,0.107,1.607,-0.178,-0.255,1.199,0.135,1.134,-0.115,1.865 | |
| 77 | +Mégantic,61885.0,27.0,25.5,95.0,4.6,9.8,3.6,1.9,0.0,21.0,,https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls,2026-08-31,1.293,-0.731,0.616,-0.415,-1.061,-1.284,-0.835,-0.115,-0.84 | |
| 78 | +Mercier,69895.0,10.3,67.9,71.0,20.3,56.8,13.0,22.3,0.0,97.2,,https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls,2026-08-31,-2.184,1.773,-0.511,0.729,2.903,1.383,0.675,-0.115,2.121 | |
| 79 | +Mille-Îles,66660.0,18.1,22.6,71.9,15.6,24.8,10.0,26.1,0.0,30.4,,https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls,2026-08-31,-0.56,-0.902,-0.469,0.386,0.204,0.532,0.957,-0.115,-0.475 | |
| 80 | +Mirabel,68370.0,13.1,21.7,92.9,4.1,16.7,9.4,7.5,0.0,26.0,,https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls,2026-08-31,-1.601,-0.955,0.518,-0.451,-0.479,0.362,-0.421,-0.115,-0.646 | |
| 81 | +Mont-Royal-Outremont,96625.0,17.0,64.4,49.4,25.3,53.4,16.0,36.8,0.0,83.5,,https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls,2026-08-31,-0.789,1.566,-1.526,1.093,2.616,2.234,1.749,-0.115,1.589 | |
| 82 | +Montarville,68015.0,24.2,15.2,90.7,5.8,40.6,19.8,9.8,0.0,26.1,,https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls,2026-08-31,0.71,-1.339,0.414,-0.327,1.536,3.313,-0.25,-0.115,-0.642 | |
| 83 | +Montmorency,74740.0,19.0,30.0,98.2,0.5,19.7,7.0,5.0,0.0,37.3,,https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls,2026-08-31,-0.372,-0.465,0.767,-0.713,-0.226,-0.32,-0.606,-0.115,-0.206 | |
| 84 | +Nelligan,79805.0,18.1,21.3,26.9,51.1,35.1,12.8,35.7,0.0,23.8,,https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls,2026-08-31,-0.56,-0.979,-2.583,2.972,1.072,1.326,1.667,-0.115,-0.731 | |
| 85 | +Nicolet-Bécancour,49390.0,24.7,24.7,98.8,0.6,13.0,5.1,1.6,0.0,18.1,,https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls,2026-08-31,0.815,-0.778,0.795,-0.706,-0.791,-0.859,-0.857,-0.115,-0.953 | |
| 86 | +Notre-Dame-de-Grâce,73265.0,17.3,63.0,25.7,54.1,48.0,12.9,34.8,0.0,82.0,,https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls,2026-08-31,-0.726,1.483,-2.64,3.19,2.16,1.355,1.601,-0.115,1.531 | |
| 87 | +Orford,54795.0,29.9,26.3,85.4,14.0,24.0,8.8,5.1,0.0,25.3,,https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls,2026-08-31,1.897,-0.683,0.165,0.27,0.136,0.191,-0.598,-0.115,-0.673 | |
| 88 | +Papineau,74845.0,18.7,26.8,92.2,6.8,12.6,6.2,4.0,0.0,18.9,,https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls,2026-08-31,-0.435,-0.654,0.485,-0.255,-0.825,-0.547,-0.68,-0.115,-0.921 | |
| 89 | +Pierre-Laporte,74615.0,22.1,46.8,68.6,17.9,31.1,10.6,23.5,0.0,56.8,,https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls,2026-08-31,0.273,0.527,-0.624,0.554,0.735,0.702,0.764,-0.115,0.551 | |
| 90 | +Pointe-aux-Trembles,54262.0,17.7,45.4,90.1,3.2,14.8,5.1,16.2,0.0,58.5,,https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls,2026-08-31,-0.643,0.444,0.386,-0.517,-0.64,-0.859,0.224,-0.115,0.617 | |
| 91 | +Pontiac,78350.0,17.0,23.8,52.3,41.8,28.7,13.1,13.6,0.0,20.5,,https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls,2026-08-31,-0.789,-0.831,-1.39,2.294,0.533,1.411,0.031,-0.115,-0.859 | |
| 92 | +Portneuf,66595.0,21.9,20.8,98.6,1.0,14.3,6.8,1.6,0.0,15.9,,https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls,2026-08-31,0.232,-1.008,0.785,-0.677,-0.682,-0.376,-0.857,-0.115,-1.038 | |
| 93 | +Prévost,61360.0,20.5,20.7,95.0,4.2,18.4,9.2,4.4,0.0,19.1,,https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls,2026-08-31,-0.06,-1.014,0.616,-0.444,-0.336,0.305,-0.65,-0.115,-0.914 | |
| 94 | +René-Lévesque,40435.0,24.2,25.6,95.0,0.4,10.6,8.0,1.1,2.2,19.0,,https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls,2026-08-31,0.71,-0.725,0.616,-0.721,-0.994,-0.036,-0.894,0.547,-0.918 | |
| 95 | +Repentigny,70715.0,22.4,26.3,94.0,2.1,17.9,9.3,12.0,0.0,37.3,,https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls,2026-08-31,0.336,-0.683,0.569,-0.597,-0.378,0.333,-0.087,-0.115,-0.206 | |
| 96 | +Richelieu,64515.0,26.5,32.4,98.5,0.8,10.6,6.3,2.9,0.0,29.9,,https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls,2026-08-31,1.189,-0.323,0.781,-0.692,-0.994,-0.518,-0.761,-0.115,-0.494 | |
| 97 | +Richmond,72780.0,18.2,24.7,94.9,3.8,20.2,7.7,3.7,0.0,23.7,,https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls,2026-08-31,-0.539,-0.778,0.612,-0.473,-0.184,-0.121,-0.702,-0.115,-0.735 | |
| 98 | +Rimouski,57191.0,23.3,35.3,99.0,0.4,21.9,6.2,2.2,0.0,31.1,,https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls,2026-08-31,0.523,-0.152,0.804,-0.721,-0.041,-0.547,-0.813,-0.115,-0.447 | |
| 99 | +Rivière-du-Loup–Témiscouata–Les Basques,63705.0,28.2,30.0,99.2,0.4,12.7,4.5,1.2,0.0,26.1,,https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls,2026-08-31,1.543,-0.465,0.814,-0.721,-0.817,-1.029,-0.887,-0.115,-0.642 | |
| 100 | +Robert-Baldwin,77275.0,19.7,31.0,21.3,53.3,33.3,9.9,41.2,0.0,33.4,,https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls,2026-08-31,-0.227,-0.406,-2.846,3.132,0.921,0.503,2.075,-0.115,-0.358 | |
| 101 | +Roberval,55230.0,26.6,26.4,99.5,0.2,11.0,4.4,0.9,0.1,23.9,,https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls,2026-08-31,1.21,-0.678,0.828,-0.735,-0.96,-1.057,-0.909,-0.085,-0.727 | |
| 102 | +Rosemont,76870.0,19.5,67.4,81.6,6.1,36.9,8.9,24.2,0.0,92.7,,https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls,2026-08-31,-0.268,1.743,-0.013,-0.306,1.224,0.22,0.816,-0.115,1.947 | |
| 103 | +Rousseau,58430.0,15.7,24.8,98.0,1.2,7.2,4.0,2.9,0.0,16.1,,https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls,2026-08-31,-1.059,-0.772,0.757,-0.662,-1.281,-1.171,-0.761,-0.115,-1.03 | |
| 104 | +Rouyn-Noranda-Témiscamingue,57735.0,21.0,33.3,93.5,5.9,14.9,9.8,1.9,0.0,32.2,,https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls,2026-08-31,0.044,-0.27,0.546,-0.32,-0.631,0.475,-0.835,-0.115,-0.405 | |
| 105 | +Saint-François,71350.0,22.7,47.5,88.3,8.2,17.3,3.9,7.2,0.0,48.4,,https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls,2026-08-31,0.398,0.568,0.301,-0.153,-0.429,-1.199,-0.443,-0.115,0.225 | |
| 106 | +Saint-Henri-Sainte-Anne,84550.0,13.2,65.2,55.9,30.4,42.3,11.2,26.0,0.0,91.4,,https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls,2026-08-31,-1.58,1.613,-1.221,1.464,1.68,0.872,0.949,-0.115,1.896 | |
| 107 | +Saint-Hyacinthe,71160.0,24.2,46.6,96.0,0.7,13.3,5.6,6.5,0.0,49.3,,https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls,2026-08-31,0.71,0.515,0.663,-0.699,-0.766,-0.717,-0.495,-0.115,0.26 | |
| 108 | +Saint-Jean,77380.0,21.6,41.5,95.8,2.7,15.6,7.7,4.7,0.0,44.0,,https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls,2026-08-31,0.169,0.214,0.654,-0.553,-0.572,-0.121,-0.628,-0.115,0.054 | |
| 109 | +Saint-Jérôme,56330.0,27.3,57.0,96.3,1.4,10.1,3.3,5.5,0.0,65.8,,https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls,2026-08-31,1.356,1.129,0.677,-0.648,-1.036,-1.369,-0.569,-0.115,0.901 | |
| 110 | +Saint-Laurent,93910.0,16.1,50.2,38.7,28.1,38.3,11.2,48.4,0.0,70.5,,https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls,2026-08-31,-0.976,0.728,-2.029,1.297,1.342,0.872,2.608,-0.115,1.084 | |
| 111 | +Sainte-Marie-Saint-Jacques,66864.0,11.7,71.3,69.1,20.1,50.7,10.8,25.9,0.0,86.4,,https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls,2026-08-31,-1.892,1.973,-0.601,0.714,2.388,0.759,0.942,-0.115,1.702 | |
| 112 | +Sainte-Rose,74990.0,15.3,20.9,74.3,11.1,26.3,11.1,26.3,0.0,23.8,,https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls,2026-08-31,-1.143,-1.002,-0.356,0.059,0.33,0.844,0.971,-0.115,-0.731 | |
| 113 | +Sanguinet,58600.0,16.1,25.6,87.4,6.0,16.6,8.6,10.9,0.0,30.4,,https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls,2026-08-31,-0.976,-0.725,0.259,-0.313,-0.488,0.135,-0.169,-0.115,-0.475 | |
| 114 | +Sherbrooke,72420.0,23.5,62.5,90.0,3.6,30.1,6.0,11.7,0.0,69.1,,https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls,2026-08-31,0.565,1.454,0.381,-0.488,0.651,-0.603,-0.11,-0.115,1.029 | |
| 115 | +Soulanges,73010.0,17.0,16.6,67.9,29.4,20.2,11.1,8.4,0.0,14.0,,https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls,2026-08-31,-0.789,-1.256,-0.657,1.391,-0.184,0.844,-0.354,-0.115,-1.112 | |
| 116 | +Taillon,74570.0,21.2,48.0,86.2,4.2,29.2,9.5,20.1,0.0,63.3,,https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls,2026-08-31,0.086,0.598,0.203,-0.444,0.575,0.39,0.512,-0.115,0.804 | |
| 117 | +Taschereau,64045.0,26.0,69.8,93.9,2.4,44.4,8.1,10.2,0.0,94.1,,https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls,2026-08-31,1.085,1.885,0.565,-0.575,1.857,-0.007,-0.221,-0.115,2.001 | |
| 118 | +Terrebonne,71340.0,17.3,27.9,92.7,3.3,17.8,10.0,11.5,0.0,32.6,,https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls,2026-08-31,-0.726,-0.589,0.508,-0.509,-0.387,0.532,-0.124,-0.115,-0.389 | |
| 119 | +Trois-Rivières,70875.0,28.0,54.8,96.1,1.0,22.6,6.1,6.0,0.1,58.5,,https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls,2026-08-31,1.502,0.999,0.668,-0.677,0.018,-0.575,-0.532,-0.085,0.617 | |
| 120 | +Ungava,45740.0,9.1,44.4,32.1,12.7,7.4,9.8,1.2,37.0,15.3,,https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls,2026-08-31,-2.434,0.385,-2.339,0.175,-1.264,0.475,-0.887,11.023,-1.061 | |
| 121 | +Vachon,71640.0,17.7,23.2,79.9,8.6,22.8,8.2,21.2,0.0,34.1,,https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls,2026-08-31,-0.643,-0.866,-0.093,-0.123,0.035,0.021,0.594,-0.115,-0.331 | |
| 122 | +Vanier-Les Rivières,70015.0,25.4,49.5,95.4,0.9,25.2,8.0,7.9,0.0,61.5,,https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls,2026-08-31,0.96,0.686,0.635,-0.684,0.238,-0.036,-0.391,-0.115,0.734 | |
| 123 | +Vaudreuil,82115.0,17.0,22.8,52.7,35.7,24.4,9.9,20.6,0.0,29.2,,https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls,2026-08-31,-0.789,-0.89,-1.371,1.85,0.17,0.503,0.549,-0.115,-0.521 | |
| 124 | +Verchères,70835.0,16.2,20.7,96.9,1.6,21.6,12.6,5.2,0.0,25.2,,https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls,2026-08-31,-0.955,-1.014,0.706,-0.633,-0.066,1.27,-0.591,-0.115,-0.677 | |
| 125 | +Verdun,70375.0,17.7,62.4,61.8,23.8,45.5,12.8,24.6,0.0,90.0,,https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls,2026-08-31,-0.643,1.448,-0.944,0.984,1.95,1.326,0.845,-0.115,1.842 | |
| 126 | +Viau,70417.0,13.7,71.7,57.5,7.9,21.4,2.4,44.2,0.0,86.3,,https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls,2026-08-31,-1.476,1.997,-1.146,-0.174,-0.083,-1.625,2.297,-0.115,1.698 | |
| 127 | +Vimont-Auteuil,60305.0,18.2,21.2,69.8,18.3,23.9,9.8,24.1,0.0,28.5,,https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls,2026-08-31,-0.539,-0.985,-0.568,0.583,0.128,0.475,0.808,-0.115,-0.548 | |
| 128 | +Westmount-Saint-Louis,86250.0,17.2,71.4,26.2,49.6,60.5,16.8,33.2,0.0,90.3,,https://docs.electionsquebec.qc.ca/PRO/6a58edde4eab9/statistiques-recensement-2021-CEP2026.xls,2026-08-31,-0.747,1.979,-2.616,2.862,3.215,2.461,1.482,-0.115,1.853 | |
added
backend/data/population/riding_similarity.json
+1 −0
@@ -0,0 +1 @@ | ||
| 1 | +{"Abitibi-Est": [{"district": "Rouyn-Noranda-Témiscamingue", "similarity": 0.923}, {"district": "Abitibi-Ouest", "similarity": 0.806}, {"district": "Verchères", "similarity": 0.756}, {"district": "Terrebonne", "similarity": 0.748}, {"district": "Masson", "similarity": 0.747}, {"district": "Borduas", "similarity": 0.726}, {"district": "Groulx", "similarity": 0.722}, {"district": "Duplessis", "similarity": 0.706}, {"district": "Saint-Jean", "similarity": 0.692}, {"district": "Chutes-de-la-Chaudière", "similarity": 0.692}], "Abitibi-Ouest": [{"district": "Dubuc", "similarity": 0.974}, {"district": "Rouyn-Noranda-Témiscamingue", "similarity": 0.943}, {"district": "Lac-Saint-Jean", "similarity": 0.923}, {"district": "Portneuf", "similarity": 0.915}, {"district": "René-Lévesque", "similarity": 0.913}, {"district": "Prévost", "similarity": 0.886}, {"district": "Maskinongé", "similarity": 0.884}, {"district": "Beauce-Nord", "similarity": 0.845}, {"district": "Charlevoix-Côte-de-Beaupré", "similarity": 0.833}, {"district": "Repentigny", "similarity": 0.832}], "Acadie": [{"district": "Jeanne-Mance-Viger", "similarity": 0.942}, {"district": "Anjou-Louis-Riel", "similarity": 0.923}, {"district": "Laval-des-Rapides", "similarity": 0.901}, {"district": "Saint-Laurent", "similarity": 0.893}, {"district": "Laurier-Dorion", "similarity": 0.866}, {"district": "Marguerite-Bourgeoys", "similarity": 0.865}, {"district": "Viau", "similarity": 0.86}, {"district": "Chomedey", "similarity": 0.856}, {"district": "D'Arcy-McGee", "similarity": 0.851}, {"district": "Maurice-Richard", "similarity": 0.793}], "Anjou-Louis-Riel": [{"district": "Laval-des-Rapides", "similarity": 0.981}, {"district": "Acadie", "similarity": 0.923}, {"district": "Jeanne-Mance-Viger", "similarity": 0.916}, {"district": "Maurice-Richard", "similarity": 0.905}, {"district": "Viau", "similarity": 0.877}, {"district": "Bourassa-Sauvé", "similarity": 0.876}, {"district": "Rosemont", "similarity": 0.849}, {"district": "Laurier-Dorion", "similarity": 0.83}, {"district": "Marie-Victorin", "similarity": 0.826}, {"district": "Camille-Laurin", "similarity": 0.822}], "Argenteuil": [{"district": "Bonaventure", "similarity": 0.956}, {"district": "Gaspé", "similarity": 0.911}, {"district": "Brome-Missisquoi", "similarity": 0.902}, {"district": "Bertrand", "similarity": 0.896}, {"district": "Îles-de-la-Madeleine", "similarity": 0.894}, {"district": "Labelle", "similarity": 0.874}, {"district": "Mégantic", "similarity": 0.86}, {"district": "Côte-du-Sud", "similarity": 0.834}, {"district": "Orford", "similarity": 0.832}, {"district": "Berthier", "similarity": 0.824}], "Arthabaska–L'Érable": [{"district": "Drummond-Bois-Francs", "similarity": 0.99}, {"district": "Champlain", "similarity": 0.983}, {"district": "Rivière-du-Loup–Témiscouata–Les Basques", "similarity": 0.977}, {"district": "Matane-Matapédia-Mitis", "similarity": 0.974}, {"district": "Roberval", "similarity": 0.974}, {"district": "Côte-du-Sud", "similarity": 0.964}, {"district": "Richelieu", "similarity": 0.961}, {"district": "Lotbinière-Frontenac", "similarity": 0.961}, {"district": "Laviolette-Saint-Maurice", "similarity": 0.95}, {"district": "Mégantic", "similarity": 0.949}], "Beauce-Nord": [{"district": "Daniel-Johnson", "similarity": 0.986}, {"district": "Bellechasse", "similarity": 0.976}, {"district": "Iberville", "similarity": 0.974}, {"district": "Portneuf", "similarity": 0.972}, {"district": "Beauce-Sud", "similarity": 0.949}, {"district": "Papineau", "similarity": 0.947}, {"district": "Dubuc", "similarity": 0.934}, {"district": "Nicolet-Bécancour", "similarity": 0.932}, {"district": "Deux-Montagnes", "similarity": 0.919}, {"district": "Maskinongé", "similarity": 0.918}], "Beauce-Sud": [{"district": "Bellechasse", "similarity": 0.972}, {"district": "Matane-Matapédia-Mitis", "similarity": 0.962}, {"district": "Lotbinière-Frontenac", "similarity": 0.96}, {"district": "Nicolet-Bécancour", "similarity": 0.96}, {"district": "Beauce-Nord", "similarity": 0.949}, {"district": "Roberval", "similarity": 0.941}, {"district": "Daniel-Johnson", "similarity": 0.938}, {"district": "Drummond-Bois-Francs", "similarity": 0.929}, {"district": "Iberville", "similarity": 0.928}, {"district": "Berthier", "similarity": 0.927}], "Beauharnois": [{"district": "Drummond-Bois-Francs", "similarity": 0.962}, {"district": "Granby", "similarity": 0.943}, {"district": "Arthabaska–L'Érable", "similarity": 0.942}, {"district": "Saint-Hyacinthe", "similarity": 0.92}, {"district": "Joliette", "similarity": 0.917}, {"district": "Beauce-Sud", "similarity": 0.898}, {"district": "Matane-Matapédia-Mitis", "similarity": 0.889}, {"district": "Laviolette-Saint-Maurice", "similarity": 0.889}, {"district": "Richelieu", "similarity": 0.888}, {"district": "Champlain", "similarity": 0.885}], "Bellechasse": [{"district": "Nicolet-Bécancour", "similarity": 0.986}, {"district": "Beauce-Nord", "similarity": 0.976}, {"district": "Beauce-Sud", "similarity": 0.972}, {"district": "Maskinongé", "similarity": 0.965}, {"district": "Lotbinière-Frontenac", "similarity": 0.965}, {"district": "Portneuf", "similarity": 0.962}, {"district": "Matane-Matapédia-Mitis", "similarity": 0.953}, {"district": "Berthier", "similarity": 0.95}, {"district": "Roberval", "similarity": 0.943}, {"district": "Daniel-Johnson", "similarity": 0.942}], "Bellefeuille": [{"district": "Mirabel", "similarity": 0.98}, {"district": "Sanguinet", "similarity": 0.961}, {"district": "Les Plaines", "similarity": 0.932}, {"district": "L'Assomption", "similarity": 0.924}, {"district": "Chauveau", "similarity": 0.913}, {"district": "Terrebonne", "similarity": 0.896}, {"district": "La Peltrie", "similarity": 0.895}, {"district": "Masson", "similarity": 0.887}, {"district": "Richmond", "similarity": 0.839}, {"district": "Rousseau", "similarity": 0.798}], "Berthier": [{"district": "Lotbinière-Frontenac", "similarity": 0.98}, {"district": "Matane-Matapédia-Mitis", "similarity": 0.977}, {"district": "Roberval", "similarity": 0.976}, {"district": "Nicolet-Bécancour", "similarity": 0.974}, {"district": "Mégantic", "similarity": 0.974}, {"district": "Gaspé", "similarity": 0.965}, {"district": "Côte-du-Sud", "similarity": 0.963}, {"district": "Bellechasse", "similarity": 0.95}, {"district": "Rivière-du-Loup–Témiscouata–Les Basques", "similarity": 0.949}, {"district": "Labelle", "similarity": 0.948}], "Bertrand": [{"district": "Labelle", "similarity": 0.982}, {"district": "Gaspé", "similarity": 0.961}, {"district": "Îles-de-la-Madeleine", "similarity": 0.959}, {"district": "Côte-du-Sud", "similarity": 0.956}, {"district": "Bonaventure", "similarity": 0.952}, {"district": "Rivière-du-Loup–Témiscouata–Les Basques", "similarity": 0.946}, {"district": "Charlevoix-Côte-de-Beaupré", "similarity": 0.942}, {"district": "Mégantic", "similarity": 0.923}, {"district": "Roberval", "similarity": 0.921}, {"district": "Champlain", "similarity": 0.917}], "Blainville": [{"district": "Chambly", "similarity": 0.987}, {"district": "La Prairie", "similarity": 0.943}, {"district": "Verchères", "similarity": 0.925}, {"district": "Chutes-de-la-Chaudière", "similarity": 0.854}, {"district": "Masson", "similarity": 0.835}, {"district": "Terrebonne", "similarity": 0.823}, {"district": "Borduas", "similarity": 0.797}, {"district": "Gatineau", "similarity": 0.785}, {"district": "Sainte-Rose", "similarity": 0.777}, {"district": "Mirabel", "similarity": 0.761}], "Bonaventure": [{"district": "Gaspé", "similarity": 0.99}, {"district": "Mégantic", "similarity": 0.963}, {"district": "Labelle", "similarity": 0.96}, {"district": "Argenteuil", "similarity": 0.956}, {"district": "Bertrand", "similarity": 0.952}, {"district": "Côte-du-Sud", "similarity": 0.952}, {"district": "Berthier", "similarity": 0.934}, {"district": "Rivière-du-Loup–Témiscouata–Les Basques", "similarity": 0.929}, {"district": "Matane-Matapédia-Mitis", "similarity": 0.921}, {"district": "Roberval", "similarity": 0.92}], "Borduas": [{"district": "Chutes-de-la-Chaudière", "similarity": 0.913}, {"district": "Verchères", "similarity": 0.898}, {"district": "Chambly", "similarity": 0.842}, {"district": "Prévost", "similarity": 0.838}, {"district": "Montarville", "similarity": 0.82}, {"district": "Blainville", "similarity": 0.797}, {"district": "Masson", "similarity": 0.773}, {"district": "Louis-Hébert", "similarity": 0.767}, {"district": "Repentigny", "similarity": 0.758}, {"district": "Chauveau", "similarity": 0.75}], "Bourassa-Sauvé": [{"district": "Viau", "similarity": 0.959}, {"district": "Laval-des-Rapides", "similarity": 0.9}, {"district": "Jeanne-Mance-Viger", "similarity": 0.899}, {"district": "Anjou-Louis-Riel", "similarity": 0.876}, {"district": "Marie-Victorin", "similarity": 0.854}, {"district": "Camille-Laurin", "similarity": 0.837}, {"district": "Acadie", "similarity": 0.792}, {"district": "Laurier-Dorion", "similarity": 0.751}, {"district": "Marguerite-Bourgeoys", "similarity": 0.749}, {"district": "Chomedey", "similarity": 0.725}], "Brome-Missisquoi": [{"district": "Orford", "similarity": 0.948}, {"district": "Argenteuil", "similarity": 0.902}, {"district": "Bonaventure", "similarity": 0.798}, {"district": "Bertrand", "similarity": 0.797}, {"district": "Îles-de-la-Madeleine", "similarity": 0.796}, {"district": "Labelle", "similarity": 0.733}, {"district": "Gaspé", "similarity": 0.727}, {"district": "Charlevoix-Côte-de-Beaupré", "similarity": 0.685}, {"district": "Côte-du-Sud", "similarity": 0.65}, {"district": "Mégantic", "similarity": 0.636}], "Camille-Laurin": [{"district": "Marie-Victorin", "similarity": 0.963}, {"district": "Hochelaga-Maisonneuve", "similarity": 0.931}, {"district": "Viau", "similarity": 0.884}, {"district": "Laurier-Dorion", "similarity": 0.871}, {"district": "Rosemont", "similarity": 0.837}, {"district": "Bourassa-Sauvé", "similarity": 0.837}, {"district": "Anjou-Louis-Riel", "similarity": 0.822}, {"district": "Maurice-Richard", "similarity": 0.792}, {"district": "Laval-des-Rapides", "similarity": 0.779}, {"district": "Gouin", "similarity": 0.762}], "Chambly": [{"district": "Blainville", "similarity": 0.987}, {"district": "Verchères", "similarity": 0.969}, {"district": "Chutes-de-la-Chaudière", "similarity": 0.92}, {"district": "La Prairie", "similarity": 0.897}, {"district": "Masson", "similarity": 0.88}, {"district": "Terrebonne", "similarity": 0.867}, {"district": "Borduas", "similarity": 0.842}, {"district": "Chauveau", "similarity": 0.823}, {"district": "Mirabel", "similarity": 0.809}, {"district": "Gatineau", "similarity": 0.756}], "Champlain": [{"district": "Rivière-du-Loup–Témiscouata–Les Basques", "similarity": 0.993}, {"district": "Arthabaska–L'Érable", "similarity": 0.983}, {"district": "Côte-du-Sud", "similarity": 0.977}, {"district": "Richelieu", "similarity": 0.974}, {"district": "Roberval", "similarity": 0.968}, {"district": "Labelle", "similarity": 0.968}, {"district": "Drummond-Bois-Francs", "similarity": 0.965}, {"district": "Laviolette-Saint-Maurice", "similarity": 0.955}, {"district": "Matane-Matapédia-Mitis", "similarity": 0.954}, {"district": "Joliette", "similarity": 0.947}], "Chapleau": [{"district": "Marie-Lacoste-Gérin-Lajoie", "similarity": 0.881}, {"district": "Rousseau", "similarity": 0.82}, {"district": "Pointe-aux-Trembles", "similarity": 0.808}, {"district": "Les Plaines", "similarity": 0.798}, {"district": "Iberville", "similarity": 0.719}, {"district": "Daniel-Johnson", "similarity": 0.686}, {"district": "Papineau", "similarity": 0.68}, {"district": "L'Assomption", "similarity": 0.679}, {"district": "Beauharnois", "similarity": 0.669}, {"district": "Deux-Montagnes", "similarity": 0.647}], "Charlesbourg": [{"district": "Lévis", "similarity": 0.939}, {"district": "Trois-Rivières", "similarity": 0.92}, {"district": "Chicoutimi", "similarity": 0.92}, {"district": "Vanier-Les Rivières", "similarity": 0.907}, {"district": "Joliette", "similarity": 0.871}, {"district": "Saint-Hyacinthe", "similarity": 0.86}, {"district": "Granby", "similarity": 0.852}, {"district": "Saint-Jérôme", "similarity": 0.818}, {"district": "Jonquière", "similarity": 0.813}, {"district": "Champlain", "similarity": 0.788}], "Charlevoix-Côte-de-Beaupré": [{"district": "Maskinongé", "similarity": 0.963}, {"district": "Îles-de-la-Madeleine", "similarity": 0.96}, {"district": "Bertrand", "similarity": 0.942}, {"district": "Lac-Saint-Jean", "similarity": 0.936}, {"district": "Labelle", "similarity": 0.928}, {"district": "Nicolet-Bécancour", "similarity": 0.922}, {"district": "Richelieu", "similarity": 0.91}, {"district": "Roberval", "similarity": 0.908}, {"district": "Rivière-du-Loup–Témiscouata–Les Basques", "similarity": 0.905}, {"district": "Côte-du-Sud", "similarity": 0.894}], "Châteauguay": [{"district": "Vaudreuil", "similarity": 0.835}, {"district": "LaFontaine", "similarity": 0.804}, {"district": "Soulanges", "similarity": 0.761}, {"district": "Vimont-Auteuil", "similarity": 0.738}, {"district": "Nelligan", "similarity": 0.673}, {"district": "Robert-Baldwin", "similarity": 0.672}, {"district": "Pontiac", "similarity": 0.666}, {"district": "Mille-Îles", "similarity": 0.636}, {"district": "Fabre", "similarity": 0.628}, {"district": "Huntingdon", "similarity": 0.617}], "Chauveau": [{"district": "La Peltrie", "similarity": 0.944}, {"district": "Richmond", "similarity": 0.943}, {"district": "Mirabel", "similarity": 0.931}, {"district": "Masson", "similarity": 0.924}, {"district": "Chutes-de-la-Chaudière", "similarity": 0.924}, {"district": "Terrebonne", "similarity": 0.917}, {"district": "Bellefeuille", "similarity": 0.913}, {"district": "Verchères", "similarity": 0.911}, {"district": "Sanguinet", "similarity": 0.893}, {"district": "L'Assomption", "similarity": 0.882}], "Chicoutimi": [{"district": "Lévis", "similarity": 0.977}, {"district": "Charlesbourg", "similarity": 0.92}, {"district": "Jonquière", "similarity": 0.913}, {"district": "Trois-Rivières", "similarity": 0.88}, {"district": "Joliette", "similarity": 0.87}, {"district": "Vanier-Les Rivières", "similarity": 0.866}, {"district": "Champlain", "similarity": 0.814}, {"district": "Granby", "similarity": 0.793}, {"district": "Rimouski", "similarity": 0.793}, {"district": "Saint-Hyacinthe", "similarity": 0.793}], "Chomedey": [{"district": "Jeanne-Mance-Viger", "similarity": 0.913}, {"district": "Marguerite-Bourgeoys", "similarity": 0.86}, {"district": "Acadie", "similarity": 0.856}, {"district": "LaFontaine", "similarity": 0.821}, {"district": "Laval-des-Rapides", "similarity": 0.784}, {"district": "D'Arcy-McGee", "similarity": 0.775}, {"district": "Anjou-Louis-Riel", "similarity": 0.739}, {"district": "Saint-Laurent", "similarity": 0.734}, {"district": "Bourassa-Sauvé", "similarity": 0.725}, {"district": "Viau", "similarity": 0.699}], "Chutes-de-la-Chaudière": [{"district": "Verchères", "similarity": 0.967}, {"district": "Chauveau", "similarity": 0.924}, {"district": "Chambly", "similarity": 0.92}, {"district": "Borduas", "similarity": 0.913}, {"district": "Masson", "similarity": 0.867}, {"district": "Blainville", "similarity": 0.854}, {"district": "Terrebonne", "similarity": 0.854}, {"district": "Prévost", "similarity": 0.82}, {"district": "La Peltrie", "similarity": 0.814}, {"district": "Richmond", "similarity": 0.813}], "Côte-du-Sud": [{"district": "Rivière-du-Loup–Témiscouata–Les Basques", "similarity": 0.994}, {"district": "Labelle", "similarity": 0.988}, {"district": "Roberval", "similarity": 0.985}, {"district": "Mégantic", "similarity": 0.984}, {"district": "Gaspé", "similarity": 0.983}, {"district": "Champlain", "similarity": 0.977}, {"district": "Matane-Matapédia-Mitis", "similarity": 0.977}, {"district": "Lotbinière-Frontenac", "similarity": 0.975}, {"district": "Arthabaska–L'Érable", "similarity": 0.964}, {"district": "Berthier", "similarity": 0.963}], "Daniel-Johnson": [{"district": "Iberville", "similarity": 0.993}, {"district": "Beauce-Nord", "similarity": 0.986}, {"district": "Papineau", "similarity": 0.979}, {"district": "Rousseau", "similarity": 0.953}, {"district": "Deux-Montagnes", "similarity": 0.943}, {"district": "Bellechasse", "similarity": 0.942}, {"district": "Beauce-Sud", "similarity": 0.938}, {"district": "Portneuf", "similarity": 0.931}, {"district": "Dubuc", "similarity": 0.899}, {"district": "L'Assomption", "similarity": 0.889}], "D'Arcy-McGee": [{"district": "Marquette", "similarity": 0.965}, {"district": "Notre-Dame-de-Grâce", "similarity": 0.964}, {"district": "Saint-Laurent", "similarity": 0.925}, {"district": "Marguerite-Bourgeoys", "similarity": 0.912}, {"district": "Westmount-Saint-Louis", "similarity": 0.901}, {"district": "Pierre-Laporte", "similarity": 0.888}, {"district": "Acadie", "similarity": 0.851}, {"district": "Robert-Baldwin", "similarity": 0.848}, {"district": "Saint-Henri-Sainte-Anne", "similarity": 0.844}, {"district": "Mont-Royal-Outremont", "similarity": 0.824}], "Deux-Montagnes": [{"district": "Daniel-Johnson", "similarity": 0.943}, {"district": "Papineau", "similarity": 0.938}, {"district": "Iberville", "similarity": 0.935}, {"district": "Beauce-Nord", "similarity": 0.919}, {"district": "Rousseau", "similarity": 0.907}, {"district": "L'Assomption", "similarity": 0.9}, {"district": "Portneuf", "similarity": 0.893}, {"district": "Dubuc", "similarity": 0.879}, {"district": "Bellechasse", "similarity": 0.869}, {"district": "Beauce-Sud", "similarity": 0.84}], "Drummond-Bois-Francs": [{"district": "Arthabaska–L'Érable", "similarity": 0.99}, {"district": "Champlain", "similarity": 0.965}, {"district": "Beauharnois", "similarity": 0.962}, {"district": "Richelieu", "similarity": 0.959}, {"district": "Matane-Matapédia-Mitis", "similarity": 0.957}, {"district": "Rivière-du-Loup–Témiscouata–Les Basques", "similarity": 0.953}, {"district": "Roberval", "similarity": 0.953}, {"district": "Joliette", "similarity": 0.951}, {"district": "Lotbinière-Frontenac", "similarity": 0.939}, {"district": "Granby", "similarity": 0.931}], "Dubuc": [{"district": "Portneuf", "similarity": 0.978}, {"district": "Abitibi-Ouest", "similarity": 0.974}, {"district": "Lac-Saint-Jean", "similarity": 0.958}, {"district": "Maskinongé", "similarity": 0.948}, {"district": "Beauce-Nord", "similarity": 0.934}, {"district": "Bellechasse", "similarity": 0.924}, {"district": "René-Lévesque", "similarity": 0.921}, {"district": "Nicolet-Bécancour", "similarity": 0.915}, {"district": "Iberville", "similarity": 0.903}, {"district": "Daniel-Johnson", "similarity": 0.899}], "Duplessis": [{"district": "Abitibi-Est", "similarity": 0.706}, {"district": "Verchères", "similarity": 0.65}, {"district": "Chambly", "similarity": 0.638}, {"district": "Blainville", "similarity": 0.632}, {"district": "Borduas", "similarity": 0.63}, {"district": "Gatineau", "similarity": 0.622}, {"district": "Rouyn-Noranda-Témiscamingue", "similarity": 0.611}, {"district": "Ungava", "similarity": 0.595}, {"district": "Masson", "similarity": 0.585}, {"district": "La Prairie", "similarity": 0.563}], "Fabre": [{"district": "Mille-Îles", "similarity": 0.955}, {"district": "Vimont-Auteuil", "similarity": 0.949}, {"district": "Sainte-Rose", "similarity": 0.925}, {"district": "Vaudreuil", "similarity": 0.849}, {"district": "Nelligan", "similarity": 0.846}, {"district": "Pontiac", "similarity": 0.796}, {"district": "La Pinière", "similarity": 0.756}, {"district": "Vachon", "similarity": 0.742}, {"district": "Robert-Baldwin", "similarity": 0.742}, {"district": "Soulanges", "similarity": 0.722}], "Gaspé": [{"district": "Bonaventure", "similarity": 0.99}, {"district": "Mégantic", "similarity": 0.987}, {"district": "Côte-du-Sud", "similarity": 0.983}, {"district": "Labelle", "similarity": 0.98}, {"district": "Rivière-du-Loup–Témiscouata–Les Basques", "similarity": 0.965}, {"district": "Berthier", "similarity": 0.965}, {"district": "Matane-Matapédia-Mitis", "similarity": 0.963}, {"district": "Roberval", "similarity": 0.963}, {"district": "Lotbinière-Frontenac", "similarity": 0.962}, {"district": "Bertrand", "similarity": 0.961}], "Gatineau": [{"district": "Soulanges", "similarity": 0.917}, {"district": "Blainville", "similarity": 0.785}, {"district": "Pontiac", "similarity": 0.767}, {"district": "Chambly", "similarity": 0.756}, {"district": "La Prairie", "similarity": 0.74}, {"district": "Verchères", "similarity": 0.709}, {"district": "Borduas", "similarity": 0.703}, {"district": "Vimont-Auteuil", "similarity": 0.678}, {"district": "Montarville", "similarity": 0.654}, {"district": "Chutes-de-la-Chaudière", "similarity": 0.654}], "Gouin": [{"district": "Mercier", "similarity": 0.965}, {"district": "Sainte-Marie-Saint-Jacques", "similarity": 0.958}, {"district": "Hochelaga-Maisonneuve", "similarity": 0.903}, {"district": "Rosemont", "similarity": 0.877}, {"district": "Hull", "similarity": 0.871}, {"district": "Saint-Henri-Sainte-Anne", "similarity": 0.858}, {"district": "Verdun", "similarity": 0.855}, {"district": "Laurier-Dorion", "similarity": 0.847}, {"district": "Maurice-Richard", "similarity": 0.798}, {"district": "Mont-Royal-Outremont", "similarity": 0.771}], "Granby": [{"district": "Saint-Hyacinthe", "similarity": 0.985}, {"district": "Joliette", "similarity": 0.98}, {"district": "Beauharnois", "similarity": 0.943}, {"district": "Saint-Jérôme", "similarity": 0.938}, {"district": "Drummond-Bois-Francs", "similarity": 0.931}, {"district": "Laviolette-Saint-Maurice", "similarity": 0.925}, {"district": "Arthabaska–L'Érable", "similarity": 0.923}, {"district": "Champlain", "similarity": 0.899}, {"district": "Saint-François", "similarity": 0.875}, {"district": "Charlesbourg", "similarity": 0.852}], "Groulx": [{"district": "Abitibi-Est", "similarity": 0.722}, {"district": "Montarville", "similarity": 0.674}, {"district": "La Prairie", "similarity": 0.631}, {"district": "Borduas", "similarity": 0.608}, {"district": "Louis-Hébert", "similarity": 0.606}, {"district": "Chambly", "similarity": 0.59}, {"district": "Blainville", "similarity": 0.572}, {"district": "Verchères", "similarity": 0.559}, {"district": "Duplessis", "similarity": 0.537}, {"district": "Rouyn-Noranda-Témiscamingue", "similarity": 0.501}], "Hochelaga-Maisonneuve": [{"district": "Camille-Laurin", "similarity": 0.931}, {"district": "Gouin", "similarity": 0.903}, {"district": "Laurier-Dorion", "similarity": 0.888}, {"district": "Marie-Victorin", "similarity": 0.877}, {"district": "Sainte-Marie-Saint-Jacques", "similarity": 0.839}, {"district": "Rosemont", "similarity": 0.831}, {"district": "Mercier", "similarity": 0.794}, {"district": "Maurice-Richard", "similarity": 0.746}, {"district": "Viau", "similarity": 0.745}, {"district": "Saint-Henri-Sainte-Anne", "similarity": 0.733}], "Hull": [{"district": "Mercier", "similarity": 0.96}, {"district": "Sainte-Marie-Saint-Jacques", "similarity": 0.959}, {"district": "Mont-Royal-Outremont", "similarity": 0.952}, {"district": "Saint-Henri-Sainte-Anne", "similarity": 0.948}, {"district": "Verdun", "similarity": 0.943}, {"district": "Westmount-Saint-Louis", "similarity": 0.91}, {"district": "Gouin", "similarity": 0.871}, {"district": "Notre-Dame-de-Grâce", "similarity": 0.842}, {"district": "Saint-Laurent", "similarity": 0.822}, {"district": "Laurier-Dorion", "similarity": 0.799}], "Huntingdon": [{"district": "Papineau", "similarity": 0.879}, {"district": "Daniel-Johnson", "similarity": 0.845}, {"district": "Deux-Montagnes", "similarity": 0.818}, {"district": "Beauce-Nord", "similarity": 0.809}, {"district": "Bellechasse", "similarity": 0.798}, {"district": "Iberville", "similarity": 0.791}, {"district": "Rousseau", "similarity": 0.777}, {"district": "Beauce-Sud", "similarity": 0.763}, {"district": "Portneuf", "similarity": 0.762}, {"district": "Argenteuil", "similarity": 0.757}], "Iberville": [{"district": "Daniel-Johnson", "similarity": 0.993}, {"district": "Beauce-Nord", "similarity": 0.974}, {"district": "Papineau", "similarity": 0.973}, {"district": "Rousseau", "similarity": 0.963}, {"district": "Deux-Montagnes", "similarity": 0.935}, {"district": "Beauce-Sud", "similarity": 0.928}, {"district": "Portneuf", "similarity": 0.918}, {"district": "Bellechasse", "similarity": 0.918}, {"district": "L'Assomption", "similarity": 0.917}, {"district": "Dubuc", "similarity": 0.903}], "Îles-de-la-Madeleine": [{"district": "Charlevoix-Côte-de-Beaupré", "similarity": 0.96}, {"district": "Bertrand", "similarity": 0.959}, {"district": "Labelle", "similarity": 0.942}, {"district": "Maskinongé", "similarity": 0.928}, {"district": "Gaspé", "similarity": 0.92}, {"district": "Bonaventure", "similarity": 0.917}, {"district": "Berthier", "similarity": 0.904}, {"district": "Nicolet-Bécancour", "similarity": 0.897}, {"district": "Richelieu", "similarity": 0.896}, {"district": "Argenteuil", "similarity": 0.894}], "Jacques-Cartier": [{"district": "Nelligan", "similarity": 0.923}, {"district": "Pontiac", "similarity": 0.898}, {"district": "Robert-Baldwin", "similarity": 0.866}, {"district": "Vaudreuil", "similarity": 0.825}, {"district": "Notre-Dame-de-Grâce", "similarity": 0.774}, {"district": "Westmount-Saint-Louis", "similarity": 0.745}, {"district": "La Pinière", "similarity": 0.73}, {"district": "Marquette", "similarity": 0.726}, {"district": "Pierre-Laporte", "similarity": 0.696}, {"district": "D'Arcy-McGee", "similarity": 0.695}], "Jean-Lesage": [{"district": "Sherbrooke", "similarity": 0.936}, {"district": "Marie-Victorin", "similarity": 0.871}, {"district": "Saint-Jérôme", "similarity": 0.814}, {"district": "Trois-Rivières", "similarity": 0.776}, {"district": "Taschereau", "similarity": 0.758}, {"district": "Saint-François", "similarity": 0.751}, {"district": "Vanier-Les Rivières", "similarity": 0.742}, {"district": "Camille-Laurin", "similarity": 0.73}, {"district": "Rosemont", "similarity": 0.68}, {"district": "Saint-Hyacinthe", "similarity": 0.672}], "Jean-Talon": [{"district": "Taschereau", "similarity": 0.878}, {"district": "Taillon", "similarity": 0.863}, {"district": "Rosemont", "similarity": 0.787}, {"district": "Maurice-Richard", "similarity": 0.772}, {"district": "Gouin", "similarity": 0.731}, {"district": "Verdun", "similarity": 0.715}, {"district": "Mercier", "similarity": 0.704}, {"district": "Mont-Royal-Outremont", "similarity": 0.682}, {"district": "Sherbrooke", "similarity": 0.672}, {"district": "Sainte-Marie-Saint-Jacques", "similarity": 0.667}], "Jeanne-Mance-Viger": [{"district": "Acadie", "similarity": 0.942}, {"district": "Marguerite-Bourgeoys", "similarity": 0.932}, {"district": "Laval-des-Rapides", "similarity": 0.924}, {"district": "Anjou-Louis-Riel", "similarity": 0.916}, {"district": "Chomedey", "similarity": 0.913}, {"district": "Bourassa-Sauvé", "similarity": 0.899}, {"district": "Viau", "similarity": 0.883}, {"district": "D'Arcy-McGee", "similarity": 0.806}, {"district": "Laurier-Dorion", "similarity": 0.782}, {"district": "Saint-Laurent", "similarity": 0.763}], "Joliette": [{"district": "Granby", "similarity": 0.98}, {"district": "Saint-Hyacinthe", "similarity": 0.956}, {"district": "Drummond-Bois-Francs", "similarity": 0.951}, {"district": "Laviolette-Saint-Maurice", "similarity": 0.947}, {"district": "Champlain", "similarity": 0.947}, {"district": "Arthabaska–L'Érable", "similarity": 0.943}, {"district": "Beauharnois", "similarity": 0.917}, {"district": "Richelieu", "similarity": 0.907}, {"district": "Rivière-du-Loup–Témiscouata–Les Basques", "similarity": 0.906}, {"district": "Jonquière", "similarity": 0.887}], "Jonquière": [{"district": "Richelieu", "similarity": 0.921}, {"district": "Lac-Saint-Jean", "similarity": 0.917}, {"district": "Chicoutimi", "similarity": 0.913}, {"district": "Saint-Jean", "similarity": 0.907}, {"district": "Drummond-Bois-Francs", "similarity": 0.897}, {"district": "Champlain", "similarity": 0.89}, {"district": "Joliette", "similarity": 0.887}, {"district": "Rimouski", "similarity": 0.871}, {"district": "Arthabaska–L'Érable", "similarity": 0.866}, {"district": "Rivière-du-Loup–Témiscouata–Les Basques", "similarity": 0.86}], "La Peltrie": [{"district": "Chauveau", "similarity": 0.944}, {"district": "Montmorency", "similarity": 0.939}, {"district": "Richmond", "similarity": 0.935}, {"district": "L'Assomption", "similarity": 0.91}, {"district": "Bellefeuille", "similarity": 0.895}, {"district": "Mirabel", "similarity": 0.851}, {"district": "Terrebonne", "similarity": 0.821}, {"district": "Chutes-de-la-Chaudière", "similarity": 0.814}, {"district": "Les Plaines", "similarity": 0.812}, {"district": "Iberville", "similarity": 0.81}], "La Pinière": [{"district": "Saint-Laurent", "similarity": 0.877}, {"district": "Robert-Baldwin", "similarity": 0.831}, {"district": "Nelligan", "similarity": 0.827}, {"district": "Pierre-Laporte", "similarity": 0.794}, {"district": "D'Arcy-McGee", "similarity": 0.769}, {"district": "Fabre", "similarity": 0.756}, {"district": "Mille-Îles", "similarity": 0.751}, {"district": "Notre-Dame-de-Grâce", "similarity": 0.739}, {"district": "Mont-Royal-Outremont", "similarity": 0.738}, {"district": "Jacques-Cartier", "similarity": 0.73}], "La Prairie": [{"district": "Blainville", "similarity": 0.943}, {"district": "Chambly", "similarity": 0.897}, {"district": "Montarville", "similarity": 0.833}, {"district": "Verchères", "similarity": 0.775}, {"district": "Sainte-Rose", "similarity": 0.775}, {"district": "Gatineau", "similarity": 0.74}, {"district": "Chutes-de-la-Chaudière", "similarity": 0.713}, {"district": "Borduas", "similarity": 0.709}, {"district": "Fabre", "similarity": 0.689}, {"district": "Mille-Îles", "similarity": 0.637}], "Labelle": [{"district": "Côte-du-Sud", "similarity": 0.988}, {"district": "Rivière-du-Loup–Témiscouata–Les Basques", "similarity": 0.986}, {"district": "Bertrand", "similarity": 0.982}, {"district": "Gaspé", "similarity": 0.98}, {"district": "Champlain", "similarity": 0.968}, {"district": "Roberval", "similarity": 0.967}, {"district": "Mégantic", "similarity": 0.963}, {"district": "Richelieu", "similarity": 0.961}, {"district": "Bonaventure", "similarity": 0.96}, {"district": "Matane-Matapédia-Mitis", "similarity": 0.95}], "Lac-Saint-Jean": [{"district": "Maskinongé", "similarity": 0.972}, {"district": "Dubuc", "similarity": 0.958}, {"district": "Richelieu", "similarity": 0.954}, {"district": "Nicolet-Bécancour", "similarity": 0.953}, {"district": "Roberval", "similarity": 0.942}, {"district": "Charlevoix-Côte-de-Beaupré", "similarity": 0.936}, {"district": "Lotbinière-Frontenac", "similarity": 0.928}, {"district": "Portneuf", "similarity": 0.923}, {"district": "Abitibi-Ouest", "similarity": 0.923}, {"district": "Matane-Matapédia-Mitis", "similarity": 0.923}], "LaFontaine": [{"district": "Robert-Baldwin", "similarity": 0.86}, {"district": "Chomedey", "similarity": 0.821}, {"district": "Châteauguay", "similarity": 0.804}, {"district": "Vaudreuil", "similarity": 0.775}, {"district": "Nelligan", "similarity": 0.766}, {"district": "Marguerite-Bourgeoys", "similarity": 0.735}, {"district": "Marquette", "similarity": 0.698}, {"district": "D'Arcy-McGee", "similarity": 0.696}, {"district": "Saint-Laurent", "similarity": 0.689}, {"district": "Vimont-Auteuil", "similarity": 0.671}], "L'Assomption": [{"district": "Rousseau", "similarity": 0.941}, {"district": "Les Plaines", "similarity": 0.939}, {"district": "Bellefeuille", "similarity": 0.924}, {"district": "Richmond", "similarity": 0.917}, {"district": "Iberville", "similarity": 0.917}, {"district": "Papineau", "similarity": 0.912}, {"district": "Sanguinet", "similarity": 0.911}, {"district": "La Peltrie", "similarity": 0.91}, {"district": "Deux-Montagnes", "similarity": 0.9}, {"district": "Daniel-Johnson", "similarity": 0.889}], "Laurier-Dorion": [{"district": "Sainte-Marie-Saint-Jacques", "similarity": 0.902}, {"district": "Hochelaga-Maisonneuve", "similarity": 0.888}, {"district": "Saint-Henri-Sainte-Anne", "similarity": 0.884}, {"district": "Viau", "similarity": 0.873}, {"district": "Camille-Laurin", "similarity": 0.871}, {"district": "Acadie", "similarity": 0.866}, {"district": "Gouin", "similarity": 0.847}, {"district": "Rosemont", "similarity": 0.844}, {"district": "Anjou-Louis-Riel", "similarity": 0.83}, {"district": "Mercier", "similarity": 0.828}], "Laval-des-Rapides": [{"district": "Anjou-Louis-Riel", "similarity": 0.981}, {"district": "Jeanne-Mance-Viger", "similarity": 0.924}, {"district": "Acadie", "similarity": 0.901}, {"district": "Bourassa-Sauvé", "similarity": 0.9}, {"district": "Viau", "similarity": 0.877}, {"district": "Maurice-Richard", "similarity": 0.856}, {"district": "Marie-Victorin", "similarity": 0.82}, {"district": "Chomedey", "similarity": 0.784}, {"district": "Rosemont", "similarity": 0.784}, {"district": "Camille-Laurin", "similarity": 0.779}], "Laviolette-Saint-Maurice": [{"district": "Champlain", "similarity": 0.955}, {"district": "Arthabaska–L'Érable", "similarity": 0.95}, {"district": "Joliette", "similarity": 0.947}, {"district": "Rivière-du-Loup–Témiscouata–Les Basques", "similarity": 0.938}, {"district": "Drummond-Bois-Francs", "similarity": 0.928}, {"district": "Granby", "similarity": 0.925}, {"district": "Côte-du-Sud", "similarity": 0.924}, {"district": "Richelieu", "similarity": 0.914}, {"district": "Roberval", "similarity": 0.907}, {"district": "Labelle", "similarity": 0.903}], "Les Plaines": [{"district": "L'Assomption", "similarity": 0.939}, {"district": "Bellefeuille", "similarity": 0.932}, {"district": "Rousseau", "similarity": 0.912}, {"district": "Sanguinet", "similarity": 0.902}, {"district": "Mirabel", "similarity": 0.873}, {"district": "La Peltrie", "similarity": 0.812}, {"district": "Papineau", "similarity": 0.812}, {"district": "Iberville", "similarity": 0.801}, {"district": "Chapleau", "similarity": 0.798}, {"district": "Deux-Montagnes", "similarity": 0.788}], "Lévis": [{"district": "Chicoutimi", "similarity": 0.977}, {"district": "Vanier-Les Rivières", "similarity": 0.944}, {"district": "Trois-Rivières", "similarity": 0.942}, {"district": "Charlesbourg", "similarity": 0.939}, {"district": "Joliette", "similarity": 0.822}, {"district": "Jonquière", "similarity": 0.812}, {"district": "Saint-Hyacinthe", "similarity": 0.766}, {"district": "Granby", "similarity": 0.756}, {"district": "Saint-Jérôme", "similarity": 0.738}, {"district": "Champlain", "similarity": 0.727}], "Lotbinière-Frontenac": [{"district": "Matane-Matapédia-Mitis", "similarity": 0.997}, {"district": "Roberval", "similarity": 0.995}, {"district": "Nicolet-Bécancour", "similarity": 0.987}, {"district": "Mégantic", "similarity": 0.987}, {"district": "Berthier", "similarity": 0.98}, {"district": "Côte-du-Sud", "similarity": 0.975}, {"district": "Rivière-du-Loup–Témiscouata–Les Basques", "similarity": 0.969}, {"district": "Bellechasse", "similarity": 0.965}, {"district": "Gaspé", "similarity": 0.962}, {"district": "Arthabaska–L'Érable", "similarity": 0.961}], "Louis-Hébert": [{"district": "Montarville", "similarity": 0.937}, {"district": "Borduas", "similarity": 0.767}, {"district": "La Prairie", "similarity": 0.626}, {"district": "Groulx", "similarity": 0.606}, {"district": "Chutes-de-la-Chaudière", "similarity": 0.568}, {"district": "Jean-Talon", "similarity": 0.563}, {"district": "Orford", "similarity": 0.542}, {"district": "Chambly", "similarity": 0.51}, {"district": "Blainville", "similarity": 0.506}, {"district": "Verchères", "similarity": 0.487}], "Marguerite-Bourgeoys": [{"district": "Jeanne-Mance-Viger", "similarity": 0.932}, {"district": "D'Arcy-McGee", "similarity": 0.912}, {"district": "Marquette", "similarity": 0.904}, {"district": "Acadie", "similarity": 0.865}, {"district": "Chomedey", "similarity": 0.86}, {"district": "Notre-Dame-de-Grâce", "similarity": 0.81}, {"district": "Saint-Laurent", "similarity": 0.791}, {"district": "Anjou-Louis-Riel", "similarity": 0.764}, {"district": "Laval-des-Rapides", "similarity": 0.76}, {"district": "Laurier-Dorion", "similarity": 0.754}], "Marie-Lacoste-Gérin-Lajoie": [{"district": "Beauce-Sud", "similarity": 0.891}, {"district": "Rousseau", "similarity": 0.89}, {"district": "Iberville", "similarity": 0.889}, {"district": "Chapleau", "similarity": 0.881}, {"district": "Daniel-Johnson", "similarity": 0.864}, {"district": "Beauharnois", "similarity": 0.862}, {"district": "Beauce-Nord", "similarity": 0.819}, {"district": "Drummond-Bois-Francs", "similarity": 0.803}, {"district": "Papineau", "similarity": 0.801}, {"district": "Montmorency", "similarity": 0.795}], "Marie-Victorin": [{"district": "Camille-Laurin", "similarity": 0.963}, {"district": "Hochelaga-Maisonneuve", "similarity": 0.877}, {"district": "Jean-Lesage", "similarity": 0.871}, {"district": "Bourassa-Sauvé", "similarity": 0.854}, {"district": "Viau", "similarity": 0.849}, {"district": "Rosemont", "similarity": 0.84}, {"district": "Anjou-Louis-Riel", "similarity": 0.826}, {"district": "Laval-des-Rapides", "similarity": 0.82}, {"district": "Laurier-Dorion", "similarity": 0.811}, {"district": "Maurice-Richard", "similarity": 0.81}], "Marquette": [{"district": "D'Arcy-McGee", "similarity": 0.965}, {"district": "Notre-Dame-de-Grâce", "similarity": 0.962}, {"district": "Marguerite-Bourgeoys", "similarity": 0.904}, {"district": "Westmount-Saint-Louis", "similarity": 0.876}, {"district": "Robert-Baldwin", "similarity": 0.848}, {"district": "Saint-Laurent", "similarity": 0.839}, {"district": "Saint-Henri-Sainte-Anne", "similarity": 0.835}, {"district": "Pierre-Laporte", "similarity": 0.797}, {"district": "Verdun", "similarity": 0.765}, {"district": "Nelligan", "similarity": 0.759}], "Maskinongé": [{"district": "Nicolet-Bécancour", "similarity": 0.985}, {"district": "Lac-Saint-Jean", "similarity": 0.972}, {"district": "Bellechasse", "similarity": 0.965}, {"district": "Charlevoix-Côte-de-Beaupré", "similarity": 0.963}, {"district": "Portneuf", "similarity": 0.961}, {"district": "Roberval", "similarity": 0.952}, {"district": "Lotbinière-Frontenac", "similarity": 0.952}, {"district": "Dubuc", "similarity": 0.948}, {"district": "Berthier", "similarity": 0.947}, {"district": "Matane-Matapédia-Mitis", "similarity": 0.942}], "Masson": [{"district": "Terrebonne", "similarity": 0.986}, {"district": "Verchères", "similarity": 0.944}, {"district": "Mirabel", "similarity": 0.931}, {"district": "Chauveau", "similarity": 0.924}, {"district": "Sanguinet", "similarity": 0.919}, {"district": "Bellefeuille", "similarity": 0.887}, {"district": "Chambly", "similarity": 0.88}, {"district": "Chutes-de-la-Chaudière", "similarity": 0.867}, {"district": "Blainville", "similarity": 0.835}, {"district": "L'Assomption", "similarity": 0.825}], "Matane-Matapédia-Mitis": [{"district": "Lotbinière-Frontenac", "similarity": 0.997}, {"district": "Roberval", "similarity": 0.994}, {"district": "Mégantic", "similarity": 0.985}, {"district": "Nicolet-Bécancour", "similarity": 0.98}, {"district": "Côte-du-Sud", "similarity": 0.977}, {"district": "Berthier", "similarity": 0.977}, {"district": "Rivière-du-Loup–Témiscouata–Les Basques", "similarity": 0.974}, {"district": "Arthabaska–L'Érable", "similarity": 0.974}, {"district": "Gaspé", "similarity": 0.963}, {"district": "Beauce-Sud", "similarity": 0.962}], "Maurice-Richard": [{"district": "Rosemont", "similarity": 0.983}, {"district": "Taillon", "similarity": 0.917}, {"district": "Anjou-Louis-Riel", "similarity": 0.905}, {"district": "Laval-des-Rapides", "similarity": 0.856}, {"district": "Taschereau", "similarity": 0.831}, {"district": "Laurier-Dorion", "similarity": 0.824}, {"district": "Verdun", "similarity": 0.813}, {"district": "Marie-Victorin", "similarity": 0.81}, {"district": "Gouin", "similarity": 0.798}, {"district": "Acadie", "similarity": 0.793}], "Mégantic": [{"district": "Gaspé", "similarity": 0.987}, {"district": "Lotbinière-Frontenac", "similarity": 0.987}, {"district": "Matane-Matapédia-Mitis", "similarity": 0.985}, {"district": "Côte-du-Sud", "similarity": 0.984}, {"district": "Roberval", "similarity": 0.983}, {"district": "Berthier", "similarity": 0.974}, {"district": "Rivière-du-Loup–Témiscouata–Les Basques", "similarity": 0.968}, {"district": "Labelle", "similarity": 0.963}, {"district": "Bonaventure", "similarity": 0.963}, {"district": "Nicolet-Bécancour", "similarity": 0.958}], "Mercier": [{"district": "Sainte-Marie-Saint-Jacques", "similarity": 0.984}, {"district": "Gouin", "similarity": 0.965}, {"district": "Hull", "similarity": 0.96}, {"district": "Verdun", "similarity": 0.934}, {"district": "Saint-Henri-Sainte-Anne", "similarity": 0.933}, {"district": "Mont-Royal-Outremont", "similarity": 0.888}, {"district": "Westmount-Saint-Louis", "similarity": 0.831}, {"district": "Laurier-Dorion", "similarity": 0.828}, {"district": "Rosemont", "similarity": 0.807}, {"district": "Hochelaga-Maisonneuve", "similarity": 0.794}], "Mille-Îles": [{"district": "Vimont-Auteuil", "similarity": 0.985}, {"district": "Fabre", "similarity": 0.955}, {"district": "Sainte-Rose", "similarity": 0.941}, {"district": "Vachon", "similarity": 0.851}, {"district": "Nelligan", "similarity": 0.778}, {"district": "Vaudreuil", "similarity": 0.777}, {"district": "La Pinière", "similarity": 0.751}, {"district": "Pontiac", "similarity": 0.689}, {"district": "Soulanges", "similarity": 0.68}, {"district": "Robert-Baldwin", "similarity": 0.675}], "Mirabel": [{"district": "Sanguinet", "similarity": 0.982}, {"district": "Bellefeuille", "similarity": 0.98}, {"district": "Chauveau", "similarity": 0.931}, {"district": "Masson", "similarity": 0.931}, {"district": "Terrebonne", "similarity": 0.928}, {"district": "L'Assomption", "similarity": 0.881}, {"district": "Les Plaines", "similarity": 0.873}, {"district": "Verchères", "similarity": 0.852}, {"district": "La Peltrie", "similarity": 0.851}, {"district": "Richmond", "similarity": 0.831}], "Mont-Royal-Outremont": [{"district": "Verdun", "similarity": 0.967}, {"district": "Westmount-Saint-Louis", "similarity": 0.958}, {"district": "Hull", "similarity": 0.952}, {"district": "Pierre-Laporte", "similarity": 0.931}, {"district": "Saint-Henri-Sainte-Anne", "similarity": 0.908}, {"district": "Mercier", "similarity": 0.888}, {"district": "Notre-Dame-de-Grâce", "similarity": 0.887}, {"district": "Sainte-Marie-Saint-Jacques", "similarity": 0.884}, {"district": "Saint-Laurent", "similarity": 0.878}, {"district": "D'Arcy-McGee", "similarity": 0.824}], "Montarville": [{"district": "Louis-Hébert", "similarity": 0.937}, {"district": "La Prairie", "similarity": 0.833}, {"district": "Borduas", "similarity": 0.82}, {"district": "Blainville", "similarity": 0.724}, {"district": "Chambly", "similarity": 0.697}, {"district": "Groulx", "similarity": 0.674}, {"district": "Gatineau", "similarity": 0.654}, {"district": "Chutes-de-la-Chaudière", "similarity": 0.642}, {"district": "Verchères", "similarity": 0.632}, {"district": "Duplessis", "similarity": 0.518}], "Montmorency": [{"district": "La Peltrie", "similarity": 0.939}, {"district": "Richmond", "similarity": 0.89}, {"district": "L'Assomption", "similarity": 0.876}, {"district": "Iberville", "similarity": 0.875}, {"district": "Beauce-Nord", "similarity": 0.844}, {"district": "Daniel-Johnson", "similarity": 0.832}, {"district": "Chauveau", "similarity": 0.822}, {"district": "Dubuc", "similarity": 0.821}, {"district": "Portneuf", "similarity": 0.817}, {"district": "Rousseau", "similarity": 0.815}], "Nelligan": [{"district": "Robert-Baldwin", "similarity": 0.967}, {"district": "Vaudreuil", "similarity": 0.947}, {"district": "Jacques-Cartier", "similarity": 0.923}, {"district": "Pontiac", "similarity": 0.908}, {"district": "Fabre", "similarity": 0.846}, {"district": "La Pinière", "similarity": 0.827}, {"district": "Vimont-Auteuil", "similarity": 0.824}, {"district": "Notre-Dame-de-Grâce", "similarity": 0.78}, {"district": "Mille-Îles", "similarity": 0.778}, {"district": "LaFontaine", "similarity": 0.766}], "Nicolet-Bécancour": [{"district": "Lotbinière-Frontenac", "similarity": 0.987}, {"district": "Bellechasse", "similarity": 0.986}, {"district": "Maskinongé", "similarity": 0.985}, {"district": "Matane-Matapédia-Mitis", "similarity": 0.98}, {"district": "Roberval", "similarity": 0.98}, {"district": "Berthier", "similarity": 0.974}, {"district": "Beauce-Sud", "similarity": 0.96}, {"district": "Mégantic", "similarity": 0.958}, {"district": "Lac-Saint-Jean", "similarity": 0.953}, {"district": "Côte-du-Sud", "similarity": 0.946}], "Notre-Dame-de-Grâce": [{"district": "Westmount-Saint-Louis", "similarity": 0.971}, {"district": "D'Arcy-McGee", "similarity": 0.964}, {"district": "Marquette", "similarity": 0.962}, {"district": "Saint-Henri-Sainte-Anne", "similarity": 0.901}, {"district": "Saint-Laurent", "similarity": 0.898}, {"district": "Pierre-Laporte", "similarity": 0.892}, {"district": "Mont-Royal-Outremont", "similarity": 0.887}, {"district": "Verdun", "similarity": 0.879}, {"district": "Hull", "similarity": 0.842}, {"district": "Robert-Baldwin", "similarity": 0.828}], "Orford": [{"district": "Brome-Missisquoi", "similarity": 0.948}, {"district": "Bertrand", "similarity": 0.845}, {"district": "Argenteuil", "similarity": 0.832}, {"district": "Îles-de-la-Madeleine", "similarity": 0.822}, {"district": "Charlevoix-Côte-de-Beaupré", "similarity": 0.766}, {"district": "Labelle", "similarity": 0.76}, {"district": "Bonaventure", "similarity": 0.758}, {"district": "Gaspé", "similarity": 0.711}, {"district": "Côte-du-Sud", "similarity": 0.672}, {"district": "Rivière-du-Loup–Témiscouata–Les Basques", "similarity": 0.662}], "Papineau": [{"district": "Daniel-Johnson", "similarity": 0.979}, {"district": "Iberville", "similarity": 0.973}, {"district": "Rousseau", "similarity": 0.959}, {"district": "Beauce-Nord", "similarity": 0.947}, {"district": "Deux-Montagnes", "similarity": 0.938}, {"district": "L'Assomption", "similarity": 0.912}, {"district": "Portneuf", "similarity": 0.894}, {"district": "Richmond", "similarity": 0.882}, {"district": "Huntingdon", "similarity": 0.879}, {"district": "Bellechasse", "similarity": 0.874}], "Pierre-Laporte": [{"district": "Mont-Royal-Outremont", "similarity": 0.931}, {"district": "Westmount-Saint-Louis", "similarity": 0.927}, {"district": "Notre-Dame-de-Grâce", "similarity": 0.892}, {"district": "Verdun", "similarity": 0.89}, {"district": "D'Arcy-McGee", "similarity": 0.888}, {"district": "Saint-Laurent", "similarity": 0.864}, {"district": "Marquette", "similarity": 0.797}, {"district": "Hull", "similarity": 0.795}, {"district": "La Pinière", "similarity": 0.794}, {"district": "Saint-Henri-Sainte-Anne", "similarity": 0.794}], "Pointe-aux-Trembles": [{"district": "Chapleau", "similarity": 0.808}, {"district": "Camille-Laurin", "similarity": 0.741}, {"district": "Marie-Victorin", "similarity": 0.726}, {"district": "Bourassa-Sauvé", "similarity": 0.701}, {"district": "Marie-Lacoste-Gérin-Lajoie", "similarity": 0.664}, {"district": "Viau", "similarity": 0.651}, {"district": "Jean-Lesage", "similarity": 0.647}, {"district": "Saint-François", "similarity": 0.608}, {"district": "Hochelaga-Maisonneuve", "similarity": 0.579}, {"district": "Les Plaines", "similarity": 0.545}], "Pontiac": [{"district": "Vaudreuil", "similarity": 0.94}, {"district": "Nelligan", "similarity": 0.908}, {"district": "Jacques-Cartier", "similarity": 0.898}, {"district": "Soulanges", "similarity": 0.89}, {"district": "Robert-Baldwin", "similarity": 0.801}, {"district": "Fabre", "similarity": 0.796}, {"district": "Vimont-Auteuil", "similarity": 0.768}, {"district": "Gatineau", "similarity": 0.767}, {"district": "Mille-Îles", "similarity": 0.689}, {"district": "Châteauguay", "similarity": 0.666}], "Portneuf": [{"district": "Dubuc", "similarity": 0.978}, {"district": "Beauce-Nord", "similarity": 0.972}, {"district": "Bellechasse", "similarity": 0.962}, {"district": "Maskinongé", "similarity": 0.961}, {"district": "Nicolet-Bécancour", "similarity": 0.939}, {"district": "Daniel-Johnson", "similarity": 0.931}, {"district": "Lac-Saint-Jean", "similarity": 0.923}, {"district": "Iberville", "similarity": 0.918}, {"district": "Abitibi-Ouest", "similarity": 0.915}, {"district": "Prévost", "similarity": 0.912}], "Prévost": [{"district": "Portneuf", "similarity": 0.912}, {"district": "Richmond", "similarity": 0.911}, {"district": "Dubuc", "similarity": 0.899}, {"district": "Abitibi-Ouest", "similarity": 0.886}, {"district": "Chauveau", "similarity": 0.855}, {"district": "Borduas", "similarity": 0.838}, {"district": "Beauce-Nord", "similarity": 0.825}, {"district": "Rouyn-Noranda-Témiscamingue", "similarity": 0.824}, {"district": "Chutes-de-la-Chaudière", "similarity": 0.82}, {"district": "Masson", "similarity": 0.812}], "René-Lévesque": [{"district": "Lac-Saint-Jean", "similarity": 0.922}, {"district": "Dubuc", "similarity": 0.921}, {"district": "Maskinongé", "similarity": 0.917}, {"district": "Abitibi-Ouest", "similarity": 0.913}, {"district": "Berthier", "similarity": 0.9}, {"district": "Portneuf", "similarity": 0.894}, {"district": "Charlevoix-Côte-de-Beaupré", "similarity": 0.889}, {"district": "Nicolet-Bécancour", "similarity": 0.884}, {"district": "Îles-de-la-Madeleine", "similarity": 0.884}, {"district": "Richelieu", "similarity": 0.865}], "Repentigny": [{"district": "Abitibi-Ouest", "similarity": 0.832}, {"district": "Dubuc", "similarity": 0.808}, {"district": "Prévost", "similarity": 0.805}, {"district": "Charlevoix-Côte-de-Beaupré", "similarity": 0.804}, {"district": "Lac-Saint-Jean", "similarity": 0.788}, {"district": "Portneuf", "similarity": 0.764}, {"district": "Maskinongé", "similarity": 0.761}, {"district": "Borduas", "similarity": 0.758}, {"district": "René-Lévesque", "similarity": 0.752}, {"district": "Rouyn-Noranda-Témiscamingue", "similarity": 0.718}], "Richelieu": [{"district": "Champlain", "similarity": 0.974}, {"district": "Rivière-du-Loup–Témiscouata–Les Basques", "similarity": 0.973}, {"district": "Roberval", "similarity": 0.969}, {"district": "Arthabaska–L'Érable", "similarity": 0.961}, {"district": "Labelle", "similarity": 0.961}, {"district": "Drummond-Bois-Francs", "similarity": 0.959}, {"district": "Lac-Saint-Jean", "similarity": 0.954}, {"district": "Côte-du-Sud", "similarity": 0.953}, {"district": "Matane-Matapédia-Mitis", "similarity": 0.953}, {"district": "Lotbinière-Frontenac", "similarity": 0.945}], "Richmond": [{"district": "Chauveau", "similarity": 0.943}, {"district": "La Peltrie", "similarity": 0.935}, {"district": "L'Assomption", "similarity": 0.917}, {"district": "Prévost", "similarity": 0.911}, {"district": "Montmorency", "similarity": 0.89}, {"district": "Papineau", "similarity": 0.882}, {"district": "Portneuf", "similarity": 0.874}, {"district": "Iberville", "similarity": 0.874}, {"district": "Beauce-Nord", "similarity": 0.87}, {"district": "Daniel-Johnson", "similarity": 0.86}], "Rimouski": [{"district": "Drummond-Bois-Francs", "similarity": 0.893}, {"district": "Maskinongé", "similarity": 0.882}, {"district": "Nicolet-Bécancour", "similarity": 0.881}, {"district": "Arthabaska–L'Érable", "similarity": 0.878}, {"district": "Lac-Saint-Jean", "similarity": 0.875}, {"district": "Champlain", "similarity": 0.875}, {"district": "Rivière-du-Loup–Témiscouata–Les Basques", "similarity": 0.872}, {"district": "Roberval", "similarity": 0.872}, {"district": "Jonquière", "similarity": 0.871}, {"district": "Matane-Matapédia-Mitis", "similarity": 0.866}], "Rivière-du-Loup–Témiscouata–Les Basques": [{"district": "Côte-du-Sud", "similarity": 0.994}, {"district": "Champlain", "similarity": 0.993}, {"district": "Roberval", "similarity": 0.986}, {"district": "Labelle", "similarity": 0.986}, {"district": "Arthabaska–L'Érable", "similarity": 0.977}, {"district": "Matane-Matapédia-Mitis", "similarity": 0.974}, {"district": "Richelieu", "similarity": 0.973}, {"district": "Lotbinière-Frontenac", "similarity": 0.969}, {"district": "Mégantic", "similarity": 0.968}, {"district": "Gaspé", "similarity": 0.965}], "Robert-Baldwin": [{"district": "Nelligan", "similarity": 0.967}, {"district": "Vaudreuil", "similarity": 0.894}, {"district": "Jacques-Cartier", "similarity": 0.866}, {"district": "LaFontaine", "similarity": 0.86}, {"district": "D'Arcy-McGee", "similarity": 0.848}, {"district": "Marquette", "similarity": 0.848}, {"district": "La Pinière", "similarity": 0.831}, {"district": "Notre-Dame-de-Grâce", "similarity": 0.828}, {"district": "Saint-Laurent", "similarity": 0.802}, {"district": "Pontiac", "similarity": 0.801}], "Roberval": [{"district": "Lotbinière-Frontenac", "similarity": 0.995}, {"district": "Matane-Matapédia-Mitis", "similarity": 0.994}, {"district": "Rivière-du-Loup–Témiscouata–Les Basques", "similarity": 0.986}, {"district": "Côte-du-Sud", "similarity": 0.985}, {"district": "Mégantic", "similarity": 0.983}, {"district": "Nicolet-Bécancour", "similarity": 0.98}, {"district": "Berthier", "similarity": 0.976}, {"district": "Arthabaska–L'Érable", "similarity": 0.974}, {"district": "Richelieu", "similarity": 0.969}, {"district": "Champlain", "similarity": 0.968}], "Rosemont": [{"district": "Maurice-Richard", "similarity": 0.983}, {"district": "Taillon", "similarity": 0.915}, {"district": "Gouin", "similarity": 0.877}, {"district": "Anjou-Louis-Riel", "similarity": 0.849}, {"district": "Laurier-Dorion", "similarity": 0.844}, {"district": "Taschereau", "similarity": 0.84}, {"district": "Marie-Victorin", "similarity": 0.84}, {"district": "Sainte-Marie-Saint-Jacques", "similarity": 0.838}, {"district": "Camille-Laurin", "similarity": 0.837}, {"district": "Hochelaga-Maisonneuve", "similarity": 0.831}], "Rousseau": [{"district": "Iberville", "similarity": 0.963}, {"district": "Papineau", "similarity": 0.959}, {"district": "Daniel-Johnson", "similarity": 0.953}, {"district": "L'Assomption", "similarity": 0.941}, {"district": "Les Plaines", "similarity": 0.912}, {"district": "Deux-Montagnes", "similarity": 0.907}, {"district": "Beauce-Nord", "similarity": 0.898}, {"district": "Marie-Lacoste-Gérin-Lajoie", "similarity": 0.89}, {"district": "Beauce-Sud", "similarity": 0.835}, {"district": "Richmond", "similarity": 0.83}], "Rouyn-Noranda-Témiscamingue": [{"district": "Abitibi-Ouest", "similarity": 0.943}, {"district": "Abitibi-Est", "similarity": 0.923}, {"district": "Dubuc", "similarity": 0.873}, {"district": "Prévost", "similarity": 0.824}, {"district": "Lac-Saint-Jean", "similarity": 0.805}, {"district": "René-Lévesque", "similarity": 0.794}, {"district": "Portneuf", "similarity": 0.775}, {"district": "Jonquière", "similarity": 0.76}, {"district": "Saint-Jean", "similarity": 0.742}, {"district": "Borduas", "similarity": 0.742}], "Saint-François": [{"district": "Saint-Jérôme", "similarity": 0.902}, {"district": "Granby", "similarity": 0.875}, {"district": "Saint-Hyacinthe", "similarity": 0.849}, {"district": "Beauharnois", "similarity": 0.816}, {"district": "Joliette", "similarity": 0.799}, {"district": "Jean-Lesage", "similarity": 0.751}, {"district": "Laviolette-Saint-Maurice", "similarity": 0.751}, {"district": "Arthabaska–L'Érable", "similarity": 0.741}, {"district": "Drummond-Bois-Francs", "similarity": 0.739}, {"district": "Marie-Lacoste-Gérin-Lajoie", "similarity": 0.718}], "Saint-Henri-Sainte-Anne": [{"district": "Verdun", "similarity": 0.955}, {"district": "Sainte-Marie-Saint-Jacques", "similarity": 0.952}, {"district": "Hull", "similarity": 0.948}, {"district": "Mercier", "similarity": 0.933}, {"district": "Westmount-Saint-Louis", "similarity": 0.917}, {"district": "Mont-Royal-Outremont", "similarity": 0.908}, {"district": "Notre-Dame-de-Grâce", "similarity": 0.901}, {"district": "Laurier-Dorion", "similarity": 0.884}, {"district": "Gouin", "similarity": 0.858}, {"district": "Saint-Laurent", "similarity": 0.846}], "Saint-Hyacinthe": [{"district": "Granby", "similarity": 0.985}, {"district": "Joliette", "similarity": 0.956}, {"district": "Saint-Jérôme", "similarity": 0.945}, {"district": "Beauharnois", "similarity": 0.92}, {"district": "Drummond-Bois-Francs", "similarity": 0.893}, {"district": "Saint-Jean", "similarity": 0.867}, {"district": "Arthabaska–L'Érable", "similarity": 0.866}, {"district": "Laviolette-Saint-Maurice", "similarity": 0.866}, {"district": "Charlesbourg", "similarity": 0.86}, {"district": "Saint-François", "similarity": 0.849}], "Saint-Jean": [{"district": "Jonquière", "similarity": 0.907}, {"district": "Beauharnois", "similarity": 0.873}, {"district": "Saint-Hyacinthe", "similarity": 0.867}, {"district": "Drummond-Bois-Francs", "similarity": 0.846}, {"district": "Granby", "similarity": 0.823}, {"district": "Joliette", "similarity": 0.821}, {"district": "Lac-Saint-Jean", "similarity": 0.802}, {"district": "Richelieu", "similarity": 0.783}, {"district": "Arthabaska–L'Érable", "similarity": 0.776}, {"district": "Rimouski", "similarity": 0.774}], "Saint-Jérôme": [{"district": "Saint-Hyacinthe", "similarity": 0.945}, {"district": "Granby", "similarity": 0.938}, {"district": "Saint-François", "similarity": 0.902}, {"district": "Joliette", "similarity": 0.884}, {"district": "Trois-Rivières", "similarity": 0.881}, {"district": "Charlesbourg", "similarity": 0.818}, {"district": "Jean-Lesage", "similarity": 0.814}, {"district": "Beauharnois", "similarity": 0.808}, {"district": "Laviolette-Saint-Maurice", "similarity": 0.808}, {"district": "Drummond-Bois-Francs", "similarity": 0.748}], "Saint-Laurent": [{"district": "D'Arcy-McGee", "similarity": 0.925}, {"district": "Notre-Dame-de-Grâce", "similarity": 0.898}, {"district": "Acadie", "similarity": 0.893}, {"district": "Mont-Royal-Outremont", "similarity": 0.878}, {"district": "La Pinière", "similarity": 0.877}, {"district": "Westmount-Saint-Louis", "similarity": 0.865}, {"district": "Pierre-Laporte", "similarity": 0.864}, {"district": "Saint-Henri-Sainte-Anne", "similarity": 0.846}, {"district": "Marquette", "similarity": 0.839}, {"district": "Hull", "similarity": 0.822}], "Sainte-Marie-Saint-Jacques": [{"district": "Mercier", "similarity": 0.984}, {"district": "Hull", "similarity": 0.959}, {"district": "Gouin", "similarity": 0.958}, {"district": "Saint-Henri-Sainte-Anne", "similarity": 0.952}, {"district": "Verdun", "similarity": 0.929}, {"district": "Laurier-Dorion", "similarity": 0.902}, {"district": "Mont-Royal-Outremont", "similarity": 0.884}, {"district": "Hochelaga-Maisonneuve", "similarity": 0.839}, {"district": "Rosemont", "similarity": 0.838}, {"district": "Westmount-Saint-Louis", "similarity": 0.833}], "Sainte-Rose": [{"district": "Mille-Îles", "similarity": 0.941}, {"district": "Fabre", "similarity": 0.925}, {"district": "Vimont-Auteuil", "similarity": 0.902}, {"district": "Vachon", "similarity": 0.885}, {"district": "Blainville", "similarity": 0.777}, {"district": "La Prairie", "similarity": 0.775}, {"district": "Chambly", "similarity": 0.688}, {"district": "Gatineau", "similarity": 0.648}, {"district": "Soulanges", "similarity": 0.64}, {"district": "Vaudreuil", "similarity": 0.633}], "Sanguinet": [{"district": "Mirabel", "similarity": 0.982}, {"district": "Bellefeuille", "similarity": 0.961}, {"district": "Masson", "similarity": 0.919}, {"district": "Terrebonne", "similarity": 0.915}, {"district": "L'Assomption", "similarity": 0.911}, {"district": "Les Plaines", "similarity": 0.902}, {"district": "Chauveau", "similarity": 0.893}, {"district": "Richmond", "similarity": 0.824}, {"district": "La Peltrie", "similarity": 0.808}, {"district": "Verchères", "similarity": 0.794}], "Sherbrooke": [{"district": "Jean-Lesage", "similarity": 0.936}, {"district": "Taschereau", "similarity": 0.921}, {"district": "Vanier-Les Rivières", "similarity": 0.824}, {"district": "Marie-Victorin", "similarity": 0.808}, {"district": "Trois-Rivières", "similarity": 0.803}, {"district": "Rosemont", "similarity": 0.779}, {"district": "Maurice-Richard", "similarity": 0.767}, {"district": "Taillon", "similarity": 0.696}, {"district": "Jean-Talon", "similarity": 0.672}, {"district": "Saint-Jérôme", "similarity": 0.672}], "Soulanges": [{"district": "Gatineau", "similarity": 0.917}, {"district": "Pontiac", "similarity": 0.89}, {"district": "Vaudreuil", "similarity": 0.843}, {"district": "Vimont-Auteuil", "similarity": 0.778}, {"district": "Châteauguay", "similarity": 0.761}, {"district": "Fabre", "similarity": 0.722}, {"district": "Nelligan", "similarity": 0.698}, {"district": "Mille-Îles", "similarity": 0.68}, {"district": "Jacques-Cartier", "similarity": 0.65}, {"district": "Sainte-Rose", "similarity": 0.64}], "Taillon": [{"district": "Maurice-Richard", "similarity": 0.917}, {"district": "Rosemont", "similarity": 0.915}, {"district": "Jean-Talon", "similarity": 0.863}, {"district": "Taschereau", "similarity": 0.818}, {"district": "Anjou-Louis-Riel", "similarity": 0.752}, {"district": "Gouin", "similarity": 0.751}, {"district": "Verdun", "similarity": 0.706}, {"district": "Sherbrooke", "similarity": 0.696}, {"district": "Mercier", "similarity": 0.679}, {"district": "Sainte-Marie-Saint-Jacques", "similarity": 0.676}], "Taschereau": [{"district": "Sherbrooke", "similarity": 0.921}, {"district": "Jean-Talon", "similarity": 0.878}, {"district": "Rosemont", "similarity": 0.84}, {"district": "Maurice-Richard", "similarity": 0.831}, {"district": "Taillon", "similarity": 0.818}, {"district": "Vanier-Les Rivières", "similarity": 0.816}, {"district": "Jean-Lesage", "similarity": 0.758}, {"district": "Trois-Rivières", "similarity": 0.696}, {"district": "Gouin", "similarity": 0.656}, {"district": "Marie-Victorin", "similarity": 0.652}], "Terrebonne": [{"district": "Masson", "similarity": 0.986}, {"district": "Verchères", "similarity": 0.929}, {"district": "Mirabel", "similarity": 0.928}, {"district": "Chauveau", "similarity": 0.917}, {"district": "Sanguinet", "similarity": 0.915}, {"district": "Bellefeuille", "similarity": 0.896}, {"district": "Chambly", "similarity": 0.867}, {"district": "Chutes-de-la-Chaudière", "similarity": 0.854}, {"district": "L'Assomption", "similarity": 0.833}, {"district": "Blainville", "similarity": 0.823}], "Trois-Rivières": [{"district": "Lévis", "similarity": 0.942}, {"district": "Vanier-Les Rivières", "similarity": 0.939}, {"district": "Charlesbourg", "similarity": 0.92}, {"district": "Saint-Jérôme", "similarity": 0.881}, {"district": "Chicoutimi", "similarity": 0.88}, {"district": "Joliette", "similarity": 0.838}, {"district": "Saint-Hyacinthe", "similarity": 0.829}, {"district": "Granby", "similarity": 0.819}, {"district": "Sherbrooke", "similarity": 0.803}, {"district": "Jean-Lesage", "similarity": 0.776}], "Ungava": [{"district": "Duplessis", "similarity": 0.595}, {"district": "René-Lévesque", "similarity": 0.212}, {"district": "Soulanges", "similarity": 0.135}, {"district": "Pontiac", "similarity": 0.122}, {"district": "Vaudreuil", "similarity": 0.122}, {"district": "Fabre", "similarity": 0.118}, {"district": "Bellefeuille", "similarity": 0.111}, {"district": "Châteauguay", "similarity": 0.108}, {"district": "Mirabel", "similarity": 0.108}, {"district": "Les Plaines", "similarity": 0.102}], "Vachon": [{"district": "Sainte-Rose", "similarity": 0.885}, {"district": "Mille-Îles", "similarity": 0.851}, {"district": "Vimont-Auteuil", "similarity": 0.819}, {"district": "Fabre", "similarity": 0.742}, {"district": "Sanguinet", "similarity": 0.698}, {"district": "Mirabel", "similarity": 0.64}, {"district": "Blainville", "similarity": 0.592}, {"district": "Masson", "similarity": 0.582}, {"district": "Terrebonne", "similarity": 0.579}, {"district": "Châteauguay", "similarity": 0.551}], "Vanier-Les Rivières": [{"district": "Lévis", "similarity": 0.944}, {"district": "Trois-Rivières", "similarity": 0.939}, {"district": "Charlesbourg", "similarity": 0.907}, {"district": "Chicoutimi", "similarity": 0.866}, {"district": "Sherbrooke", "similarity": 0.824}, {"district": "Taschereau", "similarity": 0.816}, {"district": "Jean-Lesage", "similarity": 0.742}, {"district": "Saint-Jérôme", "similarity": 0.738}, {"district": "Saint-Hyacinthe", "similarity": 0.707}, {"district": "Joliette", "similarity": 0.684}], "Vaudreuil": [{"district": "Nelligan", "similarity": 0.947}, {"district": "Pontiac", "similarity": 0.94}, {"district": "Robert-Baldwin", "similarity": 0.894}, {"district": "Vimont-Auteuil", "similarity": 0.854}, {"district": "Fabre", "similarity": 0.849}, {"district": "Soulanges", "similarity": 0.843}, {"district": "Châteauguay", "similarity": 0.835}, {"district": "Jacques-Cartier", "similarity": 0.825}, {"district": "Mille-Îles", "similarity": 0.777}, {"district": "LaFontaine", "similarity": 0.775}], "Verchères": [{"district": "Chambly", "similarity": 0.969}, {"district": "Chutes-de-la-Chaudière", "similarity": 0.967}, {"district": "Masson", "similarity": 0.944}, {"district": "Terrebonne", "similarity": 0.929}, {"district": "Blainville", "similarity": 0.925}, {"district": "Chauveau", "similarity": 0.911}, {"district": "Borduas", "similarity": 0.898}, {"district": "Mirabel", "similarity": 0.852}, {"district": "Prévost", "similarity": 0.8}, {"district": "Sanguinet", "similarity": 0.794}], "Verdun": [{"district": "Mont-Royal-Outremont", "similarity": 0.967}, {"district": "Saint-Henri-Sainte-Anne", "similarity": 0.955}, {"district": "Westmount-Saint-Louis", "similarity": 0.945}, {"district": "Hull", "similarity": 0.943}, {"district": "Mercier", "similarity": 0.934}, {"district": "Sainte-Marie-Saint-Jacques", "similarity": 0.929}, {"district": "Pierre-Laporte", "similarity": 0.89}, {"district": "Notre-Dame-de-Grâce", "similarity": 0.879}, {"district": "Gouin", "similarity": 0.855}, {"district": "Rosemont", "similarity": 0.824}], "Viau": [{"district": "Bourassa-Sauvé", "similarity": 0.959}, {"district": "Camille-Laurin", "similarity": 0.884}, {"district": "Jeanne-Mance-Viger", "similarity": 0.883}, {"district": "Laval-des-Rapides", "similarity": 0.877}, {"district": "Anjou-Louis-Riel", "similarity": 0.877}, {"district": "Laurier-Dorion", "similarity": 0.873}, {"district": "Acadie", "similarity": 0.86}, {"district": "Marie-Victorin", "similarity": 0.849}, {"district": "Marguerite-Bourgeoys", "similarity": 0.75}, {"district": "Hochelaga-Maisonneuve", "similarity": 0.745}], "Vimont-Auteuil": [{"district": "Mille-Îles", "similarity": 0.985}, {"district": "Fabre", "similarity": 0.949}, {"district": "Sainte-Rose", "similarity": 0.902}, {"district": "Vaudreuil", "similarity": 0.854}, {"district": "Nelligan", "similarity": 0.824}, {"district": "Vachon", "similarity": 0.819}, {"district": "Soulanges", "similarity": 0.778}, {"district": "Pontiac", "similarity": 0.768}, {"district": "Châteauguay", "similarity": 0.738}, {"district": "Robert-Baldwin", "similarity": 0.721}], "Westmount-Saint-Louis": [{"district": "Notre-Dame-de-Grâce", "similarity": 0.971}, {"district": "Mont-Royal-Outremont", "similarity": 0.958}, {"district": "Verdun", "similarity": 0.945}, {"district": "Pierre-Laporte", "similarity": 0.927}, {"district": "Saint-Henri-Sainte-Anne", "similarity": 0.917}, {"district": "Hull", "similarity": 0.91}, {"district": "D'Arcy-McGee", "similarity": 0.901}, {"district": "Marquette", "similarity": 0.876}, {"district": "Saint-Laurent", "similarity": 0.865}, {"district": "Sainte-Marie-Saint-Jacques", "similarity": 0.833}]} | |
| \ No newline at end of file | ||
added
backend/data/population/statistiques-recensement-2021-CEP2026.xls
+0 −0
Binary file not shown.
modified
backend/tests/test_beyond.py
+62 −0
@@ -319,3 +319,65 @@ def test_invariants_simulation(): | ||
| 319 | 319 | assert abs(s - 1.0) < 1e-6 # P(victoire) somme à 1 |
| 320 | 320 | assert all(0.0 <= v <= 1.0 for v in d["win_probs"].values()) |
| 321 | 321 | assert abs(sum(sim.national_vote.values()) - 100.0) < 0.5 |
| 322 | + | |
| 323 | + | |
| 324 | +def test_election_night_infers_national_shift(): | |
| 325 | + """Un vrai décalage national doit être retrouvé par la décomposition | |
| 326 | + hiérarchique, et un décalage nul ne doit rien inventer.""" | |
| 327 | + from app.modeling.election_night import infer_shifts | |
| 328 | + from app.modeling.simulate import SimulationInput | |
| 329 | + from app.modeling.compositions import alr, close, inv_alr | |
| 330 | + rng = np.random.default_rng(5) | |
| 331 | + D, K = 60, 6 | |
| 332 | + baselines = rng.dirichlet(np.ones(K) * 10, D) | |
| 333 | + nat = np.full(K, 1 / K) | |
| 334 | + inp = SimulationInput( | |
| 335 | + x_mean=alr(close(nat)), P=np.eye(K - 1) * 0.01, | |
| 336 | + baseline_national=nat, | |
| 337 | + district_names=[f"c{i}" for i in range(D)], | |
| 338 | + district_baselines=baselines, | |
| 339 | + district_regions=[f"r{i % 6}" for i in range(D)], | |
| 340 | + retirement_flags=np.zeros(D, dtype=int), | |
| 341 | + incumbent_party_idx=np.full(D, -1), majority_seats=31) | |
| 342 | + # vérité : PQ (idx 3) +3 pp national — rapporté dans 30 circonscriptions | |
| 343 | + true_shift_pp = np.zeros(K); true_shift_pp[3] = 3.0 | |
| 344 | + reported = [] | |
| 345 | + for i in range(30): | |
| 346 | + obs = close(np.clip(baselines[i] + true_shift_pp / 100.0, 0.001, None)) | |
| 347 | + reported.append({"district": f"c{i}", "pct_reported": 100.0, | |
| 348 | + "results": {p: float(obs[j] * 100) | |
| 349 | + for j, p in enumerate( | |
| 350 | + ["CAQ", "PCQ", "PLQ", "PQ", "QS", "AUT"])}}) | |
| 351 | + from app.config import settings | |
| 352 | + upd = infer_shifts(inp, reported, industry_sd=0.22) | |
| 353 | + shifted = inv_alr(inp.x_mean + upd.national_shift) | |
| 354 | + dpq = (shifted[3] - nat[3]) * 100 | |
| 355 | + assert 1.5 < dpq < 4.5 # décalage PQ retrouvé (~3 pp, rétréci OK) | |
| 356 | + assert upd.national_var < 0.22 ** 2 # l'incertitude nationale a diminué | |
| 357 | + # décalage nul → rien d'inventé | |
| 358 | + rep0 = [{**r, "results": {p: float(baselines[i][j] * 100) | |
| 359 | + for j, p in enumerate( | |
| 360 | + ["CAQ", "PCQ", "PLQ", "PQ", "QS", "AUT"])}} | |
| 361 | + for i, r in enumerate(reported)] | |
| 362 | + upd0 = infer_shifts(inp, rep0, industry_sd=0.22) | |
| 363 | + assert np.abs(inv_alr(inp.x_mean + upd0.national_shift) - nat).max() * 100 < 0.5 | |
| 364 | + # sous le seuil de dépouillement : aucune information | |
| 365 | + updm = infer_shifts(inp, [{**reported[0], "pct_reported": 2.0}], 0.22) | |
| 366 | + assert updm.n_informative == 0 | |
| 367 | + | |
| 368 | + | |
| 369 | +def test_demographics_feature_store(): | |
| 370 | + from app.config import DATA_DIR | |
| 371 | + from app.ingest.eq_socioeconomic import slug_of | |
| 372 | + assert slug_of("Anjou–Louis-Riel") == "anjou-louis-riel" | |
| 373 | + assert slug_of("Sainte-Marie–Saint-Jacques") == "sainte-marie-saint-jacques" | |
| 374 | + assert slug_of("D'Arcy-McGee") == "darcy-mcgee" | |
| 375 | + f = DATA_DIR / "population" / "riding_2026_demographics.csv" | |
| 376 | + if not f.exists(): | |
| 377 | + return # premier déploiement — construit par admin/demographics | |
| 378 | + import pandas as pd | |
| 379 | + df = pd.read_csv(f) | |
| 380 | + assert len(df) == 127 | |
| 381 | + assert df["population"].between(10000, 130000).all() | |
| 382 | + assert df["pct_francais"].between(1, 100).all() | |
| 383 | + assert df["pct_locataires"].between(5, 95).all() | |
modified
frontend/admin.html
+15 −0
@@ -11,6 +11,21 @@ | ||
| 11 | 11 | <meta charset="utf-8"> |
| 12 | 12 | <meta name="viewport" content="width=device-width, initial-scale=1"> |
| 13 | 13 | <title>Administration — QC Élection Forecast</title> |
| 14 | +<link rel="icon" type="image/svg+xml" href="/assets/img/favicon.svg"> | |
| 15 | +<link rel="icon" type="image/png" sizes="64x64" href="/assets/img/favicon-64.png"> | |
| 16 | +<link rel="apple-touch-icon" href="/assets/img/apple-touch-icon.png"> | |
| 17 | +<meta property="og:site_name" content="QC Élection Forecast"> | |
| 18 | +<meta property="og:type" content="website"> | |
| 19 | +<meta property="og:title" content="Administration — QC Élection Forecast"> | |
| 20 | +<meta property="og:description" content="Prévision probabiliste de l'élection générale québécoise du 5 octobre 2026 : 127 circonscriptions, modèle bayésien calibré, sources traçables."> | |
| 21 | +<meta property="og:image" content="https://www.qc-election.com/assets/img/og.png"> | |
| 22 | +<meta property="og:image:width" content="1200"> | |
| 23 | +<meta property="og:image:height" content="630"> | |
| 24 | +<meta property="og:locale" content="fr_CA"> | |
| 25 | +<meta name="twitter:card" content="summary_large_image"> | |
| 26 | +<meta name="twitter:title" content="Administration — QC Élection Forecast"> | |
| 27 | +<meta name="twitter:image" content="https://www.qc-election.com/assets/img/og.png"> | |
| 28 | +<meta name="theme-color" content="#0a0d14"> | |
| 14 | 29 | <link rel="stylesheet" href="/assets/style.css"> |
| 15 | 30 | </head> |
| 16 | 31 | <body> |
added
frontend/assets/img/apple-touch-icon.png
+0 −0
Binary file not shown.
added
frontend/assets/img/favicon-64.png
+0 −0
Binary file not shown.
added
frontend/assets/img/favicon.svg
+14 −0
@@ -0,0 +1,14 @@ | ||
| 1 | +<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64"> | |
| 2 | + <defs> | |
| 3 | + <linearGradient id="g" x1="0" y1="0" x2="1" y2="1"> | |
| 4 | + <stop offset="0" stop-color="#3f7ad6"/><stop offset="1" stop-color="#7069d6"/> | |
| 5 | + </linearGradient> | |
| 6 | + </defs> | |
| 7 | + <rect width="64" height="64" rx="14" fill="url(#g)"/> | |
| 8 | + <g transform="translate(20,17) scale(1.0)" fill="#ffffff"> | |
| 9 | + <path transform="scale(1.25)" d="M9.6 0C7.4 3 6.5 5.4 6.5 7.5c0 2.4 1.1 5 3.1 8.7 2-3.7 3.1-6.3 3.1-8.7 0-2.1-.9-4.5-3.1-7.5z"/> | |
| 10 | + <path transform="scale(1.25)" d="M7.5 16.2C7.2 12 5 9.2.6 8.7c-.3 3.6.9 6.1 3.4 7.2 1.1.5 2.3.6 3.5.3z"/> | |
| 11 | + <path transform="scale(1.25)" d="M11.7 16.2c.3-4.2 2.5-7 6.9-7.5.3 3.6-.9 6.1-3.4 7.2-1.1.5-2.3.6-3.5.3z"/> | |
| 12 | + <rect x="6" y="23.9" width="12" height="2.4" rx="1.2"/> | |
| 13 | + </g> | |
| 14 | +</svg> | |
added
frontend/assets/img/icon-512.png
+0 −0
Binary file not shown.
added
frontend/assets/img/og.png
+0 −0
Binary file not shown.
modified
frontend/aujourdhui.html
+15 −0
@@ -12,6 +12,21 @@ | ||
| 12 | 12 | <meta name="viewport" content="width=device-width, initial-scale=1"> |
| 13 | 13 | <title>Le point du jour — QC Élection Forecast</title> |
| 14 | 14 | <meta name="description" content="Le forecast du jour de l'élection québécoise 2026 : probabilités datées, ce qui a changé depuis hier, attention web, nouveaux signaux."> |
| 15 | +<link rel="icon" type="image/svg+xml" href="/assets/img/favicon.svg"> | |
| 16 | +<link rel="icon" type="image/png" sizes="64x64" href="/assets/img/favicon-64.png"> | |
| 17 | +<link rel="apple-touch-icon" href="/assets/img/apple-touch-icon.png"> | |
| 18 | +<meta property="og:site_name" content="QC Élection Forecast"> | |
| 19 | +<meta property="og:type" content="website"> | |
| 20 | +<meta property="og:title" content="Le point du jour — QC Élection Forecast"> | |
| 21 | +<meta property="og:description" content="Le forecast du jour de l'élection québécoise 2026 : probabilités datées, ce qui a changé depuis hier, attention web, nouveaux signaux."> | |
| 22 | +<meta property="og:image" content="https://www.qc-election.com/assets/img/og.png"> | |
| 23 | +<meta property="og:image:width" content="1200"> | |
| 24 | +<meta property="og:image:height" content="630"> | |
| 25 | +<meta property="og:locale" content="fr_CA"> | |
| 26 | +<meta name="twitter:card" content="summary_large_image"> | |
| 27 | +<meta name="twitter:title" content="Le point du jour — QC Élection Forecast"> | |
| 28 | +<meta name="twitter:image" content="https://www.qc-election.com/assets/img/og.png"> | |
| 29 | +<meta name="theme-color" content="#0a0d14"> | |
| 15 | 30 | <link rel="stylesheet" href="/assets/style.css"> |
| 16 | 31 | <script src="https://cdn.jsdelivr.net/npm/echarts@5.5.0/dist/echarts.min.js"></script> |
| 17 | 32 | <style> |
modified
frontend/backtest.html
+15 −0
@@ -11,6 +11,21 @@ | ||
| 11 | 11 | <meta charset="utf-8"> |
| 12 | 12 | <meta name="viewport" content="width=device-width, initial-scale=1"> |
| 13 | 13 | <title>Backtesting & calibration — QC Élection Forecast</title> |
| 14 | +<link rel="icon" type="image/svg+xml" href="/assets/img/favicon.svg"> | |
| 15 | +<link rel="icon" type="image/png" sizes="64x64" href="/assets/img/favicon-64.png"> | |
| 16 | +<link rel="apple-touch-icon" href="/assets/img/apple-touch-icon.png"> | |
| 17 | +<meta property="og:site_name" content="QC Élection Forecast"> | |
| 18 | +<meta property="og:type" content="website"> | |
| 19 | +<meta property="og:title" content="Backtesting & calibration — QC Élection Forecast"> | |
| 20 | +<meta property="og:description" content="Prévision probabiliste de l'élection générale québécoise du 5 octobre 2026 : 127 circonscriptions, modèle bayésien calibré, sources traçables."> | |
| 21 | +<meta property="og:image" content="https://www.qc-election.com/assets/img/og.png"> | |
| 22 | +<meta property="og:image:width" content="1200"> | |
| 23 | +<meta property="og:image:height" content="630"> | |
| 24 | +<meta property="og:locale" content="fr_CA"> | |
| 25 | +<meta name="twitter:card" content="summary_large_image"> | |
| 26 | +<meta name="twitter:title" content="Backtesting & calibration — QC Élection Forecast"> | |
| 27 | +<meta name="twitter:image" content="https://www.qc-election.com/assets/img/og.png"> | |
| 28 | +<meta name="theme-color" content="#0a0d14"> | |
| 14 | 29 | <link rel="stylesheet" href="/assets/style.css"> |
| 15 | 30 | <script src="https://cdn.jsdelivr.net/npm/echarts@5.5.0/dist/echarts.min.js"></script> |
| 16 | 31 | </head> |
modified
frontend/carte.html
+15 −0
@@ -11,6 +11,21 @@ | ||
| 11 | 11 | <meta charset="utf-8"> |
| 12 | 12 | <meta name="viewport" content="width=device-width, initial-scale=1"> |
| 13 | 13 | <title>Carte électorale — QC Élection Forecast</title> |
| 14 | +<link rel="icon" type="image/svg+xml" href="/assets/img/favicon.svg"> | |
| 15 | +<link rel="icon" type="image/png" sizes="64x64" href="/assets/img/favicon-64.png"> | |
| 16 | +<link rel="apple-touch-icon" href="/assets/img/apple-touch-icon.png"> | |
| 17 | +<meta property="og:site_name" content="QC Élection Forecast"> | |
| 18 | +<meta property="og:type" content="website"> | |
| 19 | +<meta property="og:title" content="Carte électorale — QC Élection Forecast"> | |
| 20 | +<meta property="og:description" content="Prévision probabiliste de l'élection générale québécoise du 5 octobre 2026 : 127 circonscriptions, modèle bayésien calibré, sources traçables."> | |
| 21 | +<meta property="og:image" content="https://www.qc-election.com/assets/img/og.png"> | |
| 22 | +<meta property="og:image:width" content="1200"> | |
| 23 | +<meta property="og:image:height" content="630"> | |
| 24 | +<meta property="og:locale" content="fr_CA"> | |
| 25 | +<meta name="twitter:card" content="summary_large_image"> | |
| 26 | +<meta name="twitter:title" content="Carte électorale — QC Élection Forecast"> | |
| 27 | +<meta name="twitter:image" content="https://www.qc-election.com/assets/img/og.png"> | |
| 28 | +<meta name="theme-color" content="#0a0d14"> | |
| 14 | 29 | <link rel="stylesheet" href="/assets/style.css"> |
| 15 | 30 | <script src="https://cdn.jsdelivr.net/npm/echarts@5.5.0/dist/echarts.min.js"></script> |
| 16 | 31 | </head> |
modified
frontend/circonscriptions.html
+61 −0
@@ -12,6 +12,21 @@ | ||
| 12 | 12 | <meta name="viewport" content="width=device-width, initial-scale=1"> |
| 13 | 13 | <title>Forecast par circonscription — QC Élection Forecast</title> |
| 14 | 14 | <meta name="description" content="Le forecast des 127 circonscriptions du Québec : probabilités de victoire, circonscriptions pivots de la majorité, champs de bataille."> |
| 15 | +<link rel="icon" type="image/svg+xml" href="/assets/img/favicon.svg"> | |
| 16 | +<link rel="icon" type="image/png" sizes="64x64" href="/assets/img/favicon-64.png"> | |
| 17 | +<link rel="apple-touch-icon" href="/assets/img/apple-touch-icon.png"> | |
| 18 | +<meta property="og:site_name" content="QC Élection Forecast"> | |
| 19 | +<meta property="og:type" content="website"> | |
| 20 | +<meta property="og:title" content="Forecast par circonscription — QC Élection Forecast"> | |
| 21 | +<meta property="og:description" content="Le forecast des 127 circonscriptions du Québec : probabilités de victoire, circonscriptions pivots de la majorité, champs de bataille."> | |
| 22 | +<meta property="og:image" content="https://www.qc-election.com/assets/img/og.png"> | |
| 23 | +<meta property="og:image:width" content="1200"> | |
| 24 | +<meta property="og:image:height" content="630"> | |
| 25 | +<meta property="og:locale" content="fr_CA"> | |
| 26 | +<meta name="twitter:card" content="summary_large_image"> | |
| 27 | +<meta name="twitter:title" content="Forecast par circonscription — QC Élection Forecast"> | |
| 28 | +<meta name="twitter:image" content="https://www.qc-election.com/assets/img/og.png"> | |
| 29 | +<meta name="theme-color" content="#0a0d14"> | |
| 15 | 30 | <link rel="stylesheet" href="/assets/style.css"> |
| 16 | 31 | <script src="https://cdn.jsdelivr.net/npm/echarts@5.5.0/dist/echarts.min.js"></script> |
| 17 | 32 | <style> |
@@ -236,8 +251,34 @@ | ||
| 236 | 251 | </tr>`).join("")} |
| 237 | 252 | </table> |
| 238 | 253 | <p class="note">${det.baseline_source || ""} · participation 2022 : ${det.turnout_2022 != null ? det.turnout_2022.toFixed(0) + " %" : "—"}</p> |
| 254 | + ${(() => { | |
| 255 | + if (ordD.length < 2) return ""; | |
| 256 | + const [p1, p2] = ordD; | |
| 257 | + const margin = exp[p1] - exp[p2]; | |
| 258 | + const swing = margin / 2; | |
| 259 | + const wp1 = ((f.win_probs || {})[p1] || 0) * 100; | |
| 260 | + // sensibilité : IC 95 % du meneur — plus il est large vs la marge, | |
| 261 | + // plus le siège est instable | |
| 262 | + const width = f.hi95 && f.lo95 ? f.hi95[p1] - f.lo95[p1] : null; | |
| 263 | + const instab = width ? Math.min(3, width / Math.max(margin, 0.1)) : null; | |
| 264 | + return `<h3 style="margin-top:14px">Sensibilité au swing</h3> | |
| 265 | + <div class="kv"><span>Marge attendue</span> | |
| 266 | + <b><span class="dot" style="background:${partyColor(p1)}"></span>${p1} | |
| 267 | + +${margin.toFixed(1)} pp sur ${p2}</b></div> | |
| 268 | + <div class="kv"><span>Chemin de bascule minimal</span> | |
| 269 | + <b>swing d'environ ${Math.max(0.1, swing).toFixed(1)} pp vers | |
| 270 | + <span class="dot" style="background:${partyColor(p2)}"></span>${p2}</b></div> | |
| 271 | + <div class="kv"><span>Stabilité</span> | |
| 272 | + <b>${wp1 >= 95 ? "verrouillée" : wp1 >= 80 ? "solide" : wp1 >= 60 ? "favorisée" | |
| 273 | + : "réellement disputée"} — P(${p1}) ${wp1.toFixed(0)} %${ | |
| 274 | + instab != null ? ` · IC ${width.toFixed(0)} pp vs marge ${margin.toFixed(1)} pp` : ""}</b></div> | |
| 275 | + <p class="note">Le « chemin de bascule » suppose un transfert direct entre les deux | |
| 276 | + meneurs; un mouvement national se propage ici en swing proportionnel (log-ratio), | |
| 277 | + donc l'ampleur réelle requise varie selon la structure locale.</p>`; | |
| 278 | + })()} | |
| 239 | 279 | </div> |
| 240 | 280 | <div> |
| 281 | + <div id="demo-${cssId(name)}"></div> | |
| 241 | 282 | <h3>Candidatures (DGEQ)</h3> |
| 242 | 283 | ${det.candidates && det.candidates.length ? `<table class="data"> |
| 243 | 284 | <tr><th>Candidat·e</th><th>Parti</th><th></th></tr> |
@@ -248,7 +289,27 @@ | ||
| 248 | 289 | </div> |
| 249 | 290 | </div></td>`; |
| 250 | 291 | tr.after(row); |
| 292 | + /* démographie officielle (Recensement 2021, limites 2026) — best-effort */ | |
| 293 | + try { | |
| 294 | + const dg = await getJSON(`${API}/demographics/${encodeURIComponent(name)}`); | |
| 295 | + const kv = (l, v, u = " %") => v != null | |
| 296 | + ? `<div class="kv"><span>${l}</span><b>${typeof v === "number" ? v.toLocaleString("fr-CA") : v}${u}</b></div>` : ""; | |
| 297 | + document.getElementById(`demo-${cssId(name)}`).innerHTML = ` | |
| 298 | + <h3>Démographie <span class="chip badge-aux">Recensement 2021 · limites 2026</span></h3> | |
| 299 | + ${kv("Population", dg.population, "")} | |
| 300 | + ${kv("65 ans et plus", dg.pct_60_plus)} | |
| 301 | + ${kv("Français à la maison", dg.pct_francais)} | |
| 302 | + ${kv("Universitaire (bacc+)", dg.pct_universitaire)} | |
| 303 | + ${kv("Locataires", dg.pct_locataires)} | |
| 304 | + ${kv("Immigrant·e·s", dg.pct_immigrants)} | |
| 305 | + ${kv("Ménages 100 k$ +", dg.pct_revenu_100k_plus)} | |
| 306 | + ${dg.similar && dg.similar.length ? `<div class="kv"><span>Semblables</span> | |
| 307 | + <b style="font-weight:500">${dg.similar.slice(0, 4).map(s => s.district).join(" · ")}</b></div>` : ""} | |
| 308 | + <p class="note"><a href="${dg.source_url}" target="_blank" rel="noopener">${dg.source}</a></p> | |
| 309 | + <div style="height:14px"></div>`; | |
| 310 | + } catch (e) { /* démographie absente : la fiche reste complète */ } | |
| 251 | 311 | } |
| 312 | + function cssId(s) { return s.replace(/[^a-zA-Z0-9]/g, "_"); } | |
| 252 | 313 | |
| 253 | 314 | ["search", "f-region", "f-cat", "f-sort"].forEach(id => |
| 254 | 315 | document.getElementById(id).addEventListener(id === "search" ? "input" : "change", render)); |
modified
frontend/index.html
+15 −0
@@ -12,6 +12,21 @@ | ||
| 12 | 12 | <meta name="viewport" content="width=device-width, initial-scale=1"> |
| 13 | 13 | <title>QC Élection Forecast — Prévision de l'élection québécoise 2026</title> |
| 14 | 14 | <meta name="description" content="Prévision probabiliste de l'élection générale québécoise 2026 : modèle bayésien, simulations Monte Carlo, sondages pondérés."> |
| 15 | +<link rel="icon" type="image/svg+xml" href="/assets/img/favicon.svg"> | |
| 16 | +<link rel="icon" type="image/png" sizes="64x64" href="/assets/img/favicon-64.png"> | |
| 17 | +<link rel="apple-touch-icon" href="/assets/img/apple-touch-icon.png"> | |
| 18 | +<meta property="og:site_name" content="QC Élection Forecast"> | |
| 19 | +<meta property="og:type" content="website"> | |
| 20 | +<meta property="og:title" content="QC Élection Forecast — Prévision de l'élection québécoise 2026"> | |
| 21 | +<meta property="og:description" content="Prévision probabiliste de l'élection générale québécoise 2026 : modèle bayésien, simulations Monte Carlo, sondages pondérés."> | |
| 22 | +<meta property="og:image" content="https://www.qc-election.com/assets/img/og.png"> | |
| 23 | +<meta property="og:image:width" content="1200"> | |
| 24 | +<meta property="og:image:height" content="630"> | |
| 25 | +<meta property="og:locale" content="fr_CA"> | |
| 26 | +<meta name="twitter:card" content="summary_large_image"> | |
| 27 | +<meta name="twitter:title" content="QC Élection Forecast — Prévision de l'élection québécoise 2026"> | |
| 28 | +<meta name="twitter:image" content="https://www.qc-election.com/assets/img/og.png"> | |
| 29 | +<meta name="theme-color" content="#0a0d14"> | |
| 15 | 30 | <link rel="stylesheet" href="/assets/style.css"> |
| 16 | 31 | <script src="https://cdn.jsdelivr.net/npm/echarts@5.5.0/dist/echarts.min.js"></script> |
| 17 | 32 | </head> |
modified
frontend/intelligence.html
+15 −0
@@ -11,6 +11,21 @@ | ||
| 11 | 11 | <meta charset="utf-8"> |
| 12 | 12 | <meta name="viewport" content="width=device-width, initial-scale=1"> |
| 13 | 13 | <title>Intelligence électorale — QC Élection Forecast</title> |
| 14 | +<link rel="icon" type="image/svg+xml" href="/assets/img/favicon.svg"> | |
| 15 | +<link rel="icon" type="image/png" sizes="64x64" href="/assets/img/favicon-64.png"> | |
| 16 | +<link rel="apple-touch-icon" href="/assets/img/apple-touch-icon.png"> | |
| 17 | +<meta property="og:site_name" content="QC Élection Forecast"> | |
| 18 | +<meta property="og:type" content="website"> | |
| 19 | +<meta property="og:title" content="Intelligence électorale — QC Élection Forecast"> | |
| 20 | +<meta property="og:description" content="Prévision probabiliste de l'élection générale québécoise du 5 octobre 2026 : 127 circonscriptions, modèle bayésien calibré, sources traçables."> | |
| 21 | +<meta property="og:image" content="https://www.qc-election.com/assets/img/og.png"> | |
| 22 | +<meta property="og:image:width" content="1200"> | |
| 23 | +<meta property="og:image:height" content="630"> | |
| 24 | +<meta property="og:locale" content="fr_CA"> | |
| 25 | +<meta name="twitter:card" content="summary_large_image"> | |
| 26 | +<meta name="twitter:title" content="Intelligence électorale — QC Élection Forecast"> | |
| 27 | +<meta name="twitter:image" content="https://www.qc-election.com/assets/img/og.png"> | |
| 28 | +<meta name="theme-color" content="#0a0d14"> | |
| 14 | 29 | <link rel="stylesheet" href="/assets/style.css"> |
| 15 | 30 | <script src="https://cdn.jsdelivr.net/npm/echarts@5.5.0/dist/echarts.min.js"></script> |
| 16 | 31 | </head> |
modified
frontend/methodologie.html
+15 −0
@@ -11,6 +11,21 @@ | ||
| 11 | 11 | <meta charset="utf-8"> |
| 12 | 12 | <meta name="viewport" content="width=device-width, initial-scale=1"> |
| 13 | 13 | <title>Méthodologie — QC Élection Forecast</title> |
| 14 | +<link rel="icon" type="image/svg+xml" href="/assets/img/favicon.svg"> | |
| 15 | +<link rel="icon" type="image/png" sizes="64x64" href="/assets/img/favicon-64.png"> | |
| 16 | +<link rel="apple-touch-icon" href="/assets/img/apple-touch-icon.png"> | |
| 17 | +<meta property="og:site_name" content="QC Élection Forecast"> | |
| 18 | +<meta property="og:type" content="website"> | |
| 19 | +<meta property="og:title" content="Méthodologie — QC Élection Forecast"> | |
| 20 | +<meta property="og:description" content="Prévision probabiliste de l'élection générale québécoise du 5 octobre 2026 : 127 circonscriptions, modèle bayésien calibré, sources traçables."> | |
| 21 | +<meta property="og:image" content="https://www.qc-election.com/assets/img/og.png"> | |
| 22 | +<meta property="og:image:width" content="1200"> | |
| 23 | +<meta property="og:image:height" content="630"> | |
| 24 | +<meta property="og:locale" content="fr_CA"> | |
| 25 | +<meta name="twitter:card" content="summary_large_image"> | |
| 26 | +<meta name="twitter:title" content="Méthodologie — QC Élection Forecast"> | |
| 27 | +<meta name="twitter:image" content="https://www.qc-election.com/assets/img/og.png"> | |
| 28 | +<meta name="theme-color" content="#0a0d14"> | |
| 14 | 29 | <link rel="stylesheet" href="/assets/style.css"> |
| 15 | 30 | </head> |
| 16 | 31 | <body> |
modified
frontend/signaux.html
+15 −0
@@ -12,6 +12,21 @@ | ||
| 12 | 12 | <meta name="viewport" content="width=device-width, initial-scale=1"> |
| 13 | 13 | <title>Au-delà des sondages — QC Élection Forecast</title> |
| 14 | 14 | <meta name="description" content="Décomposition du forecast v2 : sondages, votes réels des partielles, prior de fondamentaux, ajustement médias et ensemble avec les marchés prédictifs."> |
| 15 | +<link rel="icon" type="image/svg+xml" href="/assets/img/favicon.svg"> | |
| 16 | +<link rel="icon" type="image/png" sizes="64x64" href="/assets/img/favicon-64.png"> | |
| 17 | +<link rel="apple-touch-icon" href="/assets/img/apple-touch-icon.png"> | |
| 18 | +<meta property="og:site_name" content="QC Élection Forecast"> | |
| 19 | +<meta property="og:type" content="website"> | |
| 20 | +<meta property="og:title" content="Au-delà des sondages — QC Élection Forecast"> | |
| 21 | +<meta property="og:description" content="Décomposition du forecast v2 : sondages, votes réels des partielles, prior de fondamentaux, ajustement médias et ensemble avec les marchés prédictifs."> | |
| 22 | +<meta property="og:image" content="https://www.qc-election.com/assets/img/og.png"> | |
| 23 | +<meta property="og:image:width" content="1200"> | |
| 24 | +<meta property="og:image:height" content="630"> | |
| 25 | +<meta property="og:locale" content="fr_CA"> | |
| 26 | +<meta name="twitter:card" content="summary_large_image"> | |
| 27 | +<meta name="twitter:title" content="Au-delà des sondages — QC Élection Forecast"> | |
| 28 | +<meta name="twitter:image" content="https://www.qc-election.com/assets/img/og.png"> | |
| 29 | +<meta name="theme-color" content="#0a0d14"> | |
| 15 | 30 | <link rel="stylesheet" href="/assets/style.css"> |
| 16 | 31 | <script src="https://cdn.jsdelivr.net/npm/echarts@5.5.0/dist/echarts.min.js"></script> |
| 17 | 32 | <style> |
modified
frontend/simulateur.html
+93 −12
@@ -11,6 +11,21 @@ | ||
| 11 | 11 | <meta charset="utf-8"> |
| 12 | 12 | <meta name="viewport" content="width=device-width, initial-scale=1"> |
| 13 | 13 | <title>Simulateur de scénarios — QC Élection Forecast</title> |
| 14 | +<link rel="icon" type="image/svg+xml" href="/assets/img/favicon.svg"> | |
| 15 | +<link rel="icon" type="image/png" sizes="64x64" href="/assets/img/favicon-64.png"> | |
| 16 | +<link rel="apple-touch-icon" href="/assets/img/apple-touch-icon.png"> | |
| 17 | +<meta property="og:site_name" content="QC Élection Forecast"> | |
| 18 | +<meta property="og:type" content="website"> | |
| 19 | +<meta property="og:title" content="Simulateur de scénarios — QC Élection Forecast"> | |
| 20 | +<meta property="og:description" content="Prévision probabiliste de l'élection générale québécoise du 5 octobre 2026 : 127 circonscriptions, modèle bayésien calibré, sources traçables."> | |
| 21 | +<meta property="og:image" content="https://www.qc-election.com/assets/img/og.png"> | |
| 22 | +<meta property="og:image:width" content="1200"> | |
| 23 | +<meta property="og:image:height" content="630"> | |
| 24 | +<meta property="og:locale" content="fr_CA"> | |
| 25 | +<meta name="twitter:card" content="summary_large_image"> | |
| 26 | +<meta name="twitter:title" content="Simulateur de scénarios — QC Élection Forecast"> | |
| 27 | +<meta name="twitter:image" content="https://www.qc-election.com/assets/img/og.png"> | |
| 28 | +<meta name="theme-color" content="#0a0d14"> | |
| 14 | 29 | <link rel="stylesheet" href="/assets/style.css"> |
| 15 | 30 | <script src="https://cdn.jsdelivr.net/npm/echarts@5.5.0/dist/echarts.min.js"></script> |
| 16 | 31 | </head> |
@@ -19,7 +34,8 @@ | ||
| 19 | 34 | <div class="wrap"> |
| 20 | 35 | <div class="hero"> |
| 21 | 36 | <h1>Simulateur « et si… »</h1> |
| 22 | − <p class="sub">Modifiez le vote national, un choc régional ou la participation — le moteur relance des milliers de simulations complètes.</p> | |
| 37 | + <p class="sub">Modifiez le vote national, un choc régional ou la participation — le moteur relance des milliers de simulations complètes. Chaque scénario est <b>partageable par URL</b>.</p> | |
| 38 | + <p class="disclaimer">Un scénario est un résultat <b>conditionnel</b> (« si cette hypothèse était vraie ») — ce n'est jamais le forecast officiel, qui reste celui de l'<a href="/">accueil</a>.</p> | |
| 23 | 39 | </div> |
| 24 | 40 | |
| 25 | 41 | <div class="grid" style="grid-template-columns: 380px 1fr"> |
@@ -46,9 +62,10 @@ | ||
| 46 | 62 | <h3>Scénarios préconfigurés</h3> |
| 47 | 63 | <div style="display:flex;flex-wrap:wrap;gap:8px;margin-top:8px" id="presets"></div> |
| 48 | 64 | </div> |
| 49 | − <div style="display:flex;gap:10px;margin-top:14px"> | |
| 65 | + <div style="display:flex;gap:10px;margin-top:14px;flex-wrap:wrap"> | |
| 50 | 66 | <button class="primary" id="run">Recalculer</button> |
| 51 | 67 | <button id="reset">Réinitialiser</button> |
| 68 | + <button id="share" title="Copier un lien qui rejoue exactement ce scénario">Copier le lien du scénario</button> | |
| 52 | 69 | <span id="status" style="color:var(--muted);font-size:.82rem;align-self:center"></span> |
| 53 | 70 | </div> |
| 54 | 71 | </div> |
@@ -171,19 +188,73 @@ | ||
| 171 | 188 | return sc; |
| 172 | 189 | } |
| 173 | 190 | |
| 191 | + /* ---- scénarios partageables par URL (?s=base64url) ---- */ | |
| 192 | + let extraState = {}; // champs sans contrôle direct (poll_error_pp, régions multiples) | |
| 193 | + const b64e = o => btoa(unescape(encodeURIComponent(JSON.stringify(o)))) | |
| 194 | + .replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, ""); | |
| 195 | + const b64d = s => JSON.parse(decodeURIComponent(escape( | |
| 196 | + atob(s.replace(/-/g, "+").replace(/_/g, "/"))))); | |
| 197 | + | |
| 198 | + function fullScenario() { | |
| 199 | + const sc = currentScenario(); | |
| 200 | + if (extraState.poll_error_pp) sc.poll_error_pp = | |
| 201 | + { ...extraState.poll_error_pp, ...sc.poll_error_pp }; | |
| 202 | + if (extraState.regional_pp) sc.regional_pp = | |
| 203 | + { ...extraState.regional_pp, ...sc.regional_pp }; | |
| 204 | + return sc; | |
| 205 | + } | |
| 206 | + function syncURL() { | |
| 207 | + const sc = fullScenario(); | |
| 208 | + const empty = !Object.values(sc).some(v => Object.keys(v).length); | |
| 209 | + const url = empty ? location.pathname : `${location.pathname}?s=${b64e(sc)}`; | |
| 210 | + history.replaceState(null, "", url); | |
| 211 | + } | |
| 212 | + function applyScenario(sc) { | |
| 213 | + order.forEach(p => { | |
| 214 | + const n = (sc.national_pp || {})[p] || 0; | |
| 215 | + document.getElementById(`nat-${p}`).value = n; | |
| 216 | + document.getElementById(`natv-${p}`).textContent = | |
| 217 | + (n >= 0 ? "+" : "−") + Math.abs(n).toFixed(1); | |
| 218 | + const t = (sc.turnout_mult || {})[p] || 1; | |
| 219 | + document.getElementById(`to-${p}`).value = t; | |
| 220 | + document.getElementById(`tov-${p}`).textContent = t.toFixed(2).replace(".", ","); | |
| 221 | + }); | |
| 222 | + const regs = Object.entries(sc.regional_pp || {}); | |
| 223 | + if (regs.length) { | |
| 224 | + const [reg, pp] = regs[0]; | |
| 225 | + const [party, val] = Object.entries(pp)[0] || []; | |
| 226 | + if (party) { | |
| 227 | + document.getElementById("reg-select").value = reg; | |
| 228 | + document.getElementById("reg-party").value = party; | |
| 229 | + document.getElementById("reg-pp").value = val; | |
| 230 | + } | |
| 231 | + } | |
| 232 | + extraState = { | |
| 233 | + poll_error_pp: sc.poll_error_pp && Object.keys(sc.poll_error_pp).length | |
| 234 | + ? sc.poll_error_pp : undefined, | |
| 235 | + regional_pp: regs.length > 1 | |
| 236 | + ? Object.fromEntries(regs.slice(1)) : undefined, | |
| 237 | + }; | |
| 238 | + } | |
| 239 | + | |
| 174 | 240 | let pending = false; |
| 175 | 241 | async function run(extra) { |
| 176 | 242 | if (pending) return; |
| 177 | 243 | pending = true; |
| 178 | 244 | document.getElementById("status").textContent = "simulation en cours…"; |
| 179 | 245 | try { |
| 180 | − const body = { ...currentScenario(), ...(extra || {}), n_sims: 8000 }; | |
| 246 | + if (extra) applyScenario({ ...fullScenario(), ...extra }); | |
| 247 | + const body = { ...fullScenario(), n_sims: 8000 }; | |
| 248 | + syncURL(); | |
| 181 | 249 | const sim = await getJSON(`${API}/whatif`, { |
| 182 | 250 | method: "POST", headers: { "Content-Type": "application/json" }, |
| 183 | 251 | body: JSON.stringify(body) }); |
| 184 | 252 | renderResult(sim); |
| 253 | + const hasShock = Object.values(body).some(v => v && typeof v === "object" | |
| 254 | + && Object.keys(v).length); | |
| 185 | 255 | document.getElementById("status").textContent = |
| 186 | − `${sim.n_sims.toLocaleString("fr-CA")} simulations`; | |
| 256 | + `${sim.n_sims.toLocaleString("fr-CA")} simulations` + | |
| 257 | + (hasShock ? " · scénario conditionnel" : " · référence"); | |
| 187 | 258 | } catch (e) { |
| 188 | 259 | document.getElementById("status").textContent = "erreur : " + e.message; |
| 189 | 260 | } finally { pending = false; } |
@@ -191,19 +262,29 @@ | ||
| 191 | 262 | |
| 192 | 263 | document.getElementById("run").onclick = () => run(); |
| 193 | 264 | document.getElementById("reset").onclick = () => { |
| 194 | − order.forEach(p => { | |
| 195 | − document.getElementById(`nat-${p}`).value = 0; | |
| 196 | − document.getElementById(`natv-${p}`).textContent = "+0,0"; | |
| 197 | − document.getElementById(`to-${p}`).value = 1; | |
| 198 | − document.getElementById(`tov-${p}`).textContent = "1,00"; | |
| 199 | − }); | |
| 265 | + extraState = {}; | |
| 266 | + applyScenario({}); | |
| 200 | 267 | document.getElementById("reg-pp").value = 0; |
| 201 | 268 | run(); |
| 202 | 269 | }; |
| 270 | + document.getElementById("share").onclick = async () => { | |
| 271 | + syncURL(); | |
| 272 | + try { | |
| 273 | + await navigator.clipboard.writeText(location.href); | |
| 274 | + document.getElementById("status").textContent = "lien du scénario copié ✓"; | |
| 275 | + } catch (e) { | |
| 276 | + document.getElementById("status").textContent = location.href; | |
| 277 | + } | |
| 278 | + }; | |
| 203 | 279 | document.querySelectorAll("#presets button").forEach(b => |
| 204 | − b.onclick = () => run(PRESETS[b.dataset.k])); | |
| 280 | + b.onclick = () => { extraState = {}; run(PRESETS[b.dataset.k]); }); | |
| 205 | 281 | |
| 206 | − run(); // scénario neutre = référence | |
| 282 | + /* scénario porté par l'URL au chargement */ | |
| 283 | + const sp = new URLSearchParams(location.search).get("s"); | |
| 284 | + if (sp) { | |
| 285 | + try { applyScenario(b64d(sp)); } catch (e) { /* lien invalide → référence */ } | |
| 286 | + } | |
| 287 | + run(); | |
| 207 | 288 | })(); |
| 208 | 289 | </script> |
| 209 | 290 | </body> |
modified
frontend/sondages.html
+15 −0
@@ -11,6 +11,21 @@ | ||
| 11 | 11 | <meta charset="utf-8"> |
| 12 | 12 | <meta name="viewport" content="width=device-width, initial-scale=1"> |
| 13 | 13 | <title>Explorateur de sondages — QC Élection Forecast</title> |
| 14 | +<link rel="icon" type="image/svg+xml" href="/assets/img/favicon.svg"> | |
| 15 | +<link rel="icon" type="image/png" sizes="64x64" href="/assets/img/favicon-64.png"> | |
| 16 | +<link rel="apple-touch-icon" href="/assets/img/apple-touch-icon.png"> | |
| 17 | +<meta property="og:site_name" content="QC Élection Forecast"> | |
| 18 | +<meta property="og:type" content="website"> | |
| 19 | +<meta property="og:title" content="Explorateur de sondages — QC Élection Forecast"> | |
| 20 | +<meta property="og:description" content="Prévision probabiliste de l'élection générale québécoise du 5 octobre 2026 : 127 circonscriptions, modèle bayésien calibré, sources traçables."> | |
| 21 | +<meta property="og:image" content="https://www.qc-election.com/assets/img/og.png"> | |
| 22 | +<meta property="og:image:width" content="1200"> | |
| 23 | +<meta property="og:image:height" content="630"> | |
| 24 | +<meta property="og:locale" content="fr_CA"> | |
| 25 | +<meta name="twitter:card" content="summary_large_image"> | |
| 26 | +<meta name="twitter:title" content="Explorateur de sondages — QC Élection Forecast"> | |
| 27 | +<meta name="twitter:image" content="https://www.qc-election.com/assets/img/og.png"> | |
| 28 | +<meta name="theme-color" content="#0a0d14"> | |
| 14 | 29 | <link rel="stylesheet" href="/assets/style.css"> |
| 15 | 30 | </head> |
| 16 | 31 | <body> |
| 17 | 32 | |