0

I'm creating an app that takes a .csv file and spits out concentration values after doing some analysis on the back end. The analysis involves running a 5-parameter logistic curve using the drc() package and then storing the model coefficients to use in a function, which is where I'm running into trouble. It either doesn't recognize the argument I'm passing through the function, or it doesn't recognize the variables.

The following data can be written as a .csv file and then used in the app for a reproducible example.

smpdata <- structure(list(Sample = c("Std 0", "Std 0", "Std 1", "Std 1", 
"Std 2", "Std 2", "Std 3", "Std 3", "Std 4", "Std 4"), Absorbance = c(0.854, 
0.876, 0.736, 0.736, 0.551, 0.569, 0.46, 0.414, 0.312, 0.307), 
    Concentration = c(0, 0, 0.05, 0.05, 0.15, 0.15, 0.4, 0.4, 
    1.5, 1.5)), row.names = c(NA, 10L), class = "data.frame")


library(dplyr)
library(tidyverse)
library(drc)
library(shiny)

# function that I need to calculate concentration values
concentration <- function(y){
  
  c*(((a-d)/(y-d))^(1/m)-1)^(1/b)
}

# User uploads the .csv file

ui <- fluidPage(
  titlePanel("Microcystin Concentrations from ELISA using 5 PL Curve"),
  fluidRow(
    h4("Upload Data"),
    column(6,
           fileInput("file", "Choose CSV File",
                     multiple = F,
                     accept = c("text/csv",
                                "text/comma-separated-values,text/plain",
                                ".csv"),
                     placeholder = "CSV files only",
                     width = "100%"))),
# Results from data are shown in a table in the server
  fluidRow(
    h4("Results"),
    column(6,
           verbatimTextOutput("results"))))
)

server <- function(input, output, session) {
  
  data <- reactive({
    req(input$file)
    read.csv(input$file$datapath)
  })
  
  dt <- reactive({
    data() %>%
    filter(!Absorbance == 0) %>%
    group_by(Sample) %>%
    mutate(Mean_Absorbance = mean(Absorbance)) %>%
    distinct(Sample, .keep_all = T) %>%
    dplyr::select(Type, Sample, Mean_Absorbance, Concentration)})
  
  
  stds <- reactive({dt() %>%
      filter(Type == "Standard")})
  
  fiveplc <- reactive({drm(Mean_Absorbance ~ Concentration, data=stds(),
                 fct = LL.5(names = c("b", "d", "a", "c", "e")))})
  
  sum.fiveplc <- reactive({summary(fiveplc())})

# THIS IS WHERE THE APP STOPS WORKING
  output$results <- renderTable({
    
    b <- sum.fiveplc()$coefficients[1] # store model coefficients to variables
    d <- sum.fiveplc()$coefficients[2]
    a <- sum.fiveplc()$coefficients[3]
    c <- sum.fiveplc()$coefficients[4]
    m <- sum.fiveplc()$coefficients[5]
    
    dt()$NewConcentration <- concentration(dt()$Mean_Absorbance)
    
    dt()
  
  })

}

shinyApp(ui, server)

I keep getting errors, in this example, the error is Error: object 'd' not found. I have tried all kinds of different formats, including putting the function within the server as a reactive, but then I got the error Error: unused argument (dt()$Mean_Absorbance).

Can anyone sense what is going on wrong here?

Any help would be vastly appreciated. Thank you so much.

1 Answers1

0

Functions can look up values from their lexical scope (where they were defined), but not from their dynamic scope (environment where they are called).

You should define the coefficients as parameters to your function:

concentration <- function(y, a, b, c, d, m) {
  c * (((a - d) / (y - d)) ^ (1 / m) - 1) ^ (1 / b)
}

Then pass the fitted coefficients as arguments like so:

b <- sum.fiveplc()$coefficients[1] # store model coefficients to variables
d <- sum.fiveplc()$coefficients[2]
a <- sum.fiveplc()$coefficients[3]
c <- sum.fiveplc()$coefficients[4]
m <- sum.fiveplc()$coefficients[5]

result <- dt()
result$NewConcentration <- concentration(dt()$Mean_Absorbance, a, b, c, d, m)
result
Mikko Marttila
  • 10,972
  • 18
  • 31
  • Thank you so much! I tried that, but the error I got was "invalid (NULL) left side of assignment." Did you keep the concentration where it was, or did you put it in the renderTable() ? I tried it both ways and still got the error, but maybe I need to put it elsewhere? – Kansas Keeton May 30 '23 at 20:34
  • Ah sorry about that, I didn't notice another issue; you can't modify the reactive `dt()` by assigning a new column to it like you would a regular data frame. I've updated accordingly. – Mikko Marttila May 30 '23 at 20:40
  • Ahhh you're amazing! Thank you so so much for taking the time to help me, learning you can't modify reactive data frames was exactly what I needed to know but I didn't know what I didn't know. Thank you again! – Kansas Keeton May 30 '23 at 20:55
  • Happy to help! And yeah, learning about reactivity in Shiny can be a bit tricky as it's not so easy to just try interactively how things work. – Mikko Marttila May 30 '23 at 21:00