L’objectif de cette note est de présenter un projet fil conducteur qui permette de dérouler un ensemble d’opérateurs SIG sous R, vecteur comme raster. Le projet fil conducteur retenu concerne la classification d’un ensemble de parcelles viticoles sur un petit bassin versant vis-à-vis du risque d’érosion ravinaire. Il s’appuie sur un schéma classique de croisement entre aléa et vulnérabilité par parcelle suivant un système de score (théorique et virtuel pour simplifier l’exercice).
\[ Score_{risque}=Score_{vulnerabilite}*Score_{alea} \]
Nous négligerons dans l’approche développée beaucoup de questions et problèmes (effet de résolution spatiale des données, significativité physique de la démarche proposée, etc). Encore une fois elle n’est proposée ici qu’à des fins de simplification pédagogique.
L’aléa par parcelle est résumé par son score \(Score_{alea}\), prenant une valeur de 1 à 5 suivant la classe d’appartenance par quantile des valeurs de SPI maximum par parcelle. L’indice SPI (Stream Power index) étant défini pour chaque cellule d’un MNT simplement par :
\[ SPI=A.S \]
avec \(A\), surface drainée et \(S\) pente (s.u.).
La vulnérabilité par parcelle viticole est résumée par son score \(Score_{vulnerabilite}\), prenant également une valeur de 1 à 5, moyenne de deux indices \(Score_{NDVI}\) et \(Score_{pierosite}\).
\[Score_{vulnerabilite}=\frac{Score_{NDVI}+Score_{pierosite}}{2} \]
\(Score_{NDVI}\) prend une valeur de 1 à 5 suivant la classe d’appartenance par quantile des valeurs de NDVI (Normalized Difference Vegetation Index) moyen par parcelle. On se base sur des données images infrarouge. \(Score_{Pierosite}\) prend une valeur de 1 à 5 suivant la classe d’appartenance par quintile des valeurs de pierosité moyenne par parcelle. On se base ici sur des données terrain ponctuelles.
Le domaine spatial étudié est le bassin versant de Roujan (43.300 N, 3.190 E) d’une surface de 0.91 \(km^2\). Le bassin de Roujan est un observatoire de recherche à long-terme (ORE OMERE) équipé par l’INRA depuis 1992. La pluviométrie totale annuelle varie entre 500 et 1400 mm. Le bassin est couvert principalement de vignes avec 237 parcelles cultivées d’une surface variant de 0.03 à 2.2 ha. Ce bassin accueille également un réseau hydrographique dense (11 km). Le domaine étudié débordera cependant des strictes limites du bassin, pour limiter les effets de bord.
Situation des différents bassins versants
Les modèles numériques de terrain (MNTs) disponibles pour ce projet sont à 5 m et 1 m de résolution spatiale, acquis par stéréophotogrammétrie aérienne (5 m, source CD 34) et par LiDAR (1 m, source INSU). Ils ont été pour le MNT à 1 m ‘incrustés’ (stream burning) par le réseau hydrographique afin de représenter fidèlement les schémas d’écoulement des eaux de surface sur le terrain considéré.
Une image aérienne Infra-Rouge fausse couleur à 50 cm de résolution (BD-Ortho, Source IGN) est disponible sur la zone et sera utilisée pour dériver une carte de NDVI.
Une carte d’occupation du sol par parcelle a été réalisée par photo-interprétation et relevé terrain (Source : ORE Omere).
Le réseau hydrographique du bassin est constitué de fossés (agricoles, bord de route) buses, routes et chemins. Il résulte d’un relevé terrain (Source : ORE Omere). A NOTER que la fonction première de ce réseau est bien sur ce bassin son rôle anti-érosif car il permet pour une parcelle ‘aval’ d’intercepter et détourner le ruissellement de surface ‘amont’ (diminuer ce que l’on appelle la longueur de pente).
La piérosité sur le bassin est échantillonnée ponctuellement et est décrite au travers d’une variable qui correspond à la masse d’éléments grossiers supérieurs à 6 mm contenue dans un volume de sol de 15 cm de profondeur et d’environ 19x19 cm de surface (5.415 l). Un jeu de données de 268 échantillons sur cette variable (données AgroParisTech-INRA), variant de 0 à 3 kg environ, est disponible.
Les données nécessaires à la réalisation du TP sont disponibles à l’adresse suivante:
https://www.dropbox.com/sh/clssw0wvwwv4isa/AACVC82ZfCPhBUnH0wBVmb0-a?dl=0
library(rgdal) # lien vers la librairie GDAL
library(rgeos) # lien vers la librairie GEOS
library(gridExtra) # transformation d'un tableau en image
proj_RGF93=CRS("+init=epsg:2154") # projection du projet en RGF 93
# lecture du fichier shape délimitant l'étendue du projet
vETENDUE_RO=readOGR("datas","vETENDUE_RO RGF93") # etendue du bassin versant de Roujan
## OGR data source with driver: ESRI Shapefile
## Source: "/home/vinatier/Documents/A_SCIENTIFIQUE/ENSEIGNEMENTS/2019-03_Cartographie avec R (SILAT)/Cartes et R/datas", layer: "vETENDUE_RO RGF93"
## with 1 features
## It has 4 fields
## Integer64 fields read as strings: CONT7III_ CONT7III_I
vETENDUE_BO=readOGR("datas","vETENDUE_BO RGF93") # etendue du bassin versant du Bourdic
## OGR data source with driver: ESRI Shapefile
## Source: "/home/vinatier/Documents/A_SCIENTIFIQUE/ENSEIGNEMENTS/2019-03_Cartographie avec R (SILAT)/Cartes et R/datas", layer: "vETENDUE_BO RGF93"
## with 1 features
## It has 2 fields
vETENDUE_PE=readOGR("datas","vETENDUE_PE RGF93") # etendue du bassin versant de la Peyne
## OGR data source with driver: ESRI Shapefile
## Source: "/home/vinatier/Documents/A_SCIENTIFIQUE/ENSEIGNEMENTS/2019-03_Cartographie avec R (SILAT)/Cartes et R/datas", layer: "vETENDUE_PE RGF93"
## with 1 features
## It has 4 fields
Objectif général: Charger un fichier raster et réaliser des opérations simples.
library(raster) # analyses sur données Raster
library(RSAGA) # interfaçage avec SAGA (données Raster)
Objectif: Charger un fichier raster de type MNT
# lecture du MNT (modele numerique de terrain)
rMNT_PE=raster("datas/rMNT_PE RGF93.tif")
projection(rMNT_PE)=proj_RGF93 # attribution de la projection RGF 93 au MNT
names(rMNT_PE)="MNT" # Nommage du raster
Objectif: Découper un MNT selon une étendue donnée
# découpage de la zone à l'aide de la fonction crop
rMNT_RO=crop(rMNT_PE,vETENDUE_RO)
rMNT_BO=crop(rMNT_PE,vETENDUE_BO)
par(mfcol=c(1,2)) # Division de la fenêtre graphique en deux cases
plot(rMNT_PE,main="MNT complet") # Plot du MNT complet sur la première case
plot(vETENDUE_RO,border="red",add=T,lwd=3) # Ajout de l'étendue de découpe
plot(rMNT_RO,main="MNT découpé") # Plot du MNT découpé sur la seconde case
plot(vETENDUE_RO,border="red",add=T,lwd=3) # Ajout de l'étendue de découpe
Objectif: Changer la résolution d’un raster
# Utilisation de la fonction aggregate
rMNT_RO_LowRes<-aggregate(rMNT_RO,fact=20)
par(mfcol=c(1,2)) # Division de la fenêtre graphique en deux cases
plot(rMNT_RO,col=bpy.colors(),main="Resolution de base")
plot(rMNT_RO_LowRes,col=bpy.colors(),main="Resolution de base divisée 20 fois")
Objectif: Adapter deux rasters avec une resolution différente
rMNT_RO_resampled=resample(rMNT_RO,rMNT_RO_LowRes)
Objectif: Charger un nouveau système de projection et reprojeter un raster
# création d'un objet avec le système de projection WGS 84
proj_WGS84 <- CRS("+init=epsg:4326")
# reprojection du fichier raster
rMNT_RO_wgs84=projectRaster(from=rMNT_RO,crs=proj_WGS84)
par(mfcol=c(1,2)) # Division de la fenêtre graphique en deux cases
plot(rMNT_RO,main="Système RGF 93")
plot(rMNT_RO_wgs84,main="Système WGS 84")
Objectif: Enregistrer un fichier raster pour qu’il soit réutilisé avec d’autres logiciels (type Qgis ou SAGA…)
writeRaster(rMNT_RO_wgs84,"MNT_wgs84.tif",overwrite=TRUE)
Objectif: Calculer des variables dérivées du MNT et compilation dans un même raster
rSLOPE_RO=terrain(rMNT_RO,opt="slope") ; names(rSLOPE_RO)="Slope"
rASP_RO=terrain(rMNT_RO,opt="aspect") ; names(rASP_RO)="Aspect"
rHILL_RO=hillShade(terrain(rMNT_RO,opt="slope"),terrain(rMNT_RO,opt="aspect"))
names(rHILL_RO)="Hillshade"
rDERIVMNT_RO=stack(rSLOPE_RO,rASP_RO,rHILL_RO)
plot(rDERIVMNT_RO)
Objectif: Lisser des données raster
FenetreLissage=matrix(1,15,15) # Création de la fenêtre de lissage
rSLOPE_RO_med<- focal(rSLOPE_RO,fun=median,w=FenetreLissage) # Lissage avec filtre médian
par(mfcol=c(1,2)) # Division de la fenêtre graphique en deux cases
plot(rSLOPE_RO,col=bpy.colors(),main="Pente")
plot(rSLOPE_RO_med,col=bpy.colors(),main="Pente mediane")
Objectif général: Calculer, à partir d’une image multicanal de type Infrarouge couleur (IRC), un indice de végétation de type Normalized Difference Vegetation Index (NDVI).
Objectif: Charger des données raster multicanaux enregistrées en dalles jointives et les aligner selon une nouvelle emprise.
Ici, on charge l’orthophoto de la zone.
# identification de la liste des fichiers d'orthophoto
listOrthos=dir("datas/ORTHO/")
# ajout du chemin relatif vers les fichiers
listOrthos=paste("datas/ORTHO/",listOrthos,sep="")
rORTHOS=list() # creation d'une liste vide
# Travail sur la première bande
rORTHOS[[1]]=lapply(listOrthos,raster,band=1) # chargement des rasters
rORTHOS[[1]]=lapply(rORTHOS[[1]],aggregate,fact=5) # aggregation des rasters
rORTHOS[[1]]=lapply(rORTHOS[[1]],round) # arrondi des valeurs
rORTHOS[[1]]=do.call(merge,rORTHOS[[1]]) # fusion des rasters
# Travail sur la deuxième bande
rORTHOS[[2]]=lapply(listOrthos,raster,band=2)
rORTHOS[[2]]=lapply(rORTHOS[[2]],aggregate,fact=5)
rORTHOS[[2]]=lapply(rORTHOS[[2]],round)
rORTHOS[[2]]=do.call(merge,rORTHOS[[2]])
# Travail sur la troisième bande
rORTHOS[[3]]=lapply(listOrthos,raster,band=3)
rORTHOS[[3]]=lapply(rORTHOS[[3]],aggregate,fact=5)
rORTHOS[[3]]=lapply(rORTHOS[[3]],round)
rORTHOS[[3]]=do.call(merge,rORTHOS[[3]])
# Empilement des rasters entre eux
rORTHO_BO=stack(rORTHOS) # creation d'un RasterStack
names(rORTHO_BO)=c("R","G","B") # nommage du RasterStack
rORTHO_RO=crop(rORTHO_BO,vETENDUE_RO) # decoupage du rasterStack
Ici, on charge l’orthophoto IRC de la zone pour calculer le NDVI:
# Creation d'une fonction pour réaliser le calcul
getDALLES=function(listFiles=listOrthos,band=1,fact=5)
{tmp=lapply(listFiles,raster,band=band)
tmp=lapply(tmp,aggregate,fact=fact)
tmp=lapply(tmp,round)
tmp=do.call(merge,tmp)
tmp}
# Création de la liste des fichiers IRC
listIRCs=dir("datas/IRC/")
listIRCs=paste("datas/IRC/",listIRCs,sep="")
# Application de la fonction à toutes les bandes
rIRC_BO=lapply(1:3,function(x){getDALLES(listFiles=listIRCs,band=x,fact=5)})
# Empilement des rasters entre eux et decoupage
rIRC_BO=stack(rIRC_BO)
names(rIRC_BO)=c("V","R","PIR")
rIRC_RO=crop(rIRC_BO,vETENDUE_RO)
rNDVI_RO=(rIRC_RO[["PIR"]]-rIRC_RO[["R"]])/(rIRC_RO[["PIR"]]+rIRC_RO[["R"]])
rNDVI_RO=resample(rNDVI_RO,rMNT_RO)
rNDVI_RO=focal(rNDVI_RO,fun=median,w=matrix(1,9,9))
par(mfcol=c(1,2),mar=rep(4,4))
plot(vETENDUE_RO,main="Orthophoto en RGB",border="transparent")
plotRGB(rORTHO_RO,add=T)
plot(vETENDUE_RO,main="NDVI",border="transparent")
plot(rNDVI_RO,add=T,horizontal=T)
Objectif: Récupérer les données altimétriques (alt) pour différents pays. Changer la résolution et le système de projection pour qu’il corresponde au projet.
getData('ISO3') # Recuperation des codes de chaque pays
dir.create("tmp", showWarnings = FALSE)
dir.create("tmp/raster", showWarnings = FALSE)
rALT_FR=getData(name="alt",country="FRA",path = "tmp/raster/")
rALT_FR=projectRaster(from=rALT_FR,crs=proj_RGF93)
rALT_PE=crop(rALT_FR,extent(rMNT_PE))
rALT_PE=resample(rALT_PE,rMNT_PE)
diffRast=rALT_PE-rMNT_PE
par(mfcol=c(1,3))
plot(rMNT_PE)
plot(rALT_PE)
plot(diffRast)
listPAYS=c("URY","ESP","GRC","GUF")
# Creation d'une fonction pour récupérer les données d'un pays et calculer l'ombrage
calcHillshade=function(x){alt=getData(name="alt",country=x,path = "tmp/raster/")
hillShade(slope=terrain(alt,"slope"),
aspect=terrain(alt,"aspect"))}
# Application de la fonction
rHILL_pays=lapply(listPAYS,calcHillshade)
par(mfcol=c(2,2),mar=rep(4,4))
lapply(rHILL_pays,plot)
[[1]]
NULL
[[2]]
NULL
[[3]]
NULL
[[4]]
NULL
Objectif général: Faire appel, via R et une librairie appropriée, ici RSAGA, à un logiciel de calcul de données Raster, ici SAGA (ce dernier doit être installé sur l’ordinateur au préalable http://www.saga-gis.org/en/index.html). Réaliser la détection des plateaux et des vallées sur le bassin en calculant l’index MRVBF (multiresolution index of valley bottom flatness).
# creation d'un répertoire temporaire pour stocker les couches SAGA
dir.create("tmp", showWarnings = FALSE)
dir.create("tmp/SAGA", showWarnings = FALSE)
# ecriture du raster sous forme de fichier temporaire dans l'environnement de travail
tmpSGRD<-writeRaster(x=rMNT_RO,
filename="tmp/SAGA/tmpSGRD",
format="SAGA",overwrite=T)
if(Sys.info()['sysname']=="Linux")
myenv_saga=rsaga.env()
if(Sys.info()['sysname']=="Windows")
myenv_saga=rsaga.env(path="C:/Program Files (x86)/SAGA-GIS",
modules="C:/Program Files (x86)/SAGA-GIS/modules")
rsaga.get.libraries(path=myenv_saga$modules)
rsaga.get.lib.modules("ta_morphometry", env = myenv_saga, interactive = FALSE)
rsaga.get.usage("ta_morphometry", module=8, env = myenv_saga)
rsaga.geoprocessor("ta_morphometry",8,env=myenv_saga,
list(DEM="tmp/SAGA/tmpSGRD.sgrd",
MRVBF="tmp/SAGA/tmpSAGA",
CLASSIFY=T,T_SLOPE=100),
warn=F,
ignore.stdout=T,
check.module.exists = F)
resultSAGA<-raster("tmp/SAGA/tmpSAGA.sdat")
par(mfcol=c(1,2)) # Division de la fenêtre graphique en 2 cases
plot(rMNT_RO,main="MNT")
plot(resultSAGA,main="MRVBF")
Objectif général:Cette partie introductive sur les opérateurs de type vecteur a pour vocation de vous familiariser avec les possibilités offertes par les librairies sp, spdep, igraph ainsi que l’utilisation d’une plateforme tierce telle que GRASS via la librairie rgrass7.
library(sp) # analyses sur données vecteur
library(spdep) # géostatistiques sur données vecteur
library(igraph) # analyses de réseaux
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
library(rgrass7) # interfaçage avec Grass 7.0 (données vecteur)
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
library(doBy) # ordre et tri de tableaux
library(gridExtra) # transformation d'un tableau en image
Objectif: Charger des données vecteur de type Polygone, Ligne et Point et une table de correspondance associée.
# Chargement de la carte d'occupation du sol (emprise Bourdic)
vOCSOL_BO=readOGR("datas","vOCSOL_BO RGF93")
# Chargement des données de pédologie (emprise Peyne)
vPEDO_PE=readOGR("datas","vPEDO_PE RGF93")
# Chargement du réseau hydrographique (emprise Bourdic)
vHYDRO_BO=readOGR("datas","vHYDRO_BO RGF93")
# Chargement des données de pierosite (emprise Roujan)
vPIERO_RO=readOGR("datas","vPIERO_RO RGF93")
Ici le tableau de correspondance entre les occupations du sol et leurs identifiants:
Correspondance=
data.frame(ID=c(1220,3100,3220,2211,2212,2100,2210,1110,2220,1100),
Cover=c("Réseaux routiers et chemins (tous)","Bois",
"Landes et broussailles","Vignoble en gobelet","Vignoble palissé",
"Autres terres arables","Vignoble en transition",
"Tissu urbain continu","Arboriculture","Zones urbanisées"),
CoverEng=c("Road and rail networks","Forests","Sclerophyllous vegetation",
"Goblet vineyard","Aligned vineyard","Other arable lands",
"Transitional vineyard","Continuous urban area","Orchards",
"Discontinuous urban area"),
Color=c("#8B0000","#4DFF00","#A6FF80","#B414F1","#FFAAFF","#E0EC05",
"#FF00FF","#00004D","#DAA520","#CD0000"))
Correspondance=unique(orderBy(~ID,Correspondance)) # Tri de la table par ordre croissant de ID
On peut afficher le tableau de correspondance comme une image:
plot.new()
grid.table(Correspondance)
dOCSOL_BO_area=gArea(vOCSOL_BO,byid=T)
hist(dOCSOL_BO_area,breaks=100,xlab="Aire de chaque polygone (en m2)",main="")
Objectif: Decouper des objets vecteurs selon une emprise donnée.
vHYDRO_RO=crop(vHYDRO_BO,vETENDUE_RO)
vOCSOL_RO=crop(vOCSOL_BO,vETENDUE_RO)
vPEDO_RO=crop(vPEDO_PE,vETENDUE_RO)
A NOTER: L’opérateur […,] peut également être utilisé et est équivalent à la fonction crop.
vOCSOL_BO_centres=coordinates(vOCSOL_BO) # Récupération des centres de chacun des polygones
par(mfcol=c(1,2)) # Division de la fenêtre graphique en deux cases
plot(vOCSOL_BO,axes=F,main="")
plot(vOCSOL_BO,axes=F,main="Centres de chaque parcelle")
points(vOCSOL_BO_centres,pch=".",col="red",cex=3)
listPolygons=slot(vOCSOL_BO, "polygons") # liste de polygones du fichier vecteur
slot(listPolygons[[1]],"area") # aire du premier polygone
slot(listPolygons[[1]],"ID") # identifiant du premier polygone
vecArea=sapply(listPolygons, slot, "area") # recuperation de toutes les aires des polygones
A NOTER: Les aires calculées via les slots sont mises à jour lors des opérations de découpe par la fonction crop, au contraire des données de la table attributaire.
dOCSOL_RO_area1=sapply(slot(vOCSOL_RO, "polygons"), slot, "area")
dOCSOL_RO_area2=gArea(vOCSOL_RO,byid=T)
range(dOCSOL_RO_area1-dOCSOL_RO_area2)
Objectif: Ajouter des colonnes supplémentaires dans la table attributaire d’un shapefile. Ici on calcule l’aire, le périmètre et le rapport Périmètre/Aire de chaque polygone.
vOCSOL_BO$Area=vecArea # Ajout d'une colonne avec les aires de chaque polygone en m2
vOCSOL_BO$AreaHa=vecArea/10000 # Ajout des aires en Hectares
# Calcul des périmètres de chaque polygone
vOCSOL_BO_lines=as(vOCSOL_BO,"SpatialLines")# Transformation de chaque polygone en SpatialLines
vecPerimeters=SpatialLinesLengths(vOCSOL_BO_lines) # calcul des longueurs totales
vOCSOL_BO$Perimeter=vecPerimeters
vOCSOL_BO$Ratio=vecPerimeters/vecArea
head(vOCSOL_BO)
SP_ID Id Classvalue Area AreaHa Perimeter Ratio
0 3 3 3220 5.584522e-07 5.584522e-11 93.53468 1.674891e+08
1 4 4 2212 1.080526e+03 1.080526e-01 567.37843 5.250948e-01
2 18 18 2100 5.187976e+03 5.187976e-01 437.53198 8.433578e-02
3 50 50 3100 2.153310e+01 2.153310e-03 18.72176 8.694413e-01
4 844 844 2212 7.281970e+01 7.281970e-03 48.01518 6.593708e-01
5 845 845 2212 8.643284e+03 8.643284e-01 371.66466 4.300040e-02
Objectif: Changer le système de projection d’un shapefile.
vOCSOL_BO_wgs84=spTransform(vOCSOL_BO,proj_WGS84) # transformation du shapefile initial
par(mfcol=c(1,2)) # Division de la fenêtre graphique
plot(vOCSOL_BO,main="Système Lambert 93",axes=T)
plot(vOCSOL_BO_wgs84,main="Système WGS 84",axes=T)
Objectif: Réaliser des intersections, unions et différenciations symétriques entre deux shapefiles.
vPEDOuOCSOL=gUnion(vPEDO_RO,vOCSOL_RO,byid=T,drop_lower_td=T)
vOCSOL_RO_BO_diff=gDifference(vOCSOL_BO,vETENDUE_RO,byid=T)
A NOTER: Les opérateurs arithmétiques + et - fonctionnent également pour remplacer les fonctions gUnion et gDifference, respectivement. A conseiller car dans ce cas on conserve les données des tables attributaires.
vPEDOuOCSOL=vPEDO_RO+vOCSOL_RO
vOCSOL_RO_BO_diff=vOCSOL_BO-vETENDUE_RO
par(mfcol=c(1,4)) # Division de la fenêtre graphique
plot(vPEDO_RO,main="Couches pedologiques",col="yellow")
plot(vOCSOL_RO,main="Couches d'occupation du sol", col="red")
plot(vPEDOuOCSOL,main="Intersection OCSOL et PEDO",col="orange")
plot(vOCSOL_RO_BO_diff,main="Différence entre OCSOL et etendue")
plot(vETENDUE_RO,add=T,border="red",lwd=3)
A NOTER: Les fonctions gIntersection, gUnion et gDifference sont très sensibles aux erreurs de topologie dans les shapefiles. Pour y remédier, on peut opérer un nettoyage topologique rapide des parcelles selon la méthode du Buffer0:
vOCSOL_RO=gBuffer(vOCSOL_RO,width=0,byid=TRUE) # corrections des erreurs de topologie
vPEDO_RO=gBuffer(vPEDO_RO,width=0,byid=TRUE) # corrections des erreurs de topologie
Objectif: Agréger les polygones d’un shapefile selon les valeurs communes de sa table attributaire. Ici on agrège les occupations du sol d’un parcellaire.
IDs=vOCSOL_RO$Classvalue
IDs=factor(IDs)
vOCSOL_RO_fus=gUnaryUnion(vOCSOL_RO,id=IDs)
par(mfcol=c(1,2)) # Division de la fenêtre graphique
plot(vOCSOL_RO,main="Occupation du sol initiale")
# ajout des identifiants d'occupation du sol pour chaque parcelle
text(coordinates(vOCSOL_RO),labels=vOCSOL_RO$Classvalue,font=2,cex=0.5)
plot(vOCSOL_RO_fus,col=1:nlevels(IDs),main="Occupation du sol fusionnée")
IDs=vOCSOL_RO$Classvalue # recuperation des occupations du sol de chaque polygone
IDs=substr(IDs,1,1) # selection du premier niveau de Corine Land Cover
IDs=factor(IDs) # Factorisation
vOCSOL_RO_fus2=gUnaryUnion(vOCSOL_RO,id=IDs)
par(mfcol=c(1,2)) # Division de la fenêtre graphique
plot(vOCSOL_RO,main="Occupation du sol initiale")
# ajout des identifiants d'occupation du sol pour chaque parcelle
text(coordinates(vOCSOL_RO),labels=vOCSOL_RO$Classvalue,font=2,cex=0.5)
plot(vOCSOL_RO_fus2,col=1:nlevels(IDs),main="Occupation du sol fusionnée")
Objectif: Réaliser un polygone correspondant à la surface située à une distance maximale d’un SpatialLinesDataFrame.
Ici on applique la fonction buffer au réseau hydrographique.
vHYDRO_RO_buffer=gBuffer(vHYDRO_RO,width=30)
par(mfcol=c(1,2))
plot(vHYDRO_RO,col="blue",lwd=2)
plot(vHYDRO_RO_buffer,col="blue")
Objectif: Calculer des distances entre deux couches vecteurs. Ici on étudiera les distances entre les polygones de l’occupation du sol et du réseau hydrographique. A NOTER: Les distances sont calculées de centroide à centroide lorsqu’il s’agit de polygones.
matDist_OCSOL=gDistance(vOCSOL_RO,byid=T)
matDist_OCSOLHYDRO=gDistance(vOCSOL_RO,vHYDRO_RO,byid=T)
Ici on sélectionne les parcelles viticoles situées entre 50 et 100 mètres du réseau hydrographique.
SelViti=vOCSOL_RO$Classvalue%in%c(2210,2211,2212)
Calcul sur la base des matrices de distances centroide a centroide:
matDist_OCSOLHYDRO_seuil=(matDist_OCSOLHYDRO>50 & matDist_OCSOLHYDRO<100)
SelSeuilDist1=apply(matDist_OCSOLHYDRO_seuil,2,any)
vOCSOL_RO_sel1=vOCSOL_RO[SelSeuilDist1 & SelViti,]
Calcul avec buffers:
vBUF_50=gBuffer(vHYDRO_RO,width=50)
vBUF_100=gBuffer(vHYDRO_RO,width=100)
vOCSOL_RO_sel2=vOCSOL_RO[SelViti,]
vOCSOL_RO_sel2=vOCSOL_RO_sel2[vBUF_100-vBUF_50,]
par(mfcol=c(1,3)) # Division de la fenêtre graphique
plot(vOCSOL_RO,main="Occupation du sol initiale")
plot(vHYDRO_RO,col="blue",add=T,lwd=2)
# ajout des identifiants d'occupation du sol pour chaque parcelle
text(coordinates(vOCSOL_RO),labels=vOCSOL_RO$Classvalue,font=2,cex=0.5)
plot(vOCSOL_RO,main="Parcelles sélectionnées par Matrice",border="grey",lwd=0.5)
plot(vOCSOL_RO_sel1,add=T,col="darkgreen")
plot(vHYDRO_RO,col="blue",add=T,lwd=2)
plot(vOCSOL_RO,main="Parcelles sélectionnées par Buffer",border="grey",lwd=0.5)
plot(vOCSOL_RO_sel2,add=T,col="darkgreen")
plot(vHYDRO_RO,col="blue",add=T,lwd=2)
Objectif: Calculer la surface réelle de chaque cellule d’un MNT en tenant compte de la pente de cette surface.
rMNT_RO_sp=as(rMNT_RO,"SpatialGridDataFrame") # transformation du raster en SpatialGridDataFrame
rSA_RO=surfaceArea(rMNT_RO_sp,byCell=T) # Calcul de l'aire de chaque cellule
rSA_RO=raster(rSA_RO) # re-transformation du résultat en raster
par(mfcol=c(1,1))
plot(rSA_RO,main="Aire de chaque cellule en fonction du MNT")
Objectif: Calculer les connectivités des parcelles entre elles. Ici on prend l’exemple des connectivités entre polygones de l’occupation du sol.
connec_nb=poly2nb(vOCSOL_RO) #calcul des connections topologiques entre polygones
connec_centres=coordinates(vOCSOL_RO) # récupération des centres des polygones
Ici, on sélectionne les parcelles viticoles connectées aux parcelles de forêt.
IDviti=vOCSOL_RO$Classvalue%in%c(2210,2211,2212)
IDforet=(1:length(IDviti))[vOCSOL_RO$Classvalue==3100]
IDsel=sapply(connec_nb,function(x){sum(x%in%IDforet)})
par(mfcol=c(1,2),mar=rep(4,4))
plot(vOCSOL_RO,border="grey",main="Connections topologiques \n entre tous les polygones")
plot(connec_nb,connec_centres,add=T,pch=".",col="black")
points(connec_centres,col="red",pch=19)
plot(vOCSOL_RO,main="Parcelles viticoles \n connectées aux forêts")
plot(vOCSOL_RO[(IDsel & IDviti),],col="purple",add=T)
plot(vOCSOL_RO[IDforet,],col="darkgreen",add=T)
text(coordinates(vOCSOL_RO),labels=vOCSOL_RO$Classvalue,font=2,cex=0.5) # ajout des identifiants d'occupation du sol pour chaque parcelle
Ici, on compare, pour la parcelle centrale, les différences entre les distances à vol d’oiseau et les ordres de connectivité.
# Selection du polygone central
Poly_central=which.min(gDistance(vOCSOL_RO,SpatialPoints(vETENDUE_RO),byid=T))
# Calcul des distances à vol d'oiseau
DistPoly_central=gDistance(vOCSOL_RO[Poly_central,],vOCSOL_RO,byid=T)
vOCSOL_RO$Dist=as.vector(DistPoly_central)
# Calcul des ordres de connectivité
listNB=nblag(connec_nb,20)
listNB_Poly_central=sapply(listNB,function(x){x[[Poly_central]]})
vecID=sapply(listNB_Poly_central,length)
vecRepID=rep(1:length(vecID),times=vecID)
Ordre_Poly_Central=data.frame(ID=c(listNB_Poly_central,recursive=T),Ordre=vecRepID)
Ordre_Poly_Central=orderBy(~ID,Ordre_Poly_Central)
Ordre=merge(data.frame(ID=1:length(vOCSOL_RO)),Ordre_Poly_Central,all.x=T)
Ordre[is.na(Ordre[,2]),2]=0
vOCSOL_RO$Ordre=Ordre[,2]
par(mfcol=c(1,2))
plot(vOCSOL_RO,col=grey(vOCSOL_RO$Dist/max(vOCSOL_RO$Dist)),main="Distance à vol d'oiseau")
plot(vOCSOL_RO[Poly_central,],add=T,col="red")
plot(vOCSOL_RO,col=grey(vOCSOL_RO$Ordre/max(vOCSOL_RO$Ordre)),main="Distance topologique")
plot(vOCSOL_RO[Poly_central,],add=T,col="red")
La librairie rgrass7 offre la possibilité d’accéder à toutes les fonctions de l’environnement de travail GRASS version 7.X. Il faut également créer l’environnement de travail dans GRASS pour s’y référer par la suite. Une fois installée, on peut faire appel aux fonctions de rgrass7 de la manière suivante (on prendra l’exemple ici de la vérification et correction des topologies d’un shapefile):
dir.create("tmp", showWarnings = FALSE)
dir.create("tmp/GRASS", showWarnings = FALSE)
if(Sys.info()['sysname']=="Linux") myenv_grass="/usr/lib/grass74"
if(Sys.info()['sysname']=="Windows")myenv_grass="C:/Program Files/GRASS GIS 7.0.3"
#lancement du logiciel grass et affiliation au bon repertoire de travail
initGRASS(myenv_grass,home="tmp/GRASS",gisDbase="tmp/GRASS",override=T)
#reduction de la zone d'etude a celle de l'étendue de la zone
region=extent(vOCSOL_RO)
execGRASS("g.region",flags=c("p"),parameters=list(n=as.character(ymax(region)),
s=as.character(ymin(region)),
e=as.character(xmax(region)),
w=as.character(xmin(region))))
# Enregistrement du shapefile dans un fichier temporaire
writeVECT(vOCSOL_RO,"vec1",v.in.ogr_flags=c("o", "overwrite"))
cpt=0
cpt=cpt+1 ; execGRASS("v.clean",parameters=list(input=paste("vec",cpt,sep=""),
output=paste("vec",cpt+1,sep=""),
threshold=c(0,1,5),
type="line",
tool="break,snap,rmdangle"),
flags=c("overwrite"))
cpt=cpt+1 ; execGRASS("v.build.polylines",parameters=list(input=paste("vec",cpt,sep=""),
output=paste("vec",cpt+1,sep=""),
cats="first"),
flags=c("overwrite"))
cpt=cpt+1 ; execGRASS("v.clean",parameters=list(input=paste("vec",cpt,sep=""),
output=paste("vec",cpt+1,sep=""),
threshold=c(0,0,1,0,-1),
type="line",
tool="break,rmdupl,snap,break,rmdangle"),
flags=c("overwrite"))
cpt=cpt+1 ; execGRASS("v.generalize",parameters=list(input=paste("vec",cpt,sep=""),
output=paste("vec",cpt+1,sep=""),
method="snakes",threshold=1),flags=c("overwrite"))
cpt=cpt+1 ; execGRASS("v.type",parameters=list(input=paste("vec",cpt,sep=""),
output=paste("vec",cpt+1,sep=""),
from_type="line",
to_type="boundary"),
flags=c("overwrite"))
cpt=cpt+1 ; execGRASS("v.centroids",parameters=list(input=paste("vec",cpt,sep=""),
output=paste("vec",cpt+1,sep="")),flags=c("overwrite"))
OCSOL_clean<-readVECT(paste("vec",cpt+1,sep="")) # recuperation du fichier grass
Objectif général: L’objectif de cette partie est de vous familiariser avec les extractions de données vecteur et raster, ainsi que les fonctions de polygonisation-rasterisation disponibles.
library(akima) # interpolation spatiale
library(maptools)
Objectif: Appliquer une fonction sur les données attributaires d’un SpatialPointsDataFrame séparées par les limites d’un SpatialPolygonsDataFrame.
Ici on applique la fonction over pour extraire puis faire la moyenne des collections des relevés de piérosité correspondant à chaque polygone de l’occupation du sol.
dPIERO_RO=over(vOCSOL_RO,vPIERO_RO[,"M"],fn=mean)
names(dPIERO_RO)="PIERO"
Objectif: Rasteriser un fichier shapefile selon une grille donnée par une couche raster. Les données présentes dans la couche raster n’ont pas d’importance.
Ici, on réalise la rasterisation des occupations du sol, l’identifiant des parcelles et du réseau hydrographique selon la résolution du MNT:
rOCSOL_RO=rasterize(vOCSOL_RO,rMNT_RO,FUN="last",field="Classvalue",progress="text")
rID_RO=rasterize(vOCSOL_RO,rMNT_RO,FUN="last",field="Id",progress="text")
rHYDRO_RO=rasterize(vHYDRO_RO,rMNT_RO,field=1,progress="text",background=NA)
par(mfcol=c(1,3))
plot(vOCSOL_RO)
plot(vHYDRO_RO,col="blue",lwd=2,add=T)
text(coordinates(vOCSOL_RO),labels=vOCSOL_RO$Classvalue,font=2,cex=0.5)
plot(rOCSOL_RO,axes=F,main="Occupation du sol rasterisée",legend=F)
plot(rHYDRO_RO,add=T,col="blue",legend=F)
plot(rID_RO,axes=F,main="Identifiants polygones rasterisés",legend=F)
Objectif: Transformer un raster en SpatialPolygonsDataFrame
Ici, on transorme le réseau hydrographique:
vHYDRO_RO_trans=rasterToPolygons(rHYDRO_RO>0,dissolve=T)
par(mfcol=c(1,3))
plot(vHYDRO_RO,main="Réseau vecteur SpatialLines")
plot(rHYDRO_RO,main="Réseau raster")
plot(vHYDRO_RO_trans,main="Réseau vecteur SpatialPolygons")
Ici, on distingue trois zones de pentes (faible,moyen et forte):
# split des valeurs en trois modalités (faible,moyen et fort)
rSLOPE_RO_med_cut=cut(rSLOPE_RO_med,3)
# Transformation des limites entre modalités en SpatialLinesDataFrame
vSLOPE_RO_med_cut=rasterToPolygons(rSLOPE_RO_med_cut,dissolve=T)
par(mfcol=c(1,3))
plot(rSLOPE_RO_med,main="Pente médiane")
plot(rSLOPE_RO_med_cut,main="Pente médiane en trois modalités")
plot(vSLOPE_RO_med_cut,col=c("lightgrey","yellow","green"),main="Pente polygonisée")
Objectif: Simplifier la géométrie d’un SpatialPolygonsDataFrame, en particulier après une polygonisation issue d’un raster, pour supprimer les contours en marche d’escalier.
vSLOPE_RO_med_cut_thin=thinnedSpatialPoly(vSLOPE_RO_med_cut,tolerance=20,topologyPreserve = T)
par(mfcol=c(1,2))
plot(vSLOPE_RO_med_cut,main="Polygone en marche d'escaliers")
plot(vSLOPE_RO_med_cut_thin,main="Polygone simplifié")
Objectif: Extraire la collection de cellules d’un raster correspondant aux identifiants d’un autre raster, puis d’appliquer une fonction sur chacune des collections. On obtient un data.frame avec le résultat de la fonction, rangé dans l’ordre d’apparition des polygones dans le shapefile.
Ici, on réalise le calcul de la pente moyenne par occupation du sol:
dSLOPE_RO=zonal(rSLOPE_RO,rOCSOL_RO,fn=mean)
plot.new()
grid.table(round(dSLOPE_RO,2))
Objectif: Extraire les valeurs de raster correspondantes aux positions d’un SpatialPoints, SpatialPolygons ou SpatialLines.
Ici, on extrait les valeurs des dérivées du MNT correspondantes aux centres des parcelles.
extract(rDERIVMNT_RO,coordinates(vOCSOL_RO))
Ici, on extrait les valeurs des dérivées du MNT pour un polygone.
extract(rDERIVMNT_RO,vOCSOL_RO[3,])
Objectif: sélectionner un ensemble de cellules d’un raster situées à une distance fixée.
Ici, on applique la fonction buffer au réseau hydrographique.
# Rasterisation du réseau hydrographique
rHYDRO_RO=rHYDRO_RO>0 # Binarisation du réseau hydrographique
rHYDRO_RO_buffer=buffer(rHYDRO_RO,width=30) # creation d'un buffer a une distance de 30 mètres
rHYDRO_RO[is.na(rHYDRO_RO)]=0
par(mfcol=c(1,2)) # Division de la fenêtre graphique
plot(rHYDRO_RO_buffer,main="buffer à 30 mètres (RASTER)")
plot(vHYDRO_RO_buffer,main="buffer à 30 mètres (VECTEUR)")
Objectif: Interpolation de données ponctuelles (type SpatialPointsDataFrame) aux noeuds de la grille d’un raster suivant deux méthodes: une interpolation bilinéaire (dite interpolation TIN) et une interpolation par spline bi-cubique.
Ici, on applique l’interpolation aux données de piérosité:
vGRID_RO=rasterToPoints(rMNT_RO,spatial=T) # transformation du raster en SpatialPoints
# interpolation par spline bi-cubique des données de piérosité
vPIERO_RO_bicub=interpp(x=vPIERO_RO,z="M",xo=vGRID_RO,linear=F)
# Rasterisation des donnees sur la grille de reference
rPIERO_RO_bicub=rasterize(vPIERO_RO_bicub,rMNT_RO,field="M") # Rasterisation des points
par(mfcol=c(1,1))
plot(rPIERO_RO_bicub,main="interpolation bicubique") ; plot(vPIERO_RO,add=T)
Objectif général: On souhaite calculer la surface drainée par cellule d’un MNT à 5 m sur le bassin de Roujan mais en forçant les écoulements à suivre un réseau hydrographique (fossés, routes, chemins, buses. . .). Pour ce faire on va effectuer successivement 4 opérations classiques allant du “Stream Burning” (incrustation du réseau hydro dans le MNT) au calcul de surfaces drainées. Trois de ces opérations seront sous-traitées aux fonctions de SAGA appelées à l’aide de la librairie RSAGA (sous réserve que le logiciel SAGA soit installé): 1. Incrustation du réseau dans le MNT 2. Bouchage des trous du MNT incrusté 3. Calcul des directions de drainage et surfaces de drainage par cellule du MNT
Objectif: Incruster le réseau hydrographique dans le MNT en abaissant la valeur du réseau rasterisé à -50 mètres:
rMNT_RO_incrust=rMNT_RO-50*rHYDRO_RO # Incrustation du réseau
Objectif: Ensuite, sur le MNT incrusté, on réalise une classique opération dite de “bouche-trous” (fill sinks) qui permet d’assurer un écoulement continu amont-aval dans la MNT. Pour cela on sous-traite cette opération via SAGA par l’intermédiaire du package RSAGA:
# creation d'un répertoire temporaire pour stocker les couches SAGA
dir.create("tmp", showWarnings = FALSE)
dir.create("tmp/SAGA", showWarnings = FALSE)
# ecriture du raster sous forme de fichier temporaire dans l'environnement de travail
tmpSGRD<-writeRaster(x=rMNT_RO_incrust,
filename="tmp/SAGA/tmpSGRD",
format="SAGA",overwrite=T)
if(Sys.info()['sysname']=="Linux")
myenv_saga=rsaga.env()
if(Sys.info()['sysname']=="Windows")
myenv_saga=rsaga.env(path="C:/Program Files (x86)/SAGA-GIS",
modules="C:/Program Files (x86)/SAGA-GIS/modules")
rsaga.get.libraries(path=myenv_saga$modules)
rsaga.get.lib.modules("ta_preprocessor", env = myenv_saga, interactive = FALSE)
rsaga.get.usage("ta_preprocessor", module=5, env = myenv_saga)
rsaga.geoprocessor("ta_preprocessor",5,env=myenv_saga,
list(ELEV="tmp/SAGA/tmpSGRD.sgrd",
FILLED="tmp/SAGA/tmpSGRD.sgrd",
MINSLOPE=0.05),
warn=F,ignore.stdout=T,check.module.exists = FALSE)
Objectif: Calcul de la surface drainée par cellule en appliquant l’algorithme classique (D8) du module Catchment Area (Top-Down) de la librairie ta_hydrology.
rsaga.get.usage("ta_hydrology",0,env=myenv_saga)
rsaga.geoprocessor("ta_hydrology",0,env=myenv_saga,
list(ELEVATION="tmp/SAGA/tmpSGRD.sgrd",
METHOD=0,
FLOW="tmp/SAGA/tmpSGRD.sgrd"),
warn=F,ignore.stdout=T,check.module.exists = FALSE)
rSD_RO=raster("tmp/SAGA/tmpSGRD.sdat")
Illustration du calcul:
par(mfcol=c(1,2))
plot(rMNT_RO_incrust,main="Modèle numérique de terrain")
plot(log(rSD_RO+1),main="Surfaces drainées")
Calcul du SPI:
rSPI_RO=rSD_RO*rSLOPE_RO
par(mfcol=c(1,3),mar=rep(4,4))
plot(log(rSD_RO+1),main="Surfaces drainées")
plot(rSLOPE_RO,main="Pente")
plot(rSPI_RO,main="Stream Power Index")
Objectif: Estimer le risque par parcelle en fonction de l’aléa et des vulnérabilités calculées tout au long du TD.
dSPI_RO=zonal(rSPI_RO,rID_RO,FUN=max) # SPI maximal par parcelle
dNDVI_RO=zonal(rNDVI_RO,rID_RO,FUN=mean) # NDVI moyen par parcelle
# Creation de la table complète avec l'aléa et les vulnérabilités par parcelle
tabDonnees=data.frame(vOCSOL_RO$Classvalue,vOCSOL_RO$Id,dPIERO_RO)
tabDonnees=merge(tabDonnees,dSPI_RO,by.x="vOCSOL_RO.Id",by.y="zone",all.x=T)
tabDonnees=merge(tabDonnees,dNDVI_RO,by.x="vOCSOL_RO.Id",by.y="zone",all.x=T)
names(tabDonnees)=c("Id","Classvalue","PIERO","SPI","NDVI")
# Fonction de calcul des quantiles
calcQuantile=function(x){x=cut(x,breaks=quantile(x,probs=seq(0,1,0.2),na.rm=T),
include.lowest = T)
x=as.numeric(x)
x}
# Application de la fonction aux colonnes de la table de données
tabQuantiles=apply(tabDonnees[,-(1:2)],2,calcQuantile)
# Calcul du risque
Risque=tabQuantiles[,"SPI"]*(tabQuantiles[,"NDVI"]+tabQuantiles[,"PIERO"])/2
Risque[is.na(Risque)]=0
vOCSOL_RO$Risque=Risque
Illustration du risque par parcelle:
par(mfcol=c(1,1))
plot(vOCSOL_RO,col=grey(vOCSOL_RO$Risque/max(vOCSOL_RO$Risque)),main="Risque par parcelle")
plot(vOCSOL_RO[Risque==0,],col="red",add=T)