Оптимизация производительности Shiny + Leaflet для подробных карт с множеством «слоев»

Я хочу создать приложение Shiny, в котором раскраска картограммы основана на числовом значении одной из многих возможных количественных переменных, из которых пользователь может выбирать. В простых случаях это просто, но я не уверен в лучших практиках, когда у нас есть 20+ переменных с довольно подробными файлами форм (~ 2300 полигонов).

Может иметь значение, а может и не быть, что переменные могут быть полностью независимыми друг от друга, например, «Общая популяция» или «Средняя температура», но некоторые из них будут иметь временную взаимосвязь, например, «Общая популяция» в 3 или более моментов времени. .

Один из основных шейп-файлов, которые я использую, - это Статистическая область АБС 2. Ниже я даю плотность населения (общая численность населения / площадь) для Австралии и увеличенный вид Сиднея, чтобы лучше передать интересующий меня уровень детализации.

Австралия  Австралия Сидней Сидней

Я прочитал шейп-файл в R и значительно уменьшил сложность / количество точек, используя функцию ms_simplify() в пакете rmapshaper.

Что касается Shiny и листовок, то вот чем я занимаюсь:

  • Прежде чем объект server будет определен в server.R, я создаю первичный объект карты со всеми желаемыми «слоями». То есть буклет с многочисленными addPolygon() призывами определить окраску каждого «слоя» (группы).

    # 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"
    ) %>% ...
    
  • Затем все, кроме первого слоя, скрывается с помощью hideGroup(), чтобы первоначальный рендеринг карты не выглядел глупо.

    hideGroup("layer_1") %>% 
    hideGroup("layer_2") %>% 
    ...
    hideGroup("layer_n")
    
  • В приложении Shiny с помощью переключателей (layer_selection) пользователь может выбрать «слой», который он хотел бы видеть. Я использую observeEvent(input$layer_selection, {}) для просмотра состояния параметров переключателя. Чтобы обновить график, я использую leafletProxy() и hideGroup(), чтобы скрыть все группы, а затем showGroup(), чтобы отобразить выбранный слой.

Прошу прощения за отсутствие воспроизводимого примера.

Вопросы

  1. Как я могу оптимизировать свой код? Я очень хочу сделать его более производительным и / или простым в работе. Я обнаружил, что использование hideGroup() / showGroup() для выбора каждого слоя намного быстрее, чем использование addPolygon() для пустой карты, но это приводит к тому, что приложение загружается очень долго.

  2. Могу ли я изменить переменную, которой я раскрашиваю многоугольники, без перерисовки или добавления этих многоугольников снова? Чтобы уточнить, если у меня есть 2 разные переменные для построения, обе используют одни и те же данные формы, нужно ли мне делать 2 разных addPolygon() вызова?

  3. Есть ли более автоматический способ разумно раскрасить полигоны для каждого слоя в соответствии с желаемой палитрой (из пакета viridis?). Прямо сейчас я нахожу определение новой палитры для каждой переменной довольно громоздкой, например:

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

Дополнительный вопрос

Как работает эта карта на веб-сайте ABS? Он может быть невероятно подробным и в то же время чрезвычайно отзывчивым. Сравните детали Mesh Block с SA2 (2310 полигонов), пример ниже:

Веб-карта АБС


person dcl    schedule 31.07.2018    source источник


Ответы (1)


Поскольку вы еще не получили ответов, я опубликую несколько вещей, которые, возможно, могут вам помочь, на основе простого примера.

Конечно, было бы легче, если бы ваш был воспроизводимым; и, осмотревшись, я полагаю, вы уже заметили, что есть несколько связанных проблем / запросов (о перекрашивании полигонов), тогда как не похоже, что настоящее решение вошло в какой-либо выпуск (буклет).

С помощью описанного ниже обходного пути вы сможете избежать множественных addPolygons и охватить произвольное количество переменных (на данный момент я просто жестко запрограммировал одну переменную в вызов 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))
person RolandASc    schedule 08.08.2018