Input Filter in R - r

I have a data set named "a2". Sample Data
CID Store Distance
1 X 2
2 Y 3
2 S 5
1 A 1
3 B 10
I want to develop an app in shiny with three tabs Filter Value, Nearest Store, Nearest Client. So whatever user chooses as an input so it should display all the rows of input.
So in Filter Value Tab
Ex if i choose CID 3 then it should extract only rows having CID3.
So in Nearest Store Tab
Ex if i choose Store X then it should extract only rows having Store X.
shinyApp(
ui = fluidPage(
titlePanel("Lat Long Address Mapping in R"),
fluidRow(
mainPanel(
tabsetPanel(type = "tabs",
tabPanel("FilterValue",
selectInput('InputID', 'ID', choices=NULL, selected=NULL),
),
tabPanel("Nearest Store",
selectInput('InputStore', 'ID', choices=NULL, selected=NULL),
),
tabPanel("Nearest Client",
selectInput('InputCustomer', 'ID', choices=NULL, selected=NULL),
)
))))
,
server = function(input, output,session) {
output$FilterValue<- renderDataTable(a2)
updateSelectizeInput(session, 'InputID',
choices = a2$CID,
server = TRUE)
updateSelectizeInput(session, 'InputStore',
choices = a2$Store,
server = TRUE)
updateSelectizeInput(session, 'InputCustomer',
choices = a2$CID,
server = TRUE)
output$Nearest Client<- renderDataTable({
paste(input$InputCustomer)
})
})
However in Nearest Client Tab I want to have two filters one of CID and one of distance
So if choose CID1 and minimum distance 2 it should give me only 1 row.
My output is generating all data of a2 in tab FIlter Value and Nearest Store. I am stuck with Nearest Client Tab
Thanks
Leaflet
Data frame is a
Sample Data is as follows
ID Lat Long Address
1 12.904249 77.70253 1/2 CA
2 21.221475 72.81281 2/3 DC
3 23.039251 72.58388 3/5 HJ
library (leaflet)
shinyApp(
ui = fluidPage(
titlePanel("Lat Long Address Mapping in R"),
fluidRow(
mainPanel(
tabsetPanel(type = "tabs",
tabPanel("Map",
bootstrapPage(
tags$style(type = "text/css", "html, body {width:100%;height:100%}"),
leafletOutput("map", width = "100%", height = "100%"),
absolutePanel(
top = 80,
left = 30,
)
)
)
,
server = function(input, output,session) {
output$map <- renderLeaflet({
leaflet(a) %>%
addProviderTiles("CartoDB.Positron") %>%
addMarkers(lng = ~Long, lat = ~Lat,
popup = ~address)})
When I run this standalone it works
leaflet(a) %>%
addProviderTiles("CartoDB.Positron") %>%
addMarkers(lng = ~Long, lat = ~Lat,
popup = ~address)

You can save the data as reactive and filter them it with dplyr
a2 %>% filter(CID == input$InputID & Distance == input$InputCustomer)
This will do what you want in the last tab. The code you gave also has issues like no output for the data tables you want to render and so on.I tried not to change too much on the way you constructed it but there are better ways to build the app. Below is a working example of what I think you are asking for:
a2 <- data.frame(CID = c(1,2,2,1,3),
Store = c("X", "Y", "S", "A", "B"),
Distance = c(2,3,5,1,10), stringsAsFactors = FALSE)
library(shiny)
library(dplyr)
library(DT)
ui <- fluidPage(
fluidRow(
mainPanel(
tabsetPanel(type = "tabs",
tabPanel("FilterValue", value = "filtervalue",
selectInput('InputID', 'ID', choices=NULL, selected=NULL),
dataTableOutput("out1")
),
tabPanel("Nearest Store", value = "neareststore",
selectInput('InputStore', 'ID', choices=NULL, selected=NULL),
dataTableOutput("out2")
),
tabPanel("Nearest Client", value = "nearestclient",
selectInput('InputCustomer', 'ID', choices=NULL, selected=NULL),
dataTableOutput("out3")
)
)))
)
server <- function(input, output, session) {
filtout <- reactive({
a3 <- a2 %>% filter(CID == input$InputID)
return(a3)
})
output$out1 <- DT::renderDataTable(datatable(filtout(), options = list(searching = F,
pageLength = 20,
lengthMenu = c(5, 10, 15, 20),
scrollX = T,
autoWidth = TRUE
)))
storeout <- reactive({
a3 <- a2 %>% filter(Store == input$InputStore)
return(a3)
})
output$out2 <- DT::renderDataTable(datatable(storeout(), options = list(searching = F,
pageLength = 20,
lengthMenu = c(5, 10, 15, 20),
scrollX = T,
autoWidth = TRUE
)))
custout <- reactive({
a3 <- a2 %>% filter(CID == input$InputID & Distance == input$InputCustomer)
return(a3)
})
output$out3 <- DT::renderDataTable(datatable(custout(), options = list(searching = F,
pageLength = 20,
lengthMenu = c(5, 10, 15, 20),
scrollX = T,
autoWidth = TRUE
)))
updateSelectizeInput(session, 'InputID',
choices = a2$CID,
server = TRUE)
updateSelectizeInput(session, 'InputStore',
choices = a2$Store,
server = TRUE)
updateSelectizeInput(session, 'InputCustomer',
choices = a2$Distance,
server = TRUE)
output$nearestclient<- renderDataTable({
paste(input$InputCustomer)
})
}
shinyApp(ui, server)
New info:
So I found out the issue was the cardDB.postitron. I changed the map to what I use normally. Also I had to strip some of the UI to get it the principle working and adress variable was not provided but this should form the basis of what you need.
library(shiny)
library(leaflet)
ui <- fluidPage(
fluidRow(
mainPanel(
tabsetPanel(type = "tabs",
tabPanel(title = "Map",
leafletOutput("map")
)))))
server <- function(input, output, session) {
output$map <- renderLeaflet({
leaflet(a) %>%
addProviderTiles(providers$Esri.WorldGrayCanvas,
options = providerTileOptions(noWrap = TRUE)) %>%
addMarkers(lng = ~Long, lat = ~Lat,
popup = ~address)
})
}
shinyApp(ui, server)

Related

Subsetting dataset when condition is true in Shiny

Using the code below, I could create my shiny app. When users select "yes" instead of "No", I would like the map to display only zip codes with at least 500 participants. As shown in the picture, "no" is selected by default.
I think I need some conditional statements to subset the data, but I dont know how to make this possible!
ui <- fluidPage(
fluidRow(
sidebarPanel(width=2,
radioButtons(
inputId = "ProjectID",
label = strong("Project ID"),
selected = "18",
choices = sort(unique(IDD_nhmap$ProjectID))
),
selectInput(
inputId = "Zip",
label = "Zip Codes With atleast 500 participants",
selected = "No",
selectize = TRUE,
multiple = FALSE,
choices = c("Yes", "No")),
),
######################
mainPanel(
fluidRow(
column(width = 6, shinyjs::useShinyjs(), leafletOutput("IDD_int_map1", height = "500px"))
)
), # this closes mainPanel
), # this closes fluidRow
br(),
br()
) # this closes ui
####################################
server <- function(input, output, session) {
#ACS_Blacks
IDD_mapdata_ <- reactive ({
out_map <- IDD_nhmap %>%
filter (ProjectID %in% input$ProjectID)
return(out_map)
list(Zip_Black)
})
IDD_mapdata_1 <- reactive ({
out_map_1 <- lat_long %>%
filter (ProjectID %in% input$ProjectID)
return(out_map_1)
list(lat)
})
output$IDD_int_map1 <- renderLeaflet ({
npal2 <- colorNumeric(palette = "Greens",
domain = IDD_nhmap$Zip_Black)
labels <- sprintf(
"<strong>Zip Code=%s </strong> <br/> Count = %s <br/> Percentage = %s ",
IDD_mapdata_()$Zip,
IDD_mapdata_()$Zip_Black,
IDD_mapdata_()$state_black
) %>%
lapply(htmltools::HTML)
leaflet (IDD_mapdata_(), options = leafletOptions(zoomSnap = 0.25, zoomDelta =
0.25)) %>%
addProviderTiles("CartoDB.Positron",
options = providerTileOptions(opacity = 2)) %>% # you need this and ()to remove the backgroun (Mexico/Canda)
clearControls() %>%
clearShapes() %>%
addPolygons(
fillColor = ~npal2(Zip_Black),
stroke = T,
weight = 1,
smoothFactor = 0.2,
fillOpacity = 1,
color = "black",
label = labels,
labelOptions = labelOptions(
interactive = TRUE,
style = list(
'direction' = 'auto',
'color' =
'black',
'font-family' = 'sans-serif',
# 'font-style'= 'italic',
'box-shadow' = '3px 3px rgba(0,0,0,0.25)',
'font-size' = '14px',
'border-color' = 'rgba(0,0,0,0.5)'
)
),
highlightOptions = highlightOptions(
weight = 2,
bringToFront = T,
# color = "#666",
fillOpacity = 0.7
)
) %>%
setView(lng = IDD_mapdata_1()$long,
lat = IDD_mapdata_1()$lat,
zoom = 8) %>%
addLegend(
position = "topright",
opacity = 1,
values = IDD_nhmap$Zip_Black,
# colors= c("#FFFFE5", "#D9F0A3", "#78C679", "#006837"),
pal = npal2,
#title = (paste("%",input$ProjectID)) ,
#title = (paste("%",input$ProjectID)) ,
title = (paste("African American (ACS)")) ,
labFormat = labelFormat()
) %>%
addTiles(options = tileOptions(opacity = 2)) # you need this to remove the backgroun (Mexico/Canda)
})
}
shinyApp(ui, server)
Approach 1: checkbox input as filter/subset logic
library(shiny)
ui <- fluidPage(
sidebarLayout(
sidebarPanel(
checkboxInput("fltr", "Filter mpg above 18", value = TRUE)
),
mainPanel(
plotOutput("plot")
)
)
)
server <- function(input, output, session) {
output$plot <- renderPlot({
subset(mtcars, input$fltr | mpg <= 18) |>
plot(mpg ~ disp, data = _)
})
}
shinyApp(ui, server)
Approach 2: reactive data
This approach might be preferred if multiple components (e.g., plots, tables) use the same optionally-filtered data.
server <- function(input, output, session) {
mydat <- reactive({
dat <- mtcars
if (isTRUE(input$fltr)) {
dat <- subset(dat, mpg <= 18)
}
dat
})
output$plot <- renderPlot({
plot(mpg ~ disp, data = req(mydat()))
})
}

Gauge chart from GoogleVis displaying in browser but on shiny app I get the error $ operator is invalid for atomic vectors

I am trying to make a shiny app where I can select a location on the map and display a gauge chart for each corresponding location.
I have been able to make the app reactive but the googlevis gauge display appears on the browser instead of in the app. In the app I get the error $ operator is invalid for atomic vectors. I tried converting the data into a dataframe but I am still getting this error.
the code is as follows
library(shiny)
library(leaflet)
library(shinydashboard)
library(dplyr)
library(googleVis)
#Making the Dataframe
locations<-c("A","B","C")
x<-c(36.05617,36.05626,36.05634)
y<-c(-2.1007,-2.05553,-2.01035)
yield<-c(5.86,3.06,1.07)
df<-data.frame(locations,x,y,yield)
################## Defining UI for application ############################
ui <- shinyUI(dashboardPage(title = "Yield Lookup",
dashboardHeader(title = "Crop Yield (Tonnes per Hectare)",titleWidth = 350),
dashboardSidebar(
sidebarMenu(
menuItem("Map Dashboard", tabName = "datavis", icon = icon("map", verify_fa = FALSE)),
menuItem("Select by Location Name", icon = icon("leaf"),
selectizeInput("locations", "Click on Location", choices = levels(factor(df$locations)))
)
)
),
dashboardBody(
tabItems(
tabItem(tabName = "datavis",
h4("Map and Plot"),
fluidRow(box(width= 8, leafletOutput("map", height = 800)),
box("Gauge for crop yield by area",width = 4, htmlOutput("myplot")))
)
)
)
)
)
################## Defining Server for application ############################
server<- shinyServer(function(input,output, session){
## Sub data
lo<-reactive({
})
locat_data <- reactive({
df[df$locations %in% input$locations,]
})
output[["myplot"]] <- renderGvis({
newdf<-locat_data()%>%select(locations, yield)
newdf<-as.data.frame(newdf)
Gauge <- gvisGauge(as.data.frame(newdf),
options=list(min=0, max=6, greenFrom=4,
greenTo=6, yellowFrom=2, yellowTo=4,
redFrom=0, redTo=2, width=400, height=300))
plot(Gauge)
})
output$map <- renderLeaflet({
leaflet(df) %>%
addTiles() %>%
addCircleMarkers(lng = ~x, lat = ~y, layerId = ~locations, color = "blue", radius = 3) %>%
addCircles(lng = ~x, lat = ~y, weight = 1,
radius = 1, label = ~locations
)
})
observeEvent(input$locations,{
updateSelectInput(session, "locations", "Click on Locations",
choices = levels(factor(df$locations)),
selected = c(input$locations))
})
observeEvent(input$map_marker_click, {
click <- input$map_marker_click
location <- df[which(df$y == click$lat & df$x == click$lng), ]$locations
updateSelectInput(session, "locations", "Click on Location",
choices = levels(factor(df$locations)),
selected = c(input$locations, location))
})
})
shinyApp(ui=ui, server = server)
I am not sure where I am going wrong. Please help.
You were very close.
Just drop the plot() and leave Gauge in the server section. (Alternatively drop the Gauge <- and Gauge on the next line and just leave gvisGauge())
library(shiny)
library(leaflet)
library(shinydashboard)
library(dplyr)
library(googleVis)
#Making the Dataframe
locations<-c("A","B","C")
x<-c(36.05617,36.05626,36.05634)
y<-c(-2.1007,-2.05553,-2.01035)
yield<-c(5.86,3.06,1.07)
df<-data.frame(locations,x,y,yield)
################## Defining UI for application ############################
ui <- shinyUI(dashboardPage(title = "Yield Lookup",
dashboardHeader(title = "Crop Yield (Tonnes per Hectare)",titleWidth = 350),
dashboardSidebar(
sidebarMenu(
menuItem("Map Dashboard", tabName = "datavis", icon = icon("map", verify_fa = FALSE)),
menuItem("Select by Location Name", icon = icon("leaf"),
selectizeInput("locations", "Click on Location", choices = levels(factor(df$locations)))
)
)
),
dashboardBody(
tabItems(
tabItem(tabName = "datavis",
h4("Map and Plot"),
fluidRow(box(width= 8, leafletOutput("map", height = 800)),
box("Gauge for crop yield by area",width = 4, htmlOutput("myplot")))
)
)
)
)
)
################## Defining Server for application ############################
server<- shinyServer(function(input,output, session){
## Sub data
lo<-reactive({
})
locat_data <- reactive({
df[df$locations %in% input$locations,]
})
output[["myplot"]] <- renderGvis({
newdf<-locat_data()%>%select(locations, yield)
newdf<-as.data.frame(newdf)
Gauge <- gvisGauge(as.data.frame(newdf),
options=list(min=0, max=6, greenFrom=4,
greenTo=6, yellowFrom=2, yellowTo=4,
redFrom=0, redTo=2, width=400, height=300))
Gauge
})
output$map <- renderLeaflet({
leaflet(df) %>%
addTiles() %>%
addCircleMarkers(lng = ~x, lat = ~y, layerId = ~locations, color = "blue", radius = 3) %>%
addCircles(lng = ~x, lat = ~y, weight = 1,
radius = 1, label = ~locations
)
})
observeEvent(input$locations,{
updateSelectInput(session, "locations", "Click on Locations",
choices = levels(factor(df$locations)),
selected = c(input$locations))
})
observeEvent(input$map_marker_click, {
click <- input$map_marker_click
location <- df[which(df$y == click$lat & df$x == click$lng), ]$locations
updateSelectInput(session, "locations", "Click on Location",
choices = levels(factor(df$locations)),
selected = c(input$locations, location))
})
})
shinyApp(ui=ui, server = server)

How to display map dynamically changed as per drilldown selectInput() based on previous selections?

I would like to render a map based on selectInput(). I have two selectInput()s: first one product_type and second one product_name. In the second one selectInput() the drop down options should be display only relevant to first selectInput(). Based on these drill down inputs map should change dynamically.
Here is the code:
ui <- shinyUI(dashboardPage(
dashboardHeader(),
dashboardSidebar(),
dashboardBody(
fluidPage(
box("",
leafletOutput("abc", width = '100%', height = 300),
height = 350, width = 12),
box("",
selectInput('vtype', label = 'Prod Type',choices = brand$prod_type),
selectInput('vname', label = 'Prod Name',choices = brand$prod_name),
width = 4),
valueBoxOutput("gr", width = 8)
)
)
))
server <- shinyServer(function(input,output,session){
a <- ship %>% select(prod_name,prod_type,LON,LAT) %>% filter(prod_type == input$vtype)
output$gr <- renderValueBox({
box(table(a))
})
output$abc <- renderLeaflet({
leaflet() %>% addProviderTiles(providers$OpenTopoMap )
%>% setView(lat = a$LAT ,lng = A$LON, zoom = 4)
})
})
shinyApp(ui,server)
The dynamically changed points in the map should be marked up. I tried but could not able to build the code.
Any help on this code would be graceful for me.
I hope my example helps. I invented a data.frame 'ship' and made everything dependent on it. That means it is used for your variable 'brand' as well as 'ship'.
I'm not sure how you envisioned the value box, so I put category and products in it.
library(shiny)
library(shinydashboard)
library(dplyr)
library(leaflet)
ship <- data.frame(
product_type = c("food","food","tool","tool","tool","accessories","accessories","lighting","lighting","lighting"),
product_name=c("eggs", "bread","clamp","hammer","screw driver", "watch" ,"sun glases","LED","bulb","briquette"),
LON=c(-61.783,2.632,47.395,20.068,44.563,17.544,-170.730,-65.167,136.189,50.562),
LAT=c(17.078 ,28.163 ,40.430 ,41.143 ,40.534 ,-12.296 ,-14.318 ,-35.377 ,-24.973 ,26.019),
stringsAsFactors = F)
ui <- dashboardPage(
dashboardHeader(),
dashboardSidebar(collapsed = TRUE, disable = FALSE),
dashboardBody(
# fluidPage(
box(
leafletOutput("abc", width = '100%', height = 300),
height = 350,
width = 12),
box(
selectInput('vtype', label = 'Prod Type', choices = c("< select product type>"="", ship$product_type)),
selectInput('vname', label = 'Prod Name', choices = c("< select item>"="", ship$product_name)),
width = 4),
valueBoxOutput("gr", width = 8)
#)
)
)
server <- shinyServer(function(input,output,session){
a <- reactive({
ship %>%
select(product_name, product_type, LON, LAT) %>%
filter(product_type %in% input$vtype)
})
output$gr <- renderValueBox({
valueBox( input$vtype, paste(a()$product_name, collapse=' - ') )
})
observe({
updateSelectInput(session,
inputId='vname',
choices = c("< select item>"="", a()$product_name ))
})
output$abc <- renderLeaflet({
leaflet() %>%
addProviderTiles(providers$OpenTopoMap ) %>%
setView(lng=0, lat=0, zoom = 1)
})
observe({
selection <- a() %>% filter(product_name %in% input$vname)
leafletProxy("abc") %>%
flyTo(lat = selection$LAT,
lng = selection$LON,
zoom = 4)
})
})
shinyApp(ui,server)
Please provide example data next time.

How to add comment to a reactive data table in shiny

This question is an extension of the question I posted: this question
I created a dataframe with 3 columns: num, id and val. I want my shiny app to do the following:
a dataframe dat is filtered by num column
select an value from id column from dat (selectInput).
add text comment in a text box (textInput)
click on an action button
A new column called comment is created in the data table, text comments are added to the comment column in the row where id equals the value selected.
The code is below. I cannot figure out why it's not working.
Thank a lot in advance!
library(shiny)
library(DT)
dat = data.frame(num=rep(1:2, each=5), id=rep(LETTERS[1:5],2), val=rnorm(10))
ui = fluidPage(
fluidRow(
column(12, selectInput('selectNum', label='Select Num',
choices=1:10, selected='')),
column(2, selectInput(inputId = 'selectID',
label = 'Select ID2',
choices = LETTERS[1:10],
selected='',
multiple=TRUE)),
column(6, textInput(inputId = 'comment',
label ='Please add comment in the text box:',
value = "", width = NULL,
placeholder = NULL)),
column(2, actionButton(inputId = "button",
label = "Add Comment"))
),
fluidRow (
column(12, DT::dataTableOutput('data') )
)
)
server <- function(input, output, session) {
## make df reactive
df = reactive ({ dat %>% filter(num %in% input$selectNum) })
df_current <- reactiveVal(df())
observeEvent(input$button, {
req(df_current())
## update df by adding comments
df_new <- df_current()
df_new[df_current()$id %in% input$selectID, "Comment"] <- input$comment
df_current(df_new)
})
output$data <- DT::renderDataTable({
req(df_current())
DT::datatable(df_current(),
options = list(orderClasses = TRUE,
lengthMenu = c(5, 10, 20), pageLength = 5))
})
shinyApp(ui=ui, server=server)
Instead of using a reactive/eventReactive statement for df, it might be more natural to keep track of previously inputted comments in the Comment column using a reactiveVal object for df. See also the responses to this question: R Shiny: reactiveValues vs reactive. If you prefer to use a reactive/eventReactive statement for df it is probably better to work with a separate object to store previous input comments (instead of incorporating it into the reactive statement for df).
library(shiny)
library(DT)
dat = data.frame(num=1:10, id=LETTERS[1:10], val=rnorm(10))
ui = fluidPage(
fluidRow(
column(12, selectInput('selectNum', label='Select Num',
choices=1:10)),
column(2, selectInput(inputId = 'selectID',
label = 'Select ID2',
choices = LETTERS[1:10],
selected='',
multiple=TRUE)),
column(6, textInput(inputId = 'comment',
label ='Please add comment in the text box:',
value = "", width = NULL,
placeholder = NULL)),
column(2, actionButton(inputId = "button",
label = "Add Comment"))
),
fluidRow (
column(12, DT::dataTableOutput('data') )
)
)
server <- function(input, output, session) {
## make df reactive
df_current <- reactiveVal(dat)
observeEvent(input$button, {
req(df_current(), input$selectID %in% dat$id)
## update df by adding comments
df_new <- df_current()
df_new[df_current()$id %in% input$selectID, "Comment"] <- input$comment
df_current(df_new)
})
output$data <- DT::renderDataTable({
req(df_current())
## filter df_current by 'selectNum'
df_filtered <- df_current()[df_current()$num %in% input$selectNum, ]
## show comments if non-empty
showComments <- is.null(df_filtered$Comment) || !all(is.na(df_filtered$Comment))
DT::datatable(df_filtered,
options = list(orderClasses = TRUE,
lengthMenu = c(5, 10, 20), pageLength = 5,
columnDefs = list(
list(targets = ncol(df_filtered), visible = showComments)
)
)
)
})
}
shinyApp(ui=ui, server=server)
Edit: below an edited server function that using df_current <- reactive({...}) instead of df_current <- reactiveVal({...}) and defining a separate reactiveVal object to keep track of the comments.
server <- function(input, output, session) {
## initialize separate reactive object for comments
df_comments <- reactiveVal({
data.frame(
id = character(0),
Comment = character(0),
stringsAsFactors = FALSE
)
})
## reactive object df
df_current <- reactive({
## reactivity that df depends on
## currently df = dat does not change
df <- dat
## merge with current comments
if(nrow(df_comments()) > 0)
df <- merge(df, df_comments(), by = "id", all.x = TRUE)
return(df)
})
observeEvent(input$button, {
req(input$selectID)
## update df_comments by adding comments
df_comments_new <- rbind(df_comments(),
data.frame(id = input$selectID, Comment = input$comment)
)
## if duplicated id's keep only most recent rows
df_comments_new <- df_comments_new[!duplicated(df_comments_new$id, fromLast = TRUE), , drop = FALSE]
df_comments(df_comments_new)
})
output$data <- DT::renderDataTable({
req(df_current())
## filter df_current by 'selectNum'
df_filtered <- df_current()[df_current()$num %in% input$selectNum, ]
## show comments if non-empty
showComments <- is.null(df_filtered$Comment) || !all(is.na(df_filtered$Comment))
DT::datatable(df_filtered,
options = list(orderClasses = TRUE,
lengthMenu = c(5, 10, 20), pageLength = 5,
columnDefs = list(
list(targets = ncol(df_filtered), visible = showComments)
)
)
)
})
}
There you have got a working example.
I think the thing is that you are trying to update a value through an observeEvent which is not good according to the documentation. ?observeEvent
Use observeEvent whenever you want to perform an action in response to an event. (Note that "recalculate a value" does not generally count as performing an action–see eventReactive for that.)
library(shiny)
library(DT)
dat = data.frame(num=1:10, id=LETTERS[1:10], val=rnorm(10))
ui = fluidPage(
fluidRow(
column(12, selectInput('selectNum', label='Select Num',
choices=1:10, selected='')),
column(2, selectInput(inputId = 'selectID',
label = 'Select ID2',
choices = LETTERS[1:10],
selected='',
multiple=TRUE)),
column(6, textInput(inputId = 'comment',
label ='Please add comment in the text box:',
value = "", width = NULL,
placeholder = NULL)),
column(2, actionButton(inputId = "button",
label = "Add Comment"))
),
fluidRow (
column(12, DT::dataTableOutput('data') )
)
)
server <- function(input, output, session) {
## make df reactive
df_current = reactive({
df = dat %>% filter(num %in% input$selectNum)
if(input$button != 0) {
input$button
df[df$id %in% input$selectID, "Comment"] <- isolate(input$comment)
}
return(df)
})
output$data <- DT::renderDataTable({
req(df_current())
DT::datatable(df_current(),
options = list(orderClasses = TRUE,
lengthMenu = c(5, 10, 20), pageLength = 5))
})
}
shinyApp(ui=ui, server=server)
So you can either go with your reactive value or using eventReactive as stated in the doc.

Shiny drop down selection as input to filter

I am trying to use the tree type selected in a drop down to filter a data frame.
I have created a simple stand alone version below.
Right now, "maple" is hard coded as the tree to filter by. I would like to filter by whatever the user selects in the drop down.
Clearly, I'm new to shiny and would like to know what variable to use in replace of "maple".
server.R
library(shiny)
library(dplyr) # Needed for filter
# Read tree types
data <- c("oak", "maple", "elm")
# Read clean list of all Toronto's trees
tree_clean <- tibble (
type = c("oak", "oak", "elm", "maple", "maple", "maple"),
size = c(10, 20, 30, 10, 20, 30),
id = c(1, 2, 3, 4, 5, 6)
)
function(input, output, session){
my_list <- reactive({
my_list <- as.character(data)
})
output$tree <- renderUI({
selectInput(inputId = "tree", label = "Select a Tree", choices = my_list())
})
get_tree_data <- reactive({
filter(tree_clean, type == "maple")
})
observe({
tree_data <- get_tree_data()
print(tree_data)
})
}
ui.R
# Scrollable dropdown with 246 tree names
library(shiny)
library(shinydashboard)
header <- dashboardHeader(title = "Toronto Tree Map")
body <- dashboardBody(
fluidPage(
column(width = 9,
box(width = NULL, solidHeader = TRUE)
),
column(width = 3,
box(width = NULL,
uiOutput(outputId = "tree")
)
)
)
)
dashboardPage(
header,
dashboardSidebar(disable = TRUE),
body
)
OLD QUESTION --------------------------------------------
In Server.R I thought replacing the hardcoded, "Japanese Katsura" with input$tree would work. However, it gives the error:
Warning in is.na(e2) :
is.na() applied to non-(list or vector) of type 'NULL'
Warning: Error in filter_impl: Result must have length 567061, not 0
What variable should I replace the hardcoded "Japanese Katsura" with so that my filter is fed by the user's selection in the drop down?
Server.R
# Scrollable dropdown with 246 tree names linked to map
library(sf)
library(shiny)
library(leaflet)
library(dplyr) # Needed for filter
# Read border of Toronto
to_border <- st_read("citygcs_regional_mun_wgs84.shp", quiet = TRUE)
border <- to_border %>%
st_cast("MULTILINESTRING")
# Read list of Toronto's 246 tree types
data <- read.csv("common_tree_names_246.csv", header = FALSE)$V1
# Read clean list of all Toronto's trees
tree_clean <- st_read("trees_lower_case6.shp")
function(input, output, session){
my_list <- reactive({
my_list <- as.character(data)
})
output$tree <- renderUI({
selectInput(inputId = "tree", label = "Select a Tree", choices = my_list())
})
get_tree_data <- reactive({
filter(tree_clean, tname == "Japanese Katsura")
})
# Call once since using Leaflet proxy
output$torontoMap<-renderLeaflet({
leaflet(options = leafletOptions(minZoom = 10, maxZoom = 18), width = "100%") %>%
addTiles() %>%
addProviderTiles(providers$Stamen.Watercolor) %>%
# Centre the map in the middle of Toronto
setView(lng = -79.384293,
lat = 43.685, #43.653908,
zoom = 12)
})
observe({
tree_data <- get_tree_data()
print(nrow(tree_data))
# If the data changes, the polygons are cleared and redrawn, however, the map (above) is not redrawn
leafletProxy("torontoMap", data = tree_data) %>%
clearShapes() %>%
addCircles(data = tree_data,
color = "green",
weight = 5)
})
}
UI.R
# Scrollable dropdown with 246 tree names
library(shiny)
library(shinydashboard)
library(leaflet)
# Remember verbatimTextOutput("selection")
header <- dashboardHeader(title = "Toronto Tree Map")
body <- dashboardBody(
fluidPage(
column(width = 9,
box(width = NULL, solidHeader = TRUE,
leafletOutput("torontoMap", height = 400)
)
),
column(width = 3,
box(width = NULL,
uiOutput(outputId = "tree")
)
)
)
)
dashboardPage(
header,
dashboardSidebar(disable = TRUE),
body
)

Resources