Cartographie interactive avec R… la suite !

We want more ! We Want more ! You really like it, you want more ! (mème)
Tags : Ressources
Date :

Parce qu’il n’y a pas que leaflet dans la vie…

On vous a parlé il y a peu du package de cartographie interactive {leaflet} et de toutes les possibilités qu’il nous offrait. Mais il existe de nombreux autres packages nous permettant de représenter nos données spatiales, et comme ce serait dommage de passer à coté, je vous en propose aujourd’hui une petite vue d’ensemble. Les packages étant nombreux, je n’entrerai cette fois pas dans les détails de chaque fonction, le but étant ici de vous donner une idée générale de ce qu’il est possible de faire.

Attention, cet article contient beaucoup de cartes interactives. Il va lui falloir un peu de temps pour charger. Soyez patients… Vous pouvez aussi aller les voir directement sur notre Github : https://github.com/ThinkR-open/iframe.illustrations

Des cartes avec le package {plotly}

Beaucoup d’entre vous connaissent déjà {plotly}, fameux package qui dispose de nombreuses fonctions pour faire des graphes interactifs. Pour faire des cartes interactives, différentes approches sont possibles.

La fonction de base d’un graph interactif {plotly} : plot_ly()

Il s’agit de la fonction la plus générale : elle permet de créer un objet plotly, qu’on veuille faire un simple graphe ou une carte.

Exemple de polygones : les départements français.

# Recuperer la France Metropolitaine de {rnaturalearth}
library(rnaturalearth)
france <- ne_states(country = "France", returnclass = "sf") %>% 
  filter(!name %in% c("Guyane française", "Martinique", "Guadeloupe", "La Réunion", "Mayotte"))
# Carte
plot_ly(france, split = ~name, color = ~provnum_ne) %>% 
  layout(showlegend = FALSE) 

Cette carte est interactive, vous pouvez l’explorer

La fonction de {plotly} pour les cartes : plot_geo()

plot_geo() intègre le fait qu’on crée une carte et gère les coordonnées et le ratio longitude / latitude. Elle permet aussi d’ajouter un fond de carte avec layout(geo = ...).

Exemple de markers + polygones : population des villes du Brésil.

# Recuperer les villes du Brésil de {maps} et leurs infos de population
library(maps)
brazil_pop <- world.cities %>%
  filter(country.etc == "Brazil") %>% 
  mutate(
    # ajout de texte pour le passage de la souris
    pop_text = paste(name, "Pop", round(pop / 1e6, 2), "millions"),
    # separer les valeurs en quartiles puor les couleurs
    pop_quantile = cut(
      pop, quantile(pop), include.lowest = T,
      labels = paste(c("1st", "2nd", "3rd", "4th"), "Quantile")
    ) %>% as.ordered()
  )
# Caracteristique d'un fond de carte Amerique du Sud
fond_carte <- list(
  scope = "south america",
  showland = TRUE,
  landcolor = toRGB("gray85"),
  subunitwidth = 1,
  countrywidth = 1,
  subunitcolor = toRGB("white"),
  countrycolor = toRGB("white")
)
# Carte
plot_geo(brazil_pop,
  lon = ~long, lat = ~lat, 
  # texte au passage de la souris
  text = ~pop_text,
  # taille du marker selon la pop
  marker = ~ list(size = sqrt(pop / 10000) + 1, 
                  line = list(width = 0)),
  # couleur selon le quartile
  color = ~pop_quantile
) %>%
  layout(geo = fond_carte, title = "Populations")

Cette carte est interactive, vous pouvez l’explorer

Afficher un fond de carte Mapbox avec plot_mapbox()

Exemple de markers : quelques villes en France.

# Positions de quelques villes de France Métropolitaine
villes <- data.frame(
  name = c("Paris", "Rennes", "Toulouse", "Bordeaux", "Lyon", "Lille"),
  lat = c(48.85, 48.11, 43.60, 44.86, 45.75, 50.63),
  lon = c(2.27, -1.75, 1.36, -0.65, 4.76, 2.97),
  z = c(3, 2, 1, 3, 2, 1)
)
# Carte
villes_mapbox <- villes %>%
  plot_mapbox(
    lat = ~lat, lon = ~lon, 
    # Taille et couleur selon la latitude. Pourquoi pas ?
    size = ~lat, color = ~lat,
    # Palette de couleur de {RColorBrewer}
    colors = RColorBrewer::brewer.pal(n = 9, name = "Blues"),
    # mode d'affichage
    mode = "markers"
  ) %>%
  # Options d'affichage
  layout(
    title = "Villes en France",
    # Style du fond de carte Mapbox
    mapbox = list(
      style = "dark",
      zoom = 4,
      center = list(lat = ~ median(lat), lon = ~ median(lon))
    ),
    # Format de la légende
    legend = list(
      orientation = "h",
      font = list(size = 8)
    )
  )
villes_mapbox

Cette carte est interactive, vous pouvez l’explorer

Transformer un “ggplot” en “plotly” avec ggplotly()

Si vous êtes un pro de la cartographie avec {ggplot2}, c’est LA fonction à utiliser pour rendre vos cartes interactives. J’ai par exemple une super carte réalisée grâce à {ggplot2} :

Prenons un petit exemple avec les données de crimes aux US.

library(ggplot2)
library(dplyr)
# Données d'arrestations par Etat
arrests <- USArrests %>% 
  tibble::rownames_to_column(var = "region") %>% 
  mutate(region = tolower(region))
# Recuperation d'un fnod de carte US et jointure avec donnees de crime
arrests_map <- map_data("state") %>% 
  left_join(arrests, by = "region")
# carte statique ggplot :
carte_gg <- ggplot(arrests_map) +
  aes(long, lat, group = group) +
  geom_polygon(aes(fill = Assault), color = "white") +
  scale_fill_viridis_c(option = "C") +
  coord_quickmap()
carte_gg
# ggplotly, et la magie opère :
ggplotly(carte_gg)

Cette carte est interactive, vous pouvez l’explorer

Intégration dans Shiny

Comme les autres graphes de {plotly}, les carte créées peuvent être intégrées à vos applications Shiny via les fonctions plotlyOutput() côté UI, et renderPlotly() côté server. De façon relativement similaire, les objets {plotly} peuvent également générer des inputs en fonction de certains évènements, grâce à la fonction event_data() :

library(shiny)
library(plotly)
ui <- fluidPage(
  fluidRow(
    column(6, plotlyOutput("plot")),
    column(6, verbatimTextOutput("click"))
  )
)
server <- function(input, output, session) {
  output$plot <- renderPlotly({
    # Définir une projection pour la carte plotly
    g <- list(
      scope = 'usa',
      projection = list(type = 'albers usa'),
      lakecolor = toRGB('white')
    )
    plot_ly(z = state.area, text = state.name, locations = state.abb,
            type = 'choropleth', locationmode = 'USA-states') %>%
      layout(geo = g)
  })
  output$click <- renderPrint({
    test <- event_data("plotly_click")
    if (is.null(test)) "Cliquer sur un état pour voir les données de l'évènement" else test
  })
}
shinyApp(ui, server)

Le nombre d’évènements supportés est assez impressionnant comparé à celui proposé par leaflet : pas moins de 16 ! Pour la liste : ?event_data. Par contre, une chose très importante à souligner : si on ne spécifie pas l’argument source, la fonction event_data() ne prend par l’id de l’output plotly, et il pointe sur n’importe quel objet plotly. Si j’ai deux cartes sur mon application Shiny, event_data("plotly_click") renverra les informations de l’élément cliqué, indépendamment de la carte à laquelle il appartient. Même chose pour n’importe quel objet créé avec plotly. Attention donc si vous avez plusieurs éléments plotly !

ui <- fluidPage(
  fluidRow(
    column(6, plotlyOutput("plot")),
    column(6, plotlyOutput("plot2"))
  ),
  verbatimTextOutput("click")
)
server <- function(input, output, session) {
  output$plot <- renderPlotly({
    # Définir une projection pour la carte plotly
    g <- list(
      scope = 'usa',
      projection = list(type = 'albers usa'),
      lakecolor = toRGB('white')
    )
    plot_ly(z = state.area, text = state.name, locations = state.abb,
            type = 'choropleth', locationmode = 'USA-states', source = "p1") %>%
      layout(geo = g)
  })
  output$plot2 <- renderPlotly({
    # Définir une projection pour la carte plotly
    g <- list(
      scope = 'usa',
      projection = list(type = 'albers usa'),
      lakecolor = toRGB('white')
    )
    plot_ly(z = state.area, text = state.name, locations = state.abb,
            type = 'choropleth', locationmode = 'USA-states', source = "p2") %>%
      layout(geo = g)
  })
  output$click <- renderPrint({
    test <- event_data("plotly_click", source = "p1")
    if (is.null(test)) "Cliquer sur un état pour voir les données de l'évènement" else test
  })
}
shinyApp(ui, server)

Ici, on n’affichera que l’élément cliqué sur la première carte et non la seconde.

Vous voulez en savoir plus sur le server-side de plotly ? Go : https://plotly-r.com/linking-views-with-shiny.html

Pour plus d’exemples : https://plotly.com/r/maps/

Une carte interactive avec le package {tmap}

{tmap} est un package qui permet de réaliser des cartes statiques et interactives, et dont la syntaxe est très proche de celle du {ggplot2}, mais adaptée aux cartes. Il dispose également d’une fonction permettant de transformer des cartes tmap statiques en cartes interactives : tmap_leaflet().

Cependant, pour que les cartes soient interactives dans toute votre session, vous pouvez appeler la fonction tmap_mode(). Elle permet de modifier le mode de visualisation : mode = "plot" pour une carte statique, mode = "view" pour une carte interactive :

library(tmap)
tmap_mode(mode = "view")

Exemples de cartes {tmap} interactives

Reprenons les données des régions de France :

# Recuperer la France Metropolitaine de {rnaturalearth}
library(rnaturalearth)
france <- ne_states(country = "France", returnclass = "sf") %>% 
  filter(!name %in% c("Guyane française", "Martinique", "Guadeloupe", "La Réunion", "Mayotte"))

La fonction tm_shape() crée un élément tmap. Elle prend en argument un objet de forme, de classe sf, sp ou raster ; dans notre exemple france. La fonction tm_polygons() affiche quant à elle les polygones en question.

tm_shape(france) +
  tm_polygons()

Cette carte est interactive grâce au mode “view” dans tmap_mode()

Pour colorer nos polygones en fonction d’une variable de nos données, on le spécifie via le paramètre col de la fonction tm_polygons() :

tm_shape(france) +
  tm_polygons(col = "provnum_ne")

Cette carte est interactive grâce au mode “view” dans tmap_mode()

Superposition de plusieurs couches spatiales avec {tmap}

Il est possible d’ajouter différentes couches à notre carte avec plusieurs appels à tm_shape() et des enchaînements avec +. On souhaite par exemple ajouter des points représentant les métros à notre carte de France, modifier les couleurs des polygones, ajouter un fond de carte, …

  • la fonction tm_basemap() permet d’intégrer un fond de carte
  • la fonction tm_fill() est utilisée pour colorer les polygônes en spécifiant la colonne de couleur, la palette de couleurs, l’opacité, …
  • la fonction tm_borders() indique comment afficher les contours des formes : couleur, épaisseur, …
  • la fonction tm_symbols() permet d’afficher des points en spécifiant, couleur, taille selon une variable, échelle, …

Je vous invite à aller consulter l’aide de ces fonctions de {tmap}, ainsi que celle des autres fonctions du package.

data(metro)
metro_fr <- metro %>%
  filter(iso_a3 == "FRA")
tm_basemap("Stamen.Watercolor") +
tm_shape(france) +
  tm_fill(col = "provnum_ne", palette = "Blues", alpha = 0.8) +
  tm_borders("white", lwd = 1) +
tm_shape(metro_fr) +
  tm_symbols(col = "red", size = "pop2020", scale = 1) 

Cette carte est interactive grâce au mode “view” dans tmap_mode()

{tmap} et {leaflet} travaillent ensemble

La fonction tmap_leaflet() du package {tmap}, vous vous en doutez, a quelque chose à voir avec {leaflet}. Mais quoi exactement ? tmap_leaflet() permet en fait de créer un widget {leaflet} à partir de votre carte {tmap} statique, c’est à dire de transformer votre objet tmap en objet leaflet. On pourra ensuite appeler les fonctions du package {leaflet} pour modifier notre carte. (Vous ne connaissez pas leaflet ? Lisez notre article “Cartographie interactive : comment visualiser mes données spatiales de manière dynamique avec leaflet ?”)

Intégration des cartes {tmap} dans {shiny}

Les carte créées grâce aux fonctions de {tmap} peuvent être intégrées à vos applications Shiny via les fonctions tmapOutput() côté UI, et renderTmap() côté server. Les objets tmap peuvent également générer des inputs en fonction de certains évènements, de la même manière que les objets leaflet :

library(shiny)
library(rnaturalearth)
france <- ne_states(country = "France", returnclass = "sf") %>% 
  filter(!name %in% c("Guyane française", "Martinique", "Guadeloupe", "La Réunion", "Mayotte")) %>% 
  select(name, region, provnum_ne, geometry)
tmap_mode("view")
ui <- fluidPage(
  fluidRow(
    column(6, tmapOutput("mymap")),
    column(6, verbatimTextOutput("click"))
  )
)
server <- function(input, output, session) {
  output$mymap <- renderTmap({
    tm_basemap("Stamen.Watercolor") +
      tm_shape(france) +
      tm_fill(col = "provnum_ne", palette = "Blues", alpha = 0.8) +
      tm_borders("white", lwd = 1)
  })
  output$click <- renderPrint({
    test <- input$mymap_shape_click
    if (is.null(test)) "Cliquer sur un état pour voir les données de l'évènement" else test
  })
}
shinyApp(ui, server)

Des cartes interactives avec le package {mapview}

Autre package intéressant pour visualiser les données spatiales via des map interactives : {mapview}. Il permet la prise en charge d’objets créés via les packages {sf}, {sp}, {raster} et {satellite}.

Exploration de données géographiques avec {mapview}

mapview() est la fonction de base de ce package du même nom, elle permet de créer une carte interactive leaflet comprenant par défaut :

  • un fond de carte, avec un bouton donnant la possibilité de basculer sur 5 fonds différents
  • un bouton de zoom
  • une barre d’échelle
  • l’affichage de la latitude et de la longitude suivant la position du curseur, ainsi que du niveau de zoom
library(mapview)
mapview()

Généralement, on utilisera {mapview} un peu comme la fonction View() sur un jeu de données classiques, pour l’exploration. Il permet d’afficher rapidement une carte que l’on vient de charger dans notre session. Avec la possibilité d’explorer les variables de chacune des entités.

Exemple de polygones, une fois encore, les départements de France métropolitaine. L’argument zcol permet de notifier la variable de couleur. La légende s’affiche automatiquement, mais on peut la retirer de la carte en ajoutant legend = FALSE.

library(rnaturalearth)
france <- ne_states(country = "France", returnclass = "sf") %>% 
  filter(!name %in% c("Guyane française", "Martinique", "Guadeloupe", "La Réunion", "Mayotte"))
mapview(france, zcol = "region", legend = FALSE)

Carte interactive

Afficher plusieurs couches avec {mapview}

Pour afficher plusieurs couches de données, on donne à mapview() une liste contenant ces données spatiales. Reprenons comme dans les exemples pécédents les données de métro des villes française, du package {tmap}.

data(metro)
metro_fr <- metro %>%
  filter(iso_a3 == "FRA")
mapview(list(france, metro_fr))

Carte interactive

Mais on peut également appeler la fonction mapview() plusieurs fois via +, ce qui nous donne un champs d’action plus large. Le paramètre layer.name permet de définir le nom des layers. cex permet d’ajuster la taille des points en fonction des valeurs d’une variable.

mapview(france, zcol = "region", legend = FALSE, layer.name = "Departements") +  
  mapview(metro_fr, zcol = "name", layer.name = "Métro", cex = "pop2020")

Carte interactive

On commence à se rapprocher de la présentation d’une carte interactive pas uniquement utilisée pour l’exploration des données…

Les options des popups dans {mapview}

On remarque que par défaut, les popups contiennent une table de valeurs des variables pour l’élément cliqué. Il est possible de modifier ce contenu :

  • une table avec les valeurs de variables sélectionnées en appelant la fonction popupTable()
  • un graphe statique plot de {base}, {ggplot2} ou {lattice}, ou un graphe interactif {htmlwidgets} en appelant la fonction popupGraph()
  • une image en appelant la fonction popupImage()

Attention, les fonctions popupTable(), popupGraph() et popupImage() du package {mapview} sont obsolètes, il conviendra d’utiliser les fonctions du même nom du package {leafpop}. Ces fonctions peuvent également être appliquées aux cartes {leaflet}.

Par exemple : je souhaite afficher le nom du département ainsi que le nom de la région lorsque je clique sur le département, et une photo de la ville quand je clique sur celle-ci.

# Des images de la ville
img <- list(
  "https://upload.wikimedia.org/wikipedia/commons/thumb/7/7c/Lille_grand_place.JPG/140px-Lille_grand_place.JPG",
  "https://upload.wikimedia.org/wikipedia/commons/thumb/3/3b/Lyon_05_-_%C3%89glise_Saint-Paul_-_PA00117802.JPG/180px-Lyon_05_-_%C3%89glise_Saint-Paul_-_PA00117802.JPG",
  "http://thefatmouse.com/wp-content/gallery/marseille/thumbs/thumbs_dsc02685.jpg",
  "https://upload.wikimedia.org/wikipedia/commons/thumb/6/6e/Paris_-_Eiffelturm_und_Marsfeld2.jpg/233px-Paris_-_Eiffelturm_und_Marsfeld2.jpg"
)
mapview(france,
  zcol = "region", legend = FALSE, layer.name = "Departements",
  popup = leafpop::popupTable(france, zcol = c("name", "region"), row.numbers = FALSE)
) +
  mapview(metro_fr,
    zcol = "name", layer.name = "Métro", cex = "pop2020",
    popup = leafpop::popupImage(img), src = "remote"
  )

Carte interactive

Pour en savoir plus sur les popups, c’est par ici : https://r-spatial.github.io/mapview/articles/articles/mapview_04-popups.html

Les options {mapview}

On peut afficher les options appliquées par défaut en appelant mapviewOptions(). On a entre autres :

  • basemaps : les fonds de carte proposés
  • maxpolygons, maxpoints, maxlines : le nombre maximal de polygones, points, lignes possible
  • vector.palette : la palette de couleur utilisée (viridisLite::viridis par défaut)
  • na.color : la couleur lorsqu’on a des données manquantes
  • legend : affichage de la légende
  • legend.pos : la position de la légende

Il est possible de modifier ces options. Par exemple :

mapviewOptions(
  basemaps = c("Esri.WorldShadedRelief", "OpenStreetMap.DE"),
  raster.palette = grey.colors,
  vector.palette = colorRampPalette(c("snow", "cornflowerblue", "grey10")),
  na.color = "magenta",
  layers.control.pos = "topright")

Intégration de {mapview} dans {shiny}

Les carte créées grâce aux fonctions de {mapview} peuvent être intégrées à vos applications Shiny via les fonctions mapviewOutput() côté UI, et renderMapview() côté server.

Combinaison avec {mapedit} pour créer des objets géographiques en les dessinant

Si vous utilisez {mapedit} en combinaison avec {mapview}, vous ouvrez une application Shiny qui permet de créer manuellement des objets géographiques en tous genres : points, lignes, polygones. Vous récupérer ensuite ces objets au format {sf} dans votre session pour la suite de vos opérations. Vous ferez attention au système de projection des objets créés…

library(mapedit)
objets_sf <- mapview(france, zcol = "region", legend = FALSE) %>% 
  editMap()
# Récupérer le dernier objet créé  
mon_polygon_wgs84 <- objets_sf$finished

Cette carte est une capture d’écran

Des cartes avec le package {mapdeck}

{mapdeck}, c’est la combinaison de Mapbox, dont je vous ai déjà parlé avec leaflet, et de Deck.gl, un framework basé sur WebGL pour l’analyse visuelle exploratoire de grands ensembles de données. Comme on utilise Mapbox, il faudra, je vous le rappelle, un token Mapbox. Pour ne pas devoir le spécifier à chaque appel de fonction, on peut le définir soit comme variable d’environnement, soit via la fonction set_token() :

library(mapdeck)
# declaration du token
key <- "..."
set_token(token = key)

Soit en exécutant Sys.setenv("MAPBOX_TOKEN" = key)

Les fonds de carte {mapdeck}

La fonction mapdeck() permet de créer l’objet mapdeck. Le choix de fonds de cartes est donné par le paramètre style, à choisir entre :

  • mapbox://styles/mapbox/streets-v11
  • mapbox://styles/mapbox/outdoors-v11
  • mapbox://styles/mapbox/light-v10
  • mapbox://styles/mapbox/dark-v10
  • mapbox://styles/mapbox/satellite-v9
  • mapbox://styles/mapbox/satellite-streets-v11
# création de la carte
mapdeck(style = 'mapbox://styles/mapbox/dark-v10')

Carte interactive

Il également possible de créer son propre fond de carte personnalisé : https://docs.mapbox.com/studio-manual/reference/styles/

Note : Attention, selon votre version de Rstudio, pour visualiser votre carte, vous devrez peut-être l’ouvrir dans votre explorateur web. Par ailleurs, ces cartes ne sont à priori pas intégrables dans un markdown.

Les layers d’objets géographiques de {mapdeck}

Afficher des points sur la carte

Pour afficher des points sur notre carte, on appelle la fonction add_scatterplot(). Reprenons l’exemple précédent des villes de France :

mapdeck() %>%
  add_scatterplot(
    data = villes,
    lat = "lat", lon = "lon",
    radius = 50000, fill_colour = "z",
    tooltip = "name", auto_highlight = TRUE,
    layer_id = "scatter_layer", palette = "blues"
  )

Carte interactive

Regardons de plus près les paramètres principaux de cette fonction :

  • map : l’objet mapdeck auquel on souhaite ajouter nos éléments
  • data : les données contenant les coordonnées de nos éléments
  • lat et lon : les colonne latitude et longitude
  • radius : la taille du marker, en mètres
  • fill_colour : la colonnes correspondant aux couleur ou la couleur au format hexadécimal
  • tooltip : le nom de la colonne contenant le texte à afficher au passage du curseur
  • auto_highlight : la mise en avant de l’élément au passage du curseur
  • highlight_colour : la couleur de l’highlight au format hexadécimal
  • legend : affichage ou non de la légende
  • layer_id : l’id du layer

De la 3D interactive avec {mapdeck}

La grande révolution de ce package et qu’il permet, contrairement aux autres, d’ajouter une 3ème dimension, la hauteur. On utilise alors la fonction add_pointcloud() et son paramètre elevation. Reprenons l’exemple précédent, :

villes_h <- villes %>% 
  # Ajout de fausses altitudes
  mutate(hauteur = sample(10000:100000, size = nrow(villes)))
mapdeck(pitch = 60) %>%
  add_pointcloud(
    data = villes_h,
    lat = "lat", lon = "lon",
    elevation = "hauteur",
    fill_colour = "z", tooltip = "name", auto_highlight = TRUE,
    layer_id = "scatter_layer", palette = "blues"
  )

Carte interactive

Le paramètre pitch de la fonction mapdeck() permet de visualiser la carte depuis un autre angle et facilite ainsi la visualisation des éléments en 3D.

On peut jouer avec mais personnellement, j’ai un peu de mal à en voir une bonne application ici, les coordonnées des points sont difficillement visibles et les hauteurs difficilement appréciables.

Ajout de polygones sur la carte

On souhaite maintenant afficher les départements de France métropolitaine. On appelle ici la fonction add_geojson() :

mapdeck() %>%
  add_geojson(
    data = france, fill_colour = "region", auto_highlight = TRUE, tooltip = "name", 
    layer_id = "geojson"
  )

carte interactive

Les paramètres sont relativement identiques à ceux de la fonction add_scatterplot(). Ici encore, il est possible d’afficher nos polygones avec une troisième dimension, via la fonction add_polygon() et le paramètre elevation :

fr_3D <- france %>% 
  mutate(hauteur = provnum_ne * 10000)
mapdeck(pitch = 45) %>%
  add_polygon(
    data = fr_3D, 
    fill_colour = "region",
    auto_highlight = TRUE, tooltip = "name", 
    elevation = "hauteur",
    layer_id = "geojson"
  )

Carte interactive

Ajout de lignes et arcs avec {mapdeck}

Les lignes et les arcs permettent de traduire une information de lien, de trajets, … Nous prendrons ici l’exemple des vols entre différents aéroports :

url <- 'https://raw.githubusercontent.com/plotly/datasets/master/2011_february_aa_flight_paths.csv'
flights <- readr::read_csv(url)
## Parsed with column specification:
## cols(
##   start_lat = col_double(),
##   start_lon = col_double(),
##   end_lat = col_double(),
##   end_lon = col_double(),
##   airline = col_character(),
##   airport1 = col_character(),
##   airport2 = col_character(),
##   cnt = col_double()
## )
flights <- flights %>%
  mutate(id = seq_len(nrow(flights)), 
         stroke = sample(1:3, size = nrow(flights), replace = T))

La fonction add_line() permet de tracer des droites entre deux points, en renseignant les coordonnées du point de départ origin et celles du points d’arrivée destination :

mapdeck(style = mapdeck_style("dark")) %>%
  add_line(
    data = flights, 
    layer_id = "line_layer", 
    origin = c("start_lon", "start_lat"),
    destination = c("end_lon", "end_lat"), 
    stroke_colour = "airport1"
  )

Carte interactive

De manière identique, et en intégrant une 3ème dimension, la fonction add_arc() permet de tracer des arcs entre deux points :

mapdeck(style = mapdeck_style("dark"), pitch = 45) %>%
  add_arc(
    data = flights, 
    layer_id = "arc_layer", 
    origin = c("start_lon", "start_lat"),
    destination = c("end_lon", "end_lat"), 
    stroke_from = "airport1", stroke_to = "airport2",
    stroke_width = "stroke"
  )

Carte interactive

Animer les lignes de cartes 3D {mapdeck}

Petite touche de fun supplémentaire, il est possible d’animer les arcs grâce à la fonction add_animated_arc() que l’on appelle avec les mêmes paramètres que la fonction add_arc() (attention, il s’agit d’une fonction expérimentale, il se peut qu’elle soit modifiée dans le futur) :

mapdeck(style = mapdeck_style("dark"), pitch = 45) %>%
  add_animated_arc(
    data = flights, 
    layer_id = "arc_layer", 
    origin = c("start_lon", "start_lat"),
    destination = c("end_lon", "end_lat"), 
    stroke_from = "airport1", stroke_to = "airport2",
    stroke_width = "stroke"
  )

Carte interactive

Integration de {mapdeck} dans Shiny

Les carte créées grâce aux fonctions de {mapdeck} peuvent être intégrées à vos applications Shiny via les fonctions mapdeckOutput() côté UI, et renderMapdeck() côté server.

Les objets mapdeck peuvent également générer des inputs lorsque que l’on clique sur la carte, en appelant input$mapId_layerId_click.

Pour en savoir plus sur ce beau package de visualisation, rendez-vous sur le site dédié à {mapdeck} : https://symbolixau.github.io/mapdeck/

Des cartes interactives avec le package {highcharter}

Ce package s’appuie sur la librairie JavaScript Hightcharts et dont la fonction hcmap() permet de créer des cartes interactives. Celles-ci ne donnent pas la possibilité d’avoir un fond de carte, mais sont reltivement simples à faire. Ci-dessous un exemple d’utilisation :

library(highcharter)
library(dplyr)
data_fr <- download_map_data("countries/fr/fr-all") %>% 
  get_data_from_map() %>% 
  # Une valeur aléatoire pour la coloration
  mutate(value = 1e5 * abs(rt(nrow(.), df = 10)))
# Position de villes de France
villes <- data.frame(
  name = c("Paris", "Rennes", "Toulouse", "Bordeaux", "Lyon", "Lille"),
  lat = c(48.85, 48.11, 43.60, 44.86, 45.75, 50.63),
  lon = c(2.27, -1.75, 1.36, -0.65, 4.76, 2.97),
  z = c(3, 2, 1, 3, 2, 1)
)
# Carte
hcmap("countries/fr/fr-all",
      data = data_fr,
      value = "value",
      joinBy = c("hc-a2"),
      name = "France",
      dataLabels = list(enabled = TRUE, format = '{point.name}'),
      borderColor = "#FAFAFA", borderWidth = 0.1,
      tooltip = list(valueDecimals = 2, valuePrefix = "$",
                     valueSuffix = " €")) %>% 
  hc_add_series(data = villes, 
                type = "mapbubble", 
                name = "Villes", 
                maxSize = '10%') %>% 
  hc_mapNavigation(enabled = TRUE)  

Carte interactive

Comme les autres packages présentés dans cet article, {highcharter} dispose de fonctions propres à l’intégration des objets crées dans vos applications Shiny : renderHighchart() et highchartOutput(). Ces objets peuvent également générer des inputs en fonction de certains évènements, click, mouseOut et mouseOver grâce aux fonctions hc_add_event_point() et hc_add_event_series():

data_fr <- download_map_data("countries/fr/fr-all") %>% 
  get_data_from_map() %>%
  mutate(value = 1e5 * abs(rt(nrow(.), df = 10)))
villes <- data.frame(
  name = c("Paris", "Rennes", "Toulouse", "Bordeaux", "Lyon", "Lille"),
  lat = c(48.85, 48.11, 43.60, 44.86, 45.75, 50.63),
  lon = c(2.27, -1.75, 1.36, -0.65, 4.76, 2.97),
  z = c(3, 2, 1, 3, 2, 1)
)
ui <- fluidPage(
  fluidRow(
    column(6, highchartOutput("plot")),
    column(6, verbatimTextOutput("click"))
  )
)
server <- function(input, output, session) {
  output$plot <- renderHighchart({
    hcmap("countries/fr/fr-all",
      data = data_fr, value = "value",
      joinBy = c("hc-a2"), name = "France",
      dataLabels = list(enabled = TRUE, format = "{point.name}"),
      borderColor = "#FAFAFA", borderWidth = 0.1,
      tooltip = list(valueDecimals = 2, valuePrefix = "$",
                     valueSuffix = " €")
    ) %>%
      hc_add_series(data = villes, type = "mapbubble", name = "Villes", maxSize = "10%") %>%
      hc_add_event_point(series = "series", event = "click")
  })
  output$click <- renderPrint({
    test <- input$plot_click
    if (is.null(test)) "Cliquez sur une ville" else test
  })
}
shinyApp(ui, server)

Des cartes avec le package {ggiraph}

{ggiraph} est un package qui permet de créer des graphes interactifs, notamment via l’ajout de tooltips, d’animations, et d’actions JavaScript. Il dispose notamment d’une fonction permettant de réaliser des cartes interactives. Par exemple :

library(ggplot2)
library(ggiraph)
# Données crimes US
crimes <- data.frame(state = tolower(rownames(USArrests)), USArrests)
# Tooltips pour les évènement onclick
states_ <- sprintf("<p>%s</p>", as.character(crimes$state))
table_ <- paste0(
  "<table><tr><td>UrbanPop</td>",
  sprintf("<td>%.0f</td>", crimes$UrbanPop),
  "</tr><tr>",
  "<td>Assault</td>",
  sprintf("<td>%.0f</td>", crimes$Assault),
  "</tr></table>"
)
onclick <- sprintf(
  "window.open(\"%s%s\")",
  "http://en.wikipedia.org/wiki/",
  as.character(crimes$state)
)
crimes$labs <- paste0(states_, table_)
crimes$onclick <- onclick
# création de la carte :
states_map <- map_data("state")
gg_map <- ggplot(crimes, aes(map_id = state))
gg_map <- gg_map + geom_map_interactive(aes(
  fill = Murder,
  tooltip = labs,
  data_id = state,
  onclick = onclick
),
map = states_map
) +
  expand_limits(x = states_map$long, y = states_map$lat)
x <- girafe(ggobj = gg_map)
x

Carte interactive

Ces objets ggiraph peuvent être intégrés à Shiny grâce aux fonctions ggiraphOutput() côté UI, et renderggiraph() côté server. Ils génèrent également des inputs en fonction de certains évènements.

Pour en savoir plus sur {ggiraph}, allez faire un tour sur Github : https://davidgohel.github.io/ggiraph/index.html.

Des cartes interactives avec le package {rbokeh}

Bokeh est une librairie graphique Python permettant de faire des graphes interactifs, dont des cartes, utilisant l’API de Google Maps. Vous aurez donc besoin d’un token vous permettant de vous connecter à cette API (https://cloud.google.com/console/google/maps-apis/overview). Le package {rbokeh} en permet son utilisation dans R.

library(rbokeh)
api_key <- "..."
options(GMAP_API_KEY = api_key)
library(maps)
data(world.cities)
# Les capitales des Pays
caps <- world.cities %>% 
  filter(capital == 1) %>% 
  mutate(
    population = prettyNum(pop, big.mark = ",")
  )
figure(width = 800, height = 450, padding_factor = 0) %>%
  ly_map("world", col = "gray") %>%
  ly_points(long, lat,
    data = caps, size = 5,
    hover = c(name, country.etc, population)
  )

Autre exemple :

orstationc <- readr::read_csv("http://geog.uoregon.edu/bartlein/old_courses/geog414s05/data/orstationc.csv")
gmap(lat = 44.1, lng = -120.767, 
     zoom = 6, width = 700, height = 600) %>%
  ly_points(lon, lat,
    data = orstationc, alpha = 0.8, col = "red",
    hover = c(station, Name, elev, tann)
  )

Ces cartes peuvent s’intégrer à une application Shiny grâce aux fonctions rbokehOutput() et renderRbokeh().

Des cartes avec le package {googleVis}

Autre package de visualisation interactive, {googleVis} a lui aussi quelques fonctions propres à la visualisation de données géographiques :

  • gvisMap(), qui permet d’avoir le fond de carte de Google Maps :
library(googleVis)
data(Andrew)
M1 <- gvisMap(Andrew, "LatLong", "Tip",
  options = list(
    showTip = TRUE, showLine = TRUE, enableScrollWheel = TRUE,
    mapType = "hybrid", useMapTypeControl = TRUE,
    width = 800, height = 400
  )
)
plot(M1)
  • gvisGeoMap() :
G1 <- gvisGeoMap(Exports,
  locationvar = "Country", numvar = "Profit",
  options = list(dataMode = "regions")
)
plot(G1)
  • gvisGeoChart()
G2 <- gvisGeoChart(Exports, "Country", "Profit",
  options = list(region = "150")
)
plot(G2)

Il est possible d’intégrer ces cartes à Shiny grâce aux fonctions renderGvis() et htmlOutput().

Pour conclure sur les cartes interactives

Il existe un grand nombre de packages permettant de réaliser de superbes cartes interactives, certains plus complets que d’autres. On espère que cet article vous aura permis d’y voir plus clair, et de choisir lequel vous préférez.

Et juste pour le plaisir, un petit bonus que je trouve vraiment fun, les packages {echarts4r} et {echarts4r.assets} qui permettent de visualiser nos données sur une sphère, comme ici, à la manière de Google Earth (allez voir par là : https://echarts4r.john-coene.com/index.html) :

library(echarts4r)
# remotes::install_github('JohnCoene/echarts4r.assets')
library(echarts4r.assets)
flights %>%
  e_charts() %>%
  e_globe(
    environment = ea_asset("starfield"),
    base_texture = ea_asset("world topo"),
    height_texture = ea_asset("world topo"),
    displacementScale = 0.05
  ) %>%
  e_lines_3d(
    start_lon,
    start_lat,
    end_lon,
    end_lat,
    name = "flights",
    effect = list(show = TRUE)
  ) %>%
  e_legend(FALSE)

Carte interactive

Article rédigé par Elena Salette, avec la participation de Sébastien Rochette


À propos de l'auteur


Commentaires

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *


À lire également