rggplot2shinytidyquant

How to add a date range to ggplot in Rshiny?


I am making a shiny app to generate stock price plots. I want to generate plots given a certain date range, but I get the error "argument 1 is not a vector" whenever I try to adjust the dates. If I remove the "daterangeinput" part from my app, everything works fine. I have attached my code + data.

Run the section below to get the data.

library(tidyquant)
library(tidyverse)
library(shiny)
library(shinyWidgets)
library(shinythemes)
library(plotly)

sp500_names <- tq_index("SP500") %>% 
  slice_head(n = 10) %>% 
  select(symbol, company)

tickers <- sp500_names[,1]

prices <- tq_get(tickers, 
                 get = "stock.prices",
                 from = today() - months(24),
                 to = today(), 
                 complete_cases = F) %>% 
    select(symbol, date, close)

Code for shiny app:

ui <- fluidPage(
              
        # Title
        titlePanel("Stock Price Visualization and Forecasting"),
        
        # Sidebar
        sidebarLayout(
          sidebarPanel(width = 3,
                         pickerInput(
                         inputId = "stocks",
                         label = h4("Pick a stock"),
                         choices = tickers$symbol,
                         selected = tickers,
                         options = list(`actions-box` = TRUE),
                         multiple = T),
                       
                         # Date input
                         dateRangeInput("daterange", "Pick a Time Period",
                                  # value = today(),
                                  min = today() - months(23),
                                  max = today())),
                 
          # Plot results
          mainPanel(
            plotlyOutput("plot",height=600)
          )
        )
)



server <- function(input, output, session) {
          
            
            # Server logic based on user inputs
  
            observeEvent(input$stocks,{
              
              prices <- prices %>% 
                dplyr::filter(symbol %in% input$stocks) %>% 
                filter(date > input$daterange[1] & date <= input$daterange[2])
              
          # Create plot
  
  output$plot <- renderPlotly({
    print(
      ggplotly(prices %>% 
                 ggplot(aes(date, close, color = symbol)) + 
                 geom_line(size = 1, alpha = 0.9)+
                 theme_minimal(base_size=16) +
                 theme(axis.title=element_blank(),
                       plot.background = element_rect(fill = "white"),
                       panel.background = element_rect(fill="grey"),
                       panel.grid = element_blank(),
                       legend.text = element_text(colour="black"))
               )
             )
       })
  })   
}

shinyApp(ui, server)


Solution

  • The issue is that you have not set any start and end dates for the date range and your apps does not take care of that. Hence an easy fix would be to simply set a default start and end date. Additionally IMHO I don't see any reason for an observeEvent. Instead I would suggest to use a reactive to filter your data based on user inputs, which could then be used for plotting:

    library(tidyquant)
    library(tidyverse)
    library(shiny)
    library(shinyWidgets)
    library(shinythemes)
    library(plotly)
    
    ui <- fluidPage(
      # Title
      titlePanel("Stock Price Visualization and Forecasting"),
      # Sidebar
      sidebarLayout(
        sidebarPanel(
          width = 3,
          pickerInput(
            inputId = "stocks",
            label = h4("Pick a stock"),
            choices = tickers$symbol,
            selected = tickers,
            options = list(`actions-box` = TRUE),
            multiple = T
          ),
          # Date input
          dateRangeInput("daterange", "Pick a Time Period",
            # value = today(),
            start = min(prices$date),
            end = today(),
            min = min(prices$date),
            max = today()
          )
        ),
        # Plot results
        mainPanel(
          plotlyOutput("plot", height = 600)
        )
      )
    )
    
    server <- function(input, output, session) {
      prices_filtered <- reactive({
        req(input$stocks)
        prices %>%
          dplyr::filter(symbol %in% input$stocks) %>%
          filter(date > input$daterange[1] & date <= input$daterange[2])
      })
      
      output$plot <- renderPlotly({
        req(input$stocks)
        g <- ggplot(prices_filtered(), aes(date, close, color = symbol)) +
          geom_line(size = 1, alpha = 0.9) +
          theme_minimal(base_size = 16) +
          theme(
            axis.title = element_blank(),
            plot.background = element_rect(fill = "white"),
            panel.background = element_rect(fill = "grey"),
            panel.grid = element_blank(),
            legend.text = element_text(colour = "black")
          )
        ggplotly(g)
      })
    }
    
    shinyApp(ui, server)
    

    enter image description here