REX 06079
Contexte
Affichage des IRIS de Mandelieu-la-Napoule (06079) depuis PostGIS Alteris, avec population graduée et étiquettes — entièrement piloté depuis Claude Code via le MCP QGIS, sans interaction manuelle dans QGIS.
Données utilisées
| Table | Schéma | Contenu |
|---|---|---|
contours_iris_2025 |
insee_raw |
Géométries IRIS France entière |
iris_2025_population |
insee_raw |
Population 2022 par IRIS (recensement) |
Colonnes clés — pièges à retenir
contours_iris_2025 : colonnes standard sans espace — code_insee, code_iris, nom_iris, type_iris, geom
iris_2025_population : colonnes avec espace traînant (import INSEE brut) :
- Clé IRIS :
"IRIS "(avec espace) - Commune :
"COM "(avec espace) - Population totale 2022 :
"P22_POP "(avec espace) - Toutes les colonnes sont de type
text— caster en::numericavant usage
Résultats
9 IRIS pour 06079, population 2022 :
| code_iris | nom_iris | population |
|---|---|---|
| 060790101 | Zone d'activités | 24 |
| 060790102 | IRIS 2 | 2 701 |
| 060790103 | IRIS 3 | 2 000 |
| 060790104 | IRIS 4 | 3 058 |
| 060790105 | IRIS 5 | 2 197 |
| 060790106 | IRIS 6 | 2 432 |
| 060790107 | IRIS 7 | 3 188 |
| 060790108 | IRIS 8 | 2 944 |
| 060790109 | IRIS 9 | 2 656 |
Population min : 24 hab. (zone d'activités/naturelle) — max : 3 188 hab.
Procédure complète
Prérequis
Tunnel SSH paramiko actif (voir page 229 — Option 2) :
import sys
sys.path.insert(0, r'C:\Users\eliob\AppData\Roaming\Python\Python312\site-packages')
import paramiko
# ... lancer SSHTunnel vers localhost:5433
1. Identifier les tables
import psycopg2
conn = psycopg2.connect(host='localhost', port=5433, dbname='alteris_geo',
user='alteris_admin', password='Alteris2026')
cur = conn.cursor()
cur.execute("SELECT table_schema, table_name FROM information_schema.tables WHERE table_name ILIKE '%iris%' ORDER BY 1,2")
print(cur.fetchall())
2. Créer une vue PostgreSQL (contournement du bug URI)
Problème rencontré : charger une sous-requête SQL directement dans l'URI QGIS échoue quand la requête contient des guillemets doubles ("P22_POP "). QgsDataSourceUri.setDataSource() sur-échappe les guillemets (\\\") → couche invalide.
Solution : créer une vue PostgreSQL et charger la vue comme une table normale.
cur.execute("""
CREATE OR REPLACE VIEW insee_raw.v_iris_mandelieu_pop AS
SELECT c.fid, c.geom, c.nom_iris, c.code_iris,
ROUND(p."P22_POP "::numeric, 0)::integer AS population
FROM insee_raw.contours_iris_2025 c
LEFT JOIN insee_raw.iris_2025_population p ON p."IRIS " = c.code_iris
WHERE c.code_insee = '06079'
""")
conn.commit()
conn.close()
3. Charger la vue comme couche QGIS
from qgis.core import QgsProject, QgsVectorLayer
uri = (
'host=localhost port=5433 dbname=alteris_geo '
'user=alteris_admin password=Alteris2026 sslmode=disable '
'table="insee_raw"."v_iris_mandelieu_pop" (geom) key=fid'
)
layer = QgsVectorLayer(uri, "IRIS Mandelieu-la-Napoule", "postgres")
# → Valide: True — Entités: 9
4. Graduation par population
from qgis.core import QgsGraduatedSymbolRenderer, QgsRendererRange, QgsFillSymbol
colors = ['#EFF3FF', '#BDD7E7', '#6BAED6', '#2171B5', '#084594'] # blanc → bleu foncé
pmin, pmax = 24, 3188
step = (pmax - pmin) / 5
bounds = [pmin + i * step for i in range(6)]
ranges_def = []
for i in range(5):
lo, hi = bounds[i], bounds[i+1]
sym = QgsFillSymbol.createSimple({
'color': colors[i], 'outline_color': '#555555', 'outline_width': '0.3'
})
label = f"{int(lo):,}–{int(hi):,} hab.".replace(',', ' ')
ranges_def.append(QgsRendererRange(lo, hi, sym, label))
renderer = QgsGraduatedSymbolRenderer('population', ranges_def)
layer.setRenderer(renderer)
5. Étiquettes (nom IRIS + population)
from qgis.core import (
QgsPalLayerSettings, QgsTextFormat, QgsTextBufferSettings,
QgsVectorLayerSimpleLabeling
)
from qgis.PyQt.QtGui import QColor, QFont
pal = QgsPalLayerSettings()
pal.fieldName = "concat(nom_iris, '\n', population, ' hab.')"
pal.isExpression = True
pal.placement = QgsPalLayerSettings.Placement.OverPoint
fmt = QgsTextFormat()
fmt.setFont(QFont("Arial", 8))
fmt.setSize(8)
fmt.setColor(QColor('#1a1a1a'))
buf = QgsTextBufferSettings()
buf.setEnabled(True)
buf.setSize(1)
buf.setColor(QColor('white'))
fmt.setBuffer(buf)
pal.setFormat(fmt)
layer.setLabelsEnabled(True)
layer.setLabeling(QgsVectorLayerSimpleLabeling(pal))
QgsProject.instance().addMapLayer(layer)
Points clés et pièges
| Sujet | Constat |
|---|---|
| Colonnes INSEE avec espace | Toutes les colonnes de iris_2025_population ont un espace traînant — utiliser "IRIS ", "COM ", "P22_POP " |
| Types text | Toutes les valeurs numériques sont stockées en text — caster avec ::numeric |
| Sous-requête URI QGIS | QgsDataSourceUri.setDataSource() sur-échappe les guillemets doubles → couche invalide. Contournement : créer une vue PostgreSQL |
sys.executable QGIS |
Pointe sur qgis-bin.exe, pas python.exe — subprocess/pip inutilisable directement |
| Import manquant | QgsVectorLayerSimpleLabeling doit être importé explicitement depuis qgis.core |
Généralisation à d'autres communes
Remplacer '06079' par le code INSEE cible dans la vue :
cur.execute(f"""
CREATE OR REPLACE VIEW insee_raw.v_iris_pop AS
SELECT c.fid, c.geom, c.nom_iris, c.code_iris, c.nom_commune,
ROUND(p."P22_POP "::numeric, 0)::integer AS population
FROM insee_raw.contours_iris_2025 c
LEFT JOIN insee_raw.iris_2025_population p ON p."IRIS " = c.code_iris
WHERE c.code_insee = '{code_insee}'
""")