TERRIQRetour au récit ↗Notebook Python ↓

Montréal : lire les transformations locales

Le contexte change la lecture d’un indicateur

TERRIQ · Étude achevée · Observations jusqu’en 2025 · Révision septembre 2026

Le récit commence à Lachine : des logements autorisés, une population en hausse, puis une réoccupation commerciale concentrée sur Notre-Dame. Ahuntsic montre une hausse de population avec davantage de locaux vacants. Le Plateau présente une réoccupation importante malgré une faible hausse démographique antérieure.

Ce notebook reprend les résultats validés et vérifie les pièces qui les soutiennent. Population : 2016–2021. Locaux commerciaux : 2021–2025. L’occupation ne certifie pas des ouvertures ou fermetures d’entreprises, ni leurs revenus. La dernière cellule génère le rapport LaTeX français.

Exécuter le notebook

Python 3.9 ou plus récent, avec pandas, matplotlib et ipykernel. Décompressez l’archive de reproduction, ouvrez Jupyter dans research-deliverables/ et exécutez les cellules dans l’ordre. Les résultats sont déjà enregistrés pour la lecture sans noyau. Les entrées sont lues sans modification ; la dernière cellule écrit uniquement montreal_neighbourhood_change_fr.tex.

Les figures originales validées sont conservées. Leurs légendes d’origine sont en anglais ; les explications et les nouveaux tableaux de présentation sont en français.

Afficher le code Python · cellule 1
from pathlib import Path
from collections import Counter
import hashlib
import json
import math
import sys

import pandas as pd
import matplotlib.pyplot as plt
from IPython.display import display, Markdown, Image

candidates = [Path.cwd().resolve(), *Path.cwd().resolve().parents]
STUDY_ROOT = next((p for p in candidates if (p / 'PUBLICATION_EVIDENCE.json').is_file()
                   and (p / 'prototype/assets/study.json').is_file()), None)
if STUDY_ROOT is None:
    raise FileNotFoundError('Exécuter le notebook depuis le dossier research-deliverables de l’étude.')
DELIVERABLES = STUDY_ROOT / 'research-deliverables'
ASSETS = STUDY_ROOT / 'prototype/assets'

pd.set_option('display.max_colwidth', 100)
pd.set_option('display.max_rows', 30)
plt.rcParams.update({'figure.dpi': 125, 'font.family': 'DejaVu Sans',
                     'axes.spines.top': False, 'axes.spines.right': False})
print('Étude locale chargée. Les entrées sont lues sans modification.')
Étude locale chargée. Les entrées sont lues sans modification.

Les pièces et leur provenance

Le manifeste consigne les empreintes des entrées analytiques et des figures originales. La cellule contrôle ces fichiers, rapproche la présentation avec les preuves et relit la QA existante. Une entrée modifiée interrompt la vérification.

Afficher le code Python · cellule 2
def read_json(path):
    return json.loads(path.read_text(encoding='utf-8'))

def sha256(path):
    digest = hashlib.sha256()
    with path.open('rb') as stream:
        for chunk in iter(lambda: stream.read(1024 * 1024), b''):
            digest.update(chunk)
    return digest.hexdigest()

study = read_json(ASSETS / 'study.json')
evidence = read_json(STUDY_ROOT / 'PUBLICATION_EVIDENCE.json')
manifest = read_json(STUDY_ROOT / 'PUBLICATION_MANIFEST.json')
validation = read_json(STUDY_ROOT / 'PUBLICATION_VALIDATION.json')
assert validation['checks_passed'] == manifest['publication_checks']
assert validation['inputs_preserved'] is True
assert manifest['database_access'] == 'none'

source_checks = []
for relative, expected in manifest['input_sha256'].items():
    path = STUDY_ROOT / relative
    actual = sha256(path)
    assert actual == expected, f'Entrée modifiée : {path.name}'
    assert study['source_artifact_sha256'][path.name] == expected
    source_checks.append({'Artefact': path.name, 'SHA-256 vérifié': True})
assert sha256(STUDY_ROOT / 'PUBLICATION_EVIDENCE.json') == manifest['publication_files']['PUBLICATION_EVIDENCE.json']['sha256']
for name, recorded in manifest['figures'].items():
    assert sha256(ASSETS / 'figures' / name) == recorded['sha256'], name
for source in study['methodology_sources']['files']:
    assert sha256(ASSETS / 'methodology' / source['path']) == source['sha256']

cases = study['cases']
assert [c['tract_id'] for c in cases] == manifest['case_ids']
for c in cases:
    for key, expected in evidence[c['tract_id']].items():
        actual = c[key]
        if isinstance(expected, float):
            assert math.isclose(actual, expected, abs_tol=0.000001), (c['name'], key)
        else:
            assert actual == expected, (c['name'], key)
for key, expected in evidence['verdun'].items():
    assert study['verdun'][key] == expected, ('Verdun', key)
# Presentation-specific additions are independently checked against raw records.
raw_permits = pd.read_csv(STUDY_ROOT / 'data/deep_dive/permit_timeline.csv', dtype=str, keep_default_na=False).to_dict('records')
for record in study['verdun']['galt_records']:
    assert any(all(raw[k] == value for k, value in record.items()) for raw in raw_permits)
review = pd.read_csv(STUDY_ROOT / 'data/deep_dive/baseline_CO_description_review.csv', dtype=str, keep_default_na=False)
review = review[(review['tract_id'] == '4620305.00') & (review['housing_label_broad'] == 'True')]
classes = review['description_review_class'].value_counts()
assert len(review) == study['verdun']['housing_CO']
assert classes['principal_housing_construction_described'] == study['verdun']['principal_housing_descriptions']
assert classes['excavation_related_to_principal_building'] == study['verdun']['excavation_descriptions']
assert classes['other_work_no_new_principal_building_described'] == study['verdun']['other_descriptions']
assert study['relationship'] == evidence['relationships'][1]

print(f"Vérification : {len(source_checks)} empreintes analytiques, {len(manifest['figures'])} figures originales et 3 PDF de méthode.")
print(f"QA de publication existante : {validation['checks_passed']} contrôles et {validation['quantitative_claim_groups']} groupes de chiffres.")
display(pd.DataFrame(source_checks))
Vérification : 17 empreintes analytiques, 12 figures originales et 3 PDF de méthode.
QA de publication existante : 301 contrôles et 79 groupes de chiffres.
Résultats de la cellule 2
Artefact SHA-256 vérifié
0 relationships.csv True
1 tract_analysis.parquet True
2 baseline_CO_description_review.csv True
3 boundary_context_occupancy.csv True
4 commercial_category_composition.csv True
5 commercial_records.csv True
6 endpoint_premise_reconciliation.csv True
7 floor_comparable_category_composition.csv True
8 floor_comparable_stock.csv True
9 major_project_evidence.csv True
10 matched_transition_detail.csv True
11 permit_timeline.csv True
12 stock_panel_decomposition.csv True
13 tracts_2021.geojson True
14 source_manifest.json True
15 targeted_assessment_join_diagnostics.json True
16 official_borough_boundaries.geojson True

Population, 2016–2021

Deux recensements, sur la géographie préparée de l’étude. Ils ne décrivent ni migration annuelle ni date d’arrivée individuelle. L’arithmétique vérifie la variation publiée ; elle n’ajoute pas de conclusion analytique.

Afficher le code Python · cellule 3
population = pd.DataFrame([{
    'Dossier': c['name'], 'Secteur 2021': c['tract_id'],
    'Résidents 2016': c['population_2016'], 'Résidents 2021': c['population_2021'],
    'Variation de population (%)': c['population_change_pct'],
} for c in cases]).set_index('Dossier')
for c in cases:
    calculated = 100 * (c['population_2021'] - c['population_2016']) / c['population_2016']
    assert math.isclose(calculated, c['population_change_pct'], abs_tol=1e-10)
display(population.style.format({'Variation de population (%)': '{:+.1f}'}))
display(Image(filename=str(ASSETS / 'figures/overview_map.png'), width=1000))
Résultats de la cellule 3
  Secteur 2021 Résidents 2016 Résidents 2021 Variation de population (%)
Dossier        
Lachine 4620390.00 1198 1603 +33.8
Ahuntsic 4620270.00 4529 4739 +4.6
Plateau 4620142.00 1657 1683 +1.6
Carte originale des trois secteurs de recensement étudiés.

Carte : secteurs étudiés. Figure originale validée. Géographie : Statistique Canada ; contexte administratif actuel : Ville de Montréal. Le rapport d’aspect géographique est conservé. Les secteurs sont des unités analytiques à l’intérieur des quartiers, pas des zones de clientèle.

Les mêmes locaux, de 2021 à 2025

Le panel compare des locaux identifiables aux deux extrémités. Son dénominateur diffère de l’inventaire enquêté. Une réoccupation part de l’ensemble initialement vacant ; une transition vers la vacance, de l’ensemble initialement occupé. Des points de pourcentage d’occupation ne sont pas une croissance des revenus.

Afficher le code Python · cellule 4
panel = pd.DataFrame([{
    'Dossier': c['name'], 'Locaux appariés n': c['panel_n'],
    'Occupés 2021': c['panel_occupied_2021'], 'Vacants 2021': c['panel_vacant_2021'],
    'Occupés 2025': c['panel_occupied_2025'], 'Vacants 2025': c['panel_vacant_2025'],
    'Vacant → occupé': c['vacant_to_occupied'], 'Occupé → vacant': c['occupied_to_vacant'],
    'Variation de part occupée (points)': c['panel_occupied_change_pp'],
} for c in cases]).set_index('Dossier')
for c in cases:
    n = c['panel_n']
    assert c['panel_occupied_2021'] + c['panel_vacant_2021'] == n
    assert c['panel_occupied_2025'] + c['panel_vacant_2025'] == n
    assert c['panel_occupied_2025'] == c['panel_occupied_2021'] + c['vacant_to_occupied'] - c['occupied_to_vacant']
    expected_pp = 100 * (c['panel_occupied_2025'] - c['panel_occupied_2021']) / n
    assert math.isclose(expected_pp, c['panel_occupied_change_pp'], abs_tol=1e-10)
    assert c['vacant_to_occupied'] <= c['panel_vacant_2021']
    assert c['occupied_to_vacant'] <= c['panel_occupied_2021']
display(panel.style.format({'Variation de part occupée (points)': '{:+.1f}'}))

fig, axes = plt.subplots(1, 3, figsize=(12, 4.4), sharex=True)
for ax, c in zip(axes, cases):
    n = c['panel_n']
    occupied = [100 * c[f'panel_occupied_{year}'] / n for year in [2021, 2025]]
    vacant = [100 * c[f'panel_vacant_{year}'] / n for year in [2021, 2025]]
    ax.barh([1, 0], occupied, color='#007166', height=.45, label='Occupé')
    ax.barh([1, 0], vacant, left=occupied, color='#ead6b0', edgecolor='#8c682c', height=.45, label='Vacant')
    ax.set_yticks([1, 0], ['2021', '2025'])
    ax.set_xlim(0, 100); ax.set_xticks([0, 50, 100]); ax.set_xlabel('Part des locaux appariés (%)')
    ax.set_title(f"{c['name']} · n={n}", loc='left', fontsize=11, fontweight='bold')
    ax.text(0, -.28, f"2021: {c['panel_occupied_2021']} occupés / {c['panel_vacant_2021']} {'vacant' if c['panel_vacant_2021'] == 1 else 'vacants'}\n"
                     f"2025: {c['panel_occupied_2025']} occupés / {c['panel_vacant_2025']} vacants", fontsize=9, va='top')
    ax.set_ylim(-.72, 1.5)
handles, labels = axes[0].get_legend_handles_labels()
fig.legend(handles, labels, loc='lower center', ncol=2, frameon=False)
fig.suptitle('Occupation commerciale · locaux appariés, 2021–2025', x=.06, ha='left', fontsize=14)
fig.subplots_adjust(left=.06, right=.98, top=.8, bottom=.2, wspace=.30)
plt.show(); plt.close(fig)
Résultats de la cellule 4
  Locaux appariés n Occupés 2021 Vacants 2021 Occupés 2025 Vacants 2025 Vacant → occupé Occupé → vacant Variation de part occupée (points)
Dossier                
Lachine 25 20 5 23 2 3 0 +12.0
Ahuntsic 44 43 1 34 10 0 9 -20.5
Plateau 62 46 16 58 4 12 0 +19.4
Occupation commerciale des panels appariés, 2021 et 2025 ; effectifs occupés et vacants explicités.

Sources : enquêtes commerciales de la Ville de Montréal, 2021–2025 ; panels TERRIQ validés. Les décomptes accompagnent les deux observations. Aucun état intermédiaire n’est interpolé.

Inventaire et couverture

L’inventaire comprend des locaux hors du panel. Le périmètre comparable exclut l’étiquette de deuxième étage 2E aux deux dates. Cela réduit une différence connue sans résoudre chaque changement d’identifiant, d’unité, d’étage ou de local physique.

Afficher le code Python · cellule 5
inventory = pd.DataFrame([{
    'Dossier': c['name'], 'Tous étages, 2021': c['all_floor_stock_2021'],
    'Tous étages, 2025': c['all_floor_stock_2025'],
    'Étages comparables, 2021': c['comparable_stock_2021'],
    'Étages comparables, 2025': c['comparable_stock_2025'],
} for c in cases]).set_index('Dossier')
display(inventory)
Résultats de la cellule 5
Tous étages, 2021 Tous étages, 2025 Étages comparables, 2021 Étages comparables, 2025
Dossier
Lachine 41 41 41 41
Ahuntsic 59 52 55 52
Plateau 82 79 79 79

Lachine : relier les pièces

Observation. Au 380, avenue George-V, les autorisations du 22 octobre 2018 et du 17 juin 2019 décrivent le même projet de 51 logements. Le rôle actuel en consigne 51, avec une année de construction de 2019. La population passe de 1 198 à 1 603. Trois locaux sur Notre-Dame sont ensuite réoccupés.

Interprétation. Développement résidentiel documenté et croissance antérieure coexistent avec une réoccupation commerciale ultérieure localisée.

Question ouverte. L’effet causal des nouveaux résidents et les revenus. Au 300, avenue George-V, le rôle consigne 22 logements et une année de 2022, après le recensement. Le calendrier d’achèvement à Saint-Joseph reste non résolu. Les années foncières ne certifient pas une livraison.

Afficher le code Python · cellule 6
c = next(c for c in cases if c['key'] == 'lachine')
display(Image(filename=str(ASSETS / 'figures/lachine_case.png'), width=1000))
display(pd.DataFrame([{'Corridor': street, 'Locaux appariés changeant d’état': count}
                     for street, count in c['corridors'].items()]))
Carte et chronologie originales de Lachine.
Résultats de la cellule 6
Corridor Locaux appariés changeant d’état
0 RUE NOTRE-DAME O 3

Figure originale de Lachine. Locaux suivis, points d’autorisation George-V et trois transitions sur Notre-Dame. Au départ : 20 occupés / 5 vacants ; n=25. Commerce : 2021–2025. Deux locaux sont observés occupés pour la première fois le 28 juillet 2022 ; le troisième le 28 août 2023. Ce sont des dates d’enquête, pas d’ouverture. Les points de permis ne sont pas des empreintes immobilières ; les espacements de la chronologie ne représentent pas des durées proportionnelles. Sources : Ville de Montréal ; Statistique Canada ; étude TERRIQ.

Ahuntsic : une trajectoire divergente

Observation. La population passe de 4 529 à 4 739. Le permis Sauvé de 2017 et le rôle actuel identifient 83 logements. Neuf locaux initialement occupés sont vacants à la dernière observation.

Interprétation. Les signaux démographiques et résidentiels positifs coexistent avec davantage de vacance. La correction des étages de l’inventaire n’efface pas ces neuf transitions.

Question ouverte. Loyers, baux, demande, accessibilité et concurrence. Le calendrier du rôle Sauvé et le contexte de livraisons de la SCHL ne concordent pas ; aucun ne certifie l’achèvement du projet.

Afficher le code Python · cellule 7
c = next(c for c in cases if c['key'] == 'ahuntsic')
display(Image(filename=str(ASSETS / 'figures/ahuntsic_case.png'), width=1000))
display(pd.DataFrame([{'Corridor': street, 'Locaux appariés changeant d’état': count}
                     for street, count in c['corridors'].items()]))
Carte et chronologie originales d’Ahuntsic.
Résultats de la cellule 7
Corridor Locaux appariés changeant d’état
0 BOULEVARD SAINT-LAURENT 5
1 RUE LAJEUNESSE 2
2 RUE FOUCHER 1
3 RUE DE PORT-ROYAL E 1

Figure originale d’Ahuntsic. Neuf transitions occupé→vacant et un point d’autorisation Sauvé. Au départ : 43 occupés / 1 vacant ; n=44. Commerce : 2021–2025. Des unités distinctes peuvent partager une adresse. Certaines sont réoccupées entre deux visites : la chronologie n’implique pas un déclin continu. Sources : Ville de Montréal ; Statistique Canada ; étude TERRIQ.

Plateau : ce que la population seule masque

Observation. La population passe de 1 657 à 1 683. Douze locaux initialement vacants sont occupés à la dernière observation, sur Saint-Denis, Rachel et Duluth. Les descriptions de permis révèlent des transformations et des logements aux étages.

Interprétation. Une réoccupation substantielle accompagne une faible hausse démographique antérieure. Les seuls codes de construction neuve masqueraient aussi des transformations résidentielles.

Question ouverte. Causes de la réoccupation, performance financière et achèvement des logements. Un inventaire comparable stable n’implique pas des unités physiques ou identifiants inchangés.

Afficher le code Python · cellule 8
c = next(c for c in cases if c['key'] == 'plateau')
display(Image(filename=str(ASSETS / 'figures/plateau_case.png'), width=1000))
display(pd.DataFrame([{'Corridor': street, 'Locaux appariés changeant d’état': count}
                     for street, count in c['corridors'].items()]))
# Existing classification result; this is not a measure of sales or employment.
food = pd.DataFrame(study['plateau_food'])[['survey_edition', 'classified_occupied', 'share']]
food = food.rename(columns={'survey_edition': 'Édition de l’enquête', 'classified_occupied': 'Locaux occupés, alimentation et restauration', 'share': 'Part des locaux occupés classifiés'})
display(food.style.format({'Part des locaux occupés classifiés': '{:.1%}'}))
Carte et chronologie originales du Plateau.
Résultats de la cellule 8
Corridor Locaux appariés changeant d’état
0 AVENUE DULUTH E 2
1 RUE SAINT-DENIS 6
2 RUE RACHEL E 4
Résultats de la cellule 8
  Édition de l’enquête Locaux occupés, alimentation et restauration Part des locaux occupés classifiés
0 2021 20 36.4%
1 2025 30 42.3%

Figure originale du Plateau. Douze transitions vacant→occupé, trois corridors et transformations sélectionnées. Au départ : 46 occupés / 16 vacants ; n=62. Commerce : 2021–2025. La réoccupation n’est pas attribuée au permis antérieur. La comparaison alimentaire et restauration utilise le périmètre d’étages constant (20→30) ; le total initial tous étages était 21. Ces décomptes ne sont pas des ventes. Sources : Ville de Montréal ; Statistique Canada ; étude TERRIQ.

Autorisations et caractéristiques immobilières datées

Les descriptions originales et les dates soutiennent le récit. Une autorisation de construction ou de transformation ne certifie pas l’achèvement. Le nombre de logements touchés peut concerner un bâtiment existant ou être répété entre autorisations : il ne s’additionne pas comme des logements neufs nets.

Afficher le code Python · cellule 9
permit_rows = []
property_rows = []
for c in cases:
    for project in c['projects']:
        for record in project['permit_records']:
            permit_rows.append({'Dossier': c['name'], 'Adresse': project['address'],
                                'Date d’autorisation': record['issued_date'], 'Code': record['permit_type_code'],
                                'Champ brut des logements touchés': record['raw_dwellings_value'],
                                'Description originale des travaux': record['nature_travaux']})
    for record in c['assessments']:
        property_rows.append({'Dossier': c['name'], 'Caractéristiques immobilières': record['target'],
                              'Logements résidentiels consignés': record['current_recorded_dwelling_sum'],
                              'Années de construction inscrites': ', '.join(y for y in record['construction_years'] if y != '9999') or 'Non résolu',
                              'État modifié': record['stock_snapshot_last_modified'],
                              'Consulté': record['retrieved_date'], 'Confiance du rapprochement': record['join_confidence']})
display(pd.DataFrame(permit_rows).sort_values(['Dossier', 'Date d’autorisation']).reset_index(drop=True))
display(pd.DataFrame(property_rows))
Résultats de la cellule 9
Dossier Adresse Date d’autorisation Code Champ brut des logements touchés Description originale des travaux
0 Ahuntsic 500 rue Sauvé Est 2017-11-21 CO 83 Construire un bâtiment résidentiel contigu de 3 étages, 2 niveaux en sous-sol et 1 construction ...
1 Lachine 380 avenue George-V 2018-10-22 CO 0 51 condoplex
2 Lachine 380 avenue George-V 2019-06-17 CO 0 51 condoplex
3 Lachine 300 avenue George-V 2020-11-30 CO 22 Construction d'un immeuble de 5 étages, 22 logenements et 3 niveaux de sous-sol sur le lot numér...
4 Lachine 300 avenue George-V 2020-12-21 CA 0 BRANCHEMENT À L'ÉGOUT ET À L'AQUEDUC DE L'IMMEUBLE DE 5 ÉTAGES (22 LOGEMENTS). Complémentaire po...
5 Plateau 752 rue Rachel Est 2017-04-05 TR 8 Façade Rdc, côté gauche modifier vitrine pour ajout 1 porte en alcôve, remplacer porte centrale....
6 Plateau 752 rue Rachel Est 2019-10-09 TR 0 Suite au permis 3000640677-17, compléter les travaux aménagement des 8 logements. Aucuns travaux...
7 Plateau 4051 rue Saint-Denis 2021-08-27 TR 8 Au 2e et 3e étage, aménager 8 nouveaux logements. Au toit, ajouter des équipements mécaniques. T...
8 Plateau 4051 rue Saint-Denis 2025-04-25 TR 0 Au RC, réaménager un restaurant
Résultats de la cellule 9
Dossier Caractéristiques immobilières Logements résidentiels consignés Années de construction inscrites État modifié Consulté Confiance du rapprochement
0 Lachine 220 boulevard Saint-Joseph 0 Non résolu 2026-09-23 2026-09-30 unresolved_civic_range_parity_no_exact_220
1 Lachine 300 avenue George-V 22 2022 2026-09-23 2026-09-30 address_borough_match_no_stock_geometry
2 Lachine 380 avenue George-V property group 51 2019 2026-09-23 2026-09-30 shared_matricule_prefix_with_380_george_v_no_stock_geometry
3 Ahuntsic 500 rue Sauvé Est 83 2019 2026-09-23 2026-09-30 address_borough_match_completion_source_conflict

Historiques et premières observations d’un état différent

Les états par édition sont conservés. « Première observation occupée » ne signifie pas date d’ouverture ; « première observation vacante » ne signifie pas date de fermeture. Les unités distinctes d’une même adresse restent séparées. Seuls les locaux changeant d’état sont listés ; le dénominateur complet accompagne le tableau.

Afficher le code Python · cellule 10
history_rows = []
for c in cases:
    counts = Counter(r['transition'] for r in c['transition_premises'])
    assert counts['vacant→occupied'] == c['vacant_to_occupied']
    assert counts['occupied→vacant'] == c['occupied_to_vacant']
    dates = Counter()
    for record in c['transition_premises']:
        states = record['state_sequence'].split('→')
        assert len(states) == 5
        assert f'{states[0]}→{states[-1]}' == record['transition']
        changed_date = record.get('first_observed_occupied_after_baseline') or record.get('first_observed_vacant_after_baseline')
        dates[changed_date[:4]] += 1
        history_rows.append({'Dossier': c['name'], 'Locaux appariés n': c['panel_n'],
                             'Occupés / vacants 2021': f"{c['panel_occupied_2021']} / {c['panel_vacant_2021']}",
                             'Adresse': record['baseline_address'], 'Étage': record['baseline_floor'],
                             'Unité': record['baseline_suite'] or 'Non fourni',
                             **dict(zip(map(str, range(2021, 2026)), states)),
                             'Première observation du nouvel état': changed_date})
    assert dict(sorted(dates.items())) == c['first_observed_transition_year_counts']
histories = pd.DataFrame(history_rows)
display(histories.replace({'occupied': 'occupé', 'vacant': 'vacant', 'missing': 'non observé', 'unknown': 'inconnu'}))
Résultats de la cellule 10
Dossier Locaux appariés n Occupés / vacants 2021 Adresse Étage Unité 2021 2022 2023 2024 2025 Première observation du nouvel état
0 Lachine 25 20 / 5 685 rue Notre-Dame O RC Non fourni vacant vacant occupé occupé occupé 2023-08-28
1 Lachine 25 20 / 5 675 rue Notre-Dame O RC Non fourni vacant occupé occupé occupé occupé 2022-07-28
2 Lachine 25 20 / 5 845 rue Notre-Dame O RC Non fourni vacant occupé occupé occupé occupé 2022-07-28
3 Ahuntsic 44 43 / 1 9801 boulevard Saint-Laurent DEMI SOUS-SOL A occupé vacant occupé occupé vacant 2022-07-11
4 Ahuntsic 44 43 / 1 10134 rue Lajeunesse RC Non fourni occupé vacant vacant vacant vacant 2022-07-11
5 Ahuntsic 44 43 / 1 10215 boulevard Saint-Laurent RC Non fourni occupé occupé vacant vacant vacant 2023-06-27
6 Ahuntsic 44 43 / 1 10136 rue Lajeunesse RC Non fourni occupé occupé occupé occupé vacant 2025-07-03
7 Ahuntsic 44 43 / 1 9801 boulevard Saint-Laurent DEMI SOUS-SOL Non fourni occupé occupé occupé vacant vacant 2024-07-12
8 Ahuntsic 44 43 / 1 9699 rue Foucher RC Non fourni occupé occupé vacant vacant vacant 2023-06-07
9 Ahuntsic 44 43 / 1 10085 boulevard Saint-Laurent RC Non fourni occupé occupé occupé occupé vacant 2025-07-03
10 Ahuntsic 44 43 / 1 10045 boulevard Saint-Laurent RC Non fourni occupé occupé occupé occupé vacant 2025-07-03
11 Ahuntsic 44 43 / 1 4 rue de Port-Royal E RC Non fourni occupé vacant occupé vacant vacant 2022-08-02
12 Plateau 62 46 / 16 619 avenue Duluth E RC Non fourni vacant occupé occupé occupé occupé 2022-05-13
13 Plateau 62 46 / 16 4159 rue Saint-Denis RC Non fourni vacant vacant vacant occupé occupé 2024-05-27
14 Plateau 62 46 / 16 4123 rue Saint-Denis SOUS-SOL Non fourni vacant vacant vacant vacant occupé 2025-06-11
15 Plateau 62 46 / 16 4117 rue Saint-Denis RC Non fourni vacant vacant occupé occupé occupé 2023-05-24
16 Plateau 62 46 / 16 4109 rue Saint-Denis RC Non fourni vacant vacant vacant vacant occupé 2025-06-11
17 Plateau 62 46 / 16 4097 rue Saint-Denis RC Non fourni vacant vacant occupé occupé occupé 2023-05-24
18 Plateau 62 46 / 16 4065 rue Saint-Denis RC Non fourni vacant vacant vacant occupé occupé 2024-05-27
19 Plateau 62 46 / 16 411 avenue Duluth E RC Non fourni vacant occupé occupé occupé occupé 2022-05-13
20 Plateau 62 46 / 16 752 rue Rachel E RC Non fourni vacant vacant vacant occupé occupé 2024-05-23
21 Plateau 62 46 / 16 800 rue Rachel E RC Non fourni vacant occupé occupé occupé occupé 2022-05-13
22 Plateau 62 46 / 16 964 rue Rachel E RC Non fourni vacant vacant vacant occupé occupé 2024-05-23
23 Plateau 62 46 / 16 980 rue Rachel E RC Non fourni vacant occupé occupé occupé occupé 2022-05-13

Replacer les cas dans le contexte montréalais

L’exploration achevée retient 267 secteurs strictement admissibles. L’association de Spearman déjà consignée entre croissance antérieure et variation ultérieure de la part occupée est d’environ −0,028. Elle est reprise du dossier, sans nouvelle estimation. Une association de rang proche de zéro n’exclut pas des relations locales ou non linéaires et ne prouve pas une causalité.

Afficher le code Python · cellule 11
relationship = study['relationship']
assert relationship['n'] == manifest['eligible_scatter_n'] == 267
print(f"Association déjà consignée : Spearman rho={relationship['spearman']:.3f}; n={relationship['n']}.")
display(Image(filename=str(ASSETS / 'figures/population_vs_commerce.png'), width=1000))
display(Image(filename=str(ASSETS / 'figures/three_case_comparison.png'), width=1000))
Association déjà consignée : Spearman rho=-0.028; n=267.
Figure comparative originale ; explication et dénominateurs dans les paragraphes qui encadrent la cellule.Figure comparative originale ; explication et dénominateurs dans les paragraphes qui encadrent la cellule.

Figures comparatives originales. Population 2016–2021 ; locaux commerciaux 2021–2025. Le nuage conserve l’étendue complète ; trois observations sont hors de la vue de détail. Ensembles initiaux : Lachine 20 occupés/5 vacants, n=25 ; Ahuntsic 43/1, n=44 ; Plateau 46/16, n=62. Les transitions tracées à gauche demeurent des décomptes non négatifs. Les cas illustrent des contrastes, sans classement. Sources : Statistique Canada ; Ville de Montréal ; étude TERRIQ.

Verdun : ce que le nombre cache

Le total codé est exact, mais les descriptions distinguent construction résidentielle principale et autres travaux. La méthode d’enquête modifie également la lecture d’une baisse d’inventaire. Ces corrections sont déjà établies dans l’étude.

Afficher le code Python · cellule 12
v = study['verdun']
assert v['housing_CO'] == v['principal_housing_descriptions'] + v['excavation_descriptions'] + v['other_descriptions']
permit_review = pd.DataFrame([
    ['Événements codés construction résidentielle', v['housing_CO']],
    ['Descriptions directes de construction principale', v['principal_housing_descriptions']],
    ['Excavations associées', v['excavation_descriptions']],
    ['Autres descriptions de travaux', v['other_descriptions']],
], columns=['Description, 2016–2020', 'Événements'])
display(permit_review)
display(pd.DataFrame(v['galt_records'])[['issued_date', 'nature_travaux', 'raw_dwellings_value']]
        .rename(columns={'issued_date': 'Date d’autorisation', 'nature_travaux': 'Description originale au 200 Galt', 'raw_dwellings_value': 'Champ des logements touchés'}))
verdun_inventory = pd.DataFrame([
    ['Tous les étages principaux observés', *v['all_floor_stock']],
    ['Deuxièmes étages exclus aux deux dates', *v['comparable_stock']],
], columns=['Périmètre de l’enquête', 'Locaux 2021', 'Locaux 2025'])
verdun_inventory['Variation de l’inventaire observé'] = verdun_inventory['Locaux 2025'] - verdun_inventory['Locaux 2021']
assert v['all_floor_stock'][0] - v['comparable_stock'][0] == v['upper_floor_cohort'] == 18
display(verdun_inventory)
Résultats de la cellule 12
Description, 2016–2020 Événements
0 Événements codés construction résidentielle 289
1 Descriptions directes de construction principale 2
2 Excavations associées 2
3 Autres descriptions de travaux 285
Résultats de la cellule 12
Date d’autorisation Description originale au 200 Galt Champ des logements touchés
0 2016-08-31 EXT - Réfection de la façade et du mur arrière en brique (même brique réutilisée). 37
1 2016-10-03 EXT - Abattage d'un tilleul situé dans la cour avant car mort. 37
Résultats de la cellule 12
Périmètre de l’enquête Locaux 2021 Locaux 2025 Variation de l’inventaire observé
0 Tous les étages principaux observés 104 90 -14
1 Deuxièmes étages exclus aux deux dates 86 90 4

Observation. Les 289 événements codés comprennent 2 descriptions directes de construction résidentielle principale, 2 excavations associées et 285 autres descriptions. Au 200, rue Galt, les 37 logements touchés se répètent pour réparation de briques et retrait d’arbre mort : ce ne sont pas 74 logements neufs. Les 18 fiches occupées d’étages supérieurs vues en 2021 et 2022 sont absentes en 2023, au changement de périmètre.

Interprétation. Les agrégats ne démontrent pas des centaines de nouveaux projets résidentiels et une disparition physique des locaux.

Question ouverte. Logements achevés et statut physique des locaux non rapprochés. Des fiches manquantes ne certifient pas des fermetures.

Limites de lecture

Afficher le code Python · cellule 13
from render_latex_report_fr import SOURCES
source_rows = [{'Source': author, 'Usage': description.replace('--', '–'), 'URL publique originale': url}
               for author, description, url in SOURCES]
display(pd.DataFrame(source_rows))
for source in study['methodology_sources']['files']:
    display(Markdown(f"**{source['edition']} méthode de l’enquête :** [PDF public original]({source['url']}); "
                     f"[copie vérifiée](../prototype/assets/methodology/{source['path']})."))
Résultats de la cellule 13
Source Usage URL publique originale
0 Statistique Canada Recensement de 2021, comparateur préparé de 2016 et géographie des secteurs de 2021. https://www12.statcan.gc.ca/census-recensement/2021/dp-pd/prof/index.cfm?Lang=E
1 Ville de Montréal Permis de construction : autorisations, dates, codes et descriptions originales. https://www.donneesquebec.ca/recherche/dataset/vmtl-permis-construction
2 Ville de Montréal Locaux commerciaux : éditions de 2021 à 2025 et documents de méthode. https://www.donneesquebec.ca/recherche/dataset/vmtl-locaux-commerciaux
3 Ville de Montréal Unités d’évaluation foncière : état modifié le 23 septembre 2026 et consulté le 30 septembre 2026. https://www.donneesquebec.ca/recherche/dataset/vmtl-unites-evaluation-fonciere
4 Ville de Montréal Limites administratives actuelles, à titre de contexte cartographique. https://donneesquebec.ca/recherche/dataset/vmtl-limites-administratives-agglomeration
5 SCHL Contexte résidentiel déjà préparé ; limites de géographie et de calendrier. https://www03.cmhc-schl.gc.ca/hmip-pimh/en

2025 méthode de l’enquête : PDF public original; copie vérifiée.

2023 méthode de l’enquête : PDF public original; copie vérifiée.

2022 méthode de l’enquête : PDF public original; copie vérifiée.

Attributions

Adapté de Statistique Canada, Recensement de la population de 2021, comparateur préparé de 2016 et secteurs de 2021. Cette adaptation ne constitue pas une approbation du produit par Statistique Canada. Licence ouverte de Statistique Canada. Les données municipales et les figures sont adaptées de la Ville de Montréal sous CC BY 4.0. TERRIQ est responsable des adaptations et interprétations. Le contexte complémentaire reprend les données de la SCHL déjà préparées ; aucune approbation municipale, de Statistique Canada ou de la SCHL n’est suggérée.

Conclusion

À Lachine, logement et croissance antérieure coexistent avec une réoccupation localisée. Ahuntsic associe croissance antérieure et vacance accrue. Le Plateau présente une réoccupation substantielle avec peu de croissance antérieure. Définitions, dates et géographie changent la lecture des indicateurs.

Générer le rapport LaTeX français

La dernière cellule écrit le document autonome à partir des preuves vérifiées. Ses barres natives reprennent les mêmes dénominateurs. Les cartes et figures originales sont conservées dans le notebook. Les entrées analytiques et les documents d’origine sont lus sans modification.

Afficher le code Python · cellule 14
from render_latex_report_fr import write_report
report_path = write_report(study, DELIVERABLES / 'montreal_neighbourhood_change_fr.tex')
print(f'Création de {report_path.name} à partir des preuves vérifiées.')
print('Vérifications terminées. Le notebook reprend l’étude achevée.')
Création de montreal_neighbourhood_change_fr.tex à partir des preuves vérifiées.
Vérifications terminées. Le notebook reprend l’étude achevée.