Skip to main content

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 ::numeric avant 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}'
""")