2
votes

I'm teaching myself Shiny and I am stuck on my ggplot2 graph not being able to use the reactive dateRangeInput as my x-axis. I have a few questions:

  1. Is there a way to use my data frame to grab the min, max values for date range input instead of having to hardcode them in so that when I add more tweets to the data frame I don't have to hardcode the values each time?
  2. I am getting the error: Aesthetics must be either length 1 or the same as the data (33108): x, y when I try to use input$date as my aes(x = input$date...

library(shiny)
library(tidyr)
library(ggplot2)

tweets <- read.csv(file.choose())
colnames(tweets)[1] <- "Content"
tweets <- separate(tweets, created_at, c("Date", "Time"), sep = " ")
tweets$Date <-as.Date(tweets$Date, "%m/%d/%Y")

ui <- fluidPage(
  dateRangeInput(inputId = "date", 
              strong("Date Range"),
              start = "2009-05-04", end = "2018-02-28",
              min = "2009-05-04", max ="2018-02-28" ),
  plotOutput("Graph")
)

server <- function(input, output) {
  output$Graph <- renderPlot({
    ggplot(tweets, aes(x = input$date, y = count)) + 
      geom_bar(stat = "identity", position = "stack") +
      #scale_y_continuous(name = "Retweet Count", limits = c(0,370000), breaks=seq(0,370000,10000)) +
      theme(panel.background = element_rect(fill = "white", colour = "grey50")) 
  })
}

shinyApp(ui = ui, server = server)
2

2 Answers

4
votes

@Pete900's answer summarizes the use of updateDateRangeInput well, for further information you can refer to this part of the shiny documentation.

About your second problem: input$date will return a vector of length 2 with the first element beeing the lower and the second being the upper part of the selected range. You will most likely not use this directly as x-aesthetics but rather subset your data with this and then plot the newly subsettet data. You can e.g. write

library(dpylr) # alternatevly library(tidyverse)
newtweets <- reactive({
filter(tweets, between(date ,input$date[1], input$date[2]))
})

then, in your ggplot, use newtweets() as your data.

Update The functions filter and between() (which is a shortcut for x is greater than ... and lesser then ...) come fromt the package dplyr, which is great for working with dataframes and part of a collection of packages that play very nicely with each other called tidyverse (see here).

When you refer to the newly created reactive object newtweets(), make sure to not forget the paranthesis because it is now a function call, that enables shiny to update the dataframe should the input change.

Update

A full working example in which I create some artificial data:

library(shiny)
library(tidyverse)
library(lubridate)

# tweets <- read.csv(file.choose())

st <- ymd("2009-05-01")
en <- ymd("2018-02-28")
dates <- seq.Date(from = st, to = en, by = 1)
tweets <- tibble(date = dates, count = rnorm(length(dates), mean = 5, sd = 3))


ui <- fluidPage(
    dateRangeInput(inputId = "date",
                   strong("Date Range"),
                   start = "2009-05-04", end = "2018-02-28",
                   min = "2009-05-04", max ="2018-02-28" ),
    plotOutput("Graph")
)

server <- function(input, output) {

    newtweets <- reactive({
        filter(tweets, between(date ,input$date[1], input$date[2]))
    })

    output$Graph <- renderPlot({
        ggplot(newtweets(), aes(x = date, y = count)) +
            geom_bar(stat = "identity", position = "stack") +
            #scale_y_continuous(name = "Retweet Count", limits = c(0,370000), breaks=seq(0,370000,10000)) +
            theme(panel.background = element_rect(fill = "white", colour = "grey50"))
    })
}

shinyApp(ui = ui, server = server)
2
votes

For the first question you can use updateDateRangeInput see here. So you would find your min and max dates in tweets outside of the server function then pass them to the input. Make sure to add session to your function:

server <- function(input, output, session) {

   observe({
    updateDateRangeInput(session, "date", min = myMinDate, max = myMaxDate)
   })
}

For the second question you need to use aes_string to pass variables to ggplot, see here or here.