clear (reset) upload file input in R Shiny - r

I am building a shiny app which basically upload multiple shape files (dbf,prj,shp,shx) and creates map using leaflet package. Once the upload is done and map is created , there is reset button whose function is to clear/reset the existing values of the file input though I tried doing the same using shinyjs as well but still it seems that file Input caches the value. Below is the code which I tried out. Looking for tips to rest the file Input in below case.
## app.R ##
library(shinydashboard)
library(shinyjs)
library(leaflet)
library(sp)
library(rgdal)
ui <- dashboardPage(
dashboardHeader(title = "Basic dashboard"),
dashboardSidebar(
fileInput('uploadFile', 'Upload Files',
accept=c('text/csv', 'text/comma-separated-values,text/plain'), multiple=T),
fileInput('uploadFile2', 'Upload Files 2',
accept=c('text/csv', 'text/comma-separated-values,text/plain'), multiple=T),
actionButton('reset', 'Reset', icon = icon("minus"),style="color:rgb(57,156,8);border-color:rgb(57,156,8)"),
tags$style(type='text/css', "#reset {margin-left: 10px;}")
),
dashboardBody(
useShinyjs(),
leafletOutput("GeoStates",width = "125%", height = 500)
)
)
server <- function(input, output) {
# Folder name and uploaded file names
values <- reactiveValues(
folderName = "dataSource",
fileName = ""
)
# Expression for reading the OGR and transforming it
expr_q <- quote({
if(values$fileName == "")
return (NULL)
spTransform(readOGR(dsn = paste0(getwd(),"/",values$folderName), layer = values$fileName),
CRS("+proj=longlat +datum=WGS84"))
})
ORG0 <- reactive(expr_q, quoted = TRUE)
# Upload file
observe({
if (!is.null(input$uploadFile)){
hide(id = "uploadMsgBox", anim = TRUE)
if(!dir.exists(values$folderName))
dir.create(values$folderName,recursive = TRUE)
for(i in 1:nrow(input$uploadFile)){
values$fileName <- substr(input$uploadFile[i,1],0,nchar(input$uploadFile[i,1])-4)
file.copy(input$uploadFile[i,4],paste0(getwd(),"/",values$folderName,"/",input$uploadFile[i,1]))
}
}
})
# -------------------------------------------------------------------------------------------------------------------------------
# -------------------------------------------------------------------------------------------------------------------------------
# Folder name and uploaded file names
values2 <- reactiveValues(
folderName2 = "dataSource2",
fileName2 = ""
)
expr_q2 <- quote({
if(values2$fileName2 == "")
return (NULL)
spTransform(readOGR(dsn = paste0(getwd(),"/",values2$folderName2), layer = values2$fileName2),
CRS("+proj=longlat +datum=WGS84"))
})
ORG2 <- reactive(expr_q2, quoted = TRUE)
# Upload file 2
observe({
if (!is.null(input$uploadFile2)){
hide(id = "uploadMsgBox2", anim = TRUE)
if(!dir.exists(values2$folderName2))
dir.create(values2$folderName2,recursive = TRUE)
for(i in 1:nrow(input$uploadFile2)){
values2$fileName2 <- substr(input$uploadFile2[i,1],0,nchar(input$uploadFile2[i,1])-4)
file.copy(input$uploadFile2[i,4],paste0(getwd(),"/",values2$folderName2,"/",input$uploadFile2[i,1]))
}
}
})
#------------------------------------------------------------------------------------------------------------------
#------------------------------------------------------------------------------------------------------------------
observeEvent(input$reset, {
values$fileName == ""
values2$fileName2 == ""
ORG0 <- NULL
ORG2 <- NULL
shinyjs::reset('uploadFile')
shinyjs::reset('uploadFile2')
unlink(paste0(getwd(),"/dataSource"), recursive = TRUE)
unlink(paste0(getwd(),"/dataSource2"), recursive = TRUE)
output$GeoStates <- renderLeaflet({ })
})
#----------------------------------------------------------------------------------------------------------------
#----------------------------------------------------------------------------------------------------------------
observe({
if (!is.null(input$uploadFile) & is.null(input$uploadFile2)){
print("TEST1")
output$GeoStates <- renderLeaflet({
leaflet(data = ORG0()) %>% addTiles() %>% addPolygons(fill = FALSE, stroke = TRUE, color = "#0090C5") %>%
addLegend("bottomright", colors = "#0090C5", labels = values$fileName) %>%
addProviderTiles(providers$Esri.WorldImagery,
options = providerTileOptions(noWrap = TRUE))%>%
addScaleBar(position = "topright", options = scaleBarOptions(metric = TRUE))
})
}
if (!is.null(input$uploadFile) & !is.null(input$uploadFile2)){
print("TEST2")
output$GeoStates <- renderLeaflet({
leaflet(data = ORG0()) %>% addTiles() %>% addPolygons(fill = FALSE, stroke = TRUE, color = "#0090C5") %>%
addLegend("bottomright", colors = "#0090C5", labels = values$fileName) %>%
addProviderTiles(providers$Esri.WorldImagery,
options = providerTileOptions(noWrap = TRUE))%>%
addPolygons(fill = FALSE, stroke = TRUE, color = "#F39200", data = ORG2())%>%
addScaleBar(position = "topright", options = scaleBarOptions(metric = TRUE))
})
}
})
}
shinyApp(ui, server)

Related

I have a shiny app i want to use the click event to change selection value

I'm having a problem since I started learning shiny and R, so please be patient.
I'm working on a shiny map where whenever a user clicks on a polygon, it changes the first selection to the same area that the user picked on the map.
This is my code:
# Install an load all required packages
if (!require("pacman")) install.packages("pacman")
pacman::p_load(tidyverse, data.table, bslib, shiny, sf, leaflet, tiff, openxlsx, rgdal, purrr)
# set working directory to this script's locations: no need to check the file path manually
setwd(dirname(rstudioapi::getActiveDocumentContext()$path))
# Add the layers and the map
dir.layers <- "syr_admin_20200816.gdb"
df <- st_read(dir.layers, layer="syr_admbnda_adm1_uncs_unocha") %>%
st_transform(crs = 4326) %>%
st_zm(df, drop = TRUE) %>%
select(name=admin1Pcode, shape=SHAPE)
df <- subset(df, df$name %in% c("SY01", "SY02", "SY03", "SY04", "SY05", "SY06", "SY07"))
#ui
ui <- fluidPage(
theme = bs_theme(version = 4, bootswatch = "minty"),
# App title ----
titlePanel("Flood Model"),
# Sidebar panel for inputs ----
sidebarLayout(
position = "right",
sidebarPanel(
# Input: Choose dataset ----
selectInput("dataset", "Choose a Location:",
choices = c("location_A", "Location_B",
"Location_C", "Location_D",
"Location_E", "Location_F")),
# Input: choose file
uiOutput("secondSelection"),
# Button
downloadButton("downloadData", "Download")),
# Main panel for displaying outputs ----
mainPanel(
#loading the map in Output layer
leafletOutput("map"),
#loading the map information after hover on the map
uiOutput('map_text')
)))
# Define server logic to display and download selected file ----
server <- function(input, output, session) {
output$map <- renderUI({
HTML(paste(h4(map$name)))
})
output$map <- renderLeaflet({
leaflet(df) %>%
addPolygons(color = "gray", fillColor = "blue", weight = 1, smoothFactor = 0.5,
opacity = 1.0, fillOpacity = 0.5,
layerId = ~name,
highlightOptions = highlightOptions(color = "white", weight = 2,
bringToFront = TRUE)) %>%
addTiles()
#addProviderTiles("Esri.WorldImagery")
})
#Event click on map
observe({
event <- input$map_shape_click
#updateSelectInput(session,
# inputId = "dataset",
# choices = switch(event$id,
# "SY04" = "location_A",
# "SY01" = "Location_B",
# "SY02" = "Location_C",
# "SY03" = "Location_D",
# "SY05" = "Location_E",
# "SY06" = "Location_F" ))
print(event$id)
})
# Table of selected file ----
output$secondSelection <- renderUI({
database <- input$dataset
selectInput( "file", "Choose a file:", choices =
switch(database,
"location_A" = c("A_flood_Hazard","A_flood_depth") ,
"Location_B" = c("B_flood_Hazard","B_flood_depth"),
"Location_C" = c("C_flood_Hazard","C_flood_depth"),
"Location_D" = c("D_flood_Hazard","D_flood_depth"),
"Location_E" = c("E_flood_Hazard","E_flood_depth"),
"Location_F" = c("F_flood_Hazard","F_flood_depth")))
})
# Reactive value for selected dataset ----
datasetInput <- reactive({
switch(input$file,
"A_flood_Hazard" = A_flood_Hazard <- readTIFF("NorthDana_flood_Hazard.tif.tif") ,
"A_flood_depth" = A_flood_depth<- readTIFF("NorthDana_flood_Hazard.tif.tif") ,
"B_flood_Hazard" = B_flood_Hazard <- readTIFF("NorthDana_flood_Hazard.tif.tif") ,
"B_flood_depth" = B_flood_depth<- readTIFF("NorthDana_flood_Hazard.tif.tif") ,
"C_flood_Hazard" = C_flood_Hazard <- readTIFF("NorthDana_flood_Hazard.tif.tif") ,
"C_flood_depth" = C_flood_depth<- readTIFF("NorthDana_flood_Hazard.tif.tif") ,
"D_flood_Hazard" = D_flood_Hazard <- readTIFF("NorthDana_flood_Hazard.tif.tif") ,
"D_flood_depth" = D_flood_depth<- readTIFF("NorthDana_flood_Hazard.tif.tif") ,
"E_flood_Hazard" = E_flood_Hazard <- readTIFF("NorthDana_flood_Hazard.tif.tif") ,
"E_flood_depth" = E_flood_depth<- readTIFF("NorthDana_flood_Hazard.tif.tif") ,
"F_flood_Hazard" = F_flood_Hazard <- readTIFF("NorthDana_flood_Hazard.tif.tif") ,
"F_flood_depth" = F_flood_depth<- readTIFF("NorthDana_flood_Hazard.tif.tif") )
})
# Downloadable csv of selected dataset ----
output$downloadData <- downloadHandler(
filename = function() {
paste(input$file, ".tif.tif", sep = "")
},
content = function(file) {
writeTIFF(datasetInput(), file )
}
)
}
# Create Shiny app ----
shinyApp(ui, server)
** Consider that Df is a shape file have 6 location and only have 2 value (name and shape)**
it crashes when I start the code for the updated selection part

updatePickerInput does not respond to reactive data

I am putting together an Shiny app to allow users to upload an area of interest (AOI), and calculate the amount of overlap with an administrative boundary (WMU). Everything is working as desired, except that my picker input options do not update. The picker input works, but I would like the choices to only include the WMU that overlap the AOI instead of all possible WMU. I can calculate the WMU ID that should populate the list, shown in the "TEST_TEXT"output below the map frame, but cannot successfully update the pickerInput. This kmz will overlap the several WMU that are loaded at the beginning of the script included below:
library(shiny)
library(sf)
library(tidyverse)
library(bcdata)
library(shinyjs)
library(leaflet)
library(mapview)
library(DT)
library(pals)
library(shinyWidgets)
library(shinymanager)
WMU_DATA <-
bcdc_get_data("wildlife-management-units") %>% st_transform(4326) %>% mutate(Total.WMU.HA =
as.numeric(st_area(.)) / 10000)
##### UI #####
ui <- fluidPage(
tags$head(tags$style(
HTML(
".shiny-notification {
height: 100px;
width: 400px;
position:fixed;
top: calc(25% - 50px);;
left: calc(50% - 200px);;
}
"
)
)),
# Application title
titlePanel("Calculate Overlap With WMU"),
# Inputs
sidebarLayout(
sidebarPanel(
width = 3,
textInput(
inputId = "AOI_NAME",
label = "AOI Name",
value = NULL
),
HTML("<br><br>"),
fileInput(
inputId = "KMZ",
label = "Choose KMZ",
multiple = FALSE,
accept = c('.kmz')
),
h3("or"),
HTML("<br><br>"),
fileInput(
inputId = "SHAPEFILE",
label = "Choose shapefile",
multiple = TRUE,
accept = c('.shp', '.dbf', '.sbn', '.sbx', '.shx', '.prj', '.xml')
),
pickerInput(
inputId = "WMU_FILTER",
label = "Filter Overlapping WMU",
choices = unique(WMU_DATA$WILDLIFE_MGMT_UNIT_ID),
selected = unique(WMU_DATA$WILDLIFE_MGMT_UNIT_ID),
multiple = TRUE,
options = list(`actions-box` = TRUE)
),
HTML("<br><br>")
),
# Display OUtputs
mainPanel(
width = 9,
leafletOutput("OVERLAP_MAP", height = 750),
h3(textOutput("TEST_TEXT")),
DTOutput("AOI_OVERLAP_TABLE")
)
)
)
######server#####
server <- function(input, output, session) {
####reactive data
AOI <-
reactive({
if (is.null(input$SHAPEFILE) & !is.null(input$KMZ)) {
st_read(unzip(input$KMZ$datapath)) %>%
st_zm(drop = T) %>%
mutate(AOI_NAME = input$AOI_NAME) %>%
st_transform(4326) %>%
select(-Name)
}
else if (!is.null(input$SHAPEFILE) & is.null(input$KMZ)) {
SHAPEFILE()
}
else{
return(NULL)
}
})
WMU_OVERLAP <- reactive({
st_filter(WMU_DATA, AOI())
})
AOI_WMU_INTERSECT <-
reactive({
st_intersection(AOI(), WMU_OVERLAP()) %>%
mutate(`HA of Overlap` = round(as.numeric(st_area(.)) / 10000, 0)) %>%
mutate(`Percent of WMU` = round(`HA of Overlap` / `Total.WMU.HA` *
100, 2))
})
observeEvent(AOI_WMU_INTERSECT
,
{
updatePickerInput(
session,
"WMU_FILTER",
choices = unique(AOI_WMU_INTERSECT()$WILDLIFE_MGMT_UNIT_ID),
selected = unique(AOI_WMU_INTERSECT()$WILDLIFE_MGMT_UNIT_ID)
)
},
ignoreInit = TRUE,
ignoreNULL = TRUE)
###outputs
output$OVERLAP_MAP <-
renderLeaflet({
withProgress(message = "Calcualting Overlap", detail = "Should be done soon", {
AOI_SPATIAL <- AOI() %>% mutate(AOI_NAME = input$AOI_NAME)
WMU <-
WMU_OVERLAP() %>% filter(WILDLIFE_MGMT_UNIT_ID %in% input$WMU_FILTER)
Overlap <-
AOI_WMU_INTERSECT() %>% filter(WILDLIFE_MGMT_UNIT_ID %in% input$WMU_FILTER)
MAP <-
mapview(
Overlap,
zcol = "WILDLIFE_MGMT_UNIT_ID",
alpha.regions = 0.2,
map.types = c("Esri.WorldTopoMap", "Esri.WorldImagery"),
col.regions = alphabet(nlevels(
as.factor(WMU$WILDLIFE_MGMT_UNIT_ID)
))
) +
mapview(
WMU,
zcol = "WILDLIFE_MGMT_UNIT_ID",
alpha.regions = 0.2,
lwd = 3,
col.regions = alphabet(nlevels(
as.factor(WMU$WILDLIFE_MGMT_UNIT_ID)
)),
hide = TRUE
) +
mapview(AOI_SPATIAL,
label = "AOI_NAME",
col.regions = "red")
MAP#map %>%
setView(st_coordinates(st_centroid(st_as_sfc(
st_bbox(AOI_SPATIAL)
)))[, 1],
st_coordinates(st_centroid(st_as_sfc(
st_bbox(AOI_SPATIAL)
)))[, 2],
zoom = 9)
})
})
output$AOI_OVERLAP_TABLE <-
renderDT({
AOI_OVERLAP_TABLE <- AOI_WMU_INTERSECT() %>%
st_drop_geometry()
AOI_OVERLAP_TABLE
}, filter = "top", extensions = c("FixedHeader", "Buttons"),
options = list(
pageLength = 100,
fixedHeader = TRUE,
dom = "Bfrtip",
buttons = c('colvis', 'copy', 'excel', 'csv')
))
output$TEST_TEXT <-
renderText(unique(AOI_WMU_INTERSECT()$WILDLIFE_MGMT_UNIT_ID))
}
# Run the application
shinyApp(ui = ui, server = server)
Putting some req() and changing observeEvent() to observe() makes it work. Try this
######server#####
server <- function(input, output, session) {
####reactive data
AOI <-
reactive({
if (is.null(input$SHAPEFILE) & !is.null(input$KMZ)) {
st_read(unzip(input$KMZ$datapath)) %>%
st_zm(drop = T) %>%
mutate(AOI_NAME = input$AOI_NAME) %>%
st_transform(4326) %>%
select(-Name)
}
else if (!is.null(input$SHAPEFILE) & is.null(input$KMZ)) {
SHAPEFILE()
}
else{
return(NULL)
}
})
WMU_OVERLAP <- reactive({
req(AOI())
st_filter(WMU_DATA, AOI())
})
AOI_WMU_INTERSECT <-
reactive({
req(AOI(), WMU_OVERLAP())
st_intersection(AOI(), WMU_OVERLAP()) %>%
dplyr::mutate(`HA of Overlap` = round(as.numeric(st_area(.)) / 10000, 0)) %>%
dplyr::mutate(`Percent of WMU` = round(`HA of Overlap` / `Total.WMU.HA` *100, 2))
})
observe({updatePickerInput(
session,
"WMU_FILTER",
choices = unique(AOI_WMU_INTERSECT()$WILDLIFE_MGMT_UNIT_ID),
selected = unique(AOI_WMU_INTERSECT()$WILDLIFE_MGMT_UNIT_ID)
)
} )#, ignoreInit = TRUE, ignoreNULL = TRUE)
###outputs
output$OVERLAP_MAP <-
renderLeaflet({
req(AOI_WMU_INTERSECT())
withProgress(message = "Calcualting Overlap", detail = "Should be done soon", {
AOI_SPATIAL <- AOI() %>% dplyr::mutate(AOI_NAME = input$AOI_NAME)
WMU <-
WMU_OVERLAP() %>% dplyr::filter(WILDLIFE_MGMT_UNIT_ID %in% input$WMU_FILTER)
Overlap <-
AOI_WMU_INTERSECT() %>% dplyr::filter(WILDLIFE_MGMT_UNIT_ID %in% input$WMU_FILTER)
MAP <-
mapview(
Overlap,
zcol = "WILDLIFE_MGMT_UNIT_ID",
alpha.regions = 0.2,
map.types = c("Esri.WorldTopoMap", "Esri.WorldImagery"),
col.regions = alphabet(nlevels(
as.factor(WMU$WILDLIFE_MGMT_UNIT_ID)
))
) +
mapview(
WMU,
zcol = "WILDLIFE_MGMT_UNIT_ID",
alpha.regions = 0.2,
lwd = 3,
col.regions = alphabet(nlevels(
as.factor(WMU$WILDLIFE_MGMT_UNIT_ID)
)),
hide = TRUE
) +
mapview(AOI_SPATIAL,
label = "AOI_NAME",
col.regions = "red")
MAP#map %>%
setView(st_coordinates(st_centroid(st_as_sfc(
st_bbox(AOI_SPATIAL)
)))[, 1],
st_coordinates(st_centroid(st_as_sfc(
st_bbox(AOI_SPATIAL)
)))[, 2],
zoom = 9)
})
})
output$AOI_OVERLAP_TABLE <-
renderDT({
AOI_OVERLAP_TABLE <- AOI_WMU_INTERSECT() %>% st_drop_geometry()
AOI_OVERLAP_TABLE
}, filter = "top", extensions = c("FixedHeader", "Buttons"),
options = list(
pageLength = 100,
fixedHeader = TRUE,
dom = "Bfrtip",
buttons = c('colvis', 'copy', 'excel', 'csv')
))
output$TEST_TEXT <- renderText(unique(AOI_WMU_INTERSECT()$WILDLIFE_MGMT_UNIT_ID))
}

Load multiple shapefiles Shiny r

I am trying to load shapefiles in shiny r based on a selection users make in selectInput. This is easy to do when the user can only select one shapefile. However when the user can select multiple shapefiles it becomes trickier. I am looking for a way to avoir having to write several times addPolygons(data = input$input_company[1] %>% addPolygons(data = input$input_company[2] %>% addPolygons(data = input$input_company[3] and so on.
Here is my attempt: writing a loop in server :
# Working directory ------------------------------------------------------------
wd <- "~/path/"
# Read multiple shapefiles with standardised name ------------------------------
items <- c("item_1", "item_2", "item_3")
for (sp in items) {
files.sp <- readOGR(dsn = wd, layer = sp,
verbose = FALSE)
assign(sp, files.sp)
}
# UI ---------------------------------------------------------------------------
ui <- navbarPage(
title = "Here my Title",
id="nav",
theme = shinytheme("flatly"),
mainPanel("Interactive map",
div(class="outer",
tags$head(
includeCSS("styles.css")),
leafletOutput("m", width="100%", height="100%"),
absolutePanel(
id = "hist_panel", class = "panel panel-default",
fixed = TRUE, draggable = TRUE,
top = 100, left = "auto", right = 0,
bottom = "auto",
width = "27%", height = "auto"),
absolutePanel(
id = "hist_panel", class = "panel panel-default",
fixed = FALSE, draggable = TRUE,
top = 100, left = "auto", right = 0,
bottom = "auto",
width = "27%", height = "auto",
selectInput(inputId = "input_items", label = "Items",
choices = c("Item 1" = "item_1", "Item 2" = "item_2", "Item 3" = "item_3"),
multiple = TRUE,
selected = "item_1")),
)
)
)
# Server -----------------------------------------------------------------------
server <- function(input, output, session) {
output$m <- renderLeaflet({
for (i in 1:length(input$input_items)) {
sp <- input$input_items[i]
tmp <- get(sp)
m <- leaflet() %>%
# Add Basemap OSM
addTiles(group = "OSM (default)") %>%
addPolygons(data = get(tmp))
}
}
)
}
# Run shiny app on laptop
shinyApp(ui, server)
What I am trying to avoid is this (because I may have 100+ items to display, and also because if the user selects less than 3 items I get an error message...):
# Server -----------------------------------------------------------------------
server <- function(input, output, session) {
output$m <- renderLeaflet({
m <- leaflet() %>%
# Add Basemap OSM
addTiles(group = "OSM (default)") %>%
addPolygons(data = input$input_items[1]) %>%
addPolygons(data = input$input_items[2]) %>%
addPolygons(data = input$input_items[3])
}
)
}
Thank you!
Here is a solution
First merge shapefiles together
shp <- bind(item_1, item_2, item_3)
Then in server side:
# Server -----------------------------------------------------------------------
server <- function(input, output, session) {
observeEvent(input$input_items,{
sel_shp <- shp[shp#data$id %in% input$input_items, ]
output$m <- renderLeaflet({
m <- leaflet() %>%
# Add Basemap OSM
addTiles(group = "OSM (default)") %>%
addPolygons(data = sel_shp)
})
})
}

Upload a file and then geocode the addresses in shiny app

Error while geocoding addresses in my shiny app
I wish to upload a file in my shiny app and and then calculate latitude and longitude.Below is the code and here is the LINK(https://github.com/Pujaguptagithub/My_Data) to the dataset used.Please help as I am new to shiny.
library(shiny)
library(dplyr)
library(readxl)
library(sf)
library(mapsapi)
library(gsubfn)
library(pipeR)
ui <- fluidPage(
fileInput('csvFile', 'Choose xlsx file',
accept = c(".xlsx")),
tableOutput("rawData"),
tableOutput("modifiedData")
)
server <- function(input, output, session) {
rawData <- eventReactive(input$csvFile, {
read_excel(input$csvFile$datapath)
})
output$rawData <- renderTable({
rawData() %>% head
})
output$modifiedData <- renderTable({
rawData() %>% mutate(Locations = paste(as.character(rawData()$Address),
as.character(rawData()$City),as.character(rawData()$State),
as.character(rawData()$`Zip Code`), as.character(rawData()$Country),
sep=",")) %>%
mutate(aaa = gsub("NA;", "", Locations)) %>%
mutate(bbbb = mp_geocode(addresses = aaa, region = NULL, bounds = NULL,
key = "AIzaSyBQDna1fNBT5qeET39A0lp9nNEdezRLVyI")) %>%
mutate(ccc = mp_get_points(bbbb)) %>%
mutate(pnt = sub(ccc$pnt, pattern = "c", replacement = "")) %>%
mutate(eee = sub(pnt, pattern = "[(]", replacement = "")) %>%
mutate(ffff = sub(eee, pattern = "[)]", replacement = "")) %>%
mutate(gggg = sub(ffff, pattern = ",", replacement = "")) %>%
mutate(hhh = unlist(strsplit(gggg, split = " "))) %>%
mutate(Latitude = as.numeric(hhh[seq(2, length(hhh), 2)])) %>%
mutate(Longitude = as.numeric(hhh[seq(1, length(hhh), 2)]))
})
}
shinyApp(ui, server)
The below code works perfect outside the shiny :
Locations <- paste(Latlong$Address, Latlong$City,Latlong$State,Latlong$`Zip
Code`, Latlong$Country, sep=",")
Locations <- gsub("NA;", "", Locations)
Locations <- mp_geocode(addresses = Locations, region = NULL, bounds =
NULL, key = "AIzaSyBQDna1fNBT5qeET39A0lp9nNEdezRLVyI")
Locations = mp_get_points(Locations)
geom <- sub(Locations$pnt, pattern = "c", replacement = "")
geom <- sub(geom, pattern = "[(]", replacement = "")
geom <- sub(geom, pattern = "[)]", replacement = "")
geom <- sub(geom, pattern = ",", replacement = "")
lonlat <- unlist(strsplit(geom, split = " "))
Latlong$Latitude <- as.numeric(lonlat[seq(2, length(lonlat), 2)])
Latlong$Longitude <- as.numeric(lonlat[seq(1, length(lonlat), 2)])
check my entire app below, the only problem is due to line "df_svb <- Latlong", please help to get rid off the error.
library(shinyjs)
library(shinyWidgets)
library(shiny)
library(shinydashboard)
library(tidyverse)
library(devtools)
library(rsconnect)
library(readxl)
library(DT)
library(writexl)
library(stringi)
library(shinydashboardPlus)
library(ggmap)
library(zipcode)
library(leaflet)
library(htmltools)
library(data.table)
library(plotly)
library(mapsapi)
library(readxl)
Template <- read_excel("C:/Users/Template.xlsx")
header <- dashboardHeader(
# Set height of dashboardHeader
tags$li(class = "dropdown",
tags$style(".main-header .logo {height: 0px;}")),
title = div(img(src = 'svb_small.png',
style = "position:absolute; left:15px;
height: 80px;"))
)
##### Sidebar
sidebar <- dashboardSidebar(
shinyjs::useShinyjs(),
width = 400,
menuItem('Inputs',
id = 'side_panel',
#icon = icon("bar-chart-o"),
startExpanded = TRUE,
br(), br(),
fileInput('csvFile', 'Choose xlsx file',
accept = c(".xlsx")),
div(style = "font-size: 150%; font-family: sans-serif;",
selectizeGroupUI(
id = "my_filters",
params = list(
Country = list(inputId = "Country", title = "Country:"),
Company = list(inputId = "Company", title = "Company:")),
inline = FALSE)),
br(),
br(),
br(),
br(),
br(),
br(),
br(),
br(),
br(),
br(),
br(),
br(),
br(),
br(),
br(),
br(),
downloadBttn('downloadData',
label = 'Download Template',
style = "gradient",
color = "primary"
)
)
)
body <- dashboardBody(
tags$style(type = "text/css", "#map_1 {height: calc(100vh - 80px)
!important;}"),
addSpinner(
leafletOutput("map_1"),
spin = 'folding-cube')
)
# Put them together into a dashboardPage
ui <- dashboardPage(header,sidebar,body, skin = "black")
options(shiny.maxRequestSize = 15*1024^2)
server <- function(input, output, session) {
rawData <- eventReactive(input$csvFile, {
read_excel(input$csvFile$datapath)
})
# Download template
output$downloadData <- downloadHandler(
filename = function() {"CBRE Geocoding and mapping Application.xlsx"},
content = function(file) {write_xlsx(Template, path = file)}
)
#SelectizeGroup function creates mutually dependent input filters
res_mod <- callModule(
module = selectizeGroupServer,
id = "my_filters",
data = df_svb,
vars = c('Country', 'Company')
)
modifiedData <- renderTable({
Latlong <- rawData()
Locations <- paste(Latlong$Address,
Latlong$City,Latlong$State,Latlong$`Zip Code`,
Latlong$Country, sep=",")
Locations <- gsub("NA;", "", Locations)
Locations <- mp_geocode(addresses = Locations, region = NULL, bounds=
NULL, key =
"AIzaSyBQDna1fNBT5qeET39A0lp9nNEdezRLVyI")
Locations = mp_get_points(Locations)
geom <- sub(Locations$pnt, pattern = "c", replacement = "")
geom <- sub(geom, pattern = "[(]", replacement = "")
geom <- sub(geom, pattern = "[)]", replacement = "")
geom <- sub(geom, pattern = ",", replacement = "")
lonlat <- unlist(strsplit(geom, split = " "))
Latlong$Latitude <- as.numeric(lonlat[seq(2, length(lonlat), 2)])
Latlong$Longitude <- as.numeric(lonlat[seq(1, length(lonlat), 2)])
Latlong
})
############################################################
df_svb <- Latlong
df_svb <- Latlong%>% mutate(
X = paste0('<font color="#006A4D">',
'<font-family: sans-serif>',
'<font size = "5">',
'<strong><font color="black">Country: </font color="black">
</strong>',
Country,
'<br><strong><font color="black">Company: </font color="black">
</strong>',
Company))
qpal <- colorFactor("BuPu", as.factor(df_svb$Company))
output$map_1 <- renderLeaflet(
leaflet(data = res_mod()) %>%
setView(-94.578568, 39.099728, zoom = 5) %>%
addProviderTiles(providers$Esri.WorldImagery, group = "Imagery Map") %>%
addProviderTiles(providers$Esri.WorldStreetMap, group = 'Street Map') %>%
addCircleMarkers(~Longitude, ~Latitude, group = 'svb',
fillColor = ~qpal(res_mod()$Company),
color = c("#006A4D","#FF0000"),
stroke = FALSE,
fillOpacity = 15,radius = 15,
labelOptions = labelOptions(noHide = T)
) %>%
addLayersControl(baseGroups = c('Street Map', "Imagery Map"),
options = layersControlOptions(collapsed = TRUE)) %>%
hideGroup('CBRE Locations') %>%
addLegend("topright", pal = qpal, values = ~res_mod()$Company,
title = "Company:", opacity = 1,group = 'svb' )
)
#Zooms in map when 1 office is chosen.
observe({
req(n_distinct(res_mod()$Country) == 1)
proxy <- leafletProxy('map_1')
proxy %>% setView(head(res_mod()$Longitude,1),
head(res_mod()$Latitude,1), zoom = 12)
})
}
shinyApp(ui, server)
UPDATE:
To add the data as a map, add this to the UI definition:
leafletOutput(outputId="myMap", height = 480)
And this will guide you on creating the server function:
output$myMap <- renderLeaflet({
# Test Data
#name <- c("London","Paris","Dublin")
#latitude <- c(51.5074,48.8566, 53.3498)
#longitude <- c(0.1278,2.3522, -6.2603)
#Latlong <- data.frame(name, latitude, longitude)
# Convert data frame to shape
coordinates(Latlong)<-~longitude+latitude
proj4string(Latlong)<- CRS("+proj=longlat +datum=WGS84")
shapeData <- spTransform(data,CRS("+proj=longlat"))
# Map the shape
map <- tm_shape(shapeData, name="Cities") +
tm_dots(size=0.2,title="Cities") +
tm_basemap("OpenStreetMap")+
tm_basemap("Esri.WorldImagery")
tmap_leaflet(map)
})
Original:
The issue seems to be in your call to the geocode function mp_get_points(). This is returning an xml document that can't be inserted into the new dataframe column ccc.
Is there any reason why you abandoned your original code? This seems to work fine if I insert it into your shiny app.
output$modifiedData <- renderTable({
Latlong <- rawData()
Locations <- paste(Latlong$Address, Latlong$City,Latlong$State,Latlong$`Zip
Code`, Latlong$Country, sep=",")
Locations <- gsub("NA;", "", Locations)
Locations <- mp_geocode(addresses = Locations, region = NULL, bounds =
NULL, key = "AIzaSyBQDna1fNBT5qeET39A0lp9nNEdezRLVyI")
Locations = mp_get_points(Locations)
geom <- sub(Locations$pnt, pattern = "c", replacement = "")
geom <- sub(geom, pattern = "[(]", replacement = "")
geom <- sub(geom, pattern = "[)]", replacement = "")
geom <- sub(geom, pattern = ",", replacement = "")
lonlat <- unlist(strsplit(geom, split = " "))
Latlong$Latitude <- as.numeric(lonlat[seq(2, length(lonlat), 2)])
Latlong$Longitude <- as.numeric(lonlat[seq(1, length(lonlat), 2)])
Latlong
})

Applying leaflet map bounds to filter data, within Shiny

The code below is meant to reproduce that which is found in this example with the exception of adding an additional parameter for "speed". However, my map-datatable link has broken - Can anyone help me spot the bug? The original code updates the table based on the bounds of the map, while in my code changing the map zoom has no effect on my table. I'm also not able to get the "speed" filter to work on the table and map, which is a functionality I am looking for. Any pointers would be appreciated.
library(shiny)
library(magrittr)
library(leaflet)
library(DT)
ships <-
read.csv(
"https://raw.githubusercontent.com/Appsilon/crossfilter-demo/master/app/ships.csv"
)
ui <- shinyUI(fluidPage(
titlePanel(""),
sidebarLayout(
sidebarPanel(width = 3,
numericInput(
"speed", label = h5("Ship's Speed"), value = 100
)),
mainPanel(tabsetPanel(
type = "tabs",
tabPanel(
"Leaflet",
leafletOutput("leafletmap", width = "350px"),
dataTableOutput("tbl")
)
))
)
))
server <- shinyServer(function(input, output) {
in_bounding_box <- function(data, lat, long, bounds, speed) {
data %>%
dplyr::filter(
lat > bounds$south &
lat < bounds$north &
long < bounds$east & long > bounds$west & ship_speed < input$speed
)
}
output$leafletmap <- renderLeaflet({
leaflet() %>%
addProviderTiles("Esri.WorldImagery", group = "ESRI World Imagery") %>%
addCircleMarkers(
data = ships,
~ long ,
~ lat,
popup = ~ speed,
radius = 5 ,
stroke = FALSE,
fillOpacity = 0.8,
popupOptions = popupOptions(closeButton = FALSE)
)
})
data_map <- reactive({
if (is.null(input$map_bounds)) {
ships
} else {
bounds <- input$map_bounds
in_bounding_box(ships, lat, long, bounds, speed)
}
})
output$tbl <- DT::renderDataTable({
DT::datatable(
data_map(),
extensions = "Scroller",
style = "bootstrap",
class = "compact",
width = "100%",
options = list(
deferRender = TRUE,
scrollY = 300,
scroller = TRUE,
dom = 'tp'
)
)
})
})
shinyApp(ui = ui, server = server)
Two small changes:
In the example you linked, input$map_bounds works, because the leaflet output object is called map. However, you renamed it to leafletmap, so we should refer to input$leafletmap_bounds.
in the dplyr statement, we should refer to speed, not ship_speed.
Working code is given below, hope this helps!
library(shiny)
library(magrittr)
library(leaflet)
library(DT)
ships <-
read.csv(
"https://raw.githubusercontent.com/Appsilon/crossfilter-demo/master/app/ships.csv"
)
ui <- shinyUI(fluidPage(
titlePanel(""),
sidebarLayout(
sidebarPanel(width = 3,
numericInput(
"speed", label = h5("Ship's Speed"), value = 100
)),
mainPanel(tabsetPanel(
type = "tabs",
tabPanel(
"Leaflet",
leafletOutput("leafletmap", width = "350px"),
dataTableOutput("tbl")
)
))
)
))
server <- shinyServer(function(input, output) {
in_bounding_box <- function(data, lat, long, bounds, speed) {
data %>%
dplyr::filter(
lat > bounds$south &
lat < bounds$north &
long < bounds$east & long > bounds$west & speed < input$speed
)
}
output$leafletmap <- renderLeaflet({
leaflet() %>%
addProviderTiles("Esri.WorldImagery", group = "ESRI World Imagery") %>%
addCircleMarkers(
data = ships,
~ long ,
~ lat,
popup = ~ speed,
radius = 5 ,
stroke = FALSE,
fillOpacity = 0.8,
popupOptions = popupOptions(closeButton = FALSE)
)
})
data_map <- reactive({
if (is.null(input$leafletmap_bounds)) {
ships
} else {
bounds <- input$leafletmap_bounds
in_bounding_box(ships, lat, long, bounds, speed)
}
})
output$tbl <- DT::renderDataTable({
DT::datatable(
data_map(),
extensions = "Scroller",
style = "bootstrap",
class = "compact",
width = "100%",
options = list(
deferRender = TRUE,
scrollY = 300,
scroller = TRUE,
dom = 'tp'
)
)
})
})
shinyApp(ui = ui, server = server)
The leaflet map you are rendering is called leafletmap. So rather than referring to map_bounds try changing it to leafletmap_bounds:
data_map <- reactive({
if (is.null(input$leafletmap_bounds)) {
ships
} else {
bounds <- input$leafletmap_bounds
in_bounding_box(ships, lat, long, bounds, speed)
}
})
Also in the filter, change ship_speed to speed. Should hopefully work.

Resources