为包含许多 'layers' 的详细地图优化 Shiny + Leaflet 性能
Optimising Shiny + Leaflet performance for detailed maps with many 'layers'
我想制作一个闪亮的应用程序,其中等值线图的着色基于用户可以 许多 可能的定量变量之一的数值 select从。在简单的情况下,这很简单,但是当我们有 20 多个变量且具有非常详细的形状文件(~2300 个多边形)时,我不确定最佳实践。
变量之间可能完全独立,例如 'Total Population' 或 'Average Temperature',这可能相关也可能不相关,但其中一些变量将具有时间关系,例如 'Total Population' 在 3 个或更多时间点。
我使用的主要 shapefile 之一是 ABS Statistical Area 2。下面我给出了澳大利亚的人口密度(总数 population/area)和悉尼的放大视图,以更好地表达我感兴趣的细节水平。
澳大利亚
悉尼
我已将 shapefile 读入 R 并使用 rmapshaper
包中的 ms_simplify()
函数大大减少了点的 complexity/number。
现在就 Shiny 和传单而言,这就是我一直在做的事情:
在 server.R
中定义 server
对象之前,我构建了一个具有所有所需 'layers' 的主地图对象。也就是说,一个带有许多 addPolygon()
调用的传单来定义每个 'layer'(组)的颜色。
# 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
),用户可以 select 他们想看的 'layer'。我使用 observeEvent(input$layer_selection, {})
来观察单选按钮选项的状态。
为了更新绘图,我使用 leafletProxy()
和 hideGroup()
隐藏所有组,然后使用 showGroup()
取消隐藏 selected 图层。
对于缺少可重现的示例,我深表歉意。
问题
如何优化我的代码?我渴望让它更高效 and/or 易于使用。我发现对每一层 selection 使用 hideGroup()
's/showGroup()
比对空白地图使用 addPolygon()
快得多,但这会导致应用程序采取加载时间非常长。
我可以更改为多边形着色的变量,而无需重新绘制或再次添加这些多边形吗?澄清一下,如果我有 2 个不同的变量要绘制,都使用相同的形状数据,我是否必须执行 2 个不同的 addPolygon()
调用?
是否有更自动的方法根据所需的调色板(来自 viridis 包?)为每一层的多边形着色。现在我发现为每个变量定义一个新的调色板,相当麻烦,例如:
palette_layer_n <- colorNumeric(
palette = "viridis",
domain = aus_sa2_areas$aus_sa2_areas$var_n
)
附带问题
ABS 网站上的 this map 如何运作?它可以非常详细,但响应速度极快。将网格块细节与 SA2(2310 个多边形)进行比较,示例如下:
由于您还没有得到任何答案,我将 post 基于一个 简单示例 的一些可能对您有帮助的事情。
如果你的是可复制的当然会更容易;我想环顾四周你已经看到有几个相关的问题/请求(关于重新着色多边形),而似乎还没有真正的解决方案已经进入任何版本(传单)。
通过下面的解决方法,您应该能够避免多个 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))
我想制作一个闪亮的应用程序,其中等值线图的着色基于用户可以 许多 可能的定量变量之一的数值 select从。在简单的情况下,这很简单,但是当我们有 20 多个变量且具有非常详细的形状文件(~2300 个多边形)时,我不确定最佳实践。
变量之间可能完全独立,例如 'Total Population' 或 'Average Temperature',这可能相关也可能不相关,但其中一些变量将具有时间关系,例如 'Total Population' 在 3 个或更多时间点。
我使用的主要 shapefile 之一是 ABS Statistical Area 2。下面我给出了澳大利亚的人口密度(总数 population/area)和悉尼的放大视图,以更好地表达我感兴趣的细节水平。
澳大利亚
我已将 shapefile 读入 R 并使用 rmapshaper
包中的 ms_simplify()
函数大大减少了点的 complexity/number。
现在就 Shiny 和传单而言,这就是我一直在做的事情:
在
server.R
中定义server
对象之前,我构建了一个具有所有所需 'layers' 的主地图对象。也就是说,一个带有许多addPolygon()
调用的传单来定义每个 'layer'(组)的颜色。# 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
),用户可以 select 他们想看的 'layer'。我使用observeEvent(input$layer_selection, {})
来观察单选按钮选项的状态。 为了更新绘图,我使用leafletProxy()
和hideGroup()
隐藏所有组,然后使用showGroup()
取消隐藏 selected 图层。
对于缺少可重现的示例,我深表歉意。
问题
如何优化我的代码?我渴望让它更高效 and/or 易于使用。我发现对每一层 selection 使用
hideGroup()
's/showGroup()
比对空白地图使用addPolygon()
快得多,但这会导致应用程序采取加载时间非常长。我可以更改为多边形着色的变量,而无需重新绘制或再次添加这些多边形吗?澄清一下,如果我有 2 个不同的变量要绘制,都使用相同的形状数据,我是否必须执行 2 个不同的
addPolygon()
调用?是否有更自动的方法根据所需的调色板(来自 viridis 包?)为每一层的多边形着色。现在我发现为每个变量定义一个新的调色板,相当麻烦,例如:
palette_layer_n <- colorNumeric( palette = "viridis", domain = aus_sa2_areas$aus_sa2_areas$var_n )
附带问题
ABS 网站上的 this map 如何运作?它可以非常详细,但响应速度极快。将网格块细节与 SA2(2310 个多边形)进行比较,示例如下:
由于您还没有得到任何答案,我将 post 基于一个 简单示例 的一些可能对您有帮助的事情。
如果你的是可复制的当然会更容易;我想环顾四周你已经看到有几个相关的问题/请求(关于重新着色多边形),而似乎还没有真正的解决方案已经进入任何版本(传单)。
通过下面的解决方法,您应该能够避免多个 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))