From 340bb1045624b9c923a2615cb298fc74636a3e18 Mon Sep 17 00:00:00 2001 From: "Dr. K.D. Murray" Date: Fri, 18 Aug 2023 08:25:12 +0200 Subject: [PATCH] update tecananalyze --- platemate/tecanalyze/app.R | 155 ++++++++++++++++++++++++------------- 1 file changed, 102 insertions(+), 53 deletions(-) diff --git a/platemate/tecanalyze/app.R b/platemate/tecanalyze/app.R index 72ade6e..a6a5d36 100644 --- a/platemate/tecanalyze/app.R +++ b/platemate/tecanalyze/app.R @@ -9,29 +9,31 @@ ui <- fluidPage( fluidRow(wellPanel( numericInput("nplates", "How many plates:", 1), - checkboxInput("intercept", "Use an intercept in linear prediction model?", FALSE), + checkboxInput("intercept", "Use an intercept in linear prediction model?", TRUE), + checkboxInput("includestds", "Include standards in output table?", FALSE), + checkboxInput("stdperplate", "Use standards only from each plate to quantify each plate", TRUE), splitLayout( - numericInput("concA", "[Std A]:", 40, width="100px"), - numericInput("concB", "[Std B]:", 32, width="100px"), - numericInput("concC", "[Std C]:", 24, width="100px"), - numericInput("concD", "[Std D]:", 20, width="100px"), - numericInput("concE", "[Std E]:", 16, width="100px"), - numericInput("concF", "[Std F]:", 8, width="100px"), - numericInput("concG", "[Std G]:", 4, width="100px"), - numericInput("concH", "[Std H]:", 0, width="100px"), + numericInput("concA", "[Std A]:", 0, width="100px"), + numericInput("concB", "[Std B]:", 4, width="100px"), + numericInput("concC", "[Std C]:", 8, width="100px"), + numericInput("concD", "[Std D]:", 16, width="100px"), + numericInput("concE", "[Std E]:", 20, width="100px"), + numericInput("concF", "[Std F]:", 24, width="100px"), + numericInput("concG", "[Std G]:", 32, width="100px"), + numericInput("concH", "[Std H]:", 40, width="100px"), actionButton("reverse", "Reverse Standards"), ) )), uiOutput("plates"), fluidRow(wellPanel( actionButton(inputId="enter",label="Convert"), + downloadButton("dlBtn"), tableOutput("outtbl"), plotOutput("standardsPlot"), verbatimTextOutput("stdmdltxt") )) ) - server <- function(input, output, session) { observeEvent(input$reverse, { for (i in 1:4) { @@ -48,13 +50,21 @@ server <- function(input, output, session) { output$plates = renderUI(lapply(seq_len(input$nplates), function(i) { ti = textInput(sprintf("plate%d_name", i), "Plate Name", "") ht = rHandsontableOutput(sprintf("plate%d_hot", i)) + msg=tags$p("In the bottom status row, write EXACTLY 'STD' to mark a column as the standard column, or the name of another plate to mark that this is the standard column from that plate") cb = checkboxGroupInput(sprintf("plate%d_stds", i), "Standard column(s)", choices=as.character(1:12), inline=T) - fluidRow(wellPanel(ti, ht,cb)) + col1s = fluidRow(wellPanel( + tags$p("If this is a 'column 1s' plate, which plate name does each column belong to?"), + splitLayout( + textInput("col1of1", "1", ""), textInput("col1of2", "2", ""), textInput("col1of3", "3", ""), textInput("col1of4", "4", ""), + textInput("col1of5", "5", ""), textInput("col1of6", "6", ""), textInput("col1of7", "7", ""), textInput("col1of8", "8", ""), + textInput("col1of9", "9", ""), textInput("col1of10", "10", ""), textInput("col1of11", "11", ""), textInput("col1of12", "12", ""), + ), width="800px")) + fluidRow(wellPanel(ti, ht, msg))#,cb, col1s)) })) for(i in seq_len(input$nplates)) { local({ - DF=as.data.frame(matrix("", nrow=8, ncol=12)) + DF=as.data.frame(matrix("", nrow=9, ncol=12)) colnames(DF) = as.character(1:12) - rownames(DF) = LETTERS[1:8] + rownames(DF) = c(LETTERS[1:8], "STATUS") intbl=renderRHandsontable(rhandsontable(DF, readOnly=F)) output[[sprintf("plate%d_hot", i)]] <- intbl })} @@ -64,54 +74,93 @@ server <- function(input, output, session) { data = do.call("bind_rows", lapply(seq_len(input$nplates), function(i){ local({ pname = input[[sprintf("plate%d_name", i)]] - d = hot_to_r(input[[sprintf("plate%d_hot", i)]]) %>% - mutate(row=LETTERS[1:8]) %>% - pivot_longer(!c("row")) %>% - transmute(plate_name=pname, well=sprintf("%s%02d", row, as.integer(name)), value, col=name, row) - d + d = hot_to_r(input[[sprintf("plate%d_hot", i)]]) + rownames(d) = c(LETTERS[1:8], "status") + pl = d %>% + t() %>% + as.data.frame() %>% + rownames_to_column("col") %>% + pivot_longer(LETTERS[1:8]) %>% + transmute(plate_name=pname, col=as.integer(col), row=name, well=sprintf("%s%02d", name, col), value, + status=sub("^\\s+|\\s+$", "", status, perl=T)) + pl }) })) - stds = do.call("bind_rows", lapply(seq_len(input$nplates), function(i){ - local({ - if (length(input[[sprintf("plate%d_stds", i)]]) > 0) { - return(data.frame(plate_name=input[[sprintf("plate%d_name", i)]], - std_cols=input[[sprintf("plate%d_stds", i)]])) - } - })})) - - std_concs = do.call("bind_rows", lapply(LETTERS[1:8], function(w) { - local({ - data.frame(well=w, conc=input[[sprintf("conc%s", w)]]) - }) - })) - data = mutate(data, value=as.numeric(value)) - - std = left_join(stds, data, by=c("plate_name", "std_cols"="col")) %>% - left_join(std_concs, by=c("row"="well")) %>% - mutate(conc=as.numeric(conc), value=as.numeric(value)) - - - if (input$intercept) { - m = lm(conc ~ value, data=std) + + if (input$stdperplate) { + data$std_group=data$plate_name } else { - m = lm(conc ~ 0 + value, data=std) + data$std_group="everything" } - + stdconc = local({ + x = data.frame(row=LETTERS[1:8]) + x$conc = sapply(x$row, function(l) as.numeric(input[[sprintf("conc%s", l)]])) + x + }) + data2 = data %>% - transmute(plate_name, well, rfu=value, conc=predict(m, data)) %>% - filter(!is.na(rfu)) %>% - mutate(conc = ifelse(conc < 0, 0, conc)) + mutate(value=as.numeric(value)) %>% + group_by(std_group) %>% + group_modify( + function(df, key) { + stds = df %>% + filter(status=="STD") %>% + left_join(stdconc, by="row") + if (input$intercept) { + m = lm(conc ~ value, data=stds) + } else { + m = lm(conc ~ 0 + value, data=stds) + } + print(summary(m)) + res = df %>% + mutate( + conc=pmax(predict(m, df), 0), + r2=summary(m)$adj.r.squared, + ) + return(res) + }) %>% + ungroup() + + nonstd = data2 %>% + filter(is.na(status) | status == "") + stds = data2 %>% + filter(status=="STD") %>% + group_by(plate_name, status) %>% + summarise(col=unique(col)) + colstds = data2 %>% + filter(status %in% data2$plate_name) + + corrected_stdcols = colstds %>% + group_by(plate_name, status) %>% + summarise(src_col=unique(col)) %>% + ungroup() %>% + rename(src_plate=plate_name) %>% + left_join(stds, ., by=c("plate_name"="status")) %>% + filter(!is.na(src_plate)) %>% + left_join(colstds, by=c("src_plate"="plate_name", "src_col"="col")) %>% + mutate(well=sprintf("%s%02d", row, col)) - output$standardsPlot = renderPlot( - ggplot(std, aes(conc, value)) + - geom_point(data=std) + - geom_point(aes(conc, rfu), colour="red", data=data2) + - labs(x="Conc (ng/uL)", y="RFU", title="Standard Curve") + - theme_classic() + if (input$includestds) { + stds_fortbl = data2 %>% + filter(status=="STD") %>% + group_by(plate_name) %>% + mutate(col=NA, well=sprintf("std_%s_%i", row, stdconc[match(row, stdconc$row),"conc"])) + data3 = bind_rows(nonstd, corrected_stdcols, stds_fortbl) + } else { + data3 = bind_rows(nonstd, corrected_stdcols) + } + data3 = data3 %>% + select(plate_name, row, col, well, value, conc, r2) %>% + filter(!is.na(value)) %>% + arrange(plate_name, col, row) %>% + select(-row, -col) + + output$dlBtn <- downloadHandler( + filename = function(){"plates.csv"}, + content = function(fname){ write_csv(data3, fname, na="") } ) - output$stdmdltxt = renderPrint(summary(m)) - output$outtbl=renderTable(data2) + output$outtbl=renderTable(data3) }) }