I have an interactive visualization that connects to a city government's police data API.
When certain combinations of inputs are selected, my API call comes back empty and I get a nasty red error message (as my plot inputs are unavailable).
Can someone tell me how to display a more informative error message along the lines of, "there are no incidents matching your selection, please try again"? I would like this error message to appear as a showNotification and my ggplot not to render.
Below is an extremely stripped down version of what I am doing. Note how when a combination like "AVONDALE" and "CHEMICAL IRRITANT" is selected, the chart renders, whereas when a combination like "ENGLISH WOODS" and "TASER-BEANBAG-PEPPERBALL-40MM FOAM" is selected, an error message is returned. This error message is what I would like to address with a showNotification alert.
Note that this uses the Socrata API, so the package RSocrata must be installed and loaded.
install.packages("RSocrata")
library(shiny)
library(reshape2)
library(dplyr)
library(plotly)
library(shinythemes)
library(tibble)
library(RSocrata)
# Define UI for application that draws a histogram
ui <- fluidPage(
navbarPage("Example",
theme = shinytheme("united"),
tabPanel("Plot",
sidebarLayout(
sidebarPanel(
# neighborhood selector
selectizeInput("neighbSelect",
"Neighborhoods:",
choices = c("AVONDALE", "CLIFTON", "ENGLISH WOODS"),
multiple = FALSE)),
# incident description selector
selectizeInput("incSelect",
"Incident Type:",
choices = c("CHEMICAL IRRITANT", "TASER-BEANBAG-PEPPERBALL-40MM FOAM"),
multiple = FALSE))
),
# Output plot
mainPanel(
plotlyOutput("plot")
)
)
)
# Define server logic
server <- function(input, output) {
forceInput <- reactive({
forceInput <- read.socrata(paste0("https://data.cincinnati-oh.gov/resource/e2va-wsic.json?$where=sna_neighborhood= '", input$neighbSelect, "' AND incident_description= '", input$incSelect, "'"))
})
# Render plot
output$plot <- renderPlotly({
ggplot(data = forceInput(), aes(x = sna_neighborhood)) +
geom_histogram(stat = "count")
})
}
# Run the application
shinyApp(ui = ui, server = server)
Thank you so much for any help anyone can offer!
Im going to give an example with the shinyalert library to have the popup. Here I added the sample choice TEST to indicate no data:
#install.packages("RSocrata")
library(shiny)
library(reshape2)
library(dplyr)
library(plotly)
library(shinythemes)
library(tibble)
library(RSocrata)
library(shinyalert)
# Define UI for application that draws a histogram
ui <- fluidPage(
useShinyalert(),
navbarPage("Example",
theme = shinytheme("united"),
tabPanel("Plot",
sidebarLayout(
sidebarPanel(
# neighborhood selector
selectizeInput("neighbSelect",
"Neighborhoods:",
choices = c("AVONDALE", "CLIFTON", "ENGLISH WOODS","TEST"),
multiple = FALSE)),
# incident description selector
selectizeInput("incSelect",
"Incident Type:",
choices = c("CHEMICAL IRRITANT", "TASER-BEANBAG-PEPPERBALL-40MM FOAM"),
multiple = FALSE))
),
# Output plot
mainPanel(
plotlyOutput("plot")
)
)
)
# Define server logic
server <- function(input, output,session) {
forceInput <- reactive({
forceInput <- read.socrata(paste0("https://data.cincinnati-oh.gov/resource/e2va-wsic.json?$where=sna_neighborhood= '", input$neighbSelect, "' AND incident_description= '", input$incSelect, "'"))
if(nrow(forceInput)==0){
shinyalert("Oops!", "No data returned", type = "error")
forceInput <- NULL
}
forceInput
})
# Render plot
output$plot <- renderPlotly({
req(forceInput())
ggplot(data = forceInput(), aes(x = sna_neighborhood)) +
geom_histogram(stat = "count")
})
}
# Run the application
shinyApp(ui = ui, server = server)
Related
Colleagues,
I'm creating a Shiny app that can generate a data set with user-defined properties. The intended data-generation function can take some time, so I've substituted a very simple one.
My problem is that the app seems to just hang, or nothing happens at all, when I hit the GO button.
DEBUG in Rstudio shows nothing, and reactlog also gives no information.
Similar questions on this stackoverflow forum are more than 8 years old, and suggestions don't seem to work either.
I'm sure the solution is head-slapping simple but, right now, I'm lost.
Any suggestions from those more knowledgeable than this Shiny newbie?
## generate data set with user-defined parameters
## load libraries
library(shiny)
library(ggplot2)
library(DT)
##
options(shiny.reactlog = TRUE)
# Define UI
ui <- fluidPage(
# Application title
titlePanel("Synthesise data"),
# Sidebar
sidebarLayout(
sidebarPanel(
## Sample size
numericInput("sample_n", "Sample size", 30,
min = 10, max = 300, step = 1
),
h4("Desired scale moments"),
numericInput("target_mean", "Target mean", 4),
numericInput("target_sd", "Target st dev", 1),
hr(style = "border-top: 1px solid #000000;"),
actionButton("goButton", "Go!"),
actionButton("goChart", "show chart"),
),
mainPanel(
h4("generated data"),
# table of generated data
DT::dataTableOutput("mytable"),
# Show a plot of the generated distribution
plotOutput("resultPlot")
)
)
)
# Define server logic
server <- function(input, output) {
mytable <- reactive(input$goButton, {
## substituting data-gen function that can take some time
mydata <- rnorm(sample_n, target_mean, target_sd) |>
data.frame()
colnames(mydata) <- "scale"
# saveRDS(mydata, file = "generatedData.RDS")
output$mytable <- DT::renderDataTable(DT::datatable({
mydata
}))
})
myplot <- eventReactive(input$goChart, {
output$resultPlot <- renderPlot({
ggplot(mydata, aes(x = scale)) +
geom_density()
})
})
}
# Run the application
shinyApp(ui = ui, server = server)
Few code errors here :
forgot input$ when using sample_n, target_mean and target_sd in server
put some output definition inside eventReactive or reactive is a terrible habit
reactive is not used like you did. EventReactive is what you needed here.
Here is a corrected version of you code
library(shiny)
library(ggplot2)
library(DT)
ui <- fluidPage(
titlePanel("Synthesise data"),
sidebarLayout(
sidebarPanel(
numericInput("sample_n", "Sample size", 30,
min = 10, max = 300, step = 1
),
h4("Desired scale moments"),
numericInput("target_mean", "Target mean", 4),
numericInput("target_sd", "Target st dev", 1),
hr(style = "border-top: 1px solid #000000;"),
actionButton("goButton", "Go!"),
actionButton("goChart", "show chart"),
),
mainPanel(
h4("generated data"),
DT::dataTableOutput("mytable"),
plotOutput("resultPlot")
)
)
)
server <- function(input, output) {
mydata <- eventReactive(input$goButton, {
mydata <- data.frame(scale = rnorm(input$sample_n, input$target_mean, input$target_sd))
return(mydata)
})
output$mytable <- DT::renderDataTable(DT::datatable(
mydata()
))
output$resultPlot <- renderPlot({
input$goChart
isolate(ggplot(mydata(), aes(x = scale)) +
geom_density())
})
}
shinyApp(ui = ui, server = server)
I am building a shinyApp to display COVID-19 data. I have a file in long format that displays the day, county, positive cases, recoveries, and deaths. I am attempting to make the app where a user can select a county from a drop down menu and it will display 3 graphs of positives, recoveries, and deaths on the page. The graphs will have x-axis be dates and y-axis as a variable. Attached is the script I have so far. I have tried many different approachers, but I have no idea what to do. I am still learning R and have no prior experience with ShinyApp. Any advice or help would be appreciated. I think I have the ggPlot and output/UI right, the server logic is what is throwing me for a loop. Even just a link to a good guide would be nice. Thanks!
7/23/2020: I have updated the code. I looked in ggplot some. When I run the app, I now have the dropdown menu I wanted, but the graphs are displaying. When I create the ggplot in the console to make sure the code works on its own, I am missing the middle protion of the graph? Any ideas/fixes?
library(shiny)
library(dplyr)
library(tidyr)
library(plotly)
library(ggplot2)
library(rsconnect)
df <- read.csv("C:/Users/Nathan May/Desktop/Research Files (ABI)/Covid/Data For Shiny/Appended_File/Appended_Scraped_Files.csv") #INSERT PATH SINGLE FILE OPTION
datapos <- df[c(2,6,3)]
rsconnect::setAccountInfo(name='nathanjmay', token='A3CF4CC3DE0112B8B9F8D0BA429223D3', secret='TNwC9hxwZt+BffOhFaXD3FQsMg3eQnfaPGr0eE8S')
#UI
ui <- fluidPage(
titlePanel("COVID-19 in Arkansas Counties"),
fluidRow(
column(
width=4,
selectizeInput("County", label=h5("County"), choices= data$Counties, width="100%")
)),
fluidRow(
plotOutput(outputId = "Positive")
),
fluidRow(
plotOutput(outputId = "Recoveries")
),
fluidRow(
plotOutput(outputId = "Deaths")
),)
#SERVER
server= function(input, output) {
data <- reactive({
datapos %>% filter(County == input$County)
#GGPLOT2 for Positive
output$Positive -> renderPlot(ggplot(data=datapos, aes(x=Day, y=Positive)) +
geom_bar(stat="identity"))
#Recoveries
output$Recoveries -> renderplot()
#Deaths
output$Deaths -> renderplot()
})
}
shinyApp(ui=ui, server=server)
You're assigning all reactive expressions to the data object in the server logic, look at where you close the curly bracket. So everything get wrapped into data and nothing about your plotOutput, i.e. output$Positive, output$Recoveries, output$Death are specified in your server logic. Also the way to use reactive() feel a little awkward at first. Here's my super simply app to illustrate what you ought to do wrt to using reactive(). Again notice where you open and close the curly bracket and parentheses.
So the chain of reactions defined here are: input$state >> dat via reactive() >> output$dummy via renderPlot().
library(shiny)
library(dplyr)
library(ggplot2)
#### Fake data
df <- data.frame(state = rep(c("FL", "GA"), each = 2),
x = rnorm(4),
y = rnorm(4))
#### UI
ui <- fluidPage(
titlePanel("Old Faithful Geyser Data"),
sidebarLayout(
selectInput("state", "Choose a state:",
list(`Florida` = "FL",
`Georgia` = "GA")
),
mainPanel(
plotOutput("dummy")
)
)
)
#### Server
server <- function(input, output) {
## Essential dat is the filtered df
dat <- reactive({
df %>%
filter(state == input$state)
})
## Use dat() to access the filtered df instead of dat
output$dummy <- renderPlot({
ggplot(dat()) +
geom_point(aes(x = x, y = y))
})
}
# Run the application
shinyApp(ui = ui, server = server)
I'm trying to make a plot with reactive data from the server. Unfortunately I can't get the plot to work. I'm getting an error like: "Error:EXPR must be a length 1 vector". I tried different styles of plots and different libraries: Quantmod, ggplot, so on. Any suggestions?
Server:
library(shiny)
Dat<-read.csv("A:\\home\\Documents\\Franchise_Failureby_Brand2011.csv", sep=';')
names(Dat)[1]<-paste("Brand")
names(Dat)[2]<-paste("Failure")
names(Dat)[3]<-paste("Disbursement")
names(Dat)[4]<-paste("Disb$X$1000")
names(Dat)[5]<-paste("Chgoff")
Dat1<-Dat[is.na(Dat)==FALSE,]
Dat<-Dat1[1:578,]
# Define server logic required to draw a histogram
shinyServer(function(input, output) {
DatSv <- reactive({
Value <- switch(input$Value,
"Failure"= Dat$Failure[1:10],
"Disbursement"=Dat$Disbursement[1:10],
"Disb$X$1000"=Dat$`Disb$X$1000`[1:10],
"Chgoff"=Dat$Chgoff[1:10])
Brand<-Dat$Brand[1:10]
Brand(input$Value)
})
# Generate plot
output$plot1 <- renderPlot({
library("quantmod")
hist(DatSv(),
main=paste('r', Value, '(', Brand, ')', sep=''))
})
# Generate summary of data
output$summary<-renderPrint({
summary(Dat)
})
})
UI:
library(shiny)
shinyUI(fluidPage(
titlePanel("Plot Franchise Failure"),
sidebarLayout(
sidebarPanel(
radioButtons("n", "Chose output Y Axis:",
c("Failure" ,
"Disbursement",
"Disb$X$1000" ,
"Chgoff" )),
checkboxInput("show_xlab", "Show/Hide X Axis Label", value=TRUE),
checkboxInput("show_ylab", "Show/Hide Y Axis Label", value=TRUE),
checkboxInput("show_title", "Show/Hide Title")
),
mainPanel(
tabsetPanel(
type = "tabs",
tabPanel("Plot", plotOutput("plot1")),
tabPanel("Summary", verbatimTextOutput("summary"))
)
)
)
)
)
Hi the problem comes from connecting the inputs in the UI with the server. In the UI you have given the inputid = "n" for the radioButtons. That means we can get the Value of the Radiobuttons with input$n and not input$Value. The later is always NULL since there is no input with inputid = "Value". I had some other small problems with your code but here is a working version of the server code. I didn't modify the UI
library(shiny)
Dat<-read.csv("A:\\home\\Documents\\Franchise_Failureby_Brand2011.csv", sep=';')
names(Dat)[1]<-paste("Brand")
names(Dat)[2]<-paste("Failure")
names(Dat)[3]<-paste("Disbursement")
names(Dat)[4]<-paste("Disb$X$1000")
names(Dat)[5]<-paste("Chgoff")
Dat1<-Dat[is.na(Dat)==FALSE,]
Dat<-Dat1[1:578,]
# Define server logic required to draw a histogram
shinyServer(function(input, output) {
DatSv <- reactive({
switch(input$n,
"Failure"= gsub("%","",as.character( Dat$Failure)),
"Disbursement"=Dat$Disbursement,
"Disb$X$1000"=gsub("\\$","",as.character( Dat$`Disb$X$1000`)),
"Chgoff"=gsub("%","",as.character(Dat$Chgoff)))
})
# Generate plot
output$plot1 <- renderPlot({
library("quantmod")
hist(as.numeric(DatSv()),
main=paste('Histogram of ',input$n, sep=''),
xlab = input$n)
})
# Generate summary of data
output$summary<-renderPrint({
summary(Dat)
})
})
I need to prepare a shiny app for a school project.
This is a link of what it is supposed to look like
https://yuvaln.shinyapps.io/olympics/
If you look at the app you see there is a checkbox named medals.When you
open the app they are all selected but in the event the user decides to uncheck them all there should be a small error and no graph should be drawn.
I am having trouble getting to this, when I uncheck all the boxes in my app
it draws an empty drawing
This is the important part of the code:
fluidRow(
column(3,checkboxGroupInput("Medals", label = strong("Medals"),
choices = list("Total" = "TOTAL", "Gold" = 'GOLD',
"Silver" = 'SILVER','Bronze'='BRONZE'),
selected = c('TOTAL','GOLD','SILVER','BRONZE')))),
fluidRow(
mainPanel(plotOutput('coolplot'),width = '40%'))
)
)
server <- function(input, output){output$coolplot<-renderPlot(plot.medals2(input$country,
input$Startingyear,input$Endingyear,input$Medals))}
shinyApp(ui = ui, server = server)
I am using a function plot.medals2 that gets a vector of medals ,start year, ending year, country and returns a drawing of the graph.
Since you didn't post the complete code, I have recreated an example using the Iris data set. I guess the code below answers your question...
library(shiny)
library(ggplot2)
library(dplyr)
ui <- shinyUI(fluidPage(
# Application title
titlePanel("Checkbox example"),
fluidRow(
column(3,checkboxGroupInput("example", label = strong("Species"),
choices = levels(iris$Species),
selected = levels(iris$Species)))),
fluidRow(
mainPanel(plotOutput('coolplot'),width = '40%'))
))
server <- shinyServer(function(input, output) {
irisSubset <- reactive({
validate(
need(input$example != "", 'Please choose at least one feature.')
)
filter(iris, Species %in% input$example)
})
output$coolplot<-renderPlot({
gg <- ggplot(irisSubset(), aes(x = Species, y = Sepal.Length))
gg <- gg + geom_boxplot()
print(gg)
})
})
# Run the application
shinyApp(ui = ui, server = server)
I have a task where i need to build an rShiny app that allows the user to choose which kind of R plotting package is used in-order to display a plot.
Currently the only way i have gotten it to work (semi-decently) is using package specific functions for each package on the server side and using a series of conditional panels on the UI side.
However the problem is that when the user enters the page for the first time then all plots are initialized. Second problem is when the user changes some plot input values and after that chooses another package then the old plot will be displayed until a new plot is created.
Questions:
Is this the only available approach?
I feel that there must be a way to use reactive functions for the package selection?
I feel that it should be possible to use a single rShiny's htmlOutput (or something similar) in the ui and therefore not needing the switchPanel?
I have created a small app to demonstrate my current implementation and both problems:
server.R
library(shiny)
#library(devtools)
#install_github("ramnathv/rCharts")
library(rCharts)
shinyServer(function(input, output) {
names(iris) = gsub("\\.", "", names(iris))
#Render the Generic plot
output$GenericPlot <- renderPlot({
data = iris[0:input$variable,]
plot(data$SepalLength ~ data$SepalWidth)
})
#Render the Polychart plot
output$PolychartPlot <- renderChart({
plotData <- rPlot(SepalLength ~ SepalWidth, data = iris[0:input$variable,], color = 'Species', type = 'point')
plotData$addParams(dom = 'PolychartPlot')
return(plotData)
})
#Render the NDV3 plot
output$NDV3Plot <- renderChart({
plotData <- nPlot(SepalLength ~ SepalWidth, data = iris[0:input$variable,], group = 'Species', type = 'scatterChart')
plotData$addParams(dom = 'NDV3Plot')
return(plotData)
})
})
ui.R
library(shiny)
library(rCharts)
shinyUI(fluidPage(
sidebarLayout(
sidebarPanel(
selectInput("lib", label = "Library:",
choices = list("Generic", "rCharts Polychart", "rCharts NDV3"),
selected = "Generic"
),
numericInput("variable", "Observations:",
min = 5,
max = 150,
value = 10
)
),
mainPanel(
conditionalPanel(
condition = "input.lib == 'Generic'",
h3("Generic plot"),
plotOutput("GenericPlot")
),
conditionalPanel(
condition = "input.lib == 'rCharts Polychart'",
h3("rCharts Polychart plot"),
showOutput("PolychartPlot", "polycharts")
),
conditionalPanel(
condition = "input.lib == 'rCharts NDV3'",
h3("rCharts NDV3 plot"),
showOutput("NDV3Plot", "nvd3")
)
)
)
))
The final version will use a different dataset and more charting packages. The provided code is more of a toy example, with most of the stuff stripped out.
Make a single part in the output part of the app that includes some logic based on the input. For example,
library(shiny)
library(ggplot2)
data(cars)
server <- function(input, output) {output$plot<- renderPlot({
if (input$lib == "base") {
p <- plot(cars$speed, cars$dist)
} else if (input$lib == "ggplot") {
p <- ggplot(cars, aes(x = speed, y = dist)) + geom_point()
}
p
})
}
ui <- fluidPage(
sidebarLayout(
sidebarPanel(
selectInput("lib", "Library: ", choices = list("base", "ggplot"),
selected = "base")
),
mainPanel(plotOutput("plot"))
)
)
shinyApp(ui = ui, server = server)
This provides one plot and as soon as I change the lib option it regenerates.
Found a solution to my problem. The solution is basically to use uiOutput() in the ui.R and move the plotOutput(), showOutput() methods to the server.R.
The solution based on iacobus code:
ui.R
library(shiny)
library(rCharts)
shinyUI(fluidPage(
sidebarLayout(
sidebarPanel(
selectInput("lib", "Library: ", choices = list("base", "ggplot", "Polychart"),
selected = "base")
),
mainPanel(uiOutput("plot"))
)
))
server.R
library(shiny)
library(ggplot2)
library(rCharts)
data(cars)
server <- function(input, output) {
output$plot<- renderUI({
if (input$lib == "base") {
plotOutput("base")
} else if (input$lib == "ggplot") {
plotOutput("ggplot")
} else if (input$lib == "Polychart") {
showOutput("polychart", "polycharts")
}
})
output$base <- renderPlot({
plot(cars$speed, cars$dist)
})
output$ggplot <- renderPlot({
ggplot(cars, aes(x = speed, y = dist)) + geom_point()
})
output$polychart <- renderChart({
p <- rPlot(speed ~ dist, data = cars, type = "point")
p$addParams(dom = 'plot')
p
})
}
The difficulty arose for me, because i assumed that plotOutput(), showOutput() etc methods can only be used in the ui.R. This however is not the case.
EDIT:
It turned out that this was not enough for pollyCharts to work properly along with other rCharts packages.
instead i am using renderUI and rCharts $show to display the chart inline. The following link was helpful for me: https://github.com/ramnathv/rCharts/issues/373. In the ui i'm using htmlOutput