I would like to ask a question related to renderUI() in the shiny package. I created a shiny application, which allows users to upload a data file and filter the data. Based on the filter, my shiny application creates a ggplot2 graphic.
Data
My data file looks something like this. In order to give you some ideas, I leave the following code. Please note that all columns are in character here.
user_id <- round(runif(100, 1, 100))
latitude <- runif(100, 0.0, 90.0)
longitude <- runif(100, 0.0, 180.0)
dates <- rep(c("2014-07-01", "2014-07-02"), each = 50, length = 100)
foo <- data.frame(cbind(user_id, latitude, longitude, dates), stringsAsFactors = FALSE)
Initial attempt (failure)
I wrote the folioing server.R and ui.R. They allow me to upload a data file. But, R does not filter the data and create a graphic. There was no error message.
server.R
library(shiny)
library(data.table)
library(plyr)
library(dplyr)
library(ggplot2)
shinyServer(function(input,output) {
### Let users to choose and upload a file.
dataSet <- reactive({
if (is.null(input$file1)) {
return(NULL)
}
fread(input$file1$datapath)
})
### Now I want to create a chunk of code which filters a date set using date information
ana <- reactive({
if (is.null(dataSet)){
return(NULL)
}
dataSet() %>%
filter(dates >= input$inVar2[1], dates <= input$inVar2[2]) %>%
group_by(user_id, dates) %>%
summarize(count = n())
})
output$theGraph <- renderPlot ({
theGraph <- ggplot(ana(), aes(factor(format(dates, format = "%m%d")), count)) +
geom_boxplot() +
xlab("Dates") +
ylab("Appliacation usage (times)") +
ggtitle("How many times did each user use the app each day?")
print(theGraph)
})
})
ui.R
library(shiny)
shinyUI(fluidPage(
titlePanel("Test"),
sidebarLayout(
sidebarPanel(
fileInput("file1", "Choose file to upload",
accept = c(
"text/csv",
"text/comma-separated-values",
"text/tab-separated-values",
"text/plain",
".csv",
".tsv"
)),
dateRangeInput("inVar2", label = "Date range",
start = "2014-07-01", end = "2014-07-10")
),
mainPanel(plotOutput("theGraph"))
)
))
Second attempt (success)
I searched around on stack overflow and found the following two posts, which actually helped me write even the previous server.R. I'd like to say thank you to the contributors. Once, I read them carefully, I realized that I would probably need to use renderUI() in order to create the application I wanted. The solution was to use renderUI() and put dateRangeInput() inside of it.
The two links
shiny r: numericInput from the uploaded data
R shiny passing reactive to selectInput choices
server.R
library(shiny)
library(data.table)
library(dplyr)
library(ggplot2)
shinyServer(function(input, output) {
### Let users choose and upload a file.
dataSet <- reactive({
if (is.null(input$file1)) {
return(NULL)
}
fread(input$file1$datapath)
})
### Let users choose a date range.
output$inVar2 <- renderUI({
if (is.null(dataSet)) {
return(NULL)
}
dateRangeInput("inVar2", label = h3("Date range"),
start = "2014-07-01", end = "2014-07-10")
})
### Based on the date range, filter the data.
ana <- reactive({
if (is.null(dataSet)) {
return(NULL)
}
dataSet() %>%
filter(dates >= input$inVar2[1], dates <= input$inVar2[2]) %>%
group_by(user_id, dates) %>%
summarize(count = n())
})
### Draw a graphic
output$theGraph <- renderPlot ({
print(ana())
theGraph <- ggplot(ana(), aes(factor(format(dates, format = "%m%d")), count)) +
geom_boxplot() +
ggtitle("How many times did each user\n use the app each day?") +
xlab("Dates") +
ylab("Appliacation usage\n (times)") +
theme(plot.title = element_text(size = 25, lineheight=.8, face="bold")) +
theme(axis.text.x = element_text(angle=90, color = "black", face = "bold", size = 10)) +
theme(axis.title.x = element_text(face="bold", color = "black", size=20)) +
theme(axis.title.y = element_text(face="bold", color = "black", size=20))
print(theGraph)
})
})
ui.R
shinyUI(
fluidPage(
titlePanel("Application usage summary"),
plotOutput("theGraph"),
hr(),
fluidRow(
column(3,
fileInput("file1", h3("Choose file to upload"),
accept = c(
"text/csv",
"text/comma-separated-values",
"text/tab-separated-values",
"text/plain",
".csv",
".tsv")
)),
column(3,
uiOutput("inVar2"))
)
))
I am happy to see my shiny application working. But, I would like to know why my first attempt was not right. If you upload files before 'shinyServer(function(input, output) {' part, I think that my first approach works. But, it seems that whenever you allow users to upload a file, you somehow need renderUI().
Main question
Is there any way which I can create my type of applications using my first approach (failure approach)? If there are ways, what would they be? If there isn't any, I would like to know more about renderUI(), which seems to need more information in the CRAN manual at this point.
Minor question
When I run this application, I see this error message before uploading a file. It disappears once a data file is uploaded. (This is solved. A typo cost the whole script.)
Error: no applicable method for 'filter' applied to an object of class "NULL"
The answer to this question was to use validate.
dataSet <- reactive({
validate(
need(input$file1 != "", "Please select a data set")
)
fread(input$file1$datapath)
})
` list then you can use `renderUI`. If you simply want to update the parameters of an input control (say, range of a `sliderInput`), you can always use `updateXxxInput` rather than calling `renderUI`.
– Xin Yin Aug 09 '14 at 19:35