web-dev-qa-db-fra.com

Optimisation des performances de Shiny + Leaflet pour des cartes détaillées comportant de nombreuses "couches"

Je souhaite créer une application brillante dans laquelle la coloration d'un choroplète est basée sur la valeur numérique de l'une des nombreuses variables quantitatives possibles que l'utilisateur peut sélectionner. Dans les cas simples, cela est simple, mais je ne suis pas sûr des meilleures pratiques lorsque nous avons plus de 20 variables, avec des fichiers de formes assez détaillés (~ 2300 polygones).

Il peut être pertinent ou non que les variables puissent être complètement indépendantes les unes des autres, telles que «population totale» ou «température moyenne», mais certaines d'entre elles auront une relation temporelle, telle que «population totale», à trois moments ou plus. .

L’un des principaux fichiers de formes que j’utilise est le zone statistique ABS 2 . Ci-dessous, je donne la densité de population (population totale/zone) pour l'Australie et une vue agrandie de Sydney pour mieux rendre le niveau de détail qui m'intéresse.

AustralieAustralia SydneySydney

J'ai lu le fichier de formes dans R et ai considérablement réduit la complexité/le nombre de points en utilisant la fonction ms_simplify() dans le package rmapshaper.

Pour ce qui est de Shiny et de la brochure, voici ce que je faisais:

  • Avant que l'objet server soit défini dans server.R, je construis un objet de carte principal avec tous les "calques" souhaités. En d’autres termes, une brochure avec de nombreux appels addPolygon() pour définir la couleur de chaque couche (groupe).

    # Create main map
    primary_map <- leaflet() %>% 
    addProviderTiles(
        providers$OpenStreetMap.BlackAndWhite,
        options = providerTileOptions(opacity = 0.60)
    ) %>% 
    # Layer 0 (blank)
    addPolygons(
        data = aus_sa2_areas,
        group = "blank"
    ) %>% 
    # Layer 1
    addPolygons(
        data = aus_sa2_areas,
        fillColor = ~palette_layer_1(aus_sa2_areas$var_1),
        smoothFactor = 0.5,
        group = "layer_1"
    ) %>% 
    

    ...

    # Layer N
    addPolygons(
        data = aus_sa2_areas,
        fillColor = ~palette_layer_n(aus_sa2_areas$var_n),
        smoothFactor = 0.5,
        group = "layer_n"
    ) %>% ...
    
  • Toutes les barres du premier calque sont ensuite masquées à l’aide de hideGroup(), de sorte que le rendu initial de la carte n’a pas l’air idiot.

    hideGroup("layer_1") %>% 
    hideGroup("layer_2") %>% 
    ...
    hideGroup("layer_n")
    
  • Dans l'application Shiny, à l'aide des boutons radio (layer_selection), l'utilisateur peut sélectionner le "calque" qu'il souhaite voir. J'utilise observeEvent(input$layer_selection, {}) pour surveiller l'état des options des boutons radio. Pour mettre à jour le tracé, j'utilise leafletProxy() et hideGroup() pour masquer tous les groupes, puis showGroup() pour afficher le calque sélectionné.

Je m'excuse pour le manque d'exemple reproductible.

Des questions

  1. Comment puis-je optimiser mon code? Je suis désireux de le rendre plus performant et/ou facile à travailler. J'ai constaté que l'utilisation de hideGroup() 's/showGroup() pour chaque sélection de couche est beaucoup plus rapide que d'utiliser addPolygon() sur une carte vierge, mais le chargement de l'application prend beaucoup de temps.

  2. Puis-je changer la variable par laquelle je colorie les polygones sans redessiner ou rajouter ces polygones? Pour clarifier, si j'ai deux variables différentes à tracer, toutes deux utilisant les mêmes données de forme, dois-je effectuer 2 appels addPolygon() distincts?

  3. Existe-t-il un moyen plus automatique de colorier de manière judicieuse les polygones de chaque couche en fonction de la palette souhaitée (à partir du package viridis?). À l'heure actuelle, je trouve qu'il est difficile de définir une nouvelle palette pour chaque variable, par exemple:

    palette_layer_n <- colorNumeric(
        palette = "viridis",
        domain = aus_sa2_areas$aus_sa2_areas$var_n
    )
    

Question secondaire

Comment fonctionne cette carte sur le site Web de l'ABS? Il peut être incroyablement détaillé et extrêmement réactif. Comparez le détail du bloc maillé au SA2 (2310 polygones), exemple ci-dessous:

ABS web based map

12
dcl

Puisque vous n’avez pas encore obtenu de réponse, je vais poster quelques choses qui peuvent peut-être vous aider, sur la base d’un exemple simple.

Ce serait bien sûr plus facile si le vôtre était reproductible; et je suppose qu'en regardant autour de vous, vous avez déjà vu qu'il y avait plusieurs problèmes/demandes connexes (à propos de la nouvelle coloration des polygones), alors qu'il ne semble pas qu'une solution réelle en ait fait une publication (de dépliant).

Avec la solution ci-dessous, vous devriez être capable d'éviter plusieurs addPolygons et pouvez couvrir un nombre arbitraire de variables (pour l'instant, je viens de coder en dur une seule variable dans l'appel modFillCol).

library(leaflet)
library(maps)
library(viridis)

mapStates = map("state", fill = TRUE, plot = FALSE)

# regarding Question 3 - the way you set the domain it looks equivalent
# to just not setting it up front, i.e. domain = NULL
myPalette <- colorNumeric(
  palette = "viridis",
  domain = NULL
)

mp <- leaflet(data = mapStates) %>%
  addTiles() %>%
  addPolygons(fillColor = topo.colors(10, alpha = NULL), stroke = FALSE)

# utility function to change fill color
modFillCol <- function(x, var_x) {
  cls <- lapply(x$x$calls, function(cl) {
    if (cl$method == "addPolygons") {
      cl$args[[4]]$fillColor <- myPalette(var_x)
    }
    cl
  })
  x$x$calls <- cls
  x
}

# modify fill color depending on the variable, in this simple example
# I just use the number of characters of the state-names
mp %>%
  modFillCol(nchar(mapStates$names))
2
RolandASc