comment Add Comment
Posted on Last updated

Création d’une série de pictogrammes dynamique

Cette publication met en oeuvre un moyen automatisé de symboliser les commodités disponibles à un emplacement, en l’occurrence dans cette article les équipements sportifs, en utilisant une série d’icônes :

 

Cet article s’inspire fortement de l’article d’Anita Graser que vous pouvez retrouver ici : https://anitagraser.com/2016/03/19/creating-dynamic-icon-series/

Je vais un peu plus loin en proposant une façon de générer la table attributaire adéquate avec une requête SQL via PostgreSQL/PostGIS.

 

1 – Intégration du fichier de base

La couche géographique référence les équipements sportifs sur le territoire de ViennAgglo. L’audit a été réalisé par l’entreprise PROCESS pour le compte de ViennAgglo et notre fichier de base est un fichier Excel contenant l’ensemble des équipements par site et géo-référencés par un champ longitude et latitude. Ce fichier est épuré (reprise des noms de champ, suppression des espaces superflus, etc) et intégré à notre base PostgreSQL/PostGIS par l’intermédiaire de QGIS afin de pouvoir réaliser des requêtes SQL. Voici un extrait du fichier Excel :

 

 

 

 

2 – Requête SQL

Voici la requête SQL qui permet de grouper chaque équipement d’un site dans un seul et unique équipement. Pour rappel, notre fichier Excel référence chaque équipement (piste d’athlétisme, terrain de football, centre aquatique) de chaque site (installation) et de réaliser notre analyse thématique dans QGIS avec une série de pictogramme dynamique.

WITH
	equipement_sportif AS (
		SELECT	equipement.capv_equipement_sport.the_geom,
			equipement.capv_equipement_sport.item,
			equipement.capv_equipement_sport.numero,
			equipement.capv_equipement_sport.code_insee,
			equipement.capv_equipement_sport.nom_installation_sportive,
			equipement.capv_equipement_sport.installation_sportive,
			equipement.capv_equipement_sport.equipement_sportif
		  FROM equipement.capv_equipement_sport
		  WHERE equipement.capv_equipement_sport.longitude != 0
		  ORDER BY equipement.capv_equipement_sport.code_insee,equipement.capv_equipement_sport.nom_installation_sportive
	),
	equipement_sportif_installation_sportive_unique AS (
		SELECT	ST_CENTROID(ST_COLLECT(equipement_sportif.the_geom)) AS the_geom,
			equipement_sportif.code_insee,
			equipement_sportif.nom_installation_sportive,
			equipement_sportif.installation_sportive,
			COUNT(equipement_sportif.installation_sportive) AS nb_installation_sportive
		  FROM equipement_sportif
		  GROUP BY equipement_sportif.code_insee,equipement_sportif.nom_installation_sportive,equipement_sportif.installation_sportive
		  ORDER BY equipement_sportif.code_insee,equipement_sportif.nom_installation_sportive
	),
	equipement_sportif_unique AS (
		SELECT	ST_CENTROID(ST_COLLECT(equipement_sportif_installation_sportive_unique.the_geom)) AS the_geom,
			equipement_sportif_installation_sportive_unique.code_insee,
			equipement_sportif_installation_sportive_unique.nom_installation_sportive,
			SORT(STRING_TO_ARRAY(GROUP_CONCAT(equipement_sportif_installation_sportive_unique.installation_sportive),',')) AS array_installation_sportive,
			SUM(equipement_sportif_installation_sportive_unique.nb_installation_sportive) AS nb_installation_sportive
		  FROM equipement_sportif_installation_sportive_unique
		  GROUP BY equipement_sportif_installation_sportive_unique.code_insee,equipement_sportif_installation_sportive_unique.nom_installation_sportive
		  ORDER BY equipement_sportif_installation_sportive_unique.code_insee,equipement_sportif_installation_sportive_unique.nom_installation_sportive
	)
SELECT	row_number() OVER() AS gid,
	equipement_sportif_unique.the_geom::geometry(POINT,3945),
	equipement_sportif_unique.code_insee,
	equipement_sportif_unique.nom_installation_sportive,
	equipement_sportif_unique.array_installation_sportive,
	equipement_sportif_unique.nb_installation_sportive,
	equipement_sportif_unique.array_installation_sportive[1] AS icon1,
	equipement_sportif_unique.array_installation_sportive[2] AS icon2,
	equipement_sportif_unique.array_installation_sportive[3] AS icon3,
	equipement_sportif_unique.array_installation_sportive[4] AS icon4,
	equipement_sportif_unique.array_installation_sportive[5] AS icon5,
	equipement_sportif_unique.array_installation_sportive[6] AS icon6,
	equipement_sportif_unique.array_installation_sportive[7] AS icon7
 FROM equipement_sportif_unique

 

Explications

2-1 – Commençons par sélectionner les champs utiles à la réalisation de notre cartographie. La couche dispose de 71 champs, ne prenons que le strict minimum :

equipement_sportif AS (
	SELECT	equipement.capv_equipement_sport.the_geom,
		equipement.capv_equipement_sport.item,
		equipement.capv_equipement_sport.numero,
		equipement.capv_equipement_sport.code_insee,
		equipement.capv_equipement_sport.nom_installation_sportive,
		equipement.capv_equipement_sport.installation_sportive,
		equipement.capv_equipement_sport.equipement_sportif
	  FROM equipement.capv_equipement_sport
	  WHERE equipement.capv_equipement_sport.longitude != 0
	  ORDER BY equipement.capv_equipement_sport.code_insee,equipement.capv_equipement_sport.nom_installation_sportive
)

 

2-2 – Regroupement par site (installation)

Les équipements sportifs sélectionnés, passons à la 2ème étape qui consiste à regrouper pour chaque site les informations utiles à la réalisation de la série de pictogrammes tels que le nom du site, le nombre d’équipements (le AS nb_installation_sportive) et le type d’équipement ((le AS installation_sportive) qui sera dispatché dans une série de champs « icon1, icon2, icon3, etc » qui va permettre de générer le style de notre emplacement.

Le géo-référencement se fera donc par la récupération du centroïde de la collection de points créée par le regroupement par nom d’installation (en plus du code INSEE de la commune)s.

equipement_sportif_installation_sportive_unique AS (
	SELECT	ST_CENTROID(ST_COLLECT(equipement_sportif.the_geom)) AS the_geom,
		equipement_sportif.code_insee,
		equipement_sportif.nom_installation_sportive,
		equipement_sportif.installation_sportive,
		COUNT(equipement_sportif.installation_sportive) AS nb_installation_sportive
	  FROM equipement_sportif
	  GROUP BY equipement_sportif.code_insee,equipement_sportif.nom_installation_sportive,equipement_sportif.installation_sportive
	  ORDER BY equipement_sportif.code_insee,equipement_sportif.nom_installation_sportive
)

 

2-3 – Regroupement final & construction d’un tableau contenant les équipements du site

La troisième étape consiste à regrouper les tuples de la requête 2 par nom d’installation et code INSEE. L’étape cruciale ici réside dans cette commande (en gras dans la requête ci-dessous) qui va permettre de retourner un tableau créé à partir de la chaîne de caractère obtenue par la fonction GROUP_CONCAT (cf ici pour la fonction).

equipement_sportif_unique AS (
	SELECT	ST_CENTROID(ST_COLLECT(equipement_sportif_installation_sportive_unique.the_geom)) AS the_geom,
		equipement_sportif_installation_sportive_unique.code_insee,
		equipement_sportif_installation_sportive_unique.nom_installation_sportive,
		SORT(STRING_TO_ARRAY(GROUP_CONCAT(equipement_sportif_installation_sportive_unique.installation_sportive),',')) AS array_installation_sportive,
		SUM(equipement_sportif_installation_sportive_unique.nb_installation_sportive) AS nb_installation_sportive
	  FROM equipement_sportif_installation_sportive_unique
	  GROUP BY equipement_sportif_installation_sportive_unique.code_insee,equipement_sportif_installation_sportive_unique.nom_installation_sportive
	  ORDER BY equipement_sportif_installation_sportive_unique.code_insee,equipement_sportif_installation_sportive_unique.nom_installation_sportive
)

Attention, ici la fonction SORT() pour un tableau doit être préalablement installée dans votre base de données sous postgreSQL en activant l’extension intarray

CREATE EXTENSION intarray;

Cette fonction va nous permettre de trier les éléments du tableau par ordre alphabétique (afin d’avoir une série de pictogramme toujours dans le même ordre).

 

 

 

2-4 – Dernière étape !

On arrive donc à la dernière étape de la requête SQL :

WITH
	equipement_sportif AS (
		SELECT	equipement.capv_equipement_sport.the_geom,
			equipement.capv_equipement_sport.item,
			equipement.capv_equipement_sport.numero,
			equipement.capv_equipement_sport.code_insee,
			equipement.capv_equipement_sport.nom_installation_sportive,
			equipement.capv_equipement_sport.installation_sportive,
			equipement.capv_equipement_sport.equipement_sportif
		  FROM equipement.capv_equipement_sport
		  WHERE equipement.capv_equipement_sport.longitude != 0
		  ORDER BY equipement.capv_equipement_sport.code_insee,equipement.capv_equipement_sport.nom_installation_sportive
	),
	equipement_sportif_installation_sportive_unique AS (
		SELECT	ST_CENTROID(ST_COLLECT(equipement_sportif.the_geom)) AS the_geom,
			equipement_sportif.code_insee,
			equipement_sportif.nom_installation_sportive,
			equipement_sportif.installation_sportive,
			COUNT(equipement_sportif.installation_sportive) AS nb_installation_sportive
		  FROM equipement_sportif
		  GROUP BY equipement_sportif.code_insee,equipement_sportif.nom_installation_sportive,equipement_sportif.installation_sportive
		  ORDER BY equipement_sportif.code_insee,equipement_sportif.nom_installation_sportive
	),
	equipement_sportif_unique AS (
		SELECT	ST_CENTROID(ST_COLLECT(equipement_sportif_installation_sportive_unique.the_geom)) AS the_geom,
			equipement_sportif_installation_sportive_unique.code_insee,
			equipement_sportif_installation_sportive_unique.nom_installation_sportive,
			SORT(STRING_TO_ARRAY(GROUP_CONCAT(equipement_sportif_installation_sportive_unique.installation_sportive),',')) AS array_installation_sportive,
			SUM(equipement_sportif_installation_sportive_unique.nb_installation_sportive) AS nb_installation_sportive
		  FROM equipement_sportif_installation_sportive_unique
		  GROUP BY equipement_sportif_installation_sportive_unique.code_insee,equipement_sportif_installation_sportive_unique.nom_installation_sportive
		  ORDER BY equipement_sportif_installation_sportive_unique.code_insee,equipement_sportif_installation_sportive_unique.nom_installation_sportive
	)
SELECT	row_number() OVER() AS gid,
	equipement_sportif_unique.the_geom::geometry(POINT,3945),
	equipement_sportif_unique.code_insee,
	equipement_sportif_unique.nom_installation_sportive,
	equipement_sportif_unique.array_installation_sportive,
	equipement_sportif_unique.nb_installation_sportive,
	equipement_sportif_unique.array_installation_sportive[1] AS icon1,
	equipement_sportif_unique.array_installation_sportive[2] AS icon2,
	equipement_sportif_unique.array_installation_sportive[3] AS icon3,
	equipement_sportif_unique.array_installation_sportive[4] AS icon4,
	equipement_sportif_unique.array_installation_sportive[5] AS icon5,
	equipement_sportif_unique.array_installation_sportive[6] AS icon6,
	equipement_sportif_unique.array_installation_sportive[7] AS icon7
 FROM equipement_sportif_unique

La fin de la requête (en gras) permet de générer notre résultat en créant 7 nouveaux champs correspondant aux pictogrammes qui seront affichés dans QGIS pour chaque site (installation). Pour cela, on récupère les items du tableau grâce à leur index. Si l’item n’existe pas, la requête retourne une réponse NULL :

 

La requête réalisée dans le gestionnaire de base de données de QGIS peut être ainsi insérée dans QGIS pour être visualisée :

 

 

3 – QGIS

Dans QGIS, nous avons maintenant une couche de points (cf image ci-dessus) qui va nous permettre de générer une série de pictogramme dynamique.

 

3-1- Allons dans les propriétés de la couche et dans la gestion des styles. Activer une gestion par « Symbole Unique ». J’ai gardé un symbole point pour marquer le lieu exact du site

 

3-2 – Ajoutez une couche de symbole et choisissez « Symbole SVG »

 

3-3 – Dans le choix des symboles, j’ai préalablement créé 7 symboles SVG sous Illustrator que j’ai copié dans la bibliothèque de symboles de QGIS pour en avoir l’usage.

 

J’ai ensuite activé l’éditeur d’expression pour ajouter cette expression qui va permettre de sélectionner le symbole SVG à afficher suivant la valeur de l’attribut « icon1 » :

CASE
WHEN "icon1" = 'Athlétisme' THEN 'C:/OSGEO4~1/apps/qgis/./svg/sport/map_icon_running.svg'
WHEN "icon1" = 'Centre aquatique' THEN 'C:/OSGEO4~1/apps/qgis/./svg/sport/map_icon_swimming.svg'
WHEN "icon1" = 'Complexe sportif' THEN 'C:/OSGEO4~1/apps/qgis/./svg/sport/map_icon_complex.svg'
WHEN "icon1" = 'Plateau sportif' THEN 'C:/OSGEO4~1/apps/qgis/./svg/sport/map_icon_soccer.svg'
WHEN "icon1" = 'Salle de combat' THEN 'C:/OSGEO4~1/apps/qgis/./svg/sport/map_icon_judo.svg'
WHEN "icon1" = 'Tennis' THEN 'C:/OSGEO4~1/apps/qgis/./svg/sport/map_icon_tennis.svg'
WHEN "icon1" = 'Terrains de grands jeux' THEN 'C:/OSGEO4~1/apps/qgis/./svg/sport/map_icon_soccerfield.svg'
ELSE ''
END

 

3-4 – J’active ensuite l’éditeur d’expression de la taille du symbole afin de gérer son affichage :

 

CASE
WHEN "icon1" IS NULL THEN 0
ELSE 10
END

 

3-5 – Gestion du décalage du pictogramme – A paramétrer suivant vos goûts et la taille du pictogramme en SVG !

icon1

 

icon2

 

3-6 – Ensuite, il faut ajouter encore 6 autres symboles SVG avec les mêmes paramètres que précédemment et en n’oubliant pas de changer le nom du champ (ici icon1 en icon2) afin de gérer l’affichage du pictogramme 2 ainsi que le décalage. Ici j’ai ajouté 6 mm à chaque picto. Le picto 7 est donc à 4 + (6mm*7) = 46mm en X !

 

Nous arrivons à la fin de l’article. Dans la configuration du Marker dans QGIS, vous aurez donc un symbole « Point » pour marquer l’emplacement du site puis 7 autres symboles SVG qui correspondront aux valeurs des champs « icon1 », « icon2 », « icon3 », « icon4 », « icon5 », « icon6″ et »icon7 ».

Ajoutons que j’ai 7 champs « iconX » car j’ai 7 équipements différents : Athlétisme, Centre aquatique, Complexe sportif, Plateau sportif, Salle de combat, Tennis et Terrains de grands jeux. Actuellement, il n’y a pas de site avec l’ensemble des 7 équipements mais qui peut le plus peut le moins comme on dit !

 

Voici la cartographie finale :

 

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *