Open m-e-cws opened 6 years ago
@m-e-cws I will try to demonstrate a way of achieving your objective soon. Thanks for the report.
Just to bring this comment back up to top of mind- I can get reactivity to work after loading in the basemap with a leaflet proxy.
I was using isolate to break the reactivity before loading in the basemap, but I can’t get the basemap to change and display the reactive data I need.
Any thoughts on how to accomplish this?
@davis3tnpolitics: I'm running into the same problem.
Here's an example taken from mapedit demo.
The code line of interest is callModule(editMod, "editor", mapview(qk_rv())@map)
, where qk_rv
is intentionally set to a reactive object.
I've tried several suggestion from forums but no luck:
callModule(editMod, "editor", mapview(reactive(qk_rv))@map)
callModule(editMod, "editor", mapview(qk_rv)@map)
The only way to get it to work is with shiny::isolate()
to get a static value for qk_rv
. The downside is as @davis3tnpolitics noted - the qk_rv
doesn't update as it should.
library(mapedit)
library(mapview)
library(shiny)
library(sf)
# make the coordinates a numeric matrix
qk_mx <- data.matrix(quakes[,2:1])
# convert the coordinates to a multipoint feature
qk_mp <- st_multipoint(qk_mx)
# convert the multipoint feature to sf
qk_sf <- st_sf(st_cast(st_sfc(qk_mp), "POINT"), quakes, crs=4326)
ui <- fluidPage(
fluidRow(
# edit module ui
column(6, editModUI("editor")),
column(
6,
h3("Boxplot of Depth"),
plotOutput("selectstat")
)
)
)
server <- function(input, output, session) {
qk_rv <- reactive({qk_sf})
# edit module returns sf
edits <- callModule(editMod, "editor", mapview(qk_rv())@map)
output$selectstat <- renderPlot({
req(edits()$finished)
qk_intersect <- st_intersection(edits()$finished, qk_sf)
req(nrow(qk_intersect) > 0)
boxplot(
list(
all = as.numeric(qk_sf$depth),
selected = as.numeric(qk_intersect$depth)
),
xlab = "depth"
)
})
}
shinyApp(ui, server)
Hi @davis3tnpolitics @leungi ,
Thank you both for bringing this issue back to my attention. I had originally posted this almost two years ago, and since then I have learned a lot about reactive datasets and how they interact with leaflet maps and shiny apps. I have managed to solve my own problem, and I should have posted my own solution sooner. Below is the code which allows to subset data in an interactive leaflet map by both a slider bar, and by drawing a shape over points.
Feel free to check out a map I made which includes some extra tools for subsetting and selecting data in a leaflet map: https://englishm.shinyapps.io/Plastics/
library(mapview)
library(leaflet)
library(shiny)
library(ggplot2)
library(mapedit)
library(leaflet.extras)
library(sf)
ui.q <- fluidPage(
#Application title
titlePanel("Quake data exploration"),
sidebarLayout(
sidebarPanel(
sliderInput("range",
label = "Range of earthquake magnitude:",
min = 4.0, max = 6.4, value = c(4.0, 6.4), step = 0.1)
),
mainPanel(
fluidRow(
editModUI("editor", height = 860),
absolutePanel(id = "controls", class = "panel panel-default", fixed = TRUE,
draggable = TRUE, top = 120, left = "auto", right = 20, bottom = "auto",
width = 400, height = "auto",
h4("Summary data"),
plotOutput("plot")))
)
)
)
#Define server logic
server.q <- function(input, output){
#create a sf of the quake data.
quake_mx <- data.matrix(quakes[,2:1])
quake_mp <- st_multipoint(quake_mx)
quake_sf <- st_sf(st_cast(st_sfc(quake_mp), "POINT"), quakes, crs=4326)
#subset the quake_sf data by the range of magnitude inputted by the slider bar.
#this creates a reactive dataframe.
datasetMag <- reactive({
quake_sf[quake_sf$mag >= input$range[1] & quake_sf$mag <= input$range[2],]
})
#generate the leaflet map
#set the namespace for the map
ns <- shiny::NS("editor")
lf.quakes <- leaflet(options = leafletOptions(minZoom = 4, maxZoom = 10)) %>%
addTiles() %>%
addProviderTiles("Esri.OceanBasemap",group="OceanBasemap") %>%
addProviderTiles("Esri.WorldImagery",group="WorldImagery") %>%
addCircleMarkers(data = quake_sf, #use the non-reactive dataset
color = "red",
weight = 1,
fillOpacity = 0.7,
popup = popupTable(quake_sf, zcol = "mag"),
radius = quake_sf$mag) %>%
addLayersControl(baseGroups = c("OceanBasemap","WorldImagery"),
options = layersControlOptions(collapsed = FALSE))
#call the editMod function from 'mapedit' to use in the leaflet map.
edits <- callModule(editMod, "editor", leafmap = lf.quakes)
#now we need to create an observer so the leaflet map can 'observe' the reactive dataset and be redrawn based on the input
observeEvent(c(input$range),{
proxy.lf <- leafletProxy(ns("map"))
req(input$range)
req(nrow(datasetMag())>0)
proxy.lf %>%
clearMarkers() %>%
addCircleMarkers(data = datasetMag(), #use the reactive dataset generated above
color = "red",
weight = 1,
fillOpacity = 0.7,
popup = popupTable(quake_sf, zcol = "mag"),
radius = quake_sf$mag)
})
#generate the reactive dataset based on what is drawn on the leaflet map
datasetInput <- reactive({
req(edits()$finished)
quake_intersect <- st_intersection(edits()$finished, datasetMag()) #intersection between what is drawn and the reactive dataframe
df <- data.frame(quake_intersect)
})
#render a histogram with the reactive dataset as the output
output$plot <- renderPlot({
hist(datasetInput()$mag, col = "grey", border = "black")
})
}
shinyApp(ui.q, server.q)
Thanks prompt response and sharing @m-e-cws!
The commenting really helps with my understanding 🙏
@m-e-cws: have you encountered a case for your solution above where the CRS of the initial map (i.e. lf.quakes
) is different than that of the edits()
object?
For such a case, even after setting the edits()
object's CRS to match the initial map, st_intersection()
somehow returns empty.
I posted this issue with sf
.
Just to be clear, setting a crs won't change the coordinates. You need to st_transform
your object
Thanks for tip @tim-salabim!
This is one of those rare moments where I have to deal with objects with NA_crs_
.
I tried your suggestion, but got the following error, which is logical given st_transform()
expects a EPSG, or proj4string code.
# edits() is objected returned from mapedit selection
selected <- edits()$finished
selected_trf <- selected %>% st_transform(crs = NA_crs_)
#> Error in st_transform.sfc: sfc object should have crs set
Hello guys!
Any update about the reactive data using editMod? I'm trying to make something similar but can´t add a reactive variable or leaflet without an error on CallModule(editMod).
I want that one can upload a Shapefile, and it could be edited there
Hello,
I am self-taught in R and computer coding, so I apologize if this question is poorly worded or already answered elsewhere.
I am trying to plot a reactive dataset in editMod, while retaining the ability to use the edit (draw) functions provided by editMod. So far I have not found a way to plot reactive data using editMod.
I want a map that allows me to:
Plot spatial data that can be subsetted by some kind of reactive variable (below it is the "mag" variable)
Draw across a certain group of points and generate summary data based on the reactive subset of the plotted data.
Below is a reproducible example using the supplementary "quakes" dataset. In the below map, I can generate summary data based on a reactive dataset selected by the slider bar, but the reactive dataset is not reflected in what is plotted on the map.