library(RPostgreSQL)
library(DBI)
library(sf)
library(data.table)
Les données lues à partir d’un csv seront stockés dans un objet de classe dataframe
decath <- read.csv("decathlon.csv", header = TRUE, sep = ";", dec = ".")
Les données lues à partir d’un shapefile seront stockés dans un objet de classe sf (dataframe spatial)
zae <- st_read(dsn = '//isere/DETC/AFFAIRES/GT/DDT01-07_Foncier_économique/2_Donnees_communes/DDT01',
layer = 'ZAE')
NB : on peut aussi indiquer le chemin du dossier en relatif avec ./
Selon qu’il s’agit ou pas d’une table géographique, on obtiendra un dataframe ou un dataframe spatial
drv <- dbDriver("PostgreSQL")
conn <- dbConnect(drv, host = "srv41-map", port = "5444", user= "consultation", password="consultation", dbname="ceremabase")
com69 <- st_read(conn, query = "SELECT * FROM r_admin_express.n_adm_exp_commune_000 WHERE insee_dep = '69'")
dept <- st_read(conn, query = "SELECT * FROM r_admin_express.n_adm_exp_departement_000")
dbDisconnect(conn)
## [1] TRUE
decath$Longueur # renvoie le vecteur correspondant à la colonne "Longueur" du dataframe
decath[, "Longueur"] # idem
decath[, 3] # idem
decath[3,] # renvoie un dataframe avec uniquement la 3e ligne du dataframe initial
dept$geom # description de la géométrie (type de géométrie, projection, boite englobante)
plot(dept$geom) # affichage basique de la carte
Pour préparer un graphique, il faut souvent faire quelques manipulations à partir du jeu de données de départ (filtrer des lignes, calculer un nouveau champ, faire un pivot…) La librairie dplyr est bien pratique pour ce type de manipulations Documentation en français
library(dplyr)
filter(decath, X100m < 11) # filtrer des lignes selon une condition
select(decath, Longueur, Hauteur, Perche) # sélectionner des colonnes
arrange(decath, -Hauteur) # trier selon une colonne (le signe - permet un tri décroissant)
mutate(decath, temps_course = X100m + X400m + X1500m) # créer un nouveau champ calculé
l’opérateur %>% (appelé “pipe”) permet d’alléger le code et d’enchaîner les opérations
decath %>%
filter(X100m < 11) %>%
select(Hauteur) %>%
arrange(-Hauteur)
Je rencontre souvent des problèmes de format en lisant une table depuis ceremabase. Pour convertir a posteriori un champ d’un dataframe en UTF-8 on peut faire
com69 <- com69 %>%
mutate(nom_com = iconv(nom_com, "UTF-8"))
Pivot ou tableau croisé
epci <- com69 %>%
group_by(code_epci) %>%
summarise(population = sum(population), nombre_communes = n())
On verra plus loin que reprojection est nécessaire pour faire des cartes avec leaflet
com69_4326 <- st_transform(com69, crs = 4326)
En supprimant la géométrie d’un spatialdataframe, on obtient un simple dataframe !
d <- com69
print(class(d))
## [1] "sf" "data.frame"
d$geom <- NULL
print(class(d))
## [1] "data.frame"
R possède un puissant moteur graphique interne, qui permet de “dessiner” dans un graphique en y rajoutant des segments, des points, du texte, ou toutes sortes d’autres symboles. Toutefois, pour produire un graphique complet avec les fonctions basiques de R, il faut un peu bricoler et tatonner, en ajustant les formes, les tailles, les couleurs, les échelles.
# je prépare mes données
data <- decath %>%
filter(X100m < 11) %>%
select(Perche) %>%
arrange(-Perche)
# puis je fais mon graphique
barplot(data$Perche, xlab = "athlete", ylab ='metres')
hist(decath$X1500m, breaks = 10, col = "orange")
data <- com69 %>%
filter(code_epci != '200046977') %>%
group_by(code_epci) %>%
summarise(population = sum(population), nombre_communes = n())
pie(data$population, # les valeurs à représenter
labels = data$code_epci, # la colonne pour les étiquettes
cex = 0.7, # pour régler la taille de la police des étiquettes
main = 'population par EPCI', # titre du graphique
col = rainbow(7), # jeu de couleurs
border = NA) # supprimer les bordures
plot(decath$Poids, decath$Javelot,
xlab = "lancer du poids",
ylab = "lancer du javelot",
pch = 19,
col = "red",
cex = 2,
frame = FALSE)
avec les commandes de R
png(file = "mon_graphique.png", width = 800, height = 700)
barplot(data$Perche)
dev.off()
via l’interface de R Studio A partir de l’onglet Plots -> save as image / Save as pdf / Copy to clipboard
Par défaut, les exports se font dans le répertoire de travail Pour afficher le répertoire de travail : getwd() Pour changer de répertoire de travail : setwd(“chemin/du/répertoire/avec/des/slash/et/pas/des/antislash”)
La librairie ggplot2, mettant en œuvre la “grammaire graphique” théorisée par Leland Wilkinson, évite de tout faire à la main et se révèle très pratique lorsque l’on souhaite réaliser des graphiques plus complexes.
library(ggplot2)
introduction à ggplot2 en français
ggplot(decath, aes(x = Poids, y = Javelot, col = Competition)) +
geom_point(size = 4) +
labs(title = 'performances au décathlon')
ggplot() +
geom_sf(data = dept, aes(fill = insee_reg)) +
ggtitle('les régions de France métropolitaine') +
theme(axis.text.x=element_blank(),
axis.ticks.x=element_blank(),
axis.text.y=element_blank(),
axis.ticks.y=element_blank(),
panel.background = element_rect(fill = "white"))
library(ggspatial)
library(viridis)
epci <- com69 %>%
group_by(code_epci) %>%
summarize(geom = st_union(geom)) # on crée un geodataframe des epci
carte <- ggplot()+
annotation_map_tile(zoomin = -1) + # tuiles OSM en fond de carte
geom_sf(data = com69, aes(fill = population), colour = NA, alpha = 0.8) + # couche des communes
geom_sf(data = epci, colour = "white", fill = NA) + # couche des EPCI
scale_fill_viridis(trans = "log") + # coloration continue selon log(population)
theme(axis.text.x=element_blank(),
axis.ticks.x=element_blank(),
axis.text.y=element_blank(),
axis.ticks.y=element_blank())
carte
library(treemapify)
library(viridis)
ggplot(dept, aes(area = as.numeric(st_area(geom)), label = nom_dep_m, fill = insee_reg, subgroup = insee_reg)) +
geom_treemap() +
geom_treemap_subgroup_border() +
geom_treemap_text(colour = 'white', grow = T)
Une représentation graphique sympa pour représenter les recouvrement entre plusieurs groupes ou zonages. Documentation :
library(UpSetR)
Les données d’entrée d’un upset plot peuvent être formatées de plusieurs façons Ici je vais rajouter à mon jeu de données des colonnes qui définissent si chaque individu appartient ou pas à un groupe. Puis je vais sélectionner uniquement ces colonnes. Le tableau de départ contient 1 ligne par individu.
data <- decath%>%
mutate('fort en lancer' = ifelse (Javelot > 60, 1, 0)) %>%
mutate('fort en sprint' = ifelse (X100m < 10.9, 1, 0)) %>%
mutate('fort en saut' = ifelse (Longueur > 7.4, 1, 0)) %>%
mutate('fort en demi fond' = ifelse (X1500m < 275, 1, 0)) %>%
select('fort en lancer', 'fort en sprint', 'fort en saut', 'fort en demi fond')
up <- upset(data,
sets.x.label = "nombre de décathloniens",
mainbar.y.label = "nombre",
sets.bar.color = c('darkgreen', 'orange', 'purple', 'steelblue'),
matrix.color = 'black',
main.bar.color = "darkgrey",
point.size = 5)
# pour améliorer le rendu graphique, il faudrait colorer les points noirs de la même couleur que les barres horizontales, mais je n'ai pas trouvé le moyen de le faire simplement dans R !! (retravailler avec PhotoFiltre)
Autre formattage possible des données d’entrée : on a des ensembles A B C D … (des multipolygones par exemple) et on a au préalable calculé la taille de l’intersection entre ces ensembles pour toutes les combinaisons possibles. Chaque ligne représente une des combinaisons possibles, et on a une colonne qui représente la taille de l’intersection (ici le nombre de décathloniens, ça pourra aussi représenter une surface)
data <- decath%>%
mutate(A = ifelse (Javelot > 60, 1, 0)) %>%
mutate(B = ifelse (X100m < 10.9, 1, 0)) %>%
mutate(C = ifelse (Longueur > 7.4, 1, 0)) %>%
mutate(D = ifelse (X1500m < 275, 1, 0)) %>%
group_by(A, B, C, D) %>%
summarize(nombre = n())
data
## # A tibble: 14 x 5
## # Groups: A, B, C [8]
## A B C D nombre
## <dbl> <dbl> <dbl> <dbl> <int>
## 1 0 0 0 0 9
## 2 0 0 0 1 5
## 3 0 0 1 0 2
## 4 0 0 1 1 1
## 5 0 1 0 0 2
## 6 0 1 0 1 2
## 7 0 1 1 0 4
## 8 0 1 1 1 1
## 9 1 0 0 0 4
## 10 1 0 0 1 4
## 11 1 0 1 0 1
## 12 1 1 0 0 1
## 13 1 1 0 1 2
## 14 1 1 1 0 3
Il faut alors faire les manips suivantes sur le jeu de données pour le transformer en une liste nommée
data <- data %>%
mutate(combi = paste(ifelse (A == 1,'A',''),
ifelse (B == 1,'B',''),
ifelse (C == 1,'C',''),
ifelse (D == 1,'D',''), sep = ''))
data$combi2 <-sapply(strsplit(data$combi, ""), paste, collapse = "&")
expr <- as.list(data$nombre)
names(expr) <- data$combi2
Et enfin on peut faire l’upset plot
upset(fromExpression(expr),
sets.x.label = "nombre de décathloniens",
mainbar.y.label = "nombre",
sets.bar.color = c('darkgreen', 'orange', 'purple', 'steelblue'),
matrix.color = 'black',
main.bar.color = "darkgrey",
point.size = 5)
datap <- dept%>%mutate(superficie = as.numeric(st_area(geom)/1000000))%>%arrange(-superficie)
ggplot(datap, aes(x = reorder(nom_dep_m, -superficie), y= superficie, fill = insee_reg)) +
geom_bar(stat = 'identity') +
theme(axis.text = element_text(size = 5)) +
coord_polar()
pour sauvegarder le dernier graphique affiché
ggsave("mon_graphique.png", width = 11, height = 8) # taille en pouces ; 72 pixels par pouce par défaut
R Plot_ly est un package R permettant de créer des graphiques interactifs, ou de transformer des graphiques issus de ggplot2 pour les rendre interactifs.
Chargement de la librairie
library(plotly)
g <- ggplot(decath, aes(x = Poids, y = Javelot, col = Competition)) +
geom_point(size = 2) +
labs(title = 'performances au décathlon')
ggplotly(g)
On peut aussi coder directement le graphique dans l’esprit plotly, sans passer par un ggplot intermédiaire. La syntaxe est alors différente.
plot_ly(
y = decath$X,
x = decath$Longueur,
type = 'bar',
orientation = 'h'
) %>%
layout(title = "graphique en barres horizontales",
xaxis = list(title = 'saut en longueur (m)'))
La sortie se fait en html - Avec l’interface R Studio : viewer / export / save as web page - En commande R :
library(htmlwidgets)
p <- plot_ly(
x = row.names(data),
y = data$x,
name = "graphique barres",
type = "bar"
)
saveWidget(p, 'mon_graphique_dynamique.html', selfcontained = TRUE)
Leaflet est une bibliothèque JavaScript libre de cartographie en ligne.
R dispose d’un package simplement intitulé “leaflet” qui permet de réaliser des cartes dynamiques tout en codant en R mais avec la puissance et la diversité offerte par le package JS original.
Chargement du package et d’une couche de points
library(leaflet)
data = quakes
map <- leaflet() %>%
addTiles() %>%
setView(lng = 4, lat = 45.5, zoom = 8)
map
map <- leaflet(data) %>%
addTiles() %>%
addMarkers(~long, ~lat, popup = ~as.character(mag), label = ~as.character(mag), clusterOptions = markerClusterOptions())
map
Pour améliorer l’esthétique des popup il faut faire un peu de HTML
map <- leaflet(data[1:20,]) %>%
addTiles() %>%
addMarkers(popup = ~paste("<b> station :", stations, "</b><br>", "magnitude: ", mag, "<br>", "profondeur: ", depth, " m"),
label = ~stations)
map
Aux markers classiques qui sont toujours bleus, on peut préférer les circlemarkers dont on peut faire varier la couleur et la taille
colorIcon <- function(x) {
if (is.na(x)) {
"white"
} else if(x == "Commune") {
"blue"
} else if(x == "Conseil départemental") {
"green"
} else if(x == "Conseil régional") {
"yellow"
} else if(x == "Etablissement public de coopération intercommunale") {
"red"
} else {
"azure"
}
}
map <- leaflet() %>%
setView(lng = 4, lat = 45.5, zoom = 8) %>%
addTiles() %>%
addCircleMarkers(data = data, color = lapply(data$type_comma, colorIcon), popup = ~pilote,
label= ~code_ca) %>%
addLegend(title="Commanditaire", "bottomright", colors = c("blue", "green", "yellow", "red", "grey"),
labels = c("Commune", "Département", "Region", "EPCI", "Autres"))
map
Attention une couche de polygone peut rapidement alourdir le poids de la carte, s’il y a beaucoup de polygones et s’ils sont très découpés Dans leaflet, toutes les couches doivent être projetées en longitude / latitude
com69_4326 <- st_transform(com69, 4326)
map <- leaflet() %>%
setView(lng = 4, lat = 45.5, zoom = 8) %>%
addTiles(group = 'OSM') %>%
addPolygons(data = com69_4326, group = 'communes')
map
Il faut d’abord définir une fonction contenant les couleurs désirées
colorPoly <- function(x) {
if (is.na(x)) {
"white"
} else if(x == "Commune simple") {
"green"
} else if(x == "Préfecture de région") {
"yellow"
} else if(x == "Sous-préfecture") {
"orange"
}
}
ensuite on appelle cette fonction pour colorer chaque polygone selon la valeur d’un attribut Et on rajoute une légende reprenant ces couleurs
map <- leaflet() %>%
setView(lng = 4, lat = 45.5, zoom = 8) %>%
addTiles(group = 'OSM') %>%
addPolygons(
data = com69_4326,
weight = 1,
color = ~lapply(statut, colorPoly),
opacity = 0.7,
label = ~nom_com,
highlight = highlightOptions(weight = 3, color = 'green', bringToFront = FALSE)
) %>%
addLegend(title="type de commune", "bottomright", colors = c("green", "yellow", "orange"),
labels = c("Commune simple", "Préfecture de région", "Sous-préfecture"))
map
## Ajout d’une couche de polygones avec coloration graduelle
Même principe que ci-dessus, mais on va utiliser une palette de couleurs
bins <- c(0, 100, 1000, 10000, 100000, Inf)
pal <- colorBin("YlOrRd", domain = com69$population, bins = bins)
map <- leaflet() %>%
setView(lng = 4, lat = 45.5, zoom = 8) %>%
addTiles(group = 'OSM') %>%
addPolygons(
data = com69_4326,
fillColor = ~pal(population),
weight = 1,
opacity = 1,
color = "white",
fillOpacity = 0.7
) %>%
addLegend(pal = pal, values = bins, opacity = 0.7, title = "Population",
position = "bottomright")
map
Deux types de couches : base (que l’on sélectionne par bouton radio : une seule à la fois) et overlay (sélection par case à cocher : on peut en afficher plusieurs)
map <- leaflet() %>% setView(lng = 4, lat = 45.5, zoom = 8) %>%
addTiles(group = 'OSM') %>%
addProviderTiles(providers$Esri.WorldImagery, group = 'Satellite')%>%
addProviderTiles(providers$Stamen.Toner, group = 'Carte basique')%>%
addPolygons(data = com69_4326, group = 'communes') %>%
addLayersControl(
baseGroups = c("OSM", "Satellite", "Carte basique"),
overlayGroups = c("communes"),
options = layersControlOptions(collapsed = FALSE))
map