0

I am trying to modify the stockVis app in the shiny tutorial series to plot data using ggplot. The original app also has xts data with daily open, high, low, close (OHLC) data. I am only trying to plot closing value vs Date. I get the following error in my code, "Warning: Error in : data must be a data frame, or other object coercible by fortify(), not an S3 object with class reactiveExpr/reactive"

Edit: After Brian's comment, I edited my call in the ggplot part of the code, but now I am getting the following error message, "Warning: Error in subset.default: argument "subset" is missing, with no default"

Here is my code

#Load libraries
library(shiny)
library(quantmod)
library(ggplot2)

#source helper files
#source("helpers.R")


# Define UI ----
ui <- fluidPage(
  titlePanel("stockVis", "Test Window Title"),
  sidebarLayout(
    sidebarPanel(
      helpText("Input a stock symbol.
               Data will be collected from Yahoo Finance."),
      textInput("symb","Symbol", "SPY"),
      dateRangeInput("dates","Date Range", start="2017-01-01", end=Sys.Date()),
      br(),
      checkboxInput("log","Plot Y-axis on log scale", value = FALSE ),
      checkboxInput("adjust", "Adjust for inflation", value = FALSE),

    ),
    mainPanel(
      "Main Panel",
      plotOutput("plot")
      )
  )

)

# Define server logic ----
server <- function(input, output) {

  dataInput <- reactive({
    getSymbols(
      Symbols= input$symb, 
      src="yahoo", 
      from = input$dates[1], 
      to = input$dates[2],
      auto.assign = FALSE
    )
  })

  badf <- reactive(data.frame(dataInput)) #change xts data to date frame
  baclosedf <- reactive(subset(badf(), select=c(input$symb.Close))) #subset only closing value

  output$plot <- renderPlot({

    p1 <- ggplot(
      data=baclosedf, 
      mapping=aes(x=index(baclosedf), y=baclosedf.Close))+geom_line()+geom_point()
    print(p1)
  })
}

# Run the app ----
shinyApp(ui = ui, server = server)



Edit1:

output$plot <- renderPlot({

    p1 <- ggplot(
      data=baclosedf(), 
      mapping=aes(x=index(baclosedf()), y=baclosedf.Close()))+geom_line()+geom_point()
    print(p1)
  })

user23960
  • 1
  • 1
  • 3
  • Try with `fortify.zoo(dataInput())` – akrun Jan 02 '20 at 16:46
  • Thanks for the response. Sorry, I dont understand which part of the code you wanted me to try that with... – user23960 Jan 02 '20 at 16:49
  • I get an error in your `ui`. please correct the error to test it – akrun Jan 02 '20 at 16:50
  • UI should be fine, i rechecked the pasted code but removed the plot part below and the UI loaded. output$plot <- renderPlot({ p1 <- ggplot( data=baclosedf, mapping=aes(x=index(baclosedf), y=baclosedf.Close))+geom_line()+geom_point() print(p1) }) – user23960 Jan 02 '20 at 16:53
  • For me, I get a bracket missing and it is not working when I added the bracket – akrun Jan 02 '20 at 16:54
  • I get `Error in tag("form", list(...)) : argument is missing, with no default` – akrun Jan 02 '20 at 16:56
  • https://shiny.rstudio.com/tutorial/written-tutorial/lesson6/ that is the original code and I am only modifying the plotting part. Maybe something got truncated while copy pasting? – user23960 Jan 02 '20 at 16:56
  • 1
    Reactives are special function calls. After you define it with `foo<-reactive(...)`, you need to evaluate it in your later code, with `foo()`. So in your ggplot call, it should be `baclosedf()` etc, instead of the bare name. – Brian Jan 02 '20 at 16:57
  • @Brian thank you for writing. I did that and it seemed to have worked. However, I get a new error now. "Error in subset.default: argument "subset" is missing, with no default" – user23960 Jan 02 '20 at 17:02
  • You need to fix your `subset` call to `subset(badf(), ...)` as well. – Brian Jan 02 '20 at 19:22
  • @Brian- I did that, now I am getting "Warning: Error in as.data.frame.default: cannot coerce class ‘c("reactiveExpr", "reactive")’ to a data.frame" – user23960 Jan 02 '20 at 19:35

1 Answers1

1

There are several small but important problems in your code:

  • there is () missing when you transform dataInput as a dataframe
  • the expression you use in subset is not good. It should be c(paste0(input$symb, ".Close")) instead of c(input$symb.Close)
  • this should also be the expression to use when you select this column in the ggplot function: baclosedf()[, paste0(input$symb, ".Close")] instead of baclosedf.Close() (which does not refer to anything).

If you correct this, you can have a graph, but I suppose you want the x-axis to show the date. That is another problem since the function index will not show the dates but just a sequence of numbers: [1] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 [21] 21 22 etc.

Therefore, you need to transform the rownames (which are the dates) as a specific column. This can be made with the rownames_to_column function in the package tibble. Then, you just have to select this new column as your x-axis in ggplot. I added a line to rotate the labels of this axis but it is still unreadable and I suppose it is due to the fact there are more than thee years of data. Reduce the last date and you will see the labels.

Here's the full code:

#Load libraries
library(shiny)
library(quantmod)
library(ggplot2)
library(tibble)

#source helper files
#source("helpers.R")


# Define UI ----
ui <- fluidPage(
  titlePanel("stockVis", "Test Window Title"),
  sidebarLayout(
    sidebarPanel(
      helpText("Input a stock symbol.
               Data will be collected from Yahoo Finance."),
      textInput("symb","Symbol", "SPY"),
      dateRangeInput("dates","Date Range", start="2017-01-01", end=Sys.Date()),
      br(),
      checkboxInput("log","Plot Y-axis on log scale", value = FALSE ),
      checkboxInput("adjust", "Adjust for inflation", value = FALSE),

    ),
    mainPanel(
      "Main Panel",
      plotOutput("plot")
    )
  )

)

# Define server logic ----
server <- function(input, output) {

  dataInput <- reactive({
    getSymbols(
      Symbols= input$symb, 
      src="yahoo", 
      from = input$dates[1], 
      to = input$dates[2],
      auto.assign = FALSE
    )
  })

  badf <- reactive(data.frame(dataInput())) #change xts data to date frame
  baclosedf <- reactive({
    x <- subset(badf(), select=c(paste0(input$symb, ".Close")))
    x <- rownames_to_column(x, "Date")
    }) #subset only closing value

  output$plot <- renderPlot({

   ggplot(
      data=baclosedf(), 
      mapping=aes(x=baclosedf()$Date, y=baclosedf()[, paste0(input$symb, ".Close")], group = 1)) +
      geom_line()+
      geom_point() + 
      theme(axis.text.x = element_text(angle = 90, hjust = 1))
  })
}

# Run the app ----
shinyApp(ui = ui, server = server)

Edit: Based on this answer, I added , group = 1 in ggplot to plot the lines.

bretauv
  • 7,756
  • 2
  • 20
  • 57