Bouts de code pour Grass đ
Faire une pseudo-jointure avec Grass avec des tables DBF¶
Voici le topo: vous avez importé des données vecteur dans Grass. Ces données contiennent en plus d'autres données attributaires. Nativement, lors de l'import de la couche, Grass sépare bien les deux types d'information (exemple avec une couche nommée : COMMUNES.SHP):
- L'information géographique forme une couche vecteur. Elle sera nommée COMMUNES par défaut dans Grass.
- Les donnĂ©es attributaires sont importĂ©es par dĂ©faut dans un fichier DBF qui a le mĂȘme nom que la couche vecteur (soit COMMUNES.DBF)
- La couche vecteur reçoit un lien (v.db.connect) par défaut vers le fichier COMMUNES.DBF
Notre problĂšme est le suivant: nous souhaitons ajouter des donnĂ©es attributaires dans la table COMMUNES.DBF de la maniĂšre la plus simple possible. Si c'est une opĂ©ration qui peut sembler triviale, elle ne l'est pas nĂ©cĂ©ssairement: Grass ne sait pas gĂ©rer les jointures dynamiques (v.db.join) avec des tables DBF ! C'est Ă©galement le cas pour les requĂȘtes croisĂ©es (UPDATE table SET champ=(SELECT ...)).
Nous devons donc ruser et contourner cette limite en ajoutant les colonnes qui nous intĂ©ressent dans la table COMMUNES.DBF, le tout, en utilisant les fonctions de GRASS. L'astuce consiste Ă utiliser le format SQLite en entrĂ©e pour rĂ©aliser nos opĂ©rations de requĂȘtes puis d'exporter le rĂ©sultat dans une table DBF.
Voyons le détail des opérations:
- On commence par importer la couche des communes dans GRASS avec des données attributaires dans une base de données SQLite:
db.connect driver=sqlite database=temp_db.sqlite
v.in.ogr "dsn=/home/user/GRASS_import/COMMUNES.shp" output=COMMUNES snap=-1 min_area=0.0001 -o
- Si on fait la liste des tables DBF, on repÚre bien notre table COMMUNES. On peut également observer sa structure. On remarque une colonne nommée cat. C'est un identifiant interne à GRASS qui fait le lien avec les objets géographiques:
# v.db.connect -p permet d'afficher la liste des tables attributaires connectées à une couche vecteur :
v.db.connect -p COMMUNES
Vector map <COMMUNES@PERMANENT> is connected by:
layer <1> table <COMMUNES> in database </home/user/GRASS/DEP49/PERMANENT/dbf/> through driver<dbf> with key <cat>
# db.tables permet de liste les tables attributaires disponibles, indépendamment de leur connexion à une couche vecteur:
db.tables -p
COMMUNES
# Pour voir la structure d'une table, on utilise db.columns ou db.describe:
db.columns table=COMMUNES
cat
NOM_COM
INSEE_COM
STATUT
SUPERFICIE
POPULATION
INSEE_CANT
INSEE_ARR
ID_OBJ
db.describe -c table=COMMUNES
ncols: 9
nrows: 363
Column 1: cat:INTEGER:11
Column 2: NOM_COM:CHARACTER:50
Column 3: INSEE_COM:CHARACTER:5
Column 4: STATUT:CHARACTER:20
Column 5: SUPERFICIE:INTEGER:11
Column 6: POPULATION:INTEGER:11
Column 7: INSEE_CANT:CHARACTER:2
Column 8: INSEE_ARR:CHARACTER:1
Column 9: ID_OBJ:INTEGER:11
- Ensuite, on importe notre fichier CSV qui contient les données à joindre à la couche COMMUNES. Ce fichier se nomme DATA.csv et il utilise également un fichier DATA.csvt qui permet de définir le type des champs.
v.in.ogr "dsn=/home/user/tmp/GRASS_import/DATA.csv" output=DATA snap=-1 min_area=0.0001 -o
db.describe -c table=DATA
ncols: 6
nrows: 6
Column 1: cat:INTEGER:11
Column 2: value:INTEGER:11
Column 3: Mini:DOUBLE PRECISION:20
Column 4: Maxi:DOUBLE PRECISION:20
Column 5: Nume:INTEGER:11
Column 6: Producteur:CHARACTER:25
- Pour des raisons de jointure et de nommage de champs, nous allons supprimer la colonne cat (rajoutée automatiquement par GRASS) de la table DATA. Supprimer une colonne dans SQLite est assez compliqué. C'est pourquoi nous allons utiliser la commande db.dropcol de GRASS. Attention, la colonne cat est utilisée pour faire le lien avec les objets géographiques. Néanmoins, comme cette couche est purement attributaire, il n'y a aucun problÚme à la supprimer (ce qui n'est pas le cas de la couche COMMUNES):
db.dropcol -f table=DATA column=cat
- Création de la table jointe:
echo "CREATE TABLE COM_JOINTE AS SELECT COMMUNES.*, DATA.* FROM COMMUNES JOIN DATA ON DATA.value=COMMUNES.ID_OBJ" | db.execute
- Export de la table jointe au format DBF:
db.copy to_driver=dbf to_database=/home/user/GRASS/DEP49/PERMANENT/dbf/ to_table=COMMUNES from_driver=sqlite from_database=temp_db.sqlite from_table=COM_JOINTE
- Connexion de la couche vers la table au format DBF:
# Actuellement, notre couche COMMUNES utilise la table attributaire COMMUNES située dans une base de données SQLite:
v.db.connect -p map=COMMUNES
Vector map <COMMUNES@PERMANENT> is connected by:
layer <1> table <COMMUNES> in database <temp_db.sqlite> through driver <sqlite> with key <cat>
# On doit reconnecter la table géographique COMMUNES avec la table attributaire DBF COMMUNES:
v.db.connect -o map=COMMUNES driver=dbf database=/home/user/GRASS/DEP49/PERMANENT/dbf/ table=COMMUNES key=cat
- Les données sont maintenant importées et on peut éventuellement supprimer nos tables anciennes:
# On supprime les tables qui ne servent plus Ă rien
db.droptable -f DATA
db.droptable -f COMMUNES
# Enfin, on indique qu'on souhaite se connecter en utilisant le pilote DBF par défaut pour que les prochains imports se fasse dans ce format
db.connect driver=dbf database=/home/user/GRASS/DEP49/PERMANENT/dbf/