L’objectif est de mettre en pratique les techniques présentées dans le tutoriel, à partir de nouveaux jeux de données.
Pour cela, on utilise un jeu de données en open-data : les parkings publics géolocalisés situés dans l’agglomération bordelaise. Les données ont été téléchargées sur le site de l’open-data de Bordeaux Métropole et ont été retravaillées pour les besoins de l’exercice (script ici pour plus de détails).
Par ailleurs, notre objectif sera d’étudier la situation du centre-ville de Bordeaux en termes de présence de places de stationnement, de proportion de places adaptées aux personnes à mobilité réduite et au prix de ces places. Le contour géographique du centre-ville de Bordeaux est fourni. À noter qu’il a été créé « à la main » par les auteurs de ce TP, et qu’il ne répond à aucune définition officielle ou urbanistique précise.
Par ailleurs, à la fin de ce TP, une dernière partie consistera à approximer le nombre d’habitants vivant dans le centre-ville de Bordeaux d’après les données Filosofi 2019 carroyées.
Avant de débuter les exercices, on installe tous les packages nécessaires :
dplyr
sf
btb
mapsf
mapview
1aws.s3
(seulement si vous travaillez sur le
SSPCloud)## Liste des librairies utilisées
packages <- c("dplyr", "sf", "mapsf", "mapview", "aws.s3", "btb")
## Vérifier si la librairie est installée, si non l'installer, puis la charger
package.check <- lapply(
packages,
FUN = function(x) {
if (!require(x, character.only = TRUE)) {
install.packages(x, dependencies = TRUE)
library(x, character.only = TRUE)
}
}
)
Le code ci-dessous permet d’importer les données utilisées dans ce
tutoriel. Elles sont stockées sous Minio, dans le « bucket public » :
s3/projet-formation/r-lissage-spatial/
.
Quelques informations concernant ces jeux de données :
parking.RDS
: table de données géolocalisées concernant
les parkings publics dans l’agglomération bordelaise. Attention : on
parle de parking publics et non de places de stationnements ! Pour
chaque parking public, voici les variables renseignées :
ident
: identifiant du parking publicexploit
: exploitantnp_global
: nombre total de places de
stationnementnp_pmr
: nombre de places de stationnement pour les
personnes à mobilité réduiteth_heur
: prix horairex
: longitudey
: latitudeepsg
: code EPSG (projection géographique)bordeaux_centre.gpkg
: découpage à façon du
centre-ville de Bordeaux2.url_bucket <- "https://minio.lab.sspcloud.fr/"
object <- "r-lissage-spatial/parking.RDS"
download.file(paste0(url_bucket, bucket, "/", object), destfile = "parking.RDS")
parkings <- readRDS("parking.RDS")
object <- "r-lissage-spatial/bordeaux_centre.gpkg"
centreBdx <- st_read(paste0(url_bucket, bucket, "/", object))
Reading layer `file3873b8243dc' from data source
`https://minio.lab.sspcloud.fr/projet-formation/r-lissage-spatial/bordeaux_centre.gpkg'
using driver `GPKG'
Simple feature collection with 1 feature and 0 fields
Geometry type: POLYGON
Dimension: XY
Bounding box: xmin: 415676.3 ymin: 6419503 xmax: 419826.9 ymax: 6425297
Projected CRS: RGF93 v1 / Lambert-93
Pour information si vous voulez travailler dans le SSPCloud, l’importation peut se faire de cette manière :
genercarte
Pour visualiser les résultats de vos lissages, on crée une fonction
genercarte
de cartographie s’appuyant sur le package
mapsf
s’appuyant sur les éléments vus dans le tutoriel. On
pourra réutiliser cette fonction par la suite, et limiter ainsi le
nombre de lignes à recopier dans le code à chaque exercice).
Pour importer cette fonction dans votre environnement global, copier-coller et executer le code ci-dessous.
genercarte <- function(sfcarLisse,nomvar,nbreaks = 5,zone,titre,epais =0.2){
#'@param sfcarLisse : Table de carreaux portant les valeurs lissées
#'@param nomvar : Nom de la variable lissée à cartographier
#'@param nbreaks : Nombre de classes à représenter sur la carte (avec méthode des quantiles)
#'@param zone : Polygone de la zone d'intérêt (ex : centre de Bordeaux)
#'@param titre : Titre de la carte (chaîne de caracères)
#'@param epais : epaisseur des la grille des carreaux
#'@returns : carte produite avec le package mapsf
mf_init(x=sfcarLisse)
mf_map(x = sfcarLisse,
type = "choro",
var = nomvar,
breaks = "quantile",
nbreaks = nbreaks,
lwd = epais,
leg_pos = "bottomleft",
add = TRUE)
mf_map(x = st_cast(zone[,c("geom")], "MULTILINESTRING"),
lwd = 4,
col= "black", add = TRUE)
mf_layout(title = titre, credits = "Insee-DSAU, Bordeaux Métropole, IGN, mapsf")
}
Répondre aux questions suivantes :
parkings
?base::summary
) ident exploit np_global np_pmr th_heur x y epsg
1 CUBPK95 METPARK 355 8 2.4 417429.7 6424607 2154
2 CUBPK84 KEOLIS 199 5 3.1 418293.2 6426830 2154
3 CUBPK97 KEOLIS 102 12 4.5 410470.1 6428201 2154
4 CUBPK99 INDIGO_PARK 952 20 0.0 418288.3 6426501 2154
5 CUBPK76 KEOLIS 206 5 4.5 414215.2 6430881 2154
6 CUBPK16 METPARK 667 14 2.8 417759.4 6421534 2154
[1] 87
# 87 parkings dans la base
# Absence de valeurs manquantes dans les xy ? => Vrai
sum(is.na(parkings$x))
[1] 0
[1] 0
ident exploit np_global np_pmr th_heur
Length:87 Length:87 Min. : 46.0 Min. : 0.00 Min. : 0.000
Class :character Class :character 1st Qu.: 162.0 1st Qu.: 4.00 1st Qu.: 2.400
Mode :character Mode :character Median : 341.0 Median : 7.00 Median : 3.100
Mean : 473.9 Mean : 9.08 Mean : 3.296
3rd Qu.: 528.5 3rd Qu.:10.50 3rd Qu.: 4.050
Max. :3427.0 Max. :57.00 Max. :14.500
x y epsg
Min. :407552 Min. :6414710 Length:87
1st Qu.:415311 1st Qu.:6420763 Class :character
Median :417608 Median :6421969 Mode :character
Mean :416684 Mean :6422432
3rd Qu.:418911 3rd Qu.:6424019
Max. :422710 Max. :6433813
Observer l’emprise du contour du centre-ville de Bordeaux en
utilisant la fonction mapview::mapview
(avec un fond de
carte OpenStreetMap).
sfparkings
.mapview
.
sf::st_as_sf
. Attention à bien renseigner le
système de projection des coordonnées xy dans le paramètre
crs
.
mapview
, on additionne les
couches vectorielles avec un +
:
mapview(polygone) + mapview(points)
.
Dans le cas présent, le petit nombre de parkings ne rend pas indispensable cette phase de carroyage. Elle permet néanmoins de s’approprier un peu plus la structure spatiale des données avec le lissage.
iCellSize <- 1000
correspondant
à la taille des carreaux souhaitéecentroides
contenant les centroïdes
x_centro
et y_centro
des carreaux de 1000m à
partir de la table parkings
.nbParkings
.Pour information, les variables x_centro
et
y_centro
correspondent respectivement aux variables
x
et y
auxquelles :
# 1. Taille des carreaux
iCellSize = 1000
# 2. Centroïdes
centroides <- parkings
centroides <- btb::btb_add_centroids(pts = centroides, iCellSize = iCellSize)
# 3. Compter le nombre de parkings par carreau
centroides <- centroides %>%
group_by(x_centro, y_centro) %>%
count(name = "nbParkings")
centroides
# A tibble: 48 × 3
# Groups: x_centro, y_centro [48]
x_centro y_centro nbParkings
<dbl> <dbl> <int>
1 407500 6421500 4
2 408500 6421500 1
3 410500 6417500 1
4 410500 6424500 2
5 410500 6428500 1
6 411500 6416500 1
7 411500 6421500 1
8 411500 6422500 1
9 412500 6417500 1
10 412500 6418500 1
# ℹ 38 more rows
centroides
en grille de carreaux et stocker
le résultat dans la variable sfcarreaux
.mapview
en colorant les carreaux différemment selon le
nombre de parkings qu’ils contiennent.
btb::btb_ptsToGrid
permet de créer la
grille de carreaux.
st_join
par exemple pour réaliser
l’intersection.
mapview
, on peut utiliser les options
:zcol = "nbParkings"
col.regions = list("grey", "yellow", "red")
# 1. Générer la grille
sfcarreaux <- btb::btb_ptsToGrid(pts = centroides, sEPSG = "2154",
iCellSize = iCellSize)
# 2. Restriction du champ : on ne retient que les carreaux intersectant Bordeaux-centre
sfcarreaux <- sfcarreaux %>% st_join(centreBdx, left = F)
# sfcarreaux <- sfcarreaux[unlist(st_intersects(centreBdx, sfcarreaux)),]
centreBdxBuffer
.mapview
parkingsBuff
.parkings
non vectorielle pour garder des colonnes x
et y en vue du carroyage.
sf::st_buffer
sf::st_contains
ou
sf::st_intersects
# 1. Création d'un buffer autour du territoire
marge <- 3000
centreBdxBuffer <- st_buffer(centreBdx, dist = marge)
# 2. Cartographie avec mapview
mapview(centreBdxBuffer, col.region= "gray") + mapview(centreBdx)
# 3. Repérer les indices des observations contenues le buffer
# puis réduire la base aux seules observations dans le territoire
indiceObsContenues <- unlist(sf::st_contains(centreBdxBuffer, sfparkings))
parkingsBuff <- parkings[indiceObsContenues, ]
parkingsBuff
ident exploit np_global np_pmr th_heur x y epsg
1 CUBPK95 METPARK 355 8 2.400000 417429.7 6424607 2154
2 CUBPK84 KEOLIS 199 5 3.100000 418293.2 6426830 2154
4 CUBPK99 INDIGO_PARK 952 20 0.000000 418288.3 6426501 2154
6 CUBPK16 METPARK 667 14 2.800000 417759.4 6421534 2154
7 CUBPK02 INDIGO_PARK 1661 34 2.400000 418008.0 6422279 2154
8 CUBPK81 INDIGO_PARK 879 19 3.600000 419070.6 6420185 2154
9 CUBPK80 INTERPARKING 405 9 2.200000 419585.1 6424611 2154
11 CUBPK47 KEOLIS 46 4 3.296104 422710.0 6422372 2154
19 CUBPK87 URBIS_PARK 158 3 3.200000 418885.5 6422348 2154
21 CUBPK27 METPARK 847 15 2.800000 417987.8 6423092 2154
22 CUBPK79 METPARK 521 11 3.200000 418727.7 6422330 2154
[ reached 'max' / getOption("max.print") -- omitted 52 rows ]
nbObsLisse = 1L
dans
parkingsBuff
. Que représente-t-elle ?sfcarLisse
genercarte
.btb::btb_smooth
!
# 1. Nouvelle variable nbObsLisse
parkingsBuff$nbObsLisse <- 1L
#### C'est une variable de "comptage des observations".
# 2. Lissage
rayon <- 1700 # Rayon de lissage
tcar <- 50 # Taille des carreaux de la grille
parkingsLissage <- parkingsBuff[, c("nbObsLisse", "x", "y")]
sfcarLisse <- btb::btb_smooth(pts = parkingsLissage,
sEPSG = "2154",
iCellSize = tcar,
iBandwidth = rayon)
# 3. Filtrage : ne garder que les carreaux intersectant le centre de Bordeaux
sfcarLisse <- sfcarLisse %>% st_join(centreBdx, left = F)
lissage_maison <- function(rayon){
sfcarLisse <- btb::btb_smooth(pts = parkingsLissage,
sEPSG = "2154",
iCellSize = tcar,
iBandwidth = rayon)
sfcarLisse <- sfcarLisse %>%
st_join(centreBdx, left = F) %>%
mutate(nbObsLisse = nbObsLisse*(1000 / tcar) ^ 2)
genercarte(sfcarLisse = sfcarLisse,
nomvar = "nbObsLisse",
nbreaks = 5,
zone = centreBdx,
titre = paste0("Lissage de la densité de parkings avec un rayon de ", rayon, " m"))
}
Lisser le nombre de places de stationnement (variable
np_global
), et non plus le nombre de parkings.
rayon <- 1700
parkingsLissage <- parkingsBuff[,c("np_global", "x", "y")]
sfcarLisse <- btb::btb_smooth(pts = parkingsLissage,
sEPSG = "2154",
iCellSize = tcar,
iBandwidth = rayon)
# Filtrage des carreaux lissés dans Bordeaux centre
sfcarLisse <- sfcarLisse %>%
st_join(centreBdx, left = F) %>%
mutate(np_global = np_global * (1000 / tcar) ^ 2)
# Carte lissée
genercarte(sfcarLisse = sfcarLisse,
nomvar = "np_global",
nbreaks = 5,
zone = centreBdx,
titre = "Lissage des places de stationnement")
np_pmr
).
parkingsLissage <- parkingsBuff[,c("np_pmr", "x", "y")]
sfcarLisse <- btb::btb_smooth(pts = parkingsLissage,
sEPSG = "2154",
iCellSize = tcar,
iBandwidth = rayon)
# Filtrage des carreaux lissés dans Bordeaux centre
sfcarLisse <- sfcarLisse %>%
st_join(centreBdx, left = F)%>%
mutate(np_pmr = np_pmr * (1000 / tcar) ^ 2)
# Carte lissée
genercarte(sfcarLisse = sfcarLisse,
nomvar = "np_pmr",
nbreaks = 5,
zone = centreBdx,
titre = "Lissage des places de stationnement PMR")
btb_smooth
.
parkingsLissage <- parkingsBuff[, c("nbObsLisse", "np_global", "x", "y")]
sfcarLisse <- btb::btb_smooth(pts = parkingsLissage,
sEPSG = "2154",
iCellSize = tcar,
iBandwidth = rayon)
# Création du ratio lissé à partir des numérateur et dénominateur lissés
sfcarLisse <- sfcarLisse %>% mutate(place_par_parking = np_global/nbObsLisse)
sfcarLisse <- sfcarLisse %>% st_join(centreBdx, left = F)
genercarte(sfcarLisse = sfcarLisse,
nomvar = "place_par_parking",
nbreaks = 5,
zone = centreBdx,
titre = "Lissage du nombre de places par parking")
parkingsLissage <- parkingsBuff[, c("np_global", "np_pmr", "x", "y")]
sfcarLisse <- btb::btb_smooth(pts = parkingsLissage,
sEPSG = "2154",
iCellSize = tcar,
iBandwidth = rayon)
# Création du ratio lissé à partir des numérateur et dénominateur lissés
sfcarLisse$part_pmf <- 100 * sfcarLisse$np_pmr / sfcarLisse$np_global
sfcarLisse <- sfcarLisse %>% st_join(centreBdx, left = F)
genercarte(sfcarLisse = sfcarLisse,
nomvar = "part_pmf",
nbreaks = 5,
zone = centreBdx,
titre = "Lissage de la part de places PMR")
Lisser le prix moyen d’une heure de stationnement par parking (sans pondérer par le nombre de places)
parkingsLissage <- parkingsBuff[, c("nbObsLisse", "th_heur", "x", "y")]
sfcarLisse <- btb::btb_smooth(pts = parkingsLissage,
sEPSG = "2154",
iCellSize = tcar,
iBandwidth = rayon)
sfcarLisse$prix_moyen <- sfcarLisse$th_heur / sfcarLisse$nbObsLisse
sfcarLisse <- sfcarLisse %>% st_join(centreBdx, left = F)
genercarte(sfcarLisse = sfcarLisse,
nomvar = "prix_moyen",
nbreaks = 5,
zone = centreBdx,
titre = "Lissage du prix par parking (sans pondération)")
Lisser le prix moyen d’une heure de stationnement (prendre en compte le nombre de places de stationnement par parking).
Pour chaque parking de la base, il faut lisser :
# Création de la variable "multiplication du prix et du nmbre de places" pour chaque parking
parkingsBuff <- parkingsBuff %>% mutate(prix_x_place = np_global * th_heur)
parkingsLissage <- parkingsBuff[, c("np_global", "prix_x_place", "x", "y")]
sfcarLisse <- btb::btb_smooth(pts = parkingsLissage,
sEPSG = "2154",
iCellSize = tcar,
iBandwidth = rayon)
# Et on rapporte par le nombre de places lissé.
sfcarLisse <- sfcarLisse %>% mutate(prix_moyen_place = prix_x_place / np_global)
sfcarLisse <- sfcarLisse %>% st_join(centreBdx, left = F)
# Carte lissée
genercarte(sfcarLisse = sfcarLisse,
nomvar = "prix_moyen_place",
nbreaks = 5,
zone = centreBdx,
titre = "Lissage du prix moyen par place de stationnement")
Combien d’habitants vivent dans le centre de Bordeaux tel que nous l’avons défini ?
Pour répondre à cette question :
Comme dans le tutoriel, charger la base des données Filosofi 2019
carroyées (grille de 200m) en ne chargeant que les carreaux de la
Gironde grâce à l’option query
de
sf::st_read
.
Vérifier les projections cartographiques utilisées puis faire une intersection géographique entre les carreaux de la Gironde et le contour géographique du centre de Bordeaux
Cartographier avec mapview
les carreaux du centre de
Bordeaux.
Calculer le nombre d’habitants grâce à la variable
Ind
.
#1. Chargement des données de Filosofi 2019 en Gironde
url_bucket <- "https://minio.lab.sspcloud.fr/"
bucket <- "projet-formation"
object = "/r-lissage-spatial/carreaux_200m_met.gpkg"
st_read_maison <- function(chemin_tab){
requete <- "SELECT idcar_200m, lcog_geo, ind, geom
FROM carreaux_200m_met
WHERE SUBSTR(lcog_geo, 1, 2) IN ('33')"
sf::st_read(chemin_tab, query = requete)
}
# sans s3
car33 <- st_read_maison(paste0(url_bucket,bucket, "/", object))
# avec s3
car33 <-
aws.s3::s3read_using(
FUN = st_read_maison,
object = object,
bucket = bucket
,
opts = list("region" = "")
)
# 2. Vérification de la projection
# puis sélection des carreaux intersectant le centre de Bordeaux
head(car33)
Simple feature collection with 6 features and 3 fields
Geometry type: POLYGON
Dimension: XY
Bounding box: xmin: 438486.3 ymin: 6350085 xmax: 439499.4 ymax: 6351138
Projected CRS: RGF93 v1 / Lambert-93
idcar_200m lcog_geo ind geom
1 CRS3035RES200mN2399800E3501000 33095 3 POLYGON ((438504 6350085, 4...
2 CRS3035RES200mN2399800E3501800 33095 1 POLYGON ((439300.3 6350162,...
3 CRS3035RES200mN2400200E3501200 33095 1 POLYGON ((438667.8 6350502,...
4 CRS3035RES200mN2400400E3501400 33095 5 POLYGON ((438849.3 6350721,...
5 CRS3035RES200mN2400400E3501600 33095 4 POLYGON ((439048.4 6350740,...
6 CRS3035RES200mN2400600E3501400 33095 8 POLYGON ((438831.7 6350920,...
# Projection 2154 (Lambert93).
carreaux_centreBdx <- car33 %>% st_join(centreBdx, left = F)
# 3. Cartographie des carreaux du centre de Bordeaux
mapview(centreBdx, color = "black", lwd = 6, alpha.regions = 0, legend = F) +
mapview(carreaux_centreBdx, col.regions = "#ffff00")
# 4. Combien d'habitants dans le centre de Bordeaux ?
cat("Il y a approximativement ", sum(carreaux_centreBdx$ind), " habitants dans le centre de Bordeaux")
Il y a approximativement 137804 habitants dans le centre de Bordeaux
Reproductibilité
R version 4.3.2 (2023-10-31)
Platform: x86_64-apple-darwin20 (64-bit)
Running under: macOS Monterey 12.7.3
Matrix products: default
BLAS: /Library/Frameworks/R.framework/Versions/4.3-x86_64/Resources/lib/libRblas.0.dylib
LAPACK: /Library/Frameworks/R.framework/Versions/4.3-x86_64/Resources/lib/libRlapack.dylib; LAPACK version 3.11.0
locale:
[1] en_US.UTF-8/en_US.UTF-8/en_US.UTF-8/C/en_US.UTF-8/en_US.UTF-8
time zone: UTC
tzcode source: internal
attached base packages:
[1] stats graphics grDevices utils datasets methods base
other attached packages:
[1] btb_0.2.0 aws.s3_0.3.21 mapview_2.11.2 mapsf_0.9.0 sf_1.0-15
[6] dplyr_1.1.4 knitr_1.45
loaded via a namespace (and not attached):
[1] xfun_0.42 bslib_0.6.1 raster_3.6-26
[4] htmlwidgets_1.6.4 lattice_0.21-9 leaflet.providers_2.0.0
[7] vctrs_0.6.5 tools_4.3.2 crosstalk_1.2.1
[10] generics_0.1.3 stats4_4.3.2 curl_5.2.0
[13] tibble_3.2.1 proxy_0.4-27 fansi_1.0.6
[16] highr_0.10 pkgconfig_2.0.3 KernSmooth_2.23-22
[19] satellite_1.0.5 RColorBrewer_1.1-3 uuid_1.2-0
[22] RcppParallel_5.1.7 leaflet_2.2.1 lifecycle_1.0.4
[25] farver_2.1.1 compiler_4.3.2 stringr_1.5.1
[28] munsell_0.5.0 fontawesome_0.5.2 terra_1.7-73
[31] codetools_0.2-19 maplegend_0.1.0 htmltools_0.5.7
[34] class_7.3-22 sass_0.4.8 yaml_2.3.8
[37] pillar_1.9.0 jquerylib_0.1.4 ellipsis_0.3.2
[40] classInt_0.4-10 cachem_1.0.8 wk_0.9.1
[43] brew_1.0-10 tidyselect_1.2.0 digest_0.6.34
[46] stringi_1.8.3 fastmap_1.1.1 grid_4.3.2
[49] colorspace_2.1-0 cli_3.6.2 magrittr_2.0.3
[52] base64enc_0.1-3 utf8_1.2.4 leafem_0.2.3
[55] e1071_1.7-14 aws.signature_0.6.0 scales_1.3.0
[58] sp_2.1-3 rmarkdown_2.25 httr_1.4.7
[61] unilur_0.4.0.9100 png_0.1-8 evaluate_0.23
[64] s2_1.1.6 rlang_1.1.3 leafpop_0.1.0
[67] Rcpp_1.0.12 glue_1.7.0 DBI_1.2.2
[70] xml2_1.3.6 svglite_2.1.3 jsonlite_1.8.8
[73] R6_2.5.1 systemfonts_1.0.5 units_0.8-5
mapview
est un package de cartographie
produisant des résultats proches de leaflet
. Il est un peu
plus rapide d’utilisation quant il s’agit de produire des résultats
simples : notamment, il reprojette automatiquement les objets
géographiques que vous souhaitez cartographier. Plus d’informations ici.↩︎
construit manuellement par les auteurs de ce tutoriel en utilisant le Geoportail.↩︎