使用selectModUI
时,我想针对不同的mapedit
映射从leaflet
包中更新Shiny
。下面是一个有效的示例。
library(tidyverse)
library(shiny)
library(sf)
library(leaflet)
library(mapview)
library(mapedit)
library(DT)
library(viridis)
# Load the sf object
nc <- st_read(system.file("shape/nc.shp", package = "sf"))
# Project transformation
nc <- st_transform(nc, crs = 4326)
# Create a color function for the leaflet map
sid74_pal <- colorBin(palette = viridis(10), domain = nc$SID74, bins = 4)
# Create a leaflet map
sid74_map <- leaflet() %>%
addTiles(group = "OSM") %>%
addProviderTiles("CartoDB", group = "CartoDB") %>%
addProviderTiles("Esri.WorldImagery", group = "Esri.WorldImagery") %>%
addFeatures(nc,
color = ~sid74_pal(SID74),
label = ~htmltools::htmlEscape(NAME),
layerId = ~seq_len(length(st_geometry(nc)))) %>%
addLegend(position = "bottomright", pal = sid74_pal,
values = nc$SID74,
title = "SID74") %>%
addLayersControl(baseGroups = c("OSM", "CartoDB", "Esri.WorldImagery"))
ui <- fluidPage(
# Select Module Output
h3("Map"),
selectModUI(id = "Sel_Map"),
# Datatable Output
h3("Table"),
dataTableOutput(outputId = "Table")
)
server <- function(input, output) {
# Create selectMod
sel <- callModule(selectMod, "Sel_Map", sid74_map)
# Reactive values
rv <- reactiveValues(
selectnum = NULL,
sub_table = nc %>%
st_set_geometry(NULL) %>%
slice(0)
)
# Subset the table based on the selection
observe({
# the select module returns a reactive
gs <- sel()
# Filter for the county data
rv$selectnum <- as.numeric(gs[which(gs$selected == TRUE), "id"])
if (!is.null(rv$selectnum)){
rv$sub_table <- nc %>%
st_set_geometry(NULL) %>%
slice(rv$selectnum)
}
})
# Create a datatable
output$Table <- renderDataTable({
datatable(rv$sub_table, options = list(scrollX = TRUE))
})
}
# Run the application
shinyApp(ui = ui, server = server)
此想法是创建地图,用户可以选择或取消选择地图上的多边形。根据用户的选择,数据表输出将动态显示选择了哪个县并显示数据,如屏幕截图所示。
现在,我想添加一个选择输入,以便用户可以使用应用程序确定要显示的参数。我觉得我可以创建某种反应性或反应性值来存储地图,然后更新“以下是我创建的示例”。请注意,与示例1相比,我在示例2中创建了一个名为sid79_map
的新传单地图,并添加了一个select输入,以便人们可以选择。但是,此策略不起作用。如果有人可以指出前进的方向,那就太好了。
library(tidyverse)
library(shiny)
library(sf)
library(leaflet)
library(mapview)
library(mapedit)
library(DT)
library(viridis)
# Load the sf object
nc <- st_read(system.file("shape/nc.shp", package = "sf"))
# Project transformation
nc <- st_transform(nc, crs = 4326)
# Create a color function for the leaflet map
sid74_pal <- colorBin(palette = viridis(10), domain = nc$SID74, bins = 4)
sid79_pal <- colorBin(palette = viridis(10), domain = nc$SID79, bins = 4)
# Create a leaflet map
sid74_map <- leaflet() %>%
addTiles(group = "OSM") %>%
addProviderTiles("CartoDB", group = "CartoDB") %>%
addProviderTiles("Esri.WorldImagery", group = "Esri.WorldImagery") %>%
addFeatures(nc,
color = ~sid74_pal(SID74),
label = ~htmltools::htmlEscape(NAME),
layerId = ~seq_len(length(st_geometry(nc)))) %>%
addLegend(position = "bottomright", pal = sid74_pal,
values = nc$SID74,
title = "SID74") %>%
addLayersControl(baseGroups = c("OSM", "CartoDB", "Esri.WorldImagery"))
sid79_map <- leaflet() %>%
addTiles(group = "OSM") %>%
addProviderTiles("CartoDB", group = "CartoDB") %>%
addProviderTiles("Esri.WorldImagery", group = "Esri.WorldImagery") %>%
addFeatures(nc,
color = ~sid79_pal(SID79),
label = ~htmltools::htmlEscape(NAME),
layerId = ~seq_len(length(st_geometry(nc)))) %>%
addLegend(position = "bottomright", pal = sid79_pal,
values = nc$SID79,
title = "SID79") %>%
addLayersControl(baseGroups = c("OSM", "CartoDB", "Esri.WorldImagery"))
ui <- fluidPage(
# Select input
selectInput(inputId = "Selection", label = "Select Counties", choices = c("SID74", "SID79"), selected = "SID74"),
# Select Module Output
h3("Map"),
selectModUI(id = "Sel_Map"),
# Datatable Output
h3("Table"),
dataTableOutput(outputId = "Table")
)
server <- function(input, output) {
# Try to create reactivity based on the select input type, not working
sel_type <- reactive({
input$Selection
})
leafmap <- reactive({
if(sel_type() == "SID74"){
sid74_map
} else if (sel_type() == "SID79"){
sid79_map
}
})
# Create selectMod
sel <- callModule(selectMod, "Sel_Map", leafmap())
# Reactive values
rv <- reactiveValues(
selectnum = NULL,
sub_table = nc %>%
st_set_geometry(NULL) %>%
slice(0)
)
# Subset the table based on the selection
observe({
# the select module returns a reactive
gs <- sel()
# Filter for the county data
rv$selectnum <- as.numeric(gs[which(gs$selected == TRUE), "id"])
if (!is.null(rv$selectnum)){
rv$sub_table <- nc %>%
st_set_geometry(NULL) %>%
slice(rv$selectnum)
}
})
# Create a datatable
output$Table <- renderDataTable({
datatable(rv$sub_table, options = list(scrollX = TRUE))
})
}
# Run the application
shinyApp(ui = ui, server = server)
答案 0 :(得分:1)
主要问题是您的callModule()
必须位于反应式上下文中。
我已使用observeEvent()
稍微修改了您的示例,以解决此问题。
请参见下文(我导入了dplyr::slice
是因为我想避免加载完整的tidyverse
)。
编辑:我做了一些进一步的清理工作,并添加了selectMod
的自定义版本来解决OP的评论。
library(shiny)
library(sf)
library(leaflet)
library(mapview)
library(mapedit)
library(DT)
library(viridis)
# Load the sf object
nc <- st_read(system.file("shape/nc.shp", package = "sf"))
# Project transformation
nc <- st_transform(nc, crs = 4326)
# Create a color function for the leaflet map
sid74_pal <- colorBin(palette = viridis(10), domain = nc$SID74, bins = 4)
sid79_pal <- colorBin(palette = viridis(10), domain = nc$SID79, bins = 4)
# Create a leaflet map
sid74_map <- leaflet() %>%
addTiles(group = "OSM") %>%
addProviderTiles("CartoDB", group = "CartoDB") %>%
addProviderTiles("Esri.WorldImagery", group = "Esri.WorldImagery") %>%
addFeatures(nc,
color = ~sid74_pal(SID74),
label = ~htmltools::htmlEscape(NAME),
layerId = ~seq_len(length(st_geometry(nc)))) %>%
addLegend(position = "bottomright", pal = sid74_pal,
values = nc$SID74,
title = "SID74") %>%
addLayersControl(baseGroups = c("OSM", "CartoDB", "Esri.WorldImagery"))
sid79_map <- leaflet() %>%
addTiles(group = "OSM") %>%
addProviderTiles("CartoDB", group = "CartoDB") %>%
addProviderTiles("Esri.WorldImagery", group = "Esri.WorldImagery") %>%
addFeatures(nc,
color = ~sid79_pal(SID79),
label = ~htmltools::htmlEscape(NAME),
layerId = ~seq_len(length(st_geometry(nc)))) %>%
addLegend(position = "bottomright", pal = sid79_pal,
values = nc$SID79,
title = "SID79") %>%
addLayersControl(baseGroups = c("OSM", "CartoDB", "Esri.WorldImagery"))
selectMod <- function(input, output, session, leafmap,
styleFalse = list(fillOpacity = 0.2, weight = 1, opacity = 0.4),
styleTrue = list(fillOpacity = 0.7, weight = 3, opacity = 0.7))
{
print("*** custom selectMod")
output$map <- leaflet::renderLeaflet({
mapedit:::add_select_script(leafmap, styleFalse = styleFalse, styleTrue = styleTrue,
ns = session$ns(NULL))
})
id <- "mapedit"
select_evt <- paste0(id, "_selected")
df <- data.frame()
selections <- reactive({
id <- as.character(input[[select_evt]]$id)
if (length(df) == 0) {
# Initial case, first time module is called.
# Switching map, i.e. subsequent calls to the module.
# Note that input[[select_evt]] will always keep the last selection event,
# regardless of this module being called again.
df <<- data.frame(id = character(0), selected = logical(0),
stringsAsFactors = FALSE)
} else {
loc <- which(df$id == id)
if (length(loc) > 0) {
df[loc, "selected"] <<- input[[select_evt]]$selected
} else {
df[nrow(df) + 1, ] <<- c(id, input[[select_evt]]$selected)
}
}
return(df)
})
return(selections)
}
ui <- fluidPage(
# Select input
selectInput(inputId = "Selection", label = "Select Counties", choices = c("SID74", "SID79"), selected = "SID74"),
# Select Module Output
h3("Map"),
selectModUI(id = "Sel_Map"),
# Datatable Output
h3("Table"),
dataTableOutput(outputId = "Table")
)
server <- function(input, output) {
# Reactivity based on the select input type
leafmap <- reactive({
my_sel <- input$Selection
if (my_sel == "SID74") {
sid74_map
} else if (my_sel == "SID79") {
sid79_map
}
})
# Reactive values
rv <- reactiveValues(
sel = reactive({}),
selectnum = NULL,
sub_table = nc %>%
st_set_geometry(NULL) %>%
dplyr::slice(0)
)
# Create selectMod
observeEvent(leafmap(),
rv$sel <- callModule(selectMod, "Sel_Map", leafmap())
)
# Subset the table based on the selection
observeEvent(rv$sel(), {
# The select module returns a reactive
gs <- rv$sel()
# Filter for the county data
rv$selectnum <- as.numeric(gs[which(gs$selected == TRUE), "id"])
rv$sub_table <- nc %>%
st_set_geometry(NULL) %>%
dplyr::slice(rv$selectnum)
})
# Create a datatable
output$Table <- renderDataTable({
datatable(rv$sub_table, options = list(scrollX = TRUE))
})
}
# Run the application
shinyApp(ui = ui, server = server)