我想制作一个Shiny应用程序,其中,choropleth的颜色基于许多个可能的定量变量之一的数值,用户可以从中选择。在简单的情况下,这很简单,但是我不确定当我们有20多个变量以及非常详细的形状文件(〜2300个多边形)时的最佳做法。
变量可能彼此完全独立,例如“总人口”或“平均温度”,可能无关或无关,但其中一些变量会具有时间关系,例如“总人口”为3或更高。时间点。
ABS Statistical Area 2是我使用的主要shapefile之一。下面,我给出了澳大利亚的人口密度(总人口/区域),并放大了悉尼,以更好地传达我感兴趣的详细程度。
我已经读取了R中的shapefile,并使用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")
在“闪亮”应用程序中,使用单选按钮(layer_selection
),用户可以选择他们想要看到的“图层”。我使用observeEvent(input$layer_selection, {})
来查看单选按钮选项的状态。
要更新绘图,我使用leafletProxy()
和hideGroup()
隐藏所有组,然后使用showGroup()
取消隐藏所选图层。
我为缺少可复制的示例表示歉意。
问题
如何优化代码?我渴望使其性能更高和/或更易于使用。我发现使用hideGroup()
/ showGroup()
进行每个图层选择要比使用addPolygon()
进行空白地图绘制要快得多,但这会导致应用花费大量时间加载。
是否可以更改我为多边形着色的变量,而无需重新绘制或添加这些多边形?要澄清的是,如果我要绘制两个不同的变量(都使用相同的形状数据),我是否必须进行两个不同的addPolygon()
调用?
是否有一种更自动的方法,可以根据所需的调色板(从viridis包装中)对每一层的多边形进行合理的着色?现在,我正在为每个变量定义一个新的调色板,这很麻烦,例如:
palette_layer_n <- colorNumeric(
palette = "viridis",
domain = aus_sa2_areas$aus_sa2_areas$var_n
)
侧问
ABS网站上的this map如何工作?它可以非常详细,但响应速度非常快。将网格块细节与SA2(2310个多边形)进行比较,如下所示:
答案 0 :(得分:2)
由于您尚未获得任何答案,因此我将基于一个简单的示例发布一些可能对您有所帮助的内容。
如果您的产品具有可复制性,那当然会更容易;我想环顾四周,您已经发现有几个相关的问题/请求(关于为多边形重新着色),而似乎还没有真正的解决方案将其纳入任何版本的传单中。 >
通过以下变通方法,您应该能够避免使用多个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))