1

I would like to ask a question related to renderUI() in the 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)

})
Community
  • 1
  • 1
jazzurro
  • 23,179
  • 35
  • 66
  • 76
  • You have a typo in your first example. `mainPanel(plotOutput("thegraph"))` should be `mainPanel(plotOutput("theGraph"))` – jdharrison Aug 09 '14 at 15:11
  • Ah thank you very much. I now fixed that and see the script is working fine. Then, I now wonder if there is any difference between the two approaches. What would be advantages and disadvantages of using renderUI(), for example? – jazzurro Aug 09 '14 at 17:02
  • `renderUI` is useful for more complicated user interfaces that change on user input. For your example here I dont think `renderUI` is necessary. – jdharrison Aug 09 '14 at 17:08
  • `renderUI` makes sense if you want to dynamically create some input controls, or simply some HTML elements. Say if you want to create a `
      ` 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
  • The answer for my minor question was to use validate(). – jazzurro Aug 12 '14 at 03:39

0 Answers0