class: right, middle, title-slide # Les données spatiales ##
{sf}
{ggplot2}
###
Nina SCHIETTEKATTE
(Nicolas CASAJUS) ### .inst[Mardi 3 novembre 2020] --- class: inverse, center, middle ## Introduction --- ## Qu'est-ce qu'un objet spatial ?
Deux catégories : **1)** Les données vectorielles <br /> .center[![:scale 100%](img/vectors.png)] --- ## Qu'est-ce qu'un objet spatial ?
Deux catégories : **2)** Les données matricielles <br /> .center[![:scale 100%](img/rasters.png)] --- ## Le système de coordonnées
Un objet spatial se représente dans l'espace selon un référentiel spatial : le **système de coordonnées** (**CRS** pour _Coordinates Reference System_)
Deux types de systèmes de coordonnées existent : **1)** Les systèmes géographiques (ou non projetés) [en degrés] .center[![:scale 100%](img/projections01.png)] --- ## Le système de coordonnées
Un objet spatial se représente dans l'espace selon un référentiel spatial : le **système de coordonnées** (**CRS** pour _Coordinates Reference System_)
Deux types de systèmes de coordonnées existent : **2)** Les systèmes projetés [en mètres] .center[![:scale 100%](img/projections02.png)] --
Le choix du CRS peut être crucial et dépend souvent de l'information que l'on souhaite représenter --- ## Le système de coordonnées Sous
le CRS s'exprime selon le standard `proj4string` défini par le projet [**PROJ**](https://proj.org/) .small[`+proj=longlat +datum=WGS84 +no_defs +ellps=WGS84 +towgs84=0,0,0`] -- <br /> Chaque CRS possède un **SRID** (_Spatial Reference Identifier_) ou **EPSG** (_European Petroleum Survey Group_) : un identifiant unique qui nous évite de devoir écrire à la main le CRS au format `proj4string` `+init=epsg:4326` est l'identifiant du CRS ci-dessus .small[`+init=epsg:4326 +proj=longlat +datum=WGS84 +no_defs +ellps=WGS84 +towgs84=0,0,0`] <br /> --
Où trouver le bon CRS ? Réponse : [**Spatial Reference**](https://spatialreference.org/) --- class: inverse, center, middle ## Objets vectoriels --- ## Les packages
- Vecteurs <br /> Package | Fonctionnalités ------------------|------------------ `{sp}` | Classes et méthodes pour couches vectorielles `{rgdal}` | Lecture et écriture de couches spatiales `{rgeos}` | Opérations spatiales sur couches vectorielles `{maptools}` | Opérations spatiales sur couches vectorielles `{sf}` | Le petit dernier - Une vraie bête ! <br />
`{sf}` est devenu la "norme" : `{sf} = {sp} + {rgdal} + {rgeos}` --- ## Pourquoi `{sf}` ? - Implémentation sous
des _Simple Features_ - Standard reposant sur la norme ISO 19125 (stockage et accès) - Remplace le format d'ESRI<sup>.small[TM]</sup>, vous savez le shapefile !? - 3 packages en 1 - Syntaxe (_snake_case_) des fonctions simples (`{st_*()}`) - Objets stockés dans des `data.frame` ou des `tibble` - avec la géométrie stockée dans des `list-column` - Très grandes performances comparées à `{sp}` - Pipe-friendly et intégration au tidyverse (dont `{ggplot2}`) <br />
Edzer Pebesma le recommende 😄 --- ## Structure d'un objet `sf` <br /> .center[![:scale 100%](img/str_sf.png)] --- ## Les _Simple feature geometry_ `sfg` .center[![:scale 60%](img/sf_obj.png)] --- ## Installation <br /> ```r ## install.packages("sf") ``` --- ## Création de points spatiaux Soit les villes avec les coordonnées suivantes : ```r foix <- c(1.6053807, 42.9638998) carcassonne <- c(2.3491069, 43.2130358) rodez <- c(2.5728419, 44.3516207) ``` -- Convertissons ces vecteurs en points spatiaux : ```r foix <- sf::st_point(foix) carcassonne <- sf::st_point(carcassonne) rodez <- sf::st_point(rodez) ``` -- Et regroupons-les en un seul _spatial column_ en définissant le CRS : ```r villes <- sf::st_sfc( list(foix, carcassonne, rodez), crs = 4326 ) class(villes) ``` ``` ## [1] "sfc_POINT" "sfc" ``` --- ## Création de points spatiaux Ajoutons une table d'attributs et convertissons l'objet en _simple feature_ : ```r datas <- data.frame( ville = c("Foix", "Carcassonne", "Rodez"), population = c(9613, 45895, 23739) ) villes <- sf::st_sf(datas, geom = villes) class(villes) ``` ``` ## [1] "sf" "data.frame" ``` -- <br />
Quid des lignes et polygones ?
Voir les fonctions `st_linestring()` et `st_polygon()` --- ## Création de points spatiaux <br /> Bien souvent, vous importerez directement un `data.frame` que vous souhaiterez convertir en _simple feature_ <br /> ```r ## URL et nom du fichier url <- "https://raw.githubusercontent.com/FRBCesab/datatoolbox/master/data/" filename <- "occitanie_prefectures.csv" ## Téléchargement du fichier download.file( url = paste0(url, filename), destfile = filename ) ## Extraction du ZIP unzip(zipfile = filename) ``` --- ## Création de points spatiaux <br /> ```r ## Ouverture du csv (prefectures <- readr::read_csv("occitanie_prefectures.csv")) ``` ``` ## # A tibble: 13 × 5 ## departement prefecture population longitude latitude ## <chr> <chr> <dbl> <dbl> <dbl> ## 1 Ariège Foix 9613 1.61 43.0 ## 2 Aude Carcassonne 45895 2.35 43.2 ## 3 Aveyron Rodez 23739 2.57 44.4 ## 4 Gard Nîmes 151001 4.36 43.8 ## 5 Haute-Garonne Toulouse 475438 1.44 43.6 ## 6 Gers Auch 21618 0.585 43.6 ## 7 Hérault Montpellier 281613 3.88 43.6 ## 8 Lot Cahors 19405 1.44 44.4 ## 9 Lozère Mende 11860 3.50 44.5 ## 10 Hautes-Pyrénées Tarbes 40318 0.0781 43.2 ## 11 Pyrénées-Orientales Perpignan 121875 2.90 42.7 ## 12 Tarn Albi 49024 2.15 43.9 ## 13 Tarn-et-Garonne Montauban 60444 1.35 44.0 ``` --- ## Création de points spatiaux <br /> ```r library("magrittr") prefectures <- sf::st_as_sf( x = prefectures, coords = c("longitude", "latitude"), crs = 4326 ) prefectures %>% head(6) ``` ``` ## Simple feature collection with 6 features and 3 fields ## Geometry type: POINT ## Dimension: XY ## Bounding box: xmin: 0.5850507 ymin: 42.9639 xmax: 4.360069 ymax: 44.35162 ## Geodetic CRS: WGS 84 ## # A tibble: 6 × 4 ## departement prefecture population geometry ## <chr> <chr> <dbl> <POINT [°]> ## 1 Ariège Foix 9613 (1.605381 42.9639) ## 2 Aude Carcassonne 45895 (2.349107 43.21304) ## 3 Aveyron Rodez 23739 (2.572842 44.35162) ## 4 Gard Nîmes 151001 (4.360069 43.83742) ## 5 Haute-Garonne Toulouse 475438 (1.444247 43.60446) ## 6 Gers Auch 21618 (0.5850507 43.64636) ``` --- ## Une première carte Les packages `{rnaturalearth}` et `{rnaturalearthdata}` proposent différentes couches vectorielles, dont les limites administratives des pays du monde. Installons ces packages : ```r ## install.packages("rnaturalearth") ## install.packages("rnaturalearthdata") ``` -- <br /> Et chargeons le fond de carte du monde entier : ```r world <- rnaturalearth::ne_countries(scale = "medium", returnclass = "sf") class(world) ``` ``` ## [1] "sf" "data.frame" ``` --- ## Une première carte <img src="chunks/map1-1.png" width="100%" /> ```r ggplot(data = world) + geom_sf() + xlab("Longitude") + ylab("Latitude") + ggtitle("Carte du monde") ``` --- ## Une première carte <img src="chunks/map2-1.png" width="100%" /> ```r ggplot(data = world) + geom_sf(fill = "#49847b", colour = "#e1ddc0") + xlab("Longitude") + ylab("Latitude") + ggtitle("Carte du monde") ``` --- ## Une première carte <img src="chunks/map3-1.png" width="100%" /> ```r ggplot(data = world) + geom_sf(fill = "#49847b", colour = "#e1ddc0") + xlab("Longitude") + ylab("Latitude") + ggtitle("Carte du monde") + geom_sf(data = prefectures, colour = "black") ``` --- ## Importation d'une couche vectorielle <br /> Dans la plupart des cas, vous devrez importer une couche spatiale déjà prête. -- Téléchargeons les départements de la région Occitanie ```r ## URL et nom du fichier url <- "https://raw.githubusercontent.com/FRBCesab/datatoolbox/master/data/" filename <- "occitanie.zip" ## Téléchargement du fichier download.file( url = paste0(url, filename), destfile = filename ) ## Extraction du ZIP unzip(zipfile = filename) ``` --- ## Importation d'une couche vectorielle <br /> Que contient la couche ? ```r sf::st_layers("occitanie.shp") ``` ``` ## Driver: ESRI Shapefile ## Available layers: ## layer_name geometry_type features fields ## 1 occitanie Polygon 13 13 ``` -- <br /> Importons-la : ```r occitanie <- sf::st_read(dsn = ".", layer = "occitanie") ``` ``` ## Reading layer 'occitanie' from data source '/Users/nicolascasajus/Desktop/...' ## Simple feature collection with 13 features and 13 fields ## geometry type: MULTIPOLYGON ## dimension: XY ## bbox: xmin: -0.326875 ymin: 42.33344 xmax: 4.845344 ymax: 45.04467 ## epsg (SRID): 4326 ## proj4string: +proj=longlat +datum=WGS84 +no_defs ``` --- ## Importation d'une couche vectorielle <br /> ```r occitanie %>% head(3) ``` ``` ## Simple feature collection with 3 features and 13 fields ## Geometry type: MULTIPOLYGON ## Dimension: XY ## Bounding box: xmin: 0.8266816 ymin: 42.57232 xmax: 3.450981 ymax: 44.94122 ## Geodetic CRS: WGS 84 ## GID_0 NAME_0 GID_1 NAME_1 NL_NAME_1 GID_2 NAME_2 VARNAME_2 NL_NAME_2 TYPE_2 ENGTYPE_2 ## 1 FRA France FRA.11_1 Occitanie <NA> FRA.11.1_1 Ariège <NA> <NA> Département Department ## 2 FRA France FRA.11_1 Occitanie <NA> FRA.11.2_1 Aude <NA> <NA> Département Department ## 3 FRA France FRA.11_1 Occitanie <NA> FRA.11.3_1 Aveyron <NA> <NA> Département Department ## CC_2 HASC_2 geometry ## 1 09 FR.AG MULTIPOLYGON (((1.494104 42... ## 2 11 FR.AD MULTIPOLYGON (((3.027638 42... ## 3 12 FR.AV MULTIPOLYGON (((3.236248 43... ``` --- <img src="chunks/map4-1.png" width="70%" style="display: block; margin: auto;" /> ```r ggplot(data = occitanie) + geom_sf(fill = "#49847b", colour = "#e1ddc0") + xlab("Longitude") + ylab("Latitude") + ggtitle("OCCITANIE") ``` --- <img src="chunks/map5-1.png" width="70%" style="display: block; margin: auto;" /> ```r ggplot(data = occitanie) + geom_sf(fill = "#49847b", colour = "#e1ddc0") + xlab("Longitude") + ylab("Latitude") + ggtitle("OCCITANIE") + geom_sf(data = prefectures, colour = "#3f3f3f") ``` --- <img src="chunks/map6-1.png" width="70%" style="display: block; margin: auto;" /> ```r ggplot(data = occitanie) + geom_sf(fill = "#49847b", colour = "#e1ddc0") + xlab("Longitude") + ylab("Latitude") + ggtitle("OCCITANIE") + geom_sf(data = prefectures, colour = "#3f3f3f") + geom_sf_label(aes(label = NAME_2)) ``` --- <img src="chunks/map7-1.png" width="70%" style="display: block; margin: auto;" /> ```r ggplot(data = occitanie) + geom_sf(fill = "#49847b", colour = "#e1ddc0") + xlab("Longitude") + ylab("Latitude") + ggtitle("OCCITANIE") + geom_sf(data = prefectures, colour = "#3f3f3f") + geom_sf_label(aes(label = paste0(NAME_2, " (", CC_2, ")"))) ``` --- ## Exportation d'une couche vectorielle ```r sf::st_drivers() ``` ``` name long_name write copy is_raster is_vector vsi PCIDSK PCIDSK Database File TRUE FALSE TRUE TRUE TRUE netCDF Network Common Data Format TRUE TRUE TRUE TRUE FALSE PDF Geospatial PDF TRUE TRUE TRUE TRUE FALSE MBTiles MBTiles TRUE TRUE TRUE TRUE TRUE EEDA Earth Engine Data API FALSE FALSE FALSE TRUE FALSE ESRI Shapefile ESRI Shapefile TRUE FALSE FALSE TRUE TRUE MapInfo File MapInfo File TRUE FALSE FALSE TRUE TRUE UK .NTF UK .NTF FALSE FALSE FALSE TRUE TRUE OGR_SDTS SDTS FALSE FALSE FALSE TRUE TRUE S57 IHO S-57 (ENC) TRUE FALSE FALSE TRUE TRUE DGN Microstation DGN TRUE FALSE FALSE TRUE TRUE OGR_VRT VRT - Virtual Datasource FALSE FALSE FALSE TRUE TRUE REC EPIInfo .REC FALSE FALSE FALSE TRUE FALSE Memory Memory TRUE FALSE FALSE TRUE FALSE BNA Atlas BNA TRUE FALSE FALSE TRUE TRUE CSV Comma Separated Value (.csv) TRUE FALSE FALSE TRUE TRUE GML Geography Markup Language (GML) TRUE FALSE FALSE TRUE TRUE GPX GPX TRUE FALSE FALSE TRUE TRUE KML Keyhole Markup Language (KML) TRUE FALSE FALSE TRUE TRUE GeoJSON GeoJSON TRUE FALSE FALSE TRUE TRUE ... ... ... ... ... ... ... ``` --- ## Exportation d'une couche vectorielle <br /> Au format ESRI<sup>.small[TM]</sup> : ```r sf::st_write( obj = prefectures, dsn = ".", layer = "prefectures", driver = "ESRI Shapefile" ) ``` --- ## Le système de coordonnées Le CRS de notre couche vectorielle (monde) est-il défini ? ```r world ``` ``` Simple feature collection with 241 features and 63 fields geometry type: MULTIPOLYGON dimension: XY bbox: xmin: -180 ymin: -89.99893 xmax: 180 ymax: 83.59961 CRS: +proj=longlat +datum=WGS84 +no_defs +ellps=WGS84 +towgs84=0,0,0 ... ``` -- <br /> Supprimons-le : ```r world <- world %>% sf::st_set_crs(NA) ``` --- ## Le système de coordonnées Et redéfinissons-le : ```r world <- world %>% sf::st_set_crs(4326) ``` ``` Simple feature collection with 241 features and 63 fields geometry type: MULTIPOLYGON dimension: XY bbox: xmin: -180 ymin: -89.99893 xmax: 180 ymax: 83.59961 geographic CRS: WGS 84 ... ``` -- <br /> Projetons notre couche dans un autre système (par .ex, la projection Lambert azimuthal equal area centrée sur la France) ```r prj <- paste( "+proj=laea +lat_0=48 +lon_0=5", "+x_0=4321000 +y_0=3210000", "+ellps=GRS80 +units=m +no_defs" ) world_ortho <- world %>% sf::st_transform(crs = prj) ``` --- <img src="chunks/map9-1.png" width="60%" style="display: block; margin: auto;" /> ```r ggplot(data = world_ortho) + geom_sf(fill = "#49847b", colour = "#e1ddc0") ``` --- <img src="chunks/map10-1.png" width="60%" style="display: block; margin: auto;" /> ```r ggplot(data = world) + geom_sf(fill = "#49847b", colour = "#e1ddc0") + coord_sf(crs = prj) ``` --- ## Manipulations spatiales : sf cheat sheet .center[![:scale 90%](img/geom_ops.png)] --- ## Manipulations spatiales : sf cheat sheet Mesures géométriques Fonction R | Détails ------------------------|------------------ `sf::st_length(x)` | Longueur de lignes spatiales `sf::st_area(x)` | Superficie de polygones spatiaux `sf::st_distance(x, y)` | Distance entre deux couches `sf::st_bbox(x)` | Etentue spatiale (emprise) d'une couche Opérations géométriques unitaires Fonction R | Détails ------------------------|------------------ `sf::st_buffer(x)` | Buffers autour d'une géométrie `sf::st_boundary(x)` | Limites d'une géométrie `sf::st_convex_hull(x)` | Convex hull d'un ensemble de points `sf::st_centroid(x)` | Centroïde d'une géométrie --- ## Manipulations spatiales : sf cheat sheet Opérations géométriques binaires - `sf::st_intersects(x, y)` - `sf::st_disjoint(x, y)` - `sf::st_contains(x, y)` - `sf::st_overlaps(x, y)` - `...` <br /> Autres opérations - `sf::st_crop()` - `sf::st_intersection()` - `sf::st_difference()` - `sf::st_contains()` - `sf::st_union()` <br /> ```r ls("package:sf") ``` --- ## Interactivité
```r mapview::mapview(prefectures) ``` --- ## Interactivité
```r mapview::mapview(occitanie, zcol = "NAME_2", layer.name = "Département") + mapview::mapview(prefectures, col.regions = "#3f3f3f", cex = "population") ``` --- ## Quelques bonnes ressources <br /> - [**Spatial Data Science with R**](https://rspatial.org/raster/index.html) - [**sf vignettes**](https://r-spatial.github.io/sf/articles/sf1.html) - [**Introduction to Geospatial Raster and Vector Data with R**](https://datacarpentry.org/r-raster-vector-geospatial/) - [**StatnMap**](https://statnmap.com/fr/categories/spatial/) - [**Raster analysis in R**](https://mgimond.github.io/megug2017/) - [**Geocomputation with R**](https://geocompr.robinlovelace.net/) - [**gglot2 et sf**](https://www.r-spatial.org/r/2018/10/25/ggplot2-sf.html) - [**Très bonne introduction d'Olivier**](https://oliviergimenez.github.io/introspatialR/#1)