How do I get my R Shiny app to stop getting an invalid type (list) for a variable?

109 views Asked by At

Here's the bit of code that I am most concerned with.

server <- function(input, output, session) {
  
  df1 <- reactive({read.csv("input.csv")})
  targets <- reactive({select(df1(), Lease.Sales, Retail.Sales, Net.Margin.Lease, Net.Margin.Retail)})
  drops <- reactive({c("Lease.Sales", "Retail.Sales", "Net.Margin.Lease", "Net.Margin.Retail")})
  df2 <- reactive({df1()[, !(names(df1()) %in% drops())]})
  
  df <- reactive({lapply(df2(), function(x) {
    x <- as.numeric(gsub('[$,]', '', x))
  })})
  
  #x <- reactive({as.matrix(df())})
  #y <- reactive({as.matrix(targets()[1])})
  
  #multivar_reg <- t(cov(y(), x()) %*% solve(cov(x())))
  
  leaseType <- reactive({lm(as.matrix(targets()[1]) ~ as.matrix(df()))$coeff})
  retailType <- reactive({lm(as.matrix(targets()[2]) ~ as.matrix(df()))$coeff})
  leaseMargin <- reactive({lm(as.matrix(targets()[3]) ~ as.matrix(df()))$coeff})
  retailMargin <- reactive({lm(as.matrix(targets()[4]) ~ as.matrix(df()))$coeff})

When it gets to any lm part, in this case any of the lease/retail types/margin, it says the following. invalid type (list) for variable 'as.matrix(df())'

What am I doing wrong here?

1

There are 1 answers

0
r2evans On BEST ANSWER
  • lapply(...) is returning a list, not a data.frame. While there is a form of as.matrix that knows what to do with a data.frame, there is not one that knows what to do with a list. (A data.frame is effectively a list where all its elements are the same length. With this in mind, it is "obviously" rectangular in a sense, so it translates rather directly and unambiguously to a matrix. Unfortunately, a list is not necessarily rectangular, so there is no sane way to make assumptions of converting to a matrix ... so they don't try.)

    You can work around this with as.data.frame(lapply(...)).

  • In case this is not a simplified example (if it is, thank you), then most of your use of reactive is unnecessary, just use df1 <- read.csv(...) and deal with it as a "normal" variable.

    If instead the CSV file may change periodically, then you likely want something like

    df1 <- shiny::reactiveFileReader(3000, session, "input.csv", read.csv)
    

    which will check every 3000 milliseconds for an update to the file (i.e., its modification time). If a change is detected, then it uses read.csv here to read the file; if you have special reading needs, you'll need to update this, perhaps with an anonymous function for special arguments.

    Since this version is still reactive, you'll still use df1() elsewhere.