![drawing](https://user-images.githubusercontent.com/85548796/134670189-3518e579-cdba-4630-b35d-b902fd402df8.png)
![drawing](https://user-images.githubusercontent.com/85548796/134628003-895ecb51-fab1-4993-9cb9-53c3ea52d58b.png)
AppCarto est une application web destinée à diffuser des données SIG. Le développement a été initié par le Parc national des Pyrénées pour répondre à son besoin de partager en interne et à destination des agents les données de son système d'information géographique.
L'objectif, à terme, est d'en faire une mini-application SIG en ligne permettant notamment la création et le partage de couches de données et d'y implémenter des fonctions spatiales élémentaires (intersection / fusion ....).
AppCarto peut être vu comme une application satellite de GeoNature car elle s'appuie sur l'API de GeoNature pour l'authentification des utilisateurs (centralisation des comptes) et la recherche de taxon dans le référentiel TaxRef. Un pont doit également être configuré pour permettre d'alimenter AppCarto avec les données d'observations.
Pour les autres données, AppCarto a été pensé pour s'intégrer dans un système d'information déjà existant favorisant la centralisation des données. Les données géographiques restent où elles sont, à partir du moment où elles sont dans une base de données postgis. L'administrateur d'AppCarto n'a qu'à déclarer les couches pour les rendre disponible dans l'application.
AppCarto est une plateforme web développée principalement en python et en javascript et se basant sur les librairies suivantes:
- Flask
- SQLAlchemy
- Marshmallow
- OpenLayers
- Bootstrap
- html2canvas
- jsPDF
- select-pure
- svg-inject
- tabulator
- RainbowVis-JS
Au stade d'avancement actuel, l'application offre la possibilité à l'utilisateur :
- d'afficher des couches de données (possibilité de changer l'ordre des couches et le niveau de transparence)
- d'interroger les données d'observation naturaliste (données GeoNature)
- d'exporter la table attributaire d'une couche en CSV
- de filtrer les entités d'une couche de données à partir de la table attributaire
- de lancer des calculs d'enjeux sur un périmètre spécifique
- d'exporter des cartes en PDF
L'administrateur de l'application a quant à lui la possibilité :
- de configurer les fonds de carte affichable (flux WMTS)
- de déclarer une couche (= ajouter une couche) :
- définition du style par défaut (optionnel)
- définir la liste des champs devant être accessible
- définir si c'est une couche à enjeux
- de définir les classes (seuil et couleur) associées aux données d'observations
AppCarto s'appuie donc sur deux bases de données:
- la base dédiée à l'application (bdd_app)
- la base de données hébergeant les couches SIG (bdd_sig)
Les tables grisées sont une projection dans le cadre des développements à venir. Elles seront certainement amenées à évoluer.
La base de données applicative a été installé sur un PostgreSQL 12 en suivant les actions suivantes :
- Installer PostgreSQL (sur le serveur applicatif ou tout autre serveur).
- Créer un rôle qui sera administrateur de cette base de données.
- Se connecter à la base de données avec ce rôle
- Exécuter le contenu du fichier d'installation de la base de données install/install_db.sql
L'installation d'AppCarto a été réalisée sur un ubuntu server 20.04 Vous trouverez la procédure d'installation dans le fichier doc/installation
Il est nécessaire de peupler quelques tables afin que l'application puisse fonctionner :
Cette table permet d'activer des échelles de restitution des données d'observations. Par défaut seules sont activées les mailles de 2km, 1km, 500m, 250m, 100m
Il est possible d'ajouter d'autres échelles de restitution en ajoutant des lignes dans cette table.
Description de la table :
Nom du champ | description |
---|---|
mesh_scale_id | Clé primaire auto-incrémentée |
mesh_scale_label | Nom de l'échelle de restitution |
active | Booléen permetant d'activer ou non la restitution à cette echelle |
Cette table contient les objets géographiques correspondant aux différentes échelles de restitution. A minima, il faudra insérer les données pour les échelles activées dans app_carto.bib_mesh_scale
Description de la table :
Nom du champ | description |
---|---|
mesh_id | Clé primaire auto-incrémentée |
mesh_scale_id | Clé étrangère permettant d'associer une géométrie à une échelle de restitution |
geom | Géométrie de l'objet |
Alimenter la table app_cato.bib_commune avec les communes de votre territoire
Description de la table :
Nom du champ | description |
---|---|
insee_com | Clé primaire reprenant le code insee de la commune |
nom_com | Nom de la commune |
Par défaut, un certain nombre de statuts (et de regroupement de statut) sont déclarés. Il est possible d'en ajouter en éditant les tables suivantes :
Nom du champ | description |
---|---|
group_status_id | Clé primaire auto-incrémentée |
group_status_label | Nom textuel du regroupement de statuts |
group_status_description | Description de ce qui est contenu dans le groupe de statuts |
group_status_is_warning | Booléen permettant d'inclure les espèces ayant un statut associé à ce groupe dans le calcul des enjeux |
active | Booléen permettant d'activer ou non un groupe de statut |
Nom du champ | description |
---|---|
status_type_id | Clé primaire auto-incrémentée |
statut_type_label | Nom textuel du statut |
group_statut_id | Clé étrangère identifiant à quel groupe est associé le statut |
active | Booléen permettant d'activer ou non un statut |
Il faut alimenter l'ensemble des tables suivantes à partir des données d'observation (issue de la synthèse de GeoNature ou d'ailleur):
Table des observations
Nom du champ | description |
---|---|
obs_id | Identifiant unique de l'observation en favorisant l'identifiant dans la base de données source (ex : id_synthèse pour GeoNature ) |
obs_uuid | Identifiant unique de la donnée dans le SINP |
cd_ref | Code de référence taxon dans taxref |
group_2_inpn | Regrouppement vernaculaire issue de taxref |
date_min | Date de début d'observation |
date_max | Date de fin d'observation |
altitude_min | Altitude minimale d'observation |
altitude_max | Altitude maximal d'obervation |
nom_cite | Nom de l'espèce tel que cité par l'observateur |
nom_valide | Nom retenu de l'espèce dans taxref |
nom_vern | Nom vernaculaire de lespèce dans taxref |
regne | Regne auquel le taxon apparatient issue de taxref |
geom | Objet géométrique associé à l'observation |
Lien entre une observation et les communes
Nom du champ | description |
---|---|
obs_id | Identifiant de l'observation dans app_carto.t_observations |
insee_com | Identifiant de la commune dans app_carto.bib_commune |
Lien entre l'observation et les objets géographiques associés aux différentes échelles de restitution
Nom du champ | description |
---|---|
obs_id | Identifiant de l'observation dans app_carto.t_observations |
mesh_id | Identifiant de la maille dans app_carto.bib_mesh |
Statut de l'espèce relatif à l'observation (= une espèce protégée uniquement dans les Pyrénées-Atlantiques ne doit pas être identifiée comme protégée si elle est observée dans les hautes-Pyrénées)
Nom du champ | description |
---|---|
obs_id | Identifiant de l'observation dans app_carto.t_observations |
status_type_id | Identifiant du statut dans app_carto.bib_statut_type |
La table app_carto.bib_toponyme doit être alimentée avec les toponymes de votre territoire afin de permettre à l'utilisateur de réaliser la recherche d'un lieu-dit (barre de recherche en haut à droite de la carte).
Description de la table :
Nom du champ | description |
---|---|
toponyme_id | Clé primaire auto-incrémentée |
toponyme_nom | Toponyme textuel |
toponyme_type | Précision sur le type de toponyme (Lac, Pic, Auberge...) |
toponyme_precision_geo | Précision de localisation textuelle permettant de différencier des homonymes (ex: Vallée d'Aspe) |
geom | Géométrie de l'objet |
La déclaration d'une couche de données doit se faire en base de données en ajoutant une ligne à la table app_carto.t_layers.
Déscription de la table:
Nom du champ | description |
---|---|
layer_id | Clé primaire auto-incrémentée |
layer_schema_name | Nom du schéma dans la base de données source (bdd_sig) |
layer_table_name | Nom de la table de données dans la base de données source (bdd_sig) |
layer_group | Nom permettant de regroupper les couches sur l'interface (TODO |
layer_label | Alias du nom de la couche qui sera affiché dans l'application |
layer_is_default | (ce champ est pour l'instant sans effet. L'idée est de définir des couche qui s'affiche par défaut à l'ouverture de l'application...) |
layer_default_style | Définition du style par défaut à appliquer à la couche en format JSON |
layer_is_warning | Booléen indiquant que la couche doit être prise en compte dans le calcul des enjeux |
layer_attribution | Identification du producteur de la données (copyright) |
layer_columns | Liste (varchar[]) des champs à intérroger (champs se retrouvant dans le "select"). Attention renseigner "*" ne fonctionne pas, si on veut tous les champs de la couche, il faut tous les renseigner. |
layer_geom_column | Nom du champ stockant la géométrie dans la base de données source (bdd_sig) (ex : geom, the_geom ...) |
Les styles respectent une syntaxe JSON spécifique et fonction de la géométrie des objets.
Polygon :
- style_name = Nom du style qui sera repris dans la légende (optionnel)
- fill_color = Couleur de remplissage
ex : rgba(201,241,196,0.5)
- stroke_color = Couleur de la bordure
ex : rgba(201,241,196,0.5)
- stroke_width = Epaisseur de la bordure (en pixel)
ex : 3
- stroke_linedash = Bordure en pointillé
ex1 : [] - pas de pointillé;
ex2 : [4] - longueur du pointillé et de l'espacement de 4 pixels
ex3 : [4,8] - longueur du pointillé de 4 pixel et longueur de l'espacement de 8 pixel
Line :
- style_name = Nom du style qui sera repris dans la légende (optionnel)
- stroke_color = Couleur du trait
ex : rgba(201,241,196,0.5)
- stroke_width = Epaisseur du trait (en pixel)
ex : 3
- stroke_linedash = Trait en pointillé
ex1 : [] - pas de pointillé;
ex2 : [4] - longueur du pointillé et de l'espacement de 4 pixels
ex3 : [4,8] - longueur du pointillé de 4 pixel et longueur de l'espacement de 8 pixel
Point :
- style_name = Nom du style qui sera repris dans la légende (optionnel)
- fill_color = Couleur de remplissage
ex : rgba(201,241,196,0.5)
- stroke_color = Couleur de la bordure
ex : rgba(201,241,196,0.5)
- stroke_width = Epaisseur de la bordure (en pixel)
ex : 3
- stroke_linedash = = Bordure en pointillé
ex1 : [] - pas de pointillé;
ex2 : [4] - longueur du pointillé et de l'espacement de 4 pixels
ex3 : [4,8] - longueur du pointillé de 4 pixel et longueur de l'espacement de 8 pixel
- radius = Rayon du point (en pixel)
ex : 5
Icon :
- style_name = Nom du style qui sera repris dans la légende (optionnel)
- icon_svg_path = Chemin vers le SVG (dans static)
ex : static/images/svg/<nom_svg>.svg
- icon_color = Couleur de l'image
ex : #ff0000 ou rgba(255,0,0,1)
La couleur est en réalité une teinte qui s'applique sur le SVG.
S'il est noir, icon_color n'aura aucun impacte sur le rendu.
- icon_scale = Coeficient permetant d'agrandir ou réduire la taille du svg
ex1 : 0.04 (réduit la taille)
ex2 : 2 (augmente la taille)
- icon_opacity = Opacité de l'icone sur la carte
ex : 0.8
Dans le cas d'un style de type "icon", le fichier SVG associé devra être placé dans le dossier backend/static/images/svg/. Il est possible des les classer par sous-dossier, dans ce cas, adapter le chemin
Etiquette :
- text = Nom du champ devant être utilisé comme étiquette (obligatoire)
- max_resolution = Permet de gérer la visibilité de l'étiquette en fonction du niveau de zoom (optionnel - par défaut : 180)
ex : 150 (valeur permettant l'affichage des étiquettes pour une échelle correspondant à l'emprise du PNP)
- weight = Style d'écriture de l'étiquette (optionnel - par défaut : 'Normal')
ex 1 : Normal
ex 2 : Bold (en gras)
- size = Taille de la police (optionnel - par défaut : 12)
ex : 14
- color = Couleur du texte (optionnel - par défaut : 'rgba(0,0,0,1))
ex : rgba(201,241,196,1)
- background_color = Couleur de fond de l'étiquette (optoinnel - par défaut : 'rgba(255,255,255,0.7)')
ex : rgba(255,255,255,0.7)
Expression :
Il est possible d'appliquer des filtres sur les valeur pour appliquer un style spécifique.
Pour celà, il faut ajouter un noeud "expression" dans la définition du style.
Le champ sur lequel s'applique la condition doit être écrit de la façon suivante (en remplaçant fieldName par le nom du champ) : feature.get('fieldName')
Ensuite, renseigné l'un des opérateur suivant :
- > : supérieur
- < : inférieur
- >= : supérieur ou égal
- <= : inférieur ou égal
- == : egal
- != : différent de
- includes : Permet de controler si une valeur est contenu ou non dans une liste . exemple
- ['value1', 'value2'].includes(feature.get('fieldName')) - (equivalent d'un IN en SQL)
- !['value1', 'value2'].includes(feature.get('fieldName')) - (equivalent d'un NOT IN en SQL)
- match : contenant une partie de la chaine de caractère (equivalent d'un LIKE en SQl). Cet opérateur s'appliquant à des chaine de caractère, il faut forcer le typage du champ. Exemple :
- String(feature.get('fieldName')).match(/TextToSearch/) : Retourne vrai si la chaine de caractère contient TextToSeach
- String(feature.get('fieldName')).match(/^TextToSearch/) : Retourne vrai si la chaine de caractère commence par TextToSeach
- String(feature.get('fieldName')).match(/TextToSearch$/) : Retourne vrai si la chaine de caractère fini par TextToSeach
En cas d'apostrophe dans la valeur, il y a deux possibilité :
- Utiliser le caractère d'échappement \\ -> feature.get('fieldName') == 'text avec l\\'apostrophe'
- Soit remplacer les simples quotes entourant la chaine de caractère par \" -> feature.get('fieldName') == \"text avec l'apostrophe\"
/**
* Remplissage simple de polygone
*/
[{
"style_type": "Polygon",
"styles": [{
"style_name": "nomDuStyle",
"fill_color": "rgba(145,82,45,0.5)",
"stroke_color": "rgba(0,0,0,1)",
"stroke_width": 1,
"stroke_linedash": []
}]
}]
/**
* Syle simple pour un point
*/
[{
"style_type": "Point",
"styles": [{
"style_name": "nomDuStyle",
"fill_color": "rgba(145,82,45,0.5)",
"stroke_color": "rgba(0,0,0,1)",
"stroke_width": 1,
"stroke_linedash": [],
"radius": 5
}]
}]
/**
* Style simple pour une ligne
*/
[{
"style_type": "Line",
"styles": [{
"style_name": "nomDuStyle",
"stroke_color": "rgba(0,0,0,1)",
"stroke_width": 1,
"stroke_linedash": []
}]
}]
/**
* Exemple pour la couche de point affichant une
* icone à la place de l'objet géographique
*/
[{
"style_type": "Icon",
"styles": [{
"style_name": "nomDuStyle",
"icon_svg_path": "static/images/svg/accommodation/accommodation_shelter2.svg",
"icon_color": "rgba(0,0,0,1)",
"icon_scale": 0.04,
"icon_opacity": 1
}]
}]
/**
* Style Conditionnel
* Distinguant zone coeur et aire d'adhésion
*/
[{
"style_type": "Polygon",
"styles": [{
"style_name": "Zone Coeur",
"fill_color": "rgba(2,125,13,0.5)",
"stroke_color": "rgba(2,125,13,1)",
"stroke_width": 3,
"stroke_linedash": [],
"expression": "feature.get('id_local') == 'ZC_PNP'"
},{
"style_name": "Aire d'adhésion",
"fill_color": "rgba(201,241,196,0.5)",
"stroke_color": "rgba(201,241,196,1)",
"stroke_width": 3,
"stroke_linedash": [],
"expression": "feature.get('id_local') == 'AA_PNP'"
}]
}]
/**
* Style conditionnel complexe : ((A == "test") OR ((B == true) AND (C == 1)))
*/
[{
"style_type": "Polygon",
"styles": [{
"style_name": "nomDuStyle",
"fill_color": "rgba(255,0,0,0.5)",
"stroke_color": "rgba(255,255,0,0.5)",
"stroke_width": 2,
"stroke_linedash": [],
"expression": "feature.get('A') == 'test' || (feature.get('B') == true && feature.get('C') == 1)"
}]
}]
[{
"style_type": "Polygon",
"styles": [{
"style_name": "nomDuStyle",
"fill_color": "rgba(145,82,45,0.5)",
"stroke_color": "rgba(0,0,0,1)",
"stroke_width": 1,
"stroke_linedash": []
}]
},{
"style_type": "Line",
"styles": [{
"style_name": "nomDuStyle",
"stroke_color": "rgba(0,0,0,1)",
"stroke_width": 1,
"stroke_linedash": []
}]
}]
/**
* Etiquette simple
*/
[{
"styles": [{
"radius": 5,
"fill_color": "rgba(0,0,0,1)",
"stroke_color": "rgba(0,0,0,1)",
"stroke_width": 1,
"stroke_linedash": [],
"feature_label": {
"text": "nom"
}
}],
"style_type": "Point"
}]
/**
* Etiquette avec paramétrage avancé
*/
[{
"styles": [{
"radius": 5,
"fill_color": "rgba(0,0,0,1)",
"stroke_color": "rgba(0,0,0,1)",
"stroke_width": 1,
"stroke_linedash": [],
"feature_label": {
"text": "nom",
"max_resolution": 180,
"size": 14,
"weight": "Bold",
"color": "rgba(0,0,0,1)",
"background_color": "rgba(255,255,255,0.7)"
}
}],
"style_type": "Point"
}]
Cette partie reste à consolider en fonction des avancements du projet. En effet, en l'état aucune mise à jour n'a été réalisée.
En fonction de la version de départ, il faudra exécuter les scripts SQL update_db_to_vX.Y.sql présent dans le dossier ./install .
Pour mettre à jour la partie applicative, il faut se placer dans le dossier de l'application et lancer la commande suivante :
$ git pull
$ sudo supervisorctl restart app_carto