commit
67544a10e6
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -0,0 +1,2 @@
|
||||
^.*\.Rproj$
|
||||
^\.Rproj\.user$
|
@ -0,0 +1,159 @@
|
||||
library(GCAT)
|
||||
library(GCAT)
|
||||
library(GCAT)
|
||||
source('~/Documents/GCAT4_old/trunk/R/GCAT/R/addingParams.R')
|
||||
library(GCAT)
|
||||
source('~/Documents/GCAT4_old/trunk/R/GCAT/R/addingParams.R')
|
||||
t
|
||||
warnings()
|
||||
library(GCAT)
|
||||
source('~/Documents/GCAT4_old/trunk/R/GCAT/R/addingParams.R')
|
||||
warnings()
|
||||
library(GCAT)
|
||||
source('~/Documents/GCAT4_old/trunk/R/GCAT/R/addingParams.R')
|
||||
warnings()
|
||||
library(GCAT)
|
||||
source('~/Documents/GCAT4_old/trunk/R/GCAT/R/addingParams.R')
|
||||
library(GCAT)
|
||||
library(GCAT)
|
||||
library("GCAT")
|
||||
library("codetools")
|
||||
checkUsagePackage("GCAT")
|
||||
library(GCAT)
|
||||
library(GCAT)
|
||||
source('~/Documents/GCAT4/trunk/R/GCAT/R/addingParams.R')
|
||||
source('~/Documents/GCAT4/trunk/R/GCAT/R/addingParams.R')
|
||||
t
|
||||
checkUsagePackage("GCAT")
|
||||
library("codetoolds")
|
||||
library("codetoolss")
|
||||
library("codetools")
|
||||
checkUsagePackage("GCAT")
|
||||
library(GCAT)
|
||||
library("codetools")
|
||||
source('~/Documents/GCAT4/trunk/R/GCAT/R/addingParams.R')
|
||||
t
|
||||
checkUsagePackage("GCAT")
|
||||
library(GCAT)
|
||||
source('~/Documents/GCAT4/trunk/R/GCAT/R/fit.model.R')
|
||||
library(GCAT)
|
||||
checkUsagePackage("GCAT")
|
||||
source('~/Documents/GCAT4/trunk/R/GCAT/R/addingParams.R')
|
||||
t
|
||||
checkUsagePackage("GCAT")
|
||||
source('~/Documents/GCAT4/trunk/R/GCAT/R/class.model.R')
|
||||
library(GCAT)
|
||||
checkUsagePackage("GCAT")
|
||||
library(GCAT)
|
||||
checkUsagePackage("GCAT")
|
||||
library(GCAT)
|
||||
checkUsagePackage("GCAT")
|
||||
?? checkusagePackage
|
||||
checkUsagePackage("GCAT", all + T)
|
||||
checkUsagePackage("GCAT", all = T)
|
||||
checkUsagePackage("GCAT")
|
||||
checkUsagePackage("GCAT")
|
||||
source('~/Documents/GCAT4/trunk/R/GCAT/R/plot.fit.R')
|
||||
library(GCAT)
|
||||
checkUsagePackage("GCAT")
|
||||
library(GCAT)
|
||||
source('~/Documents/GCAT4/trunk/R/GCAT/R/addingParams.R')
|
||||
t
|
||||
t
|
||||
library(GCAT)
|
||||
source('~/Documents/GCAT4/trunk/R/GCAT/R/addingParams.R')
|
||||
t
|
||||
library(GCAT)
|
||||
source('~/Documents/GCAT4/trunk/R/GCAT/R/addingParams.R')
|
||||
t
|
||||
library(GCAT)
|
||||
source('~/Documents/GCAT4/trunk/R/GCAT/R/addingParams.R')
|
||||
t
|
||||
source('~/Documents/GCAT4/trunk/R/GCAT/R/plot.fit.R')
|
||||
library(GCAT)
|
||||
source('~/Documents/GCAT4/trunk/R/GCAT/R/plot.fit.R')
|
||||
source('~/Documents/GCAT4/trunk/R/GCAT/R/addingParams.R')
|
||||
t
|
||||
library(GCAT)
|
||||
source('~/Documents/GCAT4/trunk/R/GCAT/R/addingParams.R')
|
||||
t
|
||||
library(GCAT)
|
||||
library(GCAT)
|
||||
source('~/Documents/GCAT4/trunk/R/GCAT/R/addingParams.R')
|
||||
t
|
||||
library(GCAT)
|
||||
library(GCAT)
|
||||
library(GCAT)
|
||||
library(GCAT)
|
||||
source('~/Documents/GCAT4/trunk/R/GCAT/R/table2well.R')
|
||||
source('~/Documents/GCAT4/trunk/R/GCAT/R/addingParams.R')
|
||||
library(GCAT)
|
||||
library(GCAT)
|
||||
source('~/Documents/GCAT4/trunk/R/GCAT/R/addingParams.R')
|
||||
t
|
||||
library(GCAT)
|
||||
library(GCAT)
|
||||
library(GCAT)
|
||||
source('~/Documents/GCAT4/trunk/R/GCAT/R/addingParams.R')
|
||||
t
|
||||
library(GCAT)
|
||||
source('~/Documents/GCAT4/trunk/R/GCAT/R/addingParams.R')
|
||||
t
|
||||
library(GCAT)
|
||||
library(GCAT)
|
||||
library(GCAT)
|
||||
source('~/Documents/GCAT4/trunk/R/GCAT/R/addingParams.R')
|
||||
t
|
||||
library("codetools")
|
||||
library("GCAT")
|
||||
checkUsagePackage(GCAT)
|
||||
checkUsagePackage("GCAT)
|
||||
checkUsagePackage("GCAT")
|
||||
checkUsagePackage("GCAT")
|
||||
library(GCAT)
|
||||
source('~/Documents/GCAT4/trunk/R/GCAT/R/addingParams.R')
|
||||
t
|
||||
library(GCAT)
|
||||
source('~/Documents/GCAT4/trunk/R/GCAT/R/addingParams.R')
|
||||
t
|
||||
library(GCAT)
|
||||
source('~/Documents/GCAT4/trunk/R/GCAT/R/addingParams.R')
|
||||
t
|
||||
library(GCAT)
|
||||
source('~/Documents/GCAT4/trunk/R/GCAT/R/addingParams.R')
|
||||
t
|
||||
checkUsagePack(GCAT)
|
||||
checkUsagePackage(GCAT)
|
||||
checkUsagePackage("GCAT")
|
||||
library(GCAT)
|
||||
library(GCAT)
|
||||
library(GCAT)
|
||||
library(GCAT)
|
||||
source('~/Documents/GCAT4/trunk/R/GCAT/R/normalize.and.transform.R')
|
||||
library(GCAT)
|
||||
library(GCAT)
|
||||
library(GCAT)
|
||||
library(GCAT)
|
||||
library(GCAT)
|
||||
library(GCAT)
|
||||
library(GCAT)
|
||||
source('~/Documents/GCAT4/trunk/R/GCAT/R/plot.fit.R')
|
||||
library(GCAT)
|
||||
library(GCAT)
|
||||
library(GCAT)
|
||||
?? plot
|
||||
? plot
|
||||
library(GCAT)
|
||||
library(GCAT)
|
||||
library(GCAT)
|
||||
library(GCAT)
|
||||
library(GCAT)
|
||||
library(GCAT)
|
||||
library(GCAT)
|
||||
library(GCAT)
|
||||
library(GCAT)
|
||||
library(GCAT)
|
||||
library("codetools")
|
||||
checkPackageUsage("GCAT")
|
||||
checkUsagePackage("GCAT")
|
||||
checkUsagePackage("GCAT", all = T)
|
@ -0,0 +1,4 @@
|
||||
auto_roxygenize_for_build_and_reload="1"
|
||||
auto_roxygenize_for_build_package="1"
|
||||
auto_roxygenize_for_check="1"
|
||||
makefile_args=""
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -0,0 +1,16 @@
|
||||
{
|
||||
"contents" : "#Copyright 2012 The Board of Regents of the University of Wisconsin System.\n#Contributors: Jason Shao, James McCurdy, Enhai Xie, Adam G.W. Halstead, \n#Michael H. Whitney, Nathan DiPiazza, Trey K. Sato and Yury V. Bukhman\n#\n#This file is part of GCAT.\n#\n#GCAT is free software: you can redistribute it and/or modify\n#it under the terms of the GNU Lesser General Public License as published by\n#the Free Software Foundation, either version 3 of the License, or\n#(at your option) any later version.\n#\n#GCAT is distributed in the hope that it will be useful,\n#but WITHOUT ANY WARRANTY; without even the implied warranty of\n#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n#GNU Lesser General Public License for more details.\n#\n#You should have received a copy of the GNU Lesser General Public License \n#along with GCAT. If not, see <http://www.gnu.org/licenses/>.\n\n# Wrapper for sapply to use lapply over an array, conserving the dimensions.\naapply = function(x, FUN,...){\n dim.values = dim(x)\n\tdim.names = dimnames(x)\n\tx = lapply(x, function(x){FUN(x,...)})\n\tdim(x) = dim.values\n\tdimnames(x) = dim.names\n\treturn(x)\n\t}\n\n# A function to manually create an unchecked exception.\nexception = function(class, msg)\n{\n cond <- simpleError(msg)\n class(cond) <- c(class, \"MyException\", class(cond))\n stop(cond)\n}\n",
|
||||
"created" : 1425413273698.000,
|
||||
"dirty" : false,
|
||||
"encoding" : "UTF-8",
|
||||
"folds" : "",
|
||||
"hash" : "3044086993",
|
||||
"id" : "4E20D973",
|
||||
"lastKnownWriteTime" : 1424208963,
|
||||
"path" : "~/Documents/GCAT4/trunk/R/GCAT/R/misc.R",
|
||||
"project_path" : "R/misc.R",
|
||||
"properties" : {
|
||||
},
|
||||
"source_on_save" : false,
|
||||
"type" : "r_source"
|
||||
}
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -0,0 +1,16 @@
|
||||
{
|
||||
"contents" : "# Default NAMESPACE created by R\n# Remove the previous line if you edit this file\n\n# Export all names\nexportPattern(\".\")\n\n# Import all packages listed as Imports or Depends\nimport(\"pheatmap\", \"gplots\")\n",
|
||||
"created" : 1428439772005.000,
|
||||
"dirty" : false,
|
||||
"encoding" : "UTF-8",
|
||||
"folds" : "",
|
||||
"hash" : "749067415",
|
||||
"id" : "907B51DB",
|
||||
"lastKnownWriteTime" : 1423260997,
|
||||
"path" : "~/Documents/GCAT4/trunk/R/GCAT/NAMESPACE",
|
||||
"project_path" : "NAMESPACE",
|
||||
"properties" : {
|
||||
},
|
||||
"source_on_save" : false,
|
||||
"type" : "r_namespace"
|
||||
}
|
@ -0,0 +1,16 @@
|
||||
{
|
||||
"contents" : "#Copyright 2012 The Board of Regents of the University of Wisconsin System.\n#Contributors: Jason Shao, James McCurdy, Enhai Xie, Adam G.W. Halstead,\n#Michael H. Whitney, Nathan DiPiazza, Trey K. Sato and Yury V. Bukhman\n#\n#This file is part of GCAT.\n#\n#GCAT is free software: you can redistribute it and/or modify\n#it under the terms of the GNU Lesser General Public License as published by\n#the Free Software Foundation, either version 3 of the License, or\n#(at your option) any later version.\n#\n#GCAT is distributed in the hope that it will be useful,\n#but WITHOUT ANY WARRANTY; without even the implied warranty of\n#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n#GNU Lesser General Public License for more details.\n#\n#You should have received a copy of the GNU Lesser General Public License \n#along with GCAT. If not, see <http://www.gnu.org/licenses/>.\n########################################################################\n# #\n# <model> class definition and functions. Objects contain equations #\n# and other information for parameterized growth curve models. #\n# #\n########################################################################\nsetClass(\"model\", representation(name = \"character\",\n expression = \"expression\",\n formula = \"formula\",\n guess = \"function\"))\n# Slots:\n# name - a simple description of the model.\n# expression - an object of class \"expression\" that evaluates the response (transformed OD) with respect to the variable Time.\n# formula - same as expression, but with y as the response.\n# guess - a function that computes initial guesses for the parameters given a well object with a valid \"screen.data\" slot\n# containing useable OD values and slope estimates\n# --------------------------------------------------------------------\n###################### BEGIN PROTOTYPING ACCESSOR METHODS##############\n\n# Minh: Let this code fragment be F1.\nif (!isGeneric(\"getName\")){\n if (is.function(\"getName\"))\n fun <- getName\n else\n fun <- function(object) standardGeneric(\"getName\")\n setGeneric(\"getName\", fun)\n}\n# End of F1\nsetMethod(\"getName\", \"model\", function(object) object@name)\n\n# Minh: Let this line be F2.\nsetGeneric(\"getExpression\", function(object){standardGeneric(\"getExpression\")})\n# Question: How is F1 different from F2?\n\nsetMethod(\"getExpression\", \"model\",\n function(object){\n return(object@expression)\n })\n\nsetGeneric(\"getFormula\", function(object){standeardGeneric(\"getFormula\")})\nsetMethod(\"getFormula\", \"model\", \n function(object){\n return(object@formula)\n })\n\nsetGeneric(\"getGuess\", function(object){standeardGeneric(\"getGuess\")})\nsetMethod(\"getGuess\", \"model\", \n function(object){\n return(object@guess)\n })\n######################## ENG PROTOTYPING ########################\n\n# Function to create a new model\n#' Model \n#' \n#' Function to create a new model \n#' @param name The name of the model \n#' @param expression Expression of the model \n#' @param formula The formula of this model \n#' @param guess The guess of this model \n#' @return The new model \nmodel = function(name, expression, formula, guess){\n new(\"model\", name = name, expression = expression, formula = formula, guess = guess)\n}\n\nloess.g = function(well,smooth.param=0.75){\n #data = data.from(well)\n #growth = data[,2]\n #Time = data[,1]\n Time = data.from(well)[,1]\n \n # predicted growth values to be used in estimating growth curve parameters\n loess.fit = loess(data.from(well)[,2]~Time,span=smooth.param)\n t = seq(from = min(Time), to = max(Time), by = (max(Time)-min(Time))/1000)\n y = predict(loess.fit, data.frame(Time=t))\n attr(y,\"names\") = NULL # need to remove the names to prevent them from showing up in the returned vector\n \n # Remove any data points where y has not been estimated\n filt = is.finite(y)\n t = t[filt]\n y = y[filt] # remove any NA etc\n \n # specific growth using loess to find max derivative\n delta.t = diff(t)\n dydt = diff(y)/delta.t\n u = max(dydt)\n \n # lower and upper asymptotes\n b = min(y)\n A = max(y) - min(y)\n \n # inflection point\n inflection.pt.index = which.max(dydt)\n inflection.time = t[inflection.pt.index]\n inflection.y = y[inflection.pt.index]\n \n # lag time\n lam = inflection.time - (inflection.y-b)/u\n \n # Return named array of estimates\n c(A = A, b = b, lam = lam, u = u)\n}\n\n\n",
|
||||
"created" : 1425419995370.000,
|
||||
"dirty" : false,
|
||||
"encoding" : "UTF-8",
|
||||
"folds" : "",
|
||||
"hash" : "2225975310",
|
||||
"id" : "992E3490",
|
||||
"lastKnownWriteTime" : 1425511077,
|
||||
"path" : "~/Documents/GCAT4/trunk/R/GCAT/R/class.model.R",
|
||||
"project_path" : "R/class.model.R",
|
||||
"properties" : {
|
||||
},
|
||||
"source_on_save" : false,
|
||||
"type" : "r_source"
|
||||
}
|
File diff suppressed because one or more lines are too long
@ -0,0 +1,17 @@
|
||||
{
|
||||
"contents" : "setwd(\"~/Downloads/\")\nfile.list = file.name = \"YPDAFEXglucoseTests_2-25-10.csv\"\nlayout.file = \"YPDAFEXglucoseTests_2-25-10_Layout.csv\"\nsingle.plate = T\nout.dir = getwd()\ngraphic.dir = paste(out.dir, \"/pics\", sep = \"\")\nadd.constant = 1\nblank.value = NULL\nstart.index = 2\ngrowth.cutoff = 0.05\nuse.linear.param = F\nuse.loess = F\nsmooth.param = 0.6\npoints.to.remove = 0\nremove.jumps = F\nsilent = F\nverbose = T\nreturn.fit = F\noverview.jpgs = T\nplate.nrow = 8\nplate.ncol = 12\ninput.skip.lines = 0\nmulti.column.headers = c(\"Plate ID\", \"Well\", \"OD\", \"Time\")\nsingle.column.headers = c(\"\",\"A1\")\nlayout.sheet.headers = c(\"Strain\", \"Media Definition\")\n\nt = gcat.analysis.main(file.list, single.plate, layout.file = NULL, \n out.dir = getwd(), graphic.dir = paste(out.dir, \"/pics\", sep = \"\"), \n add.constant = 1, blank.value = NULL, start.index = 2, growth.cutoff = 0.05,\n use.linear.param=use.linear.param, use.loess=use.loess, smooth.param=0.1,\n points.to.remove = 0, remove.jumps = F, time.input = NA,\n plate.nrow = 8, plate.ncol = 12, input.skip.lines = 0,\n multi.column.headers = c(\"Plate.ID\", \"Well\", \"OD\", \"Time\"), single.column.headers = c(\"\",\"A1\"), \n layout.sheet.headers = c(\"Strain\", \"Media Definition\"),\n silent = F, verbose = F, return.fit = F, overview.jpgs = T)\n",
|
||||
"created" : 1425413468083.000,
|
||||
"dirty" : false,
|
||||
"encoding" : "UTF-8",
|
||||
"folds" : "",
|
||||
"hash" : "3533220190",
|
||||
"id" : "E3886516",
|
||||
"lastKnownWriteTime" : 1425422563,
|
||||
"path" : "~/Documents/GCAT4/trunk/R/GCAT/R/addingParams.R",
|
||||
"project_path" : "R/addingParams.R",
|
||||
"properties" : {
|
||||
"tempName" : "Untitled1"
|
||||
},
|
||||
"source_on_save" : false,
|
||||
"type" : "r_source"
|
||||
}
|
@ -0,0 +1,2 @@
|
||||
{
|
||||
}
|
@ -0,0 +1,2 @@
|
||||
{
|
||||
}
|
@ -0,0 +1,2 @@
|
||||
{
|
||||
}
|
@ -0,0 +1,2 @@
|
||||
{
|
||||
}
|
@ -0,0 +1,2 @@
|
||||
{
|
||||
}
|
@ -0,0 +1,3 @@
|
||||
{
|
||||
"tempName" : "Untitled1"
|
||||
}
|
@ -0,0 +1,2 @@
|
||||
{
|
||||
}
|
@ -0,0 +1,2 @@
|
||||
{
|
||||
}
|
@ -0,0 +1,2 @@
|
||||
{
|
||||
}
|
@ -0,0 +1,3 @@
|
||||
{
|
||||
"tempName" : "Untitled1"
|
||||
}
|
@ -0,0 +1,2 @@
|
||||
{
|
||||
}
|
@ -0,0 +1,2 @@
|
||||
{
|
||||
}
|
@ -0,0 +1,2 @@
|
||||
{
|
||||
}
|
@ -0,0 +1,2 @@
|
||||
{
|
||||
}
|
@ -0,0 +1,2 @@
|
||||
{
|
||||
}
|
@ -0,0 +1,2 @@
|
||||
{
|
||||
}
|
@ -0,0 +1,2 @@
|
||||
{
|
||||
}
|
@ -0,0 +1,2 @@
|
||||
{
|
||||
}
|
@ -0,0 +1,2 @@
|
||||
{
|
||||
}
|
@ -0,0 +1,2 @@
|
||||
{
|
||||
}
|
@ -0,0 +1,2 @@
|
||||
{
|
||||
}
|
@ -0,0 +1,2 @@
|
||||
{
|
||||
}
|
@ -0,0 +1,2 @@
|
||||
{
|
||||
}
|
@ -0,0 +1,2 @@
|
||||
{
|
||||
}
|
@ -0,0 +1,2 @@
|
||||
{
|
||||
}
|
@ -0,0 +1,2 @@
|
||||
{
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
~%2FDocuments%2FGCAT4%2Ftrunk%2FR%2FGCAT%2FNAMESPACE="972C75E0"
|
||||
~%2FDocuments%2FGCAT4%2Ftrunk%2FR%2FGCAT%2FR%2FGCAT.main.R="11120BC5"
|
||||
~%2FDocuments%2FGCAT4%2Ftrunk%2FR%2FGCAT%2FR%2FaddingParams.R="54A894D0"
|
||||
~%2FDocuments%2FGCAT4%2Ftrunk%2FR%2FGCAT%2FR%2Fclass.model.R="9127986F"
|
||||
~%2FDocuments%2FGCAT4%2Ftrunk%2FR%2FGCAT%2FR%2Fclass.well.R="8250000E"
|
||||
~%2FDocuments%2FGCAT4%2Ftrunk%2FR%2FGCAT%2FR%2Ffit.model.R="3F8DCF42"
|
||||
~%2FDocuments%2FGCAT4%2Ftrunk%2FR%2FGCAT%2FR%2Ffitted.calculations.R="E533697B"
|
||||
~%2FDocuments%2FGCAT4%2Ftrunk%2FR%2FGCAT%2FR%2Fmisc.R="8341E8EB"
|
||||
~%2FDocuments%2FGCAT4%2Ftrunk%2FR%2FGCAT%2FR%2Fnormalize.and.transform.R="EDBD9DE"
|
||||
~%2FDocuments%2FGCAT4%2Ftrunk%2FR%2FGCAT%2FR%2Fplot.fit.R="2E01469A"
|
||||
~%2FDocuments%2FGCAT4%2Ftrunk%2FR%2FGCAT%2FR%2Fslope.analysis.R="4E0B0FCA"
|
||||
~%2FDocuments%2FGCAT4%2Ftrunk%2FR%2FGCAT%2FR%2Ftable.output.R="B005EA5F"
|
||||
~%2FDocuments%2FGCAT4%2Ftrunk%2FR%2FGCAT%2FR%2Ftable2well.R="A3297EED"
|
||||
~%2FDocuments%2FGCAT4%2Ftrunk%2FR%2FGCAT%2Fman%2Fgcat.load.data.Rd="2A2D32C6"
|
||||
~%2FDocuments%2FGCAT4_old%2Ftrunk%2FR%2FGCAT%2FR%2FGCAT.main.R="61AC4784"
|
||||
~%2FDocuments%2FGCAT4_old%2Ftrunk%2FR%2FGCAT%2FR%2FaddingParams.R="DEDB5126"
|
||||
~%2FDocuments%2FGCAT4_old%2Ftrunk%2FR%2FGCAT%2FR%2Fclass.model.R="8CEE19EC"
|
||||
~%2FDocuments%2FGCAT4_old%2Ftrunk%2FR%2FGCAT%2FR%2Ffit.model.R="9D1E246E"
|
@ -0,0 +1,17 @@
|
||||
Package: GCAT
|
||||
Title: Growth Curve Analysis Tool
|
||||
Description: Imports high-throughput growth curve data from microtiter
|
||||
plate reads in .csv format and performs non-linear
|
||||
regression using the Richards, Logistic, or Gompertz functions.
|
||||
Richards is used unless the shape parameter is not significant.
|
||||
Local polynomial regression can be performed as well.
|
||||
GCAT estimates important growth characteristics
|
||||
(specific growth rate, maximum growth capacity, and lag time)
|
||||
for each well in a read.
|
||||
The code was written by Jason Shao (no longer at GLBRC) and Nate DiPiazza.
|
||||
Version: 5.0
|
||||
Depends: pheatmap, gplots
|
||||
Maintainer: Yury Bukhman <ybukhman@glbrc.wisc.edu>
|
||||
License: LGPL-3
|
||||
Date: 2014-02-10
|
||||
Author: Jason Shao, Nate DiPiazza <ndipiazza@wisc.edu>, Minh Duc Bui, Yury V Bukhman
|
@ -0,0 +1,17 @@
|
||||
Version: 1.0
|
||||
|
||||
RestoreWorkspace: Default
|
||||
SaveWorkspace: Default
|
||||
AlwaysSaveHistory: Default
|
||||
|
||||
EnableCodeIndexing: Yes
|
||||
UseSpacesForTab: Yes
|
||||
NumSpacesForTab: 2
|
||||
Encoding: UTF-8
|
||||
|
||||
RnwWeave: Sweave
|
||||
LaTeX: pdfLaTeX
|
||||
|
||||
BuildType: Package
|
||||
PackageInstallArgs: --no-multiarch --with-keep.source
|
||||
PackageRoxygenize: rd
|
@ -0,0 +1,8 @@
|
||||
# Default NAMESPACE created by R
|
||||
# Remove the previous line if you edit this file
|
||||
|
||||
# Export all names
|
||||
exportPattern(".")
|
||||
|
||||
# Import all packages listed as Imports or Depends
|
||||
import("pheatmap", "gplots")
|
@ -0,0 +1,17 @@
|
||||
Version: 1.0
|
||||
|
||||
RestoreWorkspace: Default
|
||||
SaveWorkspace: Default
|
||||
AlwaysSaveHistory: Default
|
||||
|
||||
EnableCodeIndexing: Yes
|
||||
UseSpacesForTab: Yes
|
||||
NumSpacesForTab: 2
|
||||
Encoding: UTF-8
|
||||
|
||||
RnwWeave: Sweave
|
||||
LaTeX: pdfLaTeX
|
||||
|
||||
BuildType: Package
|
||||
PackageInstallArgs: --no-multiarch --with-keep.source
|
||||
PackageRoxygenize: rd
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -0,0 +1,16 @@
|
||||
{
|
||||
"contents" : "#Copyright 2012 The Board of Regents of the University of Wisconsin System.\n#Contributors: Jason Shao, James McCurdy, Enhai Xie, Adam G.W. Halstead,\n#Michael H. Whitney, Nathan DiPiazza, Trey K. Sato and Yury V. Bukhman\n#\n#This file is part of GCAT.\n#\n#GCAT is free software: you can redistribute it and/or modify\n#it under the terms of the GNU Lesser General Public License as published by\n#the Free Software Foundation, either version 3 of the License, or\n#(at your option) any later version.\n#\n#GCAT is distributed in the hope that it will be useful,\n#but WITHOUT ANY WARRANTY; without even the implied warranty of\n#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n#GNU Lesser General Public License for more details.\n#\n#You should have received a copy of the GNU Lesser General Public License \n#along with GCAT. If not, see <http://www.gnu.org/licenses/>.\n########################################################################\n# #\n# <model> class definition and functions. Objects contain equations #\n# and other information for parameterized growth curve models. #\n# #\n########################################################################\nsetClass(\"model\", representation(name = \"character\",\n expression = \"expression\",\n formula = \"formula\",\n guess = \"function\"))\n# Slots:\n# name - a simple description of the model.\n# expression - an object of class \"expression\" that evaluates the response (transformed OD) with respect to the variable Time.\n# formula - same as expression, but with y as the response.\n# guess - a function that computes initial guesses for the parameters given a well object with a valid \"screen.data\" slot\n# containing useable OD values and slope estimates\n# --------------------------------------------------------------------\n# Function to create a new model \t \n#' Model \n#' \n#' Function to create a new model \n#' @param name The name of the model \n#' @param expression Expression of the model \n#' @param formula The formula of this model \n#' @param guess The guess of this model \n#' @return The new model \nmodel = function(name, expression, formula, guess){\n new(\"model\", name = name, expression = expression, formula = formula, guess = guess)\n}\n\nloess.g = function(well,smooth.param=0.75){\n data = data.from(well)\n growth = data[,2]\n Time = data[,1]\n \n # predicted growth values to be used in estimating growth curve parameters\n loess.fit = loess(growth~Time,span=smooth.param)\n t = seq(from = min(Time), to = max(Time), by = (max(Time)-min(Time))/1000)\n y = predict(loess.fit, data.frame(Time=t))\n attr(y,\"names\") = NULL # need to remove the names to prevent them from showing up in the returned vector\n \n # Remove any data points where y has not been estimated\n filt = is.finite(y)\n t = t[filt]\n y = y[filt] # remove any NA etc\n \n # specific growth using loess to find max derivative\n delta.t = diff(t)\n dydt = diff(y)/delta.t\n u = max(dydt)\n \n # lower and upper asymptotes\n b = min(y)\n A = max(y) - min(y)\n \n # inflection point\n inflection.pt.index = which.max(dydt)\n inflection.time = t[inflection.pt.index]\n inflection.y = y[inflection.pt.index]\n \n # lag time\n lam = inflection.time - (inflection.y-b)/u\n \n # Return named array of estimates\n c(A = A, b = b, lam = lam, u = u)\n}\n\n\n",
|
||||
"created" : 1423869204555.000,
|
||||
"dirty" : false,
|
||||
"encoding" : "UTF-8",
|
||||
"folds" : "",
|
||||
"hash" : "3423035371",
|
||||
"id" : "EE21755B",
|
||||
"lastKnownWriteTime" : 1423869219,
|
||||
"path" : "~/Documents/GCAT4_old/trunk/R/GCAT/R/class.model.R",
|
||||
"project_path" : "class.model.R",
|
||||
"properties" : {
|
||||
},
|
||||
"source_on_save" : false,
|
||||
"type" : "r_source"
|
||||
}
|
@ -0,0 +1,2 @@
|
||||
{
|
||||
}
|
@ -0,0 +1,2 @@
|
||||
{
|
||||
}
|
@ -0,0 +1,2 @@
|
||||
{
|
||||
}
|
@ -0,0 +1,2 @@
|
||||
{
|
||||
}
|
@ -0,0 +1,2 @@
|
||||
{
|
||||
}
|
@ -0,0 +1,2 @@
|
||||
{
|
||||
}
|
@ -0,0 +1,2 @@
|
||||
{
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
~%2FDocuments%2FGCAT4_old%2Ftrunk%2FR%2FGCAT%2FR%2FGCAT.main.R="59ABD774"
|
||||
~%2FDocuments%2FGCAT4_old%2Ftrunk%2FR%2FGCAT%2FR%2Fclass.model.R="6E6918EE"
|
||||
~%2FDocuments%2FGCAT4_old%2Ftrunk%2FR%2FGCAT%2FR%2Ffit.model.R="5C623936"
|
||||
~%2FDocuments%2FGCAT4_old%2Ftrunk%2FR%2FGCAT%2FR%2Ffitted.calculations.R="2ACDF6EF"
|
||||
~%2FDocuments%2FGCAT4_old%2Ftrunk%2FR%2FGCAT%2FR%2Fnormalize.and.transform.R="F3CF638E"
|
||||
~%2FDocuments%2FGCAT4_old%2Ftrunk%2FR%2FGCAT%2FR%2Fplot.fit.R="EFF3E540"
|
||||
~%2FDocuments%2FGCAT4_old%2Ftrunk%2FR%2FGCAT%2FR%2Ftable2well.R="9402820B"
|
@ -0,0 +1,585 @@
|
||||
#Copyright 2012 The Board of Regents of the University of Wisconsin System.
|
||||
#Contributors: Jason Shao, James McCurdy, Enhai Xie, Adam G.W. Halstead,
|
||||
#Michael H. Whitney, Nathan DiPiazza, Trey K. Sato and Yury V. Bukhman
|
||||
#
|
||||
#This file is part of GCAT.
|
||||
#
|
||||
#GCAT is free software: you can redistribute it and/or modify
|
||||
#it under the terms of the GNU Lesser General Public License as published by
|
||||
#the Free Software Foundation, either version 3 of the License, or
|
||||
#(at your option) any later version.
|
||||
#
|
||||
#GCAT is distributed in the hope that it will be useful,
|
||||
#but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
#GNU Lesser General Public License for more details.
|
||||
#
|
||||
#You should have received a copy of the GNU Lesser General Public License
|
||||
#along with GCAT. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
# GCAT version 5.00
|
||||
# Notes by Jason
|
||||
# 08/18/2011
|
||||
|
||||
# Initialization
|
||||
|
||||
|
||||
PLATE.LETTERS = paste(rep(c("", LETTERS), each = 26), rep(LETTERS, 26), sep="")
|
||||
global.version.number = packageDescription(pkg="GCAT")$Version
|
||||
|
||||
########################################################################
|
||||
# #
|
||||
# Top-level functions for analysis of screening data from .csv files. #
|
||||
# #
|
||||
########################################################################
|
||||
# This functions is called directly by the user interface.
|
||||
# They in turn call the main function <gcat.fit.main> (below) multiple times for each data file provided in <file.list>.
|
||||
|
||||
# Arguments:
|
||||
# file.list - a list of full paths to .csv files. all files must be in the same format (see <single.plate>)
|
||||
# single.plate - are the file in the single plate (wide) format vs. the multi-plate (long) format?
|
||||
# layout.file - (optional) provide full path to a layout file with strain and media definitions (applies to all files in list)
|
||||
|
||||
# out.dir - name a directory to output the table of curve parameters to (defaults to working directory)
|
||||
# graphic.dir - name a directory to output the images of the fitted curves to (defaults to subdirectory "pics" of <out.dir> above)
|
||||
|
||||
|
||||
# add.constant- should be a numeric constant that will be added to each curve before the log transform (defaults to 1)
|
||||
# blank.value - user can enter a blank OD measurement for uninoculated wells. if NULL, defaults to the value of the first OD measurement of each well.
|
||||
# start.index - which timepoint should be used as the first one after inoculation (defaults to the 2th one)
|
||||
# growth.cutoff - minimum threshold for curve growth.
|
||||
# points.to.remove - a list of numbers referring to troublesome points that should be removed across all wells.
|
||||
# remove.jumps - should the slope checking function be on the lookout for large jumps in OD?
|
||||
|
||||
# silent - should messages be returned to the console?
|
||||
# verbose - should sub-functions return messages to console? (when I say verbose, I mean it!)
|
||||
|
||||
# Returns:
|
||||
# if <return.fit> = F (default), avector of full paths to all the files generated by the function.
|
||||
# otherwise, the fitted array of well objects.
|
||||
|
||||
# Use this function to analyze any set of .csv files using the same plate layout info.
|
||||
|
||||
#' Analyze screening growth data from the given .csv files.
|
||||
#'
|
||||
#' Top-level GCAT function
|
||||
#'
|
||||
#' @param file.list A list of full paths to .csv files. all files must be in the same format (see <single.plate>)
|
||||
#' @param single.plate The file in the single plate (wide) format vs. the multi-plate (long) format?
|
||||
#' @param layout.file Full path to a layout file with strain and media definitions (applies to all files in list)
|
||||
#' @param out.dir A directory to output the table of curve parameters to (defaults to working directory)
|
||||
#' @param graphic.dir A directory to output the images of the fitted curves to (defaults to subdirectory "pics" of <out.dir> above)
|
||||
#' @param use.linear.param Whether to use linear parameters or not?
|
||||
#' @param use.loess Whether to use LOESS model or not?
|
||||
#' @param smooth.param Smoothing parameter for LOESS model.
|
||||
#' @param add.constant A numeric constant that will be added to each curve before the log transform (defaults to 1)
|
||||
#' @param blank.value User can enter a blank OD measurement for uninoculated wells. if NULL, defaults to the value of the first OD measurement of each well.
|
||||
#' @param start.index Which timepoint should be used as the first one after inoculation (defaults to the 2th one)
|
||||
#' @param growth.cutoff Minimum threshold for curve growth.
|
||||
#' @param points.to.remove A list of numbers referring to troublesome points that should be removed across all wells.
|
||||
#' @param remove.jumps Should the slope checking function be on the lookout for large jumps in OD?
|
||||
#' @param time.input The time setting in which the current system is running?
|
||||
#' @param plate.nrow The number of rows in a plate.
|
||||
#' @param plate.ncol The number of columns in a plate.
|
||||
#' @param input.skip.lines If specified, this number of lines shall be skipped from the top when reading the input file with read.csv
|
||||
#' @param multi.column.headers The headers of the result tabular data when analyzing multiple plates at once.
|
||||
#' @param single.column.headers The headers of the result tebaular data when analyzaing a single plate.
|
||||
#' @param layout.sheet.headers The headers of the layout file?
|
||||
#' @param silent Shoulde messages be returned to the console?
|
||||
#' @param verbose Should sub-functions return messages to console? (when I say verbose, I mean it!)
|
||||
#' @param overview.jpgs Should GCAT enable an overview image?
|
||||
#'
|
||||
#' @return A list of the output files.
|
||||
gcat.analysis.main = function(file.list, single.plate, layout.file = NULL,
|
||||
out.dir = getwd(), graphic.dir = paste(out.dir, "/pics", sep = ""),
|
||||
add.constant = 0.1, blank.value = NULL, start.index = 2, growth.cutoff = 0.05,
|
||||
use.linear.param = F, use.loess = F, smooth.param=0.1,
|
||||
points.to.remove = 0, remove.jumps = F, time.input = NA,
|
||||
plate.nrow = 8, plate.ncol = 12, input.skip.lines = 0,
|
||||
multi.column.headers = c("Plate.ID", "Well", "OD", "Time"), single.column.headers = c("","A1"),
|
||||
layout.sheet.headers = c("Strain", "Media Definition"),
|
||||
silent = T, verbose = F, return.fit = F, overview.jpgs = T){
|
||||
|
||||
# MB: Prototyping system unwanted argument guarding. Proper function
|
||||
# will be added in the future.
|
||||
# Not the best solution.
|
||||
if (is.na(time.input)) {
|
||||
if (single.plate)
|
||||
time.input = 1/3600
|
||||
else
|
||||
exception("Error: ", "time.input is NA.")
|
||||
}
|
||||
|
||||
if (add.constant < 0)
|
||||
exception("Error: ", "The constant r should not be negative.")
|
||||
# End prototyping temporary solution.
|
||||
|
||||
upload.timestamp = strftime(Sys.time(), format="%Y-%m-%d %H:%M:%S") # Get a timestamp for the time of upload.
|
||||
fitted.well.array.master = list()
|
||||
source.file.list = c()
|
||||
|
||||
dim(fitted.well.array.master) = c(plate.nrow,plate.ncol,0)
|
||||
dimnames(fitted.well.array.master) = list(PLATE.LETTERS[1:plate.nrow], 1:plate.ncol, c())
|
||||
|
||||
for(file.name in file.list){
|
||||
|
||||
# Call <gcat.fit.main> on the file with single plate options
|
||||
fitted.well.array = try(gcat.fit.main(file.name = file.name, load.type = "csv",
|
||||
single.plate = single.plate, layout.file = layout.file, start.index = start.index,
|
||||
time.input = time.input, add.constant = add.constant, blank.value = blank.value,
|
||||
growth.cutoff = growth.cutoff, points.to.remove = points.to.remove, remove.jumps = remove.jumps,
|
||||
use.linear.param=use.linear.param, use.loess=use.loess, smooth.param=smooth.param,
|
||||
plate.nrow = plate.nrow, plate.ncol = plate.ncol, multi.column.headers = multi.column.headers,
|
||||
single.column.headers = single.column.headers, layout.sheet.headers = layout.sheet.headers,
|
||||
input.skip.lines = input.skip.lines, silent = silent, verbose = verbose), silent = T)
|
||||
|
||||
# Return error message if the function fails.
|
||||
if(class(fitted.well.array) == "try-error")
|
||||
return(as.character(fitted.well.array))
|
||||
}
|
||||
|
||||
# Add fitted well array onto existing fitted wells
|
||||
fitted.well.array.master = gcat.append.arrays(fitted.well.array.master, fitted.well.array, plate.ncol, plate.nrow)
|
||||
|
||||
# Remove the "processed_" tag from file names and add to the list of source files.
|
||||
source.file.list = c(source.file.list, basename(paste(strsplit(file.name, "processed_")[[1]],collapse="/")))
|
||||
|
||||
out.files = try(gcat.output.main(fitted.well.array.master, out.prefix = "output",
|
||||
source.file.list = source.file.list, upload.timestamp = upload.timestamp,
|
||||
growth.cutoff = growth.cutoff, add.constant = add.constant, blank.value = blank.value, start.index = start.index,
|
||||
points.to.remove = points.to.remove, remove.jumps = remove.jumps,
|
||||
out.dir = out.dir, graphic.dir = graphic.dir, overview.jpgs=overview.jpgs,
|
||||
use.linear.param=use.linear.param, use.loess=use.loess, plate.ncol = plate.ncol, plate.nrow = plate.nrow,
|
||||
silent = silent), silent = T)
|
||||
|
||||
# Return file list or error message otherwise return "successful analysis" message (?)
|
||||
|
||||
# file.list = c("Data was successfully analyzed.", file.list) # <--- yet to be implemented. causes errors downstream right now
|
||||
if(class(out.files) == "try-error") return(as.character(out.files))
|
||||
|
||||
if(return.fit) return(fitted.well.array.master)
|
||||
else return(out.files)
|
||||
}
|
||||
|
||||
########################################################################
|
||||
# #
|
||||
# Main function for analysis of screening data from input tables. #
|
||||
# #
|
||||
########################################################################
|
||||
# This is the main function that handles all the analyses for files in both single and multiple plate formats.
|
||||
# It is called by the top level function <analysis.main>
|
||||
#
|
||||
# It then calls the following functions on each member of the array:
|
||||
# - curve normalization and standardization: <gcat.start.times>, <remove.points>, <normalize.ODs>, <transform.ODs>,
|
||||
# - curve shape analysis before model fitting: <fill.slopes>, <check.curve>, <classify.curve>
|
||||
# - to fit a nonlinear model to the growth data: <fit.model>
|
||||
# Finally, it returns the fitted array of well objects.
|
||||
|
||||
#' Main analysis function for GCAT
|
||||
#'
|
||||
#' This is the main function that handles all the analyses for data files in both single and multiple plate formats.
|
||||
#' It is called by the top level function \code{gcat.analysis.main} along with \code{gcat.output.main}.
|
||||
#'
|
||||
#' @param file.name Complete path and file name of a comma-separated values (.csv) file containing growth curve data
|
||||
#' in the multiple-plate (long) format.
|
||||
#' @param input.data A list of tables representing input files read with \code{read.table}. Used to save time in cases
|
||||
#' of running multiple analyses on the same dataset. If used, the function will ignore \code{file.name} entirely.
|
||||
#' @param load.type .csv by default.
|
||||
#' @param layout.file Specifies the location of a layout file containing identifying information.
|
||||
#' @param single.plate Whether the GCAT is analyzing a single plate or not.
|
||||
#' @param blank.value Blank OD measurement for uninoculated wells. By default(NULL), the value of the first OD
|
||||
#'measurement in each well is used.
|
||||
#' @param start.index Which timepoint should be used as the first one after inoculation?
|
||||
#' @param time.input Either a character describing the format used to convert timestamps in the input to numbers
|
||||
#' representing number of seconds (see \code{strptime}), or a factor to divide entries in the Time column by to get the
|
||||
#' numbers of hours.
|
||||
#' @param normalize.method Describes the method used by \code{normalize.ODs} to normalize cell density values using blank reads.
|
||||
#' @param add.constant A value for r in the log(OD + r) transformation.
|
||||
#' @param use.log Should the analysis use log on all values.
|
||||
#' @param points.to.remove A vector of integers specifying which timepoints should be removed across all wells.
|
||||
#' By default(0) none are marked for removal.
|
||||
#' @param use.linear.param Should the linear parameter be used or not.
|
||||
#' @param use.loess Should the loess model be used or not.
|
||||
#' @param smooth.param If loess model is used, this parameter define the smoothing parameter for the loess model.
|
||||
#' @param fall.cutoff A cutoff used by \code{check.slopes} to decide on thresholds for jumps and tanking.
|
||||
#' @param growth.cutoff A threshold used by check.growth to decide whether a well displays growth.
|
||||
#' @param remove.jumps Should jumps in OD detected by the subfunction \code{check.slopes}?
|
||||
#' @param plate.nrow The number of rows in the input files.
|
||||
#' @param plate.ncol The number of columns in the input files.
|
||||
#' @param input.skip.lines If specified, this number of lines shall be skipped from the top when reading the input file with read.csv
|
||||
#' @param multi.column.headers The headers of the column when analyzing multiple plates.
|
||||
#' @param single.column.headers The headers of the column when analyzing a single plate.
|
||||
#' @param layour.sheet.headers The headers of the layout file.
|
||||
#' @param growth.model What growth model should be used?
|
||||
#' @param backup.growth.model If the main growth model fails, the back up model will be used.
|
||||
#' @param silent Surpress all messages.
|
||||
#' @param verbose Display all messages when analyzing each well.
|
||||
#'
|
||||
#' @return An array of well objects
|
||||
gcat.fit.main = function(file.name, input.data = NULL, load.type = "csv", layout.file = NULL,
|
||||
single.plate = F, blank.value = NULL, start.index = 2, time.input = NA,
|
||||
normalize.method = "default", add.constant = 1, use.log = T, points.to.remove = 0,
|
||||
use.linear.param=F, use.loess=F, smooth.param=0.1,
|
||||
fall.cutoff = -0.0025, growth.cutoff = 0.05, remove.jumps = F,
|
||||
plate.nrow = 8, plate.ncol = 12, input.skip.lines = 0,
|
||||
multi.column.headers = c("Plate.ID", "Well", "OD", "Time"), single.column.headers = c("","A1"),
|
||||
layout.sheet.headers = c("Strain", "Media Definition"),
|
||||
growth.model = NA, backup.growth.model = NA,
|
||||
silent = F, verbose = F){
|
||||
|
||||
# Explanation of arguments:
|
||||
|
||||
# ---File Handling---
|
||||
# file.name - full path to an excel spreadsheet, .csv or tab-delimited text file, in either the single or multiple-plate format
|
||||
# input.data - use pre-loaded data set (output from <gcat.load.data> function only). will override <file.name> if not NULL
|
||||
# load.type - supports "csv."
|
||||
# layout.file - full path to a file containing the plate layout in the same format as <file.name>. will not be used if <load.type> is "xlsx"
|
||||
|
||||
# ---Input file format---
|
||||
# single.plate - true denotes data in single-plate format, i.e. simple OD output. false denotes multiple-plate robotic screening output.
|
||||
# note: reading directly from excel to R results in timestamps being converted to days.
|
||||
|
||||
# ---Normalization and Transforms---
|
||||
# blank.value - user can enter a blank OD measurement for uninoculated wells. if NULL, defaults to the value of the first OD measurement of each well.
|
||||
# start.index - which timepoint should be used as the first one after inoculation (defaults to the 2th one)
|
||||
# normalize.method - how should each growth curve be normalized? allowed values are:
|
||||
# "first": subtracts the first OD, assumed to be the blank, from all ODs
|
||||
# "none": does nothing, assumes no blank. highly recommend log(OD+1) transform in this case.
|
||||
# "average.first": forces all filled wells on each plate to match the average value at <start.index> (after subtracting the first OD)
|
||||
# add.constant - a numeric constant that will be added to each curve before the log transform (defaults to 1)
|
||||
# use.log - should a log transform be applied to the data after normalization?
|
||||
# points.to.remove - a list of numbers referring to troublesome points that should be removed across all wells.
|
||||
|
||||
# ---Pre-fitting processing---
|
||||
# fall.cutoff - a cutoff value for determining whether OD falls significantly between two timepoints. see <check.slopes> in prefit.processing.R for details.
|
||||
# growth.cutoff - a cutoff value for determining whether a well contains a successfully growing culture or not.
|
||||
# remove.jumps - should the slope checking function be on the lookout for large jumps in OD?
|
||||
|
||||
# ---Model fitting---
|
||||
# model - which parametrized growth model to use? can be richards, gompertz, or logistic. models are defined as objects of class model, see "model.class.R"
|
||||
# backup.model - which model should be used if fitting using <model> fails? should ideally be simpler than the main model (less parameters)
|
||||
|
||||
# ---Miscellanous input/output preferences---
|
||||
# silent - should messages be returned to the console?
|
||||
# verbose - should sub-functions return messages to console? (when I say verbose, I mean it!)
|
||||
# unlog - should exported graphics be transformed back to the OD scale?
|
||||
# return.fit - should the function return an array of wells? if not, it will return a list of generated files.
|
||||
|
||||
|
||||
########################################################################
|
||||
# Read from .csv file #
|
||||
########################################################################
|
||||
#
|
||||
# The functions used here are found in table2well.R
|
||||
|
||||
if(!silent) cat("\nReading input files...")
|
||||
# Read from .csv or tab-delimited text file using <gcat.load.data> (in load.R)
|
||||
# if <layout.file> is provided, it will be used here.
|
||||
|
||||
plate.layout = NULL
|
||||
# Read layout file if it is specified.
|
||||
if(!is.null(layout.file)){
|
||||
if(load.type=="csv") plate.layout = read.csv(layout.file,header=T,stringsAsFactors=F)
|
||||
else plate.layout = read.table(layout.file,header=T,sep="\t",stringsAsFactors=F)
|
||||
if(!silent) cat("\n\tAdded plate layout information from", layout.file, "\n")
|
||||
}
|
||||
|
||||
# Load the data
|
||||
well.array = try(gcat.load.data(file.name = file.name, input.data = input.data,
|
||||
plate.layout = plate.layout, plate.nrow = plate.nrow, plate.ncol = plate.ncol,
|
||||
input.skip.lines = input.skip.lines, multi.column.headers = multi.column.headers,
|
||||
single.column.headers = single.column.headers, layout.sheet.headers = layout.sheet.headers,
|
||||
blank.value = blank.value, start.index = start.index, single.plate = single.plate,
|
||||
load.type = load.type, silent=silent),silent=silent)
|
||||
|
||||
# Return an error if there is a problem with file loading.
|
||||
if (class(well.array) == "try-error")
|
||||
stop("Error in <gcat.load.data>: ", well.array)
|
||||
|
||||
|
||||
# !---At this point, <well.array> is an array of well objects, each containing raw data and media/strain information if provided---
|
||||
|
||||
# Attempt to apply time formatting to all wells in array
|
||||
well.array = try(aapply(well.array, gcat.start.times, start.index = start.index, time.input = time.input),silent=silent)
|
||||
|
||||
# Return an error if there is a problem with time formatting
|
||||
if (class(well.array) == "try-error")
|
||||
stop("Error in <gcat.start.times>: ", well.array)
|
||||
|
||||
########################################################################
|
||||
# Perform normalization and transformation of raw data #
|
||||
########################################################################
|
||||
#
|
||||
# The functions used here are found in normalize.and.transform.R
|
||||
|
||||
if(!silent) cat("\nProcessing raw data...")
|
||||
|
||||
# Set all timepoints to active for now using "points.to.remove=0" argument with <remove.points>
|
||||
# adds an extra column to the "well.array" slot of each well specifying which points to remove when data is retrieved from the well
|
||||
well.array = aapply(well.array, remove.points, points = 0)
|
||||
|
||||
# Normalize ODs using specified method and adding a constant if desired.
|
||||
# sets the "norm" slot of each well to a value to be subtracted from OD values whenever data is retrieved from the well
|
||||
well.array = try(normalize.ODs(well.array, normalize.method = normalize.method,
|
||||
start.index = start.index, blank.value = blank.value, add.constant = add.constant),silent=silent)
|
||||
|
||||
# Return an error if there is a problem with normalization
|
||||
if (class(well.array) == "try-error")
|
||||
stop("Error in <normalize.ODs>: ", well.array)
|
||||
|
||||
# Transform ODs on the logarithmic scale, regardless of whether <use.log> is true
|
||||
# an extra column of log-transformed values is added to the "well.array" slot of each well
|
||||
# the "use.log" slot of each well is set instead to determine whether the transformed values will be returned when data is retrieved from the well.
|
||||
well.array = try(aapply(well.array, transform.ODs, start.index = start.index, blank.value = blank.value, use.log = use.log, constant.added = add.constant),silent=silent)
|
||||
|
||||
# Return an error if there is a problem with transformation
|
||||
if (class(well.array) == "try-error")
|
||||
stop("Error in <transform.ODs>: ", well.array)
|
||||
|
||||
# Remove specified timepoints across wells (use "points.to.remove=NULL" if no points to remove)
|
||||
well.array = try(aapply(well.array, remove.points, points = points.to.remove),silent=silent)
|
||||
|
||||
# Return an error if there is a problem with point removal
|
||||
if (class(well.array) == "try-error")
|
||||
stop("Error in <remove.points>: ", well.array)
|
||||
|
||||
|
||||
|
||||
########################################################################
|
||||
# Pre-fitting data processing (analysis of curve shapes) #
|
||||
########################################################################
|
||||
#
|
||||
# The functions used here are found in slope.analysis.R
|
||||
|
||||
# Estimate slope at each timepoint
|
||||
# add a column to the "well.array" slot of each well with the local slope at each timepoint
|
||||
|
||||
well.array = try(aapply(well.array, calculate.slopes, silent=!verbose),silent=silent)
|
||||
|
||||
# Return an error if there is a problem with slope calculation
|
||||
if (class(well.array) == "try-error")
|
||||
stop("Error in <calculate.slopes>: ", well.array)
|
||||
|
||||
# Check slopes for tanking and/or jumping behavior
|
||||
# fills the "curve.par" slot of each well with <tanking.start>, denoting the timepoint at which tanking starts (if none, value is NA)
|
||||
# uses <remove.points> to remove all points after <tanking.start>
|
||||
# It will also fill the "jump.error" slot with a status message, and try to use an automated process to remove the
|
||||
# erroneous points if <remove.jumps> is true (default false).
|
||||
|
||||
well.array = try(aapply(well.array, check.slopes, fall.cutoff = fall.cutoff, remove.jumps = remove.jumps, silent=!verbose, draw = F),silent=silent)
|
||||
|
||||
# Return an error if there is a problem with slope analysis
|
||||
if (class(well.array) == "try-error")
|
||||
stop("Error in <check.slopes>: ", well.array)
|
||||
|
||||
|
||||
# Check curves for growth above cutoff
|
||||
# fills the "curve.par" slot of each well with <no.growth>, denoting whether the well has no detectable growth.
|
||||
well.array = try(aapply(well.array, check.growth, growth.cutoff = growth.cutoff, start.index = start.index),silent=silent)
|
||||
|
||||
# Return an error if there is a problem with growth.check
|
||||
if (class(well.array) == "try-error")
|
||||
stop("Error in <check.growth>: ", well.array)
|
||||
|
||||
########################################################################
|
||||
# Fit parameterized models to data #
|
||||
########################################################################
|
||||
#
|
||||
# The functions used here are found in fit.model.R
|
||||
|
||||
# Fit each well with the selected model and attempt to catch failed fittings with the backup model
|
||||
# skips wells designated as <no.growth> above
|
||||
# fills the "fit.info" slot of each well with "success," "failed," or "skipped"
|
||||
# if fit was successful:
|
||||
# fills the "equation" and "model.name" slots with the relevant info for the successful model
|
||||
# fills the "fit.par" slot with fitted parameters if fit is successful
|
||||
|
||||
if(!silent) cat("\nFitting models to data...")
|
||||
well.array = aapply(well.array, fit.model, growth.model=growth.model,
|
||||
backup.growth.model = backup.growth.model, use.linear.param=use.linear.param,
|
||||
use.loess=use.loess, smooth.param=smooth.param, silent=!verbose)
|
||||
|
||||
# Return an error if there is a problem with model fitting
|
||||
if (class(well.array) == "try-error")
|
||||
stop("Error in <fit.model>: ", well.array)
|
||||
|
||||
if(!silent) cat("\ndone!\n")
|
||||
return(well.array)
|
||||
}
|
||||
|
||||
|
||||
########################################################################
|
||||
# #
|
||||
# Output function for generating files from fitted data. #
|
||||
# #
|
||||
########################################################################
|
||||
#' Output function for generating files from fitted data.
|
||||
#'
|
||||
#' Handles files and directories, calls \code{table.out}, \code{plate.overview} and \code{view.fit}
|
||||
#' to generate output tables and graphics.
|
||||
#'
|
||||
#' @param fitted.well.array A list of fitted well objects.
|
||||
#' @param out.prefix Prefix that is in the name of output files.
|
||||
#' @param blank.value User can enter a blank OD measurement for uninoculated wells.
|
||||
#' If NULL, defaults to the value of the first OD measurement of each well.
|
||||
#' @param start.index Which timepoint should be used as the first one after inoculation (defaults to the 2th one)
|
||||
#' @param growth.cutoff Minimum threshold for curve growth.
|
||||
#' @param points.to.remove A list of numbers referring to troublesome points that should be removed across all wells.
|
||||
#' @param remove.jumps Should the slope checking function be on the lookout for large jumps in OD?
|
||||
#' @param out.dir name a directory to output the table of curve parameters to (defaults to working directory)
|
||||
#' @param graphic.dir name a directory to output the images of the fitted curves to
|
||||
#' (defaults to subdirectory "pics" of <out.dir> above)
|
||||
#' @param overview.jpgs should jpgs be generated for each plate with the overview graphic?
|
||||
#' This is for backwards compatibility with the old web server.
|
||||
#' @param silent should messages be returned to the console?
|
||||
#' @param unlog should exported graphics be transformed back to the OD scale?
|
||||
#' @param constant.added (should be the same value as add.constant above) -
|
||||
#' used to readjust for the constant added during the log transform when plotting ODs.
|
||||
#' @return A list of output files if success.
|
||||
|
||||
gcat.output.main = function(fitted.well.array, out.prefix = "", source.file.list, upload.timestamp = NULL,
|
||||
add.constant, blank.value, start.index, growth.cutoff, points.to.remove, remove.jumps,
|
||||
out.dir = getwd(), graphic.dir = paste(out.dir,"/pics",sep = ""), overview.jpgs = T,
|
||||
use.linear.param=F, use.loess=F, plate.nrow = 8, plate.ncol = 12,
|
||||
unlog = F, silent = T){
|
||||
|
||||
# Prepare timestamp for addition to output file names.
|
||||
filename.timestamp = strftime(upload.timestamp, format="_%Y-%m-%d_%H.%M.%S")
|
||||
|
||||
########################################################################
|
||||
# Prepare to write to output files #
|
||||
########################################################################
|
||||
if(is.null(blank.value)) blank.value = "First timepoint in well"
|
||||
|
||||
if(!silent) cat("\nFinding/creating new output directories...")
|
||||
|
||||
old.wd = getwd()
|
||||
# Create output directory if it doesn't exist
|
||||
if(class(try(setwd(out.dir), silent = T)) == "try-error"){
|
||||
if(!silent) cat("\ncreating new output directory")
|
||||
if (class(try(dir.create(out.dir))) == "try-error")
|
||||
stop("Error creating new output directory!")
|
||||
}
|
||||
|
||||
# Create graphics directory if it doesn't exist
|
||||
if(class(try(setwd(graphic.dir), silent = T)) == "try-error"){
|
||||
if(!silent) cat("\ncreating new graphics directory")
|
||||
if (class(try(dir.create(graphic.dir))) == "try-error")
|
||||
stop("Error creating new graphics directory!")
|
||||
}
|
||||
|
||||
########################################################################
|
||||
# Populate a data table with fit results and write to file #
|
||||
########################################################################
|
||||
#
|
||||
# The functions used here are found in table.output.R
|
||||
|
||||
# Creates a table with a row for each well and a column for each of various identifiers and fitted and calculated parameters.
|
||||
|
||||
if(!silent) cat("\nPopulating data table...")
|
||||
table.fit = try(table.out(fitted.well.array, filename.timestamp=filename.timestamp,use.linear.param=use.linear.param, use.loess=use.loess, constant.added=add.constant))
|
||||
|
||||
# Return an error if there is a problem with returning the table
|
||||
if (class(fitted.well.array) == "try-error")
|
||||
stop("Error in <table.out>: ", fitted.well.array)
|
||||
|
||||
|
||||
# Set working directory to <out.dir>
|
||||
if (class(try(setwd(out.dir))) == "try-error")
|
||||
stop("Error setting directory for table output")
|
||||
|
||||
# Write output table to file in <out.dir>
|
||||
table.filename = paste(out.dir, "/", out.prefix, "_gcat.fit", filename.timestamp, ".txt", sep = "")
|
||||
if (class(try(write.table(table.fit, table.filename, sep = "\t", row.names = F))) == "try-error")
|
||||
stop("Error writing tabular output")
|
||||
|
||||
# ---If successfully written, add postscript and start a list of generated files.
|
||||
generated.files = table.filename
|
||||
|
||||
########################################################################
|
||||
# Write individual fit and overview graphics to file #
|
||||
########################################################################
|
||||
#
|
||||
# The functions used here are found in graphic.output.R
|
||||
|
||||
if(!silent) cat("\nDrawing graphics...")
|
||||
|
||||
# Set working directory to <graphic.dir>
|
||||
if (class(try(setwd(graphic.dir))) == "try-error")
|
||||
stop("Error setting directory for graphic output")
|
||||
# Use function <pdf.by.plate> to write fit graphics to file.
|
||||
|
||||
graphic.files = try(pdf.by.plate(fitted.well.array, out.prefix=out.prefix, upload.timestamp = upload.timestamp,
|
||||
unlog=unlog,constant.added=add.constant,overview.jpgs=overview.jpgs, plate.ncol = plate.ncol, plate.nrow = plate.nrow),silent=silent)
|
||||
|
||||
if (class(graphic.files) == "try-error")
|
||||
stop("Error in <pdf.by.plate>: ", graphic.files)
|
||||
|
||||
# If successfully written, add to the list of generated files.
|
||||
generated.files = c(generated.files, graphic.files)
|
||||
|
||||
########################################################################
|
||||
# Add a postscript to the output table with legend and file info. #
|
||||
########################################################################
|
||||
#
|
||||
sink(table.filename, append = T)
|
||||
analysis.timestamp = strftime(Sys.time(), format="%Y-%m-%d %H:%M:%S")
|
||||
cat("\n# Raw OD values are adjusted and log-transformed before fitting a growth curve as follows: log.OD = log(OD - blank + const) where blank is OD of blank medium and const is specified by the user (1 by default)",
|
||||
"\n# Values are reported on the above 'log.OD' scale unless otherwise specified.",
|
||||
"\n# .SE columns report standard errors of those values that are estimated directly as parameters of global sigmoid models.",
|
||||
"\n# .OD columns report values back-transformed to the linear 'OD - blank' scale.",
|
||||
"\n")
|
||||
|
||||
cat("\n# -- Explanation of columns --",
|
||||
"\n# - model: Name of the model the well was successfully fit with (if any)",
|
||||
"\n# - lag.time: Lag time estimate inferred from the fitted model",
|
||||
"\n# - inflection.time: inflection time point of the growth curve when drawn on the log scale",
|
||||
"\n# - max.spec.growth.rate: maximum specific growth rate estimate inferred from the fitted model. Estimated as the first derivative of the growth curve at inflection time point",
|
||||
"\n# - baseline: growth curve baseline. Global sigmoid model: baseline is parameter 'b' of the model. LOESS: baseline is the same as the lowest predicted log.OD value",
|
||||
"\n# - amplitude: difference between upper plateau and baseline values. Global sigmoid model: amplitude is parameter 'A' of the model. LOESS: amplitude = max.log.OD - min.log.OD",
|
||||
"\n# - plateau: upper asymptote value of the fitted model. Global sigmoid model: plateau = b + A. LOESS: plateau = max.log.OD",
|
||||
"\n# - inoc.log.OD: log.OD value at inoculation. Estimated value from the fitted model is used, rather than the actual measurement",
|
||||
"\n# - max.log.OD: maximal log.OD value reached during the experiment. Estimated value from the fitted model is used rather than the actual measurement",
|
||||
"\n# - projected.growth: maximal projected growth over inoculation value. Global sigmoid model: projected.growth = plateau - inoc.log.OD. LOESS: not reported",
|
||||
"\n# - achieved.growth: maximal growth over inoculation value actually achieved during the experiment. achieved.growth = max.log.OD - inoc.log.OD",
|
||||
"\n# - shape.par: shape parameter of the Richard equation",
|
||||
"\n# - R.squared: goodness of fit metric. Also known as coefficient of determination. R.squared is usually between 0 and 1. A value close to 1 indicates good fit.",
|
||||
"\n# - RSS: residual sum of squares. Another goodness of fit metric. Smaller values indicate better fits.",
|
||||
"\n# - empty: (Well indicator)",
|
||||
"\n# - an 'E' indicates that the well was empty and no growth was detected. ",
|
||||
"\n# - an 'I' indicates that the well was inoculated and growth was detected above the threshold. ",
|
||||
"\n# - an 'E*' indicates that the well was empty and growth was detected (possible contamination). ",
|
||||
"\n# - an '!' indicates that the well was inoculated and no growth was detected. ",
|
||||
"\n# - asymp.not.reached: shows “L” if the bottom asymptote (baseline) was not reached and “U” if the upper asymptote (plateau) was not reached.",
|
||||
"\n# - tank: (Tanking indicator) If a number is present then the growth trend was determined to tank at that timepoint index.",
|
||||
"\n# - other: Additional flag column. Displays information about whether jumps in OD were detected and what was done about them.",
|
||||
"\n# - pdf.file and page.no: location of the figure for this well in the output .pdf files."
|
||||
)
|
||||
|
||||
# Analysis information
|
||||
|
||||
cat("\n#\n# -- Source file information--",
|
||||
"\n# ", paste(source.file.list, collapse = "\n# "),
|
||||
"\n# analyzed using GCAT v", global.version.number,
|
||||
"\n# request sent: ", upload.timestamp,
|
||||
"\n# completed: ", analysis.timestamp,
|
||||
"\n#\n# -- Parameters used in current analysis --",
|
||||
"\n# - Constant added to log(OD + n) transformation:", add.constant,
|
||||
"\n# - Blank OD value: ", blank.value,
|
||||
"\n# - Index of inoculation timepoint", start.index,
|
||||
"\n# - Minimum growth threshold:", growth.cutoff,
|
||||
"\n# - Removed points:", paste(points.to.remove, collapse = " "),
|
||||
"\n# - Jump detection:", remove.jumps)
|
||||
sink()
|
||||
|
||||
########################################################################
|
||||
# Return values to R #
|
||||
########################################################################
|
||||
#
|
||||
|
||||
if(!silent) cat("\ndone!")
|
||||
setwd(old.wd)
|
||||
# Return list of generated files
|
||||
return(generated.files)
|
||||
}
|
||||
|
@ -0,0 +1,35 @@
|
||||
setwd("~/Downloads/")
|
||||
file.list = file.name = "YPDAFEXglucoseTests_2-25-10.csv"
|
||||
layout.file = "YPDAFEXglucoseTests_2-25-10_Layout.csv"
|
||||
single.plate = T
|
||||
out.dir = getwd()
|
||||
graphic.dir = paste(out.dir, "/pics", sep = "")
|
||||
add.constant = 1
|
||||
blank.value = NULL
|
||||
start.index = 2
|
||||
growth.cutoff = 0.05
|
||||
use.linear.param = F
|
||||
use.loess = F
|
||||
smooth.param = 0.6
|
||||
points.to.remove = 0
|
||||
remove.jumps = F
|
||||
silent = F
|
||||
verbose = T
|
||||
return.fit = F
|
||||
overview.jpgs = T
|
||||
plate.nrow = 8
|
||||
plate.ncol = 12
|
||||
input.skip.lines = 0
|
||||
multi.column.headers = c("Plate ID", "Well", "OD", "Time")
|
||||
single.column.headers = c("","A1")
|
||||
layout.sheet.headers = c("Strain", "Media Definition")
|
||||
|
||||
t = gcat.analysis.main(file.list, single.plate, layout.file = NULL,
|
||||
out.dir = getwd(), graphic.dir = paste(out.dir, "/pics", sep = ""),
|
||||
add.constant = 1, blank.value = NULL, start.index = 2, growth.cutoff = 0.05,
|
||||
use.linear.param=use.linear.param, use.loess=use.loess, smooth.param=0.1,
|
||||
points.to.remove = 0, remove.jumps = F, time.input = NA,
|
||||
plate.nrow = 8, plate.ncol = 12, input.skip.lines = 0,
|
||||
multi.column.headers = c("Plate.ID", "Well", "OD", "Time"), single.column.headers = c("","A1"),
|
||||
layout.sheet.headers = c("Strain", "Media Definition"),
|
||||
silent = F, verbose = F, return.fit = F, overview.jpgs = T)
|
@ -0,0 +1,122 @@
|
||||
#Copyright 2012 The Board of Regents of the University of Wisconsin System.
|
||||
#Contributors: Jason Shao, James McCurdy, Enhai Xie, Adam G.W. Halstead,
|
||||
#Michael H. Whitney, Nathan DiPiazza, Trey K. Sato and Yury V. Bukhman
|
||||
#
|
||||
#This file is part of GCAT.
|
||||
#
|
||||
#GCAT is free software: you can redistribute it and/or modify
|
||||
#it under the terms of the GNU Lesser General Public License as published by
|
||||
#the Free Software Foundation, either version 3 of the License, or
|
||||
#(at your option) any later version.
|
||||
#
|
||||
#GCAT is distributed in the hope that it will be useful,
|
||||
#but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
#GNU Lesser General Public License for more details.
|
||||
#
|
||||
#You should have received a copy of the GNU Lesser General Public License
|
||||
#along with GCAT. If not, see <http://www.gnu.org/licenses/>.
|
||||
########################################################################
|
||||
# #
|
||||
# <model> class definition and functions. Objects contain equations #
|
||||
# and other information for parameterized growth curve models. #
|
||||
# #
|
||||
########################################################################
|
||||
setClass("model", representation(name = "character",
|
||||
expression = "expression",
|
||||
formula = "formula",
|
||||
guess = "function"))
|
||||
# Slots:
|
||||
# name - a simple description of the model.
|
||||
# expression - an object of class "expression" that evaluates the response (transformed OD) with respect to the variable Time.
|
||||
# formula - same as expression, but with y as the response.
|
||||
# guess - a function that computes initial guesses for the parameters given a well object with a valid "screen.data" slot
|
||||
# containing useable OD values and slope estimates
|
||||
# --------------------------------------------------------------------
|
||||
###################### BEGIN PROTOTYPING ACCESSOR METHODS##############
|
||||
|
||||
# Minh: Let this code fragment be F1.
|
||||
if (!isGeneric("getName")){
|
||||
if (is.function("getName"))
|
||||
fun <- getName
|
||||
else
|
||||
fun <- function(object) standardGeneric("getName")
|
||||
setGeneric("getName", fun)
|
||||
}
|
||||
# End of F1
|
||||
setMethod("getName", "model", function(object) object@name)
|
||||
|
||||
# Minh: Let this line be F2.
|
||||
setGeneric("getExpression", function(object){standardGeneric("getExpression")})
|
||||
# Question: How is F1 different from F2?
|
||||
|
||||
setMethod("getExpression", "model",
|
||||
function(object){
|
||||
return(object@expression)
|
||||
})
|
||||
|
||||
setGeneric("getFormula", function(object){standeardGeneric("getFormula")})
|
||||
setMethod("getFormula", "model",
|
||||
function(object){
|
||||
return(object@formula)
|
||||
})
|
||||
|
||||
setGeneric("getGuess", function(object){standeardGeneric("getGuess")})
|
||||
setMethod("getGuess", "model",
|
||||
function(object){
|
||||
return(object@guess)
|
||||
})
|
||||
######################## ENG PROTOTYPING ########################
|
||||
|
||||
# Function to create a new model
|
||||
#' Model
|
||||
#'
|
||||
#' Function to create a new model
|
||||
#' @param name The name of the model
|
||||
#' @param expression Expression of the model
|
||||
#' @param formula The formula of this model
|
||||
#' @param guess The guess of this model
|
||||
#' @return The new model
|
||||
model = function(name, expression, formula, guess){
|
||||
new("model", name = name, expression = expression, formula = formula, guess = guess)
|
||||
}
|
||||
|
||||
loess.g = function(well,smooth.param=0.75){
|
||||
#data = data.from(well)
|
||||
#growth = data[,2]
|
||||
#Time = data[,1]
|
||||
Time = data.from(well)[,1]
|
||||
|
||||
# predicted growth values to be used in estimating growth curve parameters
|
||||
loess.fit = loess(data.from(well)[,2]~Time,span=smooth.param)
|
||||
t = seq(from = min(Time), to = max(Time), by = (max(Time)-min(Time))/1000)
|
||||
y = predict(loess.fit, data.frame(Time=t))
|
||||
attr(y,"names") = NULL # need to remove the names to prevent them from showing up in the returned vector
|
||||
|
||||
# Remove any data points where y has not been estimated
|
||||
filt = is.finite(y)
|
||||
t = t[filt]
|
||||
y = y[filt] # remove any NA etc
|
||||
|
||||
# specific growth using loess to find max derivative
|
||||
delta.t = diff(t)
|
||||
dydt = diff(y)/delta.t
|
||||
u = max(dydt)
|
||||
|
||||
# lower and upper asymptotes
|
||||
b = min(y)
|
||||
A = max(y) - min(y)
|
||||
|
||||
# inflection point
|
||||
inflection.pt.index = which.max(dydt)
|
||||
inflection.time = t[inflection.pt.index]
|
||||
inflection.y = y[inflection.pt.index]
|
||||
|
||||
# lag time
|
||||
lam = inflection.time - (inflection.y-b)/u
|
||||
|
||||
# Return named array of estimates
|
||||
c(A = A, b = b, lam = lam, u = u)
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,435 @@
|
||||
#Copyright 2012 The Board of Regents of the University of Wisconsin System.
|
||||
#Contributors: Jason Shao, James McCurdy, Enhai Xie, Adam G.W. Halstead,
|
||||
#Michael H. Whitney, Nathan DiPiazza, Trey K. Sato and Yury V. Bukhman
|
||||
#
|
||||
#This file is part of GCAT.
|
||||
#
|
||||
#GCAT is free software: you can redistribute it and/or modify
|
||||
#it under the terms of the GNU Lesser General Public License as published by
|
||||
#the Free Software Foundation, either version 3 of the License, or
|
||||
#(at your option) any later version.
|
||||
#
|
||||
#GCAT is distributed in the hope that it will be useful,
|
||||
#but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
#GNU Lesser General Public License for more details.
|
||||
#
|
||||
#You should have received a copy of the GNU Lesser General Public License
|
||||
#along with GCAT. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
########################################################################
|
||||
# #
|
||||
# <well> class definition and functions. Objects contain raw #
|
||||
# data from screening runs on single wells from 96-well plates, and #
|
||||
# other slots for processing and model-fitting details. #
|
||||
# #
|
||||
########################################################################
|
||||
|
||||
# Windows OS compatibility
|
||||
Sys.setlocale(locale="C")
|
||||
#require(RExcelXML)
|
||||
|
||||
# Treat nls and loess as S4 classes to avoid warnings
|
||||
setOldClass("nls")
|
||||
setOldClass("loess")
|
||||
setClass("well", representation(position = "character",
|
||||
well.info = "list",
|
||||
screen.data = "data.frame",
|
||||
start.index = "numeric",
|
||||
use.log = "logical",
|
||||
norm = "numeric",
|
||||
curve.par = "list",
|
||||
fit.par = "list",
|
||||
fit.std.err = "list",
|
||||
equation = "expression",
|
||||
model.name = "character",
|
||||
fit.info = "character",
|
||||
add.info = "character",
|
||||
inflection.time = "numeric",
|
||||
rss = "numeric",
|
||||
loess = "loess",
|
||||
nls = "nls"))
|
||||
|
||||
# Slots:
|
||||
# position - 3-member vector containing identifying information for the well: row (letters), column (numbers) and plate ID.
|
||||
# well.info - a list containing strain and media names if provided
|
||||
# screen.data - a data frame with Time and raw OD values. This is the only slot that is filled upon creation of a well object.
|
||||
# as different functions are run on the well the data frame gets filled with additional columns.
|
||||
# use.log - a single logical value denoting whether to return log-transformed values when data is requested from the well
|
||||
# norm - a value to subtract from all OD values before returning data. filled by <normalize.ODs> (see normalize.and.transform.R)
|
||||
# curve.par - a list of parameters that denote whether the well is empty, whether it contains ODs indicating a viable culture, whether it tanks at a certain timepoint.
|
||||
|
||||
# if model fitting using <fit.model> is successful:
|
||||
# fit.par - will be a list containing the fitted model parameters
|
||||
# fit.std.err - will be a list containing the standard errors for the fitted model parameters
|
||||
# equation - will contain an expression for evaluating the successfully fitted model
|
||||
# model.name - will contain the name of the successfully fit model
|
||||
|
||||
# fit.info - a message with info about whether the fit was successful, failed, or skipped.
|
||||
# add.info - a message with info about whether jumps in OD were detected or removed, or if ODs were detected below the blank OD.
|
||||
# inflection.time - the Time value at the point where the specific growth is located. no longer a formula param NWD
|
||||
# rss - residual sum of squares
|
||||
# loess - object returned by running loess on the normalized well data
|
||||
# nls - object returned by running nls on the normalized well data
|
||||
|
||||
setGeneric("getPosition", function(object){standeardGeneric("getPosition")})
|
||||
setMethod("getPosition", "well",
|
||||
function(object){
|
||||
return(object@position)
|
||||
})
|
||||
|
||||
setGeneric("getWellInfo", function(object){standeardGeneric("getWellInfo")})
|
||||
setMethod("getWellInfo", "well",
|
||||
function(object){
|
||||
return(object@well.info)
|
||||
})
|
||||
|
||||
setGeneric("getScreenData", function(object){standeardGeneric("getScreenData")})
|
||||
setMethod("getScreenData", "well",
|
||||
function(object){
|
||||
return(object@screen.data)
|
||||
})
|
||||
|
||||
setGeneric("getStartIndex", function(object){standeardGeneric("getStartIndex")})
|
||||
setMethod("getStartIndex", "well",
|
||||
function(object){
|
||||
return(object@start.index)
|
||||
})
|
||||
|
||||
setGeneric("getUseLog", function(object){standeardGeneric("getUseLog")})
|
||||
setMethod("getUseLog", "well",
|
||||
function(object){
|
||||
return(object@use.log)
|
||||
})
|
||||
|
||||
setGeneric("getNorm", function(object){standeardGeneric("getNorm")})
|
||||
setMethod("getNorm", "well",
|
||||
function(object){
|
||||
return(object@norm)
|
||||
})
|
||||
|
||||
setGeneric("getCurPar", function(object){standeardGeneric("getCurPar")})
|
||||
setMethod("getCurPar", "well",
|
||||
function(object){
|
||||
return(object@curve.par)
|
||||
})
|
||||
|
||||
setGeneric("getFitErr", function(object){standeardGeneric("getFitErr")})
|
||||
setMethod("getFitErr", "well",
|
||||
function(object){
|
||||
return(object@fit.std.err)
|
||||
})
|
||||
|
||||
setGeneric("getEquation", function(object){standeardGeneric("getEquation")})
|
||||
setMethod("getEquation", "well",
|
||||
function(object){
|
||||
return(object@equation)
|
||||
})
|
||||
|
||||
setGeneric("getModelName", function(object){standeardGeneric("getModelName")})
|
||||
setMethod("getModelName", "well",
|
||||
function(object){
|
||||
return(object@model.name)
|
||||
})
|
||||
|
||||
setGeneric("getFitInfo", function(object){standeardGeneric("getFitInfo")})
|
||||
setMethod("getFitInfo", "well",
|
||||
function(object){
|
||||
return(object@fit.info)
|
||||
})
|
||||
|
||||
setGeneric("getAddInfo", function(object){standeardGeneric("getAddInfo")})
|
||||
setMethod("getAddInfo", "well",
|
||||
function(object){
|
||||
return(object@add.info)
|
||||
})
|
||||
|
||||
setGeneric("getInflectionTime", function(object){standeardGeneric("getInflectionTime")})
|
||||
setMethod("getInflectionTime", "well",
|
||||
function(object){
|
||||
return(object@inflection.time)
|
||||
})
|
||||
|
||||
setGeneric("getRSS", function(object){standeardGeneric("getRSS")})
|
||||
setMethod("getRSS", "well",
|
||||
function(object){
|
||||
return(object@rss)
|
||||
})
|
||||
|
||||
setGeneric("getLoess", function(object){standeardGeneric("getLoess")})
|
||||
setMethod("getLoess", "well",
|
||||
function(object){
|
||||
return(object@loess)
|
||||
})
|
||||
|
||||
setGeneric("getnls", function(object){standeardGeneric("getnls")})
|
||||
setMethod("getnls", "well",
|
||||
function(object){
|
||||
return(object@nls)
|
||||
})
|
||||
|
||||
setGeneric("getFitPar", function(object){standeardGeneric("getFitPar")})
|
||||
setMethod("getFitPar", "well",
|
||||
function(object){
|
||||
return(object@fit.par)
|
||||
})
|
||||
|
||||
# --------------------------------------------------------------------
|
||||
# Function to create a new well (requires only Time and OD vectors, which will fill slot "screen.data")
|
||||
# slots "nls" and "loess" are initialized to empty lists
|
||||
well = function(Time = NULL, OD = NULL){
|
||||
x = list()
|
||||
class(x) = "loess"
|
||||
y = list()
|
||||
class(y) = "nls"
|
||||
new("well", screen.data = data.frame(Time, OD, stringsAsFactors=F), loess=x, nls=y)
|
||||
}
|
||||
|
||||
# -----------------------------------------------------------------------
|
||||
#### A show method for well ####
|
||||
setMethod("show", "well",
|
||||
function(object) {
|
||||
print("Object of class well")
|
||||
print("@position:")
|
||||
print(object@position)
|
||||
print("@well.info:")
|
||||
print(object@well.info)
|
||||
print("@screen.data:")
|
||||
print(head(object@screen.data))
|
||||
print("...")
|
||||
print(paste(nrow(object@screen.data),"rows of data"))
|
||||
print(paste("@start.index:",object@start.index))
|
||||
print(paste("@use.log:",object@use.log))
|
||||
print(paste("@norm:",object@norm))
|
||||
print("@curve.par:")
|
||||
print(object@curve.par)
|
||||
print("@fit.par:")
|
||||
print(object@fit.par)
|
||||
print("@fit.std.err:")
|
||||
print(object@fit.std.err)
|
||||
print(paste("@equation:",object@equation))
|
||||
print(paste("@model.name:",object@model.name))
|
||||
print(paste("@fit.info:",object@fit.info))
|
||||
print(paste("@add.info:",object@add.info))
|
||||
print(paste("@inflection.time:",object@inflection.time))
|
||||
print(paste("@rss:",object@rss))
|
||||
if (length(object@nls) > 0) {
|
||||
print("@nls:")
|
||||
print(object@nls)
|
||||
} else {
|
||||
print("no nls model")
|
||||
}
|
||||
if (length(object@loess) > 0) {
|
||||
print("@loess:")
|
||||
print(object@loess)
|
||||
} else {
|
||||
print("no loess model")
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
#### A plot method for well ####
|
||||
# x - object of class well
|
||||
# y - not used
|
||||
# constant.added - used to readjust for the constant added during the log transform: log.OD = log(OD - blank + constant.added)
|
||||
# xlim - x axis limits, vector of length 2
|
||||
# ylim - y axis limits, vector of length 2
|
||||
# scale - determines the font scale for the entire graph. all cex values are calculated from this
|
||||
# number.points - should points be labeled with numeric indices?
|
||||
# draw.symbols - should <check.slopes> be called on the well and markings drawn on the graph?
|
||||
# show.text - show R^2 and growth curve parameters as text on the plot
|
||||
# show.calc - draw lines that illustrate growth curve parameters
|
||||
# draw.guess - initial guess model. Drawn if specified
|
||||
# well.number - the number of the well in an array of wells
|
||||
# ... - additional arguments passed to the generic plot function
|
||||
|
||||
setMethod("plot",
|
||||
signature(x = "well", y="missing"),
|
||||
function (x, y, constant.added = 1.0, xlim = NULL, ylim = NULL,
|
||||
well.number = NULL, scale = 1, number.points = T, draw.symbols = F, show.text = T, show.calc = T, draw.guess = NULL, ...)
|
||||
{
|
||||
# Determine the boundaries for the axes (if user did not specify them)
|
||||
if(is.null(ylim)){
|
||||
min.y = min(data.from(x, remove = F, remove.tanking = F)[,2], na.rm = T)
|
||||
min.y = min(min.y, x@fit.par$b)
|
||||
max.y = max(data.from(x, remove = F, remove.tanking = F)[,2], na.rm = T)
|
||||
max.y = max(max.y, x@fit.par$b + x@fit.par$A)
|
||||
ylim = c(min.y, min.y + (max.y-min.y)*1.15)
|
||||
}
|
||||
if(is.null(xlim)){
|
||||
min.x = min(data.from(x, remove = F, remove.tanking = F)[,1], na.rm = T)
|
||||
max.x = max(data.from(x, remove = F, remove.tanking = F)[,1], na.rm = T)
|
||||
xlim = c(min.x - 0.05 * (max.x-min.x), max.x)
|
||||
}
|
||||
|
||||
|
||||
# Title of plot: [well number] plate name; well name;
|
||||
# strain name; media name
|
||||
|
||||
main = paste(plate.name(x), " ", well.name(x), "\n",
|
||||
strain.name(x), "; ", media.name(x), sep = "")
|
||||
if (!is.null(well.number)) main = paste("[", well.number , "] ", main, sep="")
|
||||
|
||||
# Draw the data and symbols if <draw.symbols> is true.
|
||||
plot.data(x, main = main, scale = scale, constant.added=constant.added,
|
||||
number.points = number.points, draw.symbols = draw.symbols, xlim = xlim, ylim = ylim, ...)
|
||||
|
||||
# Draw the fitted model.
|
||||
plot.model(x, scale = scale, constant.added=constant.added)
|
||||
|
||||
# Draw text info if specified.
|
||||
if(show.text)
|
||||
draw.text(x, scale = scale * 0.5, xlim = xlim, ylim = ylim,...)
|
||||
|
||||
# Show calculated parameters if specified.
|
||||
if (show.calc)
|
||||
draw.calc.par(x, scale = scale * 0.5, constant.added = constant.added)
|
||||
|
||||
# Draw initial guess if a model is specified.
|
||||
if (class(draw.guess) == "model"){
|
||||
Time = data.from(x)$Time
|
||||
guess = eval(getExpression(draw.guess), as.list(getGuess(draw.guess)(x)))
|
||||
try(lines(Time, guess, col = "brown2"), silent = T)
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
########################################################################
|
||||
# Some miscellaneous functions to extract info from well objects #
|
||||
# Most of these return a single value from the well. #
|
||||
########################################################################
|
||||
#
|
||||
# Since many of these need to be applied to all wells over an array, while conserving the dimensions of
|
||||
# that array, this file includes a wrapper function <aapply> (see bottom of file).
|
||||
|
||||
plate.name = function(well)
|
||||
getPosition(well)[1]
|
||||
|
||||
# Return the full alphanumeric well name (with leading zeros if applicable)
|
||||
well.name = function(well){
|
||||
row = getPosition(well)[2]
|
||||
col = as.numeric(getPosition(well)[3])
|
||||
if (col>9)
|
||||
col = as.character(col)
|
||||
else
|
||||
col = paste("0", col, sep = "")
|
||||
|
||||
paste(row,col,sep = "")
|
||||
}
|
||||
|
||||
is.empty = function(well)
|
||||
getCurPar(well)$empty.well
|
||||
|
||||
lacks.growth = function(well)
|
||||
getCurPar(well)$no.growth
|
||||
|
||||
tanking.start = function(well)
|
||||
getCurPar(well)$tanking.start
|
||||
|
||||
removed.points = function(well)
|
||||
(1:length(well))[getScreenData(well)$Remove]
|
||||
|
||||
remaining.points = function(well,...){
|
||||
as.numeric(rownames(data.from(well,...)))
|
||||
}
|
||||
|
||||
strain.name = function(well){
|
||||
if(is.null(getWellInfo(well)$Strain))
|
||||
return("<NA>")
|
||||
else
|
||||
return(getWellInfo(well)$Strain)
|
||||
}
|
||||
media.name = function(well){
|
||||
if(is.null(getWellInfo(well)$Media))
|
||||
return("<NA>")
|
||||
else
|
||||
return(getWellInfo(well)$Media)
|
||||
}
|
||||
|
||||
raw.data = function(well)
|
||||
data.from(well, remove.tanking = F, remove = F, na.rm = F, raw.data = T)
|
||||
|
||||
contains.fit = function(well)
|
||||
length(getFitPar(well)) > 0
|
||||
|
||||
setMethod("length", signature(x = "well"), function(x) length(x@screen.data[,1]))
|
||||
|
||||
# The <data.from> function has some options: by default it returns a two-column data frame with time and OD
|
||||
# (or log OD if the <use.log> slot is true in the object), after normalization to the value specified in <norm> slot.
|
||||
# - With <remove> set to true the rows specified in the <remove> column of the <screen.data> slot are not returned.
|
||||
# - With <remove.tanking> set to true all the rows after the <tanking.start> index are removed.
|
||||
# - Setting <raw.data> to true overrides all these settings and just returns 2 columns with Time and Raw OD.
|
||||
|
||||
data.from = function(well, remove = T, remove.tanking = T, raw.data = F, na.rm = F){
|
||||
|
||||
if (length(getUseLog(well)) == 0)
|
||||
OD.column = "OD"
|
||||
else if (getUseLog(well))
|
||||
OD.column = "log.OD"
|
||||
else
|
||||
OD.column = "OD"
|
||||
|
||||
if (raw.data){
|
||||
OD.column = "OD"
|
||||
norm = 0
|
||||
}
|
||||
else if (!getUseLog(well))
|
||||
norm = getNorm(well)
|
||||
else
|
||||
norm = 0
|
||||
|
||||
if(remove.tanking & is.numeric(tanking.start(well)))
|
||||
well = remove.points(well, (tanking.start(well)):length(well))
|
||||
if (!remove | is.null(getScreenData(well)$Remove))
|
||||
output = getScreenData(well)[c("Time", OD.column)]
|
||||
else
|
||||
output = getScreenData(well)[!getScreenData(well)$Remove ,c("Time", OD.column)]
|
||||
|
||||
output[,2] = output[,2] - norm
|
||||
|
||||
if (!raw.data){
|
||||
if (!length(getUseLog(well)))
|
||||
names(output)[2] = "Corrected.OD"
|
||||
if (!getUseLog(well))
|
||||
names(output)[2] = "Corrected.OD"
|
||||
}
|
||||
|
||||
if (na.rm)
|
||||
output[!is.na(output[,2]),]
|
||||
else
|
||||
output
|
||||
}
|
||||
|
||||
|
||||
# Functions much like <data.from> but gives a single vector containing the
|
||||
# slope at each point. Has a parameter allowing removal of NA values.
|
||||
|
||||
slopes = function(well, remove = T, remove.tanking = T, na.rm = F){
|
||||
|
||||
if(remove.tanking & is.numeric(tanking.start(well)))
|
||||
well = remove.points(well, (tanking.start(well)):length(well))
|
||||
if (!remove | is.null(getScreenData(well)$Remove))
|
||||
output = getScreenData(well)$Slope
|
||||
else
|
||||
output = getScreenData(well)$Slope[!getScreenData(well)$Remove]
|
||||
|
||||
if (na.rm)
|
||||
output[!is.na(output)]
|
||||
else
|
||||
output
|
||||
}
|
||||
|
||||
# -----------------------------------------------------------------------
|
||||
# Well array functions: these must be used on entire arrays of well objects
|
||||
# instead of single ones.
|
||||
|
||||
plate.names = function(well.array)
|
||||
dimnames(well.array)[[3]]
|
||||
|
||||
tanking.start.values = function(well.array, array = F){
|
||||
if (array)
|
||||
aapply(well.array, function(well) tanking.start(well))
|
||||
else
|
||||
sapply(well.array, function(well) tanking.start(well))
|
||||
}
|
||||
|
@ -0,0 +1,257 @@
|
||||
#Copyright 2012 The Board of Regents of the University of Wisconsin System.
|
||||
#Contributors: Jason Shao, James McCurdy, Enhai Xie, Adam G.W. Halstead,
|
||||
#Michael H. Whitney, Nathan DiPiazza, Trey K. Sato and Yury V. Bukhman
|
||||
#
|
||||
#This file is part of GCAT.
|
||||
#
|
||||
#GCAT is free software: you can redistribute it and/or modify
|
||||
#it under the terms of the GNU Lesser General Public License as published by
|
||||
#the Free Software Foundation, either version 3 of the License, or
|
||||
#(at your option) any later version.
|
||||
#
|
||||
#GCAT is distributed in the hope that it will be useful,
|
||||
#but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
#GNU Lesser General Public License for more details.
|
||||
#
|
||||
#You should have received a copy of the GNU Lesser General Public License
|
||||
#along with GCAT. If not, see <http://www.gnu.org/licenses/>.
|
||||
########################################################################
|
||||
# #
|
||||
# Fit a parameterized model to the growth data in a well object. #
|
||||
# #
|
||||
# There are now three modelling choices: #
|
||||
# 1) Sigmoid model (no linear param c) #
|
||||
# 2) Linear Sigmoid model #
|
||||
# 3) Loess (with optional smoothing parameter) #
|
||||
########################################################################
|
||||
#' fit.model
|
||||
#'
|
||||
#' This function will use the function stored in the "guess" slot of \code{growth.model} to calculate initial guesses
|
||||
#' for growth.model parameters, then it will use the "formula" slot with \code{nls} to fit a non-linear least squares
|
||||
#' \code{growth.model} or Local Polynomial Regression Fitting to the data. Richards model is first fitted.
|
||||
#' If the shape parameter is statisticaly significant then Richards is used. If it is within 2 SE of 1 or Zero than
|
||||
#' a simpler model is preferred. If the Richards fit fails, then Logistic is tried. If it fails, Gompertz is tried.
|
||||
#' Model fit failure is reported if none of the models can sucessfully fit the data
|
||||
#'
|
||||
#' @param input.well The well needed to be fitted with the given model.
|
||||
#' @param growth.model What growth model should be used?
|
||||
#' @param backup.growth.model If \code{gowth.mode} fails, this model will be used.
|
||||
#' @param fit.if.no.growth should the function attempt to fit a well even if there was no growth detected? default is F
|
||||
#' @param silent output back to R console?
|
||||
#' @param use.linear.param: Should an additional linear parameter (c) be used when fitting the data to the model?
|
||||
#' @param use.loess: Should Local Polynomial Regression Fitting (loess function) be used instead of nls?
|
||||
#' @param smooth.param: If loess is used, an optional smoothing parameter. Default is .6
|
||||
fit.model = function(input.well, growth.model, backup.growth.model = NULL, fit.if.no.growth = F,
|
||||
use.linear.param=F, use.loess=F, smooth.param, silent = T){
|
||||
|
||||
# Conditional breakpoint: go into debugging mode when fitting a specific well
|
||||
#if (input.well@position["row"] == "A" && input.well@position["col"] == "12") browser()
|
||||
|
||||
# Change all relevant slots to <NA> or blank values
|
||||
input.well@model.name = "<NA>"
|
||||
input.well@fit.par = list()
|
||||
input.well@equation = expression()
|
||||
|
||||
# Get OD vs. time data from well
|
||||
input.data = data.from(input.well, na.rm = T)
|
||||
|
||||
# Skip well if <no.growth> in slot "curve.par" is set to true, and <fit.if.no.growth> is false.
|
||||
if(!fit.if.no.growth & lacks.growth(input.well)){
|
||||
input.well@fit.info = "skipped - no growth in well."
|
||||
if (!silent)
|
||||
cat(plate.name(input.well), well.name(input.well), ":", input.well@fit.info, "\n")
|
||||
return(input.well)
|
||||
}
|
||||
# Skip well if there are fewer than 5 data points left in the analysis.
|
||||
if (length(input.data$Time) < 5){
|
||||
input.well@fit.info = "skipped - not enough points."
|
||||
if (!silent)
|
||||
cat(plate.name(input.well), well.name(input.well), ":", input.well@fit.info, "\n")
|
||||
return(input.well)
|
||||
}
|
||||
|
||||
# Change column headers of input.data to the more general "Time" vs. "y"
|
||||
names(input.data) = c("Time", "y")
|
||||
|
||||
# Set a lower bound for nls model parameters A and b to slightly lower than min(y)
|
||||
low.y = min(input.data$y,na.rm=T)
|
||||
low.y = low.y - 0.1*abs(low.y)
|
||||
|
||||
# Extract the model formula from <growth.model> (slot "formula")
|
||||
# Use the function from slot "guess" to calculate initial guesses for model parameters based on slope estimates in <input.well>
|
||||
# Attempt to fit a nonlinear least squares odel using <nls>
|
||||
|
||||
# Creating loess, logistics, richards, and gompertz model.
|
||||
loess.e = expression("loess")
|
||||
loess.f = formula(Time ~ y)
|
||||
loess.model = model("local polynomial regression fit.", loess.e, loess.f, loess.g)
|
||||
|
||||
### Testing accessor method for class model.
|
||||
#print(getName(loess.model))
|
||||
#print(getFormula(loess.model))
|
||||
#print(getGuess(loess.model))
|
||||
### End testing ###
|
||||
|
||||
remove(loess.e, loess.f)
|
||||
|
||||
########################################################################
|
||||
# Create the logistic 4-parameter model (when v ~ 1) #
|
||||
########################################################################
|
||||
logistic.g = function(well,smooth.param=0.75) {
|
||||
loess.model@guess(well,smooth.param)
|
||||
}
|
||||
|
||||
########################################################################
|
||||
# Create the Richards 5-parameter model #
|
||||
########################################################################
|
||||
richards.g = function(well,smooth.param=0.75){
|
||||
c(loess.model@guess(well,smooth.param),v=0.5)
|
||||
}
|
||||
|
||||
########################################################################
|
||||
# Create the Gompertz model (might be useful as a #
|
||||
# limiting case of Richards model when v ~ 0) #
|
||||
########################################################################
|
||||
gompertz.g = function(well,smooth.param=0.75){
|
||||
loess.model@guess(well,smooth.param)
|
||||
}
|
||||
|
||||
logistic.e = expression((A/(1+exp((4*u/A)*(lam-Time)+2)))+b)
|
||||
logistic.f = formula(y~(A/(1+exp((4*u/A)*(lam-Time)+2)))+b)
|
||||
logistic = model("logistic sigmoid.", logistic.e, logistic.f, logistic.g)
|
||||
remove(logistic.e, logistic.f, logistic.g)
|
||||
|
||||
richards.e = expression(A*(1+v*exp(1+v)*exp((u/A)*(1+v)**(1+1/v)*(lam-Time)))**(-1/v)+b)
|
||||
richards.f = formula(y~A*(1+v*exp(1+v)*exp((u/A)*(1+v)**(1+1/v)*(lam-Time)))**(-1/v)+b)
|
||||
richards = model("richards sigmoid", richards.e, richards.f, richards.g)
|
||||
remove(richards.e, richards.f, richards.g)
|
||||
|
||||
gompertz.e = expression(A*exp(-exp((u*exp(1)/A)*(lam-Time)+1))+b)
|
||||
gompertz.f = formula(y~A*exp(-exp((u*exp(1)/A)*(lam-Time)+1))+b)
|
||||
gompertz = model("gompertz sigmoid", gompertz.e, gompertz.f, gompertz.g)
|
||||
remove(gompertz.e, gompertz.f, gompertz.g)
|
||||
|
||||
|
||||
|
||||
# 3) Loess (with optional smoothing parameter)
|
||||
if(use.loess){
|
||||
number.of.points = nrow(input.well@screen.data)
|
||||
if (smooth.param <= 1/number.of.points)
|
||||
exception("Invalid input", "Smoothing parameter is out of range.")
|
||||
|
||||
fit = try(loess(y~Time, data=input.data, span=smooth.param), silent=TRUE)
|
||||
input.well@loess = fit
|
||||
if (class(fit) != "loess") stop("loess fit failed on well", paste(input.well@position,collapse=" "))
|
||||
input.well@fit.info = "Loess model fit successfully."
|
||||
input.well@model.name = loess.model@name
|
||||
input.well@equation = loess.model@expression
|
||||
# There are no estimated params, so just return the initial guesses
|
||||
input.well@fit.par = append(as.list(loess.model@guess(input.well,smooth.param)),list("smoothing parameter"=smooth.param))
|
||||
# Note: since there are no params there are no Std. Errors either
|
||||
input.well@inflection.time = inflection.time(input.well)
|
||||
# calculate Rss for loess
|
||||
input.well@rss = sum((input.data$y-predict(fit))**2)
|
||||
} else {
|
||||
fit = fit.nls.model(input.well,richards)
|
||||
# should we use richards? Yes, unless the v param is close to 1 or Zero
|
||||
if(class(fit) == "nls"){
|
||||
rich.fit = fit # if v is significant or other fits consequently fail
|
||||
fit.par = as.list(coef(fit))
|
||||
# is fit similar to the Logistic?
|
||||
if(fit.par$v >= .5 && abs(fit.par$v-1) < 2*summary(fit)$parameters["v","Std. Error"] ){
|
||||
fit = fit.nls.model(input.well,logistic)
|
||||
input.well@fit.info = paste("Logistic model fit successfully.")
|
||||
input.well@model.name = logistic@name
|
||||
input.well@equation = logistic@expression
|
||||
# is fit similar to Gompertz?
|
||||
}else if(fit.par$v < .5 && abs(fit.par$v) < 2*summary(fit)$parameters["v","Std. Error"]){
|
||||
fit = fit.nls.model(input.well,gompertz)
|
||||
input.well@fit.info = "Gompertz model fit successfully."
|
||||
input.well@model.name = gompertz@name
|
||||
input.well@equation = gompertz@expression
|
||||
# v param is significant. stick with Richards
|
||||
}else{
|
||||
input.well@fit.info = paste("Richards model fit successfully.")
|
||||
input.well@model.name = richards@name
|
||||
input.well@equation = richards@expression
|
||||
}
|
||||
# just in case logistic or gompertz failed to fit...
|
||||
if(class(fit) != "nls"){
|
||||
fit = rich.fit
|
||||
input.well@fit.info = paste("Richards model fit successfully.")
|
||||
input.well@model.name = richards@name
|
||||
input.well@equation = richards@expression
|
||||
}
|
||||
} else{
|
||||
# Richards failed. try backup models
|
||||
fit = fit.nls.model(input.well,logistic)
|
||||
if(class(fit) != "nls"){
|
||||
# last resort try gompertz
|
||||
fit = fit.nls.model(input.well,gompertz)
|
||||
if(class(fit) != "nls"){
|
||||
input.well@fit.info = "Model fitting failed."
|
||||
} else{
|
||||
input.well@fit.info = "Gompertz model fit successfully."
|
||||
input.well@model.name = gompertz@name
|
||||
input.well@equation = gompertz@expression
|
||||
}
|
||||
}else{
|
||||
input.well@fit.info = paste("Logistic model fit successfully.")
|
||||
input.well@model.name = logistic@name
|
||||
input.well@equation = logistic@expression
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# If no error was reported by the model fitting, add coefficients to slot "fit.par",
|
||||
# Also add the Standard Errors for each parameter
|
||||
if (class(fit) == "nls"){
|
||||
input.well@nls = fit
|
||||
input.well@inflection.time = inflection.time(input.well)
|
||||
input.well@fit.par = as.list(coef(fit))
|
||||
rSs = sum(residuals(fit)**2)
|
||||
|
||||
if (length(rSs) != 0)
|
||||
input.well@rss = rSs
|
||||
else
|
||||
input.well@rss = NA
|
||||
input.well@fit.std.err = as.list(summary(fit)$parameters[,"Std. Error"])
|
||||
}
|
||||
# Output to console
|
||||
if (!silent)
|
||||
cat(plate.name(input.well), well.name(input.well), ":", input.well@fit.info, "\n")
|
||||
return(input.well)
|
||||
}
|
||||
|
||||
# Fit nls model to a well using a specified model
|
||||
# Arguments:
|
||||
# input.well: object of class well
|
||||
# model: object of class model, e.g. richards, gompertz or logistic
|
||||
fit.nls.model <- function (input.well, model) {
|
||||
# Get OD vs. time data from well
|
||||
input.data = data.from(input.well, na.rm = T)
|
||||
# Change column headers of input.data to the more general "Time" vs. "y"
|
||||
names(input.data) = c("Time", "y")
|
||||
|
||||
# Set a lower bound for nls model parameters A and b to slightly lower than min(y)
|
||||
low.y = min(input.data$y,na.rm=T)
|
||||
low.y = low.y - 0.1*abs(low.y)
|
||||
|
||||
# Set the initial guess
|
||||
start = model@guess(input.well)
|
||||
|
||||
# Set lower bounds
|
||||
if (length(start) == 4) {
|
||||
lower = c(low.y,low.y,0,0)
|
||||
} else if (length(start) == 5) {
|
||||
lower = c(low.y,low.y,0,0,0.07)
|
||||
} else {
|
||||
stop("Unsupported model: ", model@name)
|
||||
}
|
||||
# Make sure initial guess values do not violate lower bounds
|
||||
start[start < lower] = lower[start < lower]
|
||||
|
||||
# Fit the model
|
||||
try(nls(formula = model@formula, data = input.data, start = start, algorithm="port", lower=lower), silent = TRUE)
|
||||
}
|
@ -0,0 +1,381 @@
|
||||
#Copyright 2012 The Board of Regents of the University of Wisconsin System.
|
||||
#Contributors: Jason Shao, James McCurdy, Enhai Xie, Adam G.W. Halstead,
|
||||
#Michael H. Whitney, Nathan DiPiazza, Trey K. Sato and Yury V. Bukhman
|
||||
#
|
||||
#This file is part of GCAT.
|
||||
#
|
||||
#GCAT is free software: you can redistribute it and/or modify
|
||||
#it under the terms of the GNU Lesser General Public License as published by
|
||||
#the Free Software Foundation, either version 3 of the License, or
|
||||
#(at your option) any later version.
|
||||
#
|
||||
#GCAT is distributed in the hope that it will be useful,
|
||||
#but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
#GNU Lesser General Public License for more details.
|
||||
#
|
||||
#You should have received a copy of the GNU Lesser General Public License
|
||||
#along with GCAT. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
########################################################################
|
||||
# #
|
||||
# Functions to calculate various things about wells based on fit model #
|
||||
# #
|
||||
########################################################################
|
||||
|
||||
# S3 generic
|
||||
lag <- function(fitted.well, ...)
|
||||
{
|
||||
UseMethod("lag")
|
||||
}
|
||||
|
||||
#
|
||||
# Common arguments:
|
||||
# fitted.well - should be a well containing the results of <fit.model>, most functions will return NA if well has not been fit yet.
|
||||
# unlog - should the value be returned on the linear scale as opposed to the log-transformed scale?
|
||||
# constant.added - for returning values on the linear scale, what was the constant added before the log transform?
|
||||
# digits - passed to the <round> function, default is no rounding (infinity digits)
|
||||
|
||||
unlog = function(x, constant.added) {
|
||||
########################################################################
|
||||
# Transform values back to OD scale #
|
||||
########################################################################
|
||||
exp(x) - constant.added
|
||||
}
|
||||
|
||||
well.eval = function(fitted.well, Time = NULL){
|
||||
########################################################################
|
||||
# Evaluate estimated OD at any timepoints using the fitted model #
|
||||
########################################################################
|
||||
|
||||
# If no timepoints are provided, use the ones collected in the experiment itself.
|
||||
if(!is.numeric(Time))
|
||||
Time = data.from(fitted.well)$Time
|
||||
|
||||
# Use of equation is deprecated. Use nls and loess models stored in the well object instead
|
||||
# Attempt to use <eval> with the fitted equation and parameters to get estimates for OD at the given timepoints.
|
||||
#output = try(eval(fitted.well@equation, fitted.well@fit.par), silent = T)
|
||||
|
||||
# Predict log.OD value(s) using nls model if present. If no nls model, try using loess.
|
||||
if (length(fitted.well@nls)>0) {
|
||||
output = try(predict(fitted.well@nls,list(Time=Time)),silent=T)
|
||||
} else if (length(fitted.well@loess)>0) {
|
||||
output = try(predict(fitted.well@loess,Time),silent=T)
|
||||
} else {
|
||||
output = NA
|
||||
}
|
||||
|
||||
# Return values. If OD evaluation failed for any reason, return NULL.
|
||||
if (is.numeric(output)){
|
||||
return(output)
|
||||
} else {
|
||||
return(NULL)
|
||||
}
|
||||
}
|
||||
|
||||
model.residuals = function(fitted.well, unlog = F){
|
||||
########################################################################
|
||||
# Evaluate model residuals using the measured vs. fitted log.OD values #
|
||||
########################################################################
|
||||
measured.OD = data.from(fitted.well)[,2]
|
||||
|
||||
# Use <well.eval> with no Time argument to get fitted OD values at measured timepoints.
|
||||
predicted.OD = well.eval(fitted.well)
|
||||
|
||||
# If all values are valid, return the differences
|
||||
if (!is.numeric(predicted.OD))
|
||||
return(NA)
|
||||
else
|
||||
return(measured.OD - predicted.OD)
|
||||
}
|
||||
|
||||
dev.from.mean = function(fitted.well){
|
||||
########################################################################
|
||||
# Evaluate deviations of log.OD values from the mean #
|
||||
########################################################################
|
||||
measured.ODs = data.from(fitted.well,remove=T,na.rm=T)[,2]
|
||||
|
||||
# Get the mean values of these measured ODs.
|
||||
mean.ODs = mean(measured.ODs)
|
||||
|
||||
if (!is.numeric(mean.ODs))
|
||||
return (NA)
|
||||
else
|
||||
return (measured.ODs - mean.ODs)
|
||||
}
|
||||
|
||||
rss = function(fitted.well){
|
||||
#######################################################################
|
||||
# Get the residual sum of square. #
|
||||
#######################################################################
|
||||
if (length(fitted.well@rss) == 0)
|
||||
return (NA)
|
||||
else
|
||||
return (fitted.well@rss)
|
||||
}
|
||||
|
||||
model.good.fit = function(fitted.well, digits = Inf){
|
||||
########################################################################
|
||||
# Calculate a metric for fit accuracy using squared residuals #
|
||||
########################################################################
|
||||
|
||||
# Sum of squared residuals
|
||||
RSS = rss(fitted.well)
|
||||
|
||||
# Total sum of squared
|
||||
tot = sum(dev.from.mean(fitted.well)^2)
|
||||
|
||||
# Coefficient of determination
|
||||
return (1 - RSS/tot)
|
||||
}
|
||||
|
||||
parameter.text = function(fitted.well){
|
||||
########################################################################
|
||||
# Output a string with values of fitted parameters #
|
||||
########################################################################
|
||||
|
||||
# Get a list of fitted parameters
|
||||
fit.par = fitted.well@fit.par
|
||||
|
||||
# Giving the parameter text descriptive names.
|
||||
if (length(fitted.well@fit.par) != 0){
|
||||
names(fit.par)[1] = "A"
|
||||
names(fit.par)[2] = "b"
|
||||
names(fit.par)[3] = "lambda"
|
||||
names(fit.par)[4] = "max.spec.growth.rate"
|
||||
|
||||
if (fitted.well@model.name == "richards sigmoid"){
|
||||
names(fit.par)[5] = "shape.par"
|
||||
}
|
||||
|
||||
if (fitted.well@model.name == "richards sigmoid with linear par."){
|
||||
names(fit.par)[5] = "shape.param"
|
||||
names(fit.par)[6] = "linear term"
|
||||
}
|
||||
|
||||
if (fitted.well@model.name == "logistic sigmoid with linear par.")
|
||||
names(fit.par)[5] = "linear.term"
|
||||
|
||||
# if loess, just show smoothing param
|
||||
if(fitted.well@model.name == "local polynomial regression fit.")
|
||||
fit.par = fitted.well@fit.par["smoothing parameter"]
|
||||
}
|
||||
|
||||
# Return nothing if the list is empty. Otherwise, concatenate the terms in the list with the parameter names.
|
||||
if(!is.list(fit.par))
|
||||
return()
|
||||
else{
|
||||
output = ""
|
||||
i = 1
|
||||
while(i <= length(fit.par)){
|
||||
output = paste(output, names(fit.par)[i], "=", round(as.numeric(fit.par[i]),3), "; ", sep = "")
|
||||
i = i + 1
|
||||
if (i %% 6 == 0)
|
||||
output = paste(output, "\n")
|
||||
}
|
||||
output
|
||||
}
|
||||
}
|
||||
|
||||
max.spec.growth.rate = function(fitted.well, digits = Inf, ...){
|
||||
########################################################################
|
||||
# Calculate maximum specific growth rate #
|
||||
########################################################################
|
||||
if(length(fitted.well@fit.par) == 0)
|
||||
return(NA)
|
||||
|
||||
round(fitted.well@fit.par$u,digits)
|
||||
}
|
||||
|
||||
|
||||
plateau = function(fitted.well, digits = Inf){
|
||||
########################################################################
|
||||
# Calculate plateau log.OD from fitted parameters #
|
||||
########################################################################
|
||||
if(length(fitted.well@fit.par) == 0)
|
||||
return(NA)
|
||||
|
||||
plat = fitted.well@fit.par$A + fitted.well@fit.par$b
|
||||
|
||||
if (!is.numeric(plat)) {
|
||||
plat = NA
|
||||
} else {
|
||||
plat = round(plat, digits)
|
||||
}
|
||||
return(plat)
|
||||
}
|
||||
|
||||
baseline = function(fitted.well, digits = Inf){
|
||||
########################################################################
|
||||
# Calculate baseline log.OD from fitted parameters #
|
||||
########################################################################
|
||||
if(length(fitted.well@fit.par) == 0)
|
||||
return(NA)
|
||||
|
||||
base = fitted.well@fit.par$b
|
||||
|
||||
# If A (plateau OD) is invalid, return NA.
|
||||
if (!is.numeric(fitted.well@fit.par$A))
|
||||
base = NA
|
||||
# If b (baseline OD) is invalid but plateau OD was valid, return zero.
|
||||
else if (!is.numeric(base))
|
||||
base = 0
|
||||
else{
|
||||
base = round(base, digits)
|
||||
}
|
||||
return(base)
|
||||
}
|
||||
|
||||
inoc.log.OD = function(fitted.well, digits = Inf){
|
||||
########################################################################
|
||||
# Calculate log.OD at inoculation from fitted parameters #
|
||||
########################################################################
|
||||
|
||||
# Evaluated the fitted model at the inoculation timepoint (should be zero from using <start.times> from table2wells.R)
|
||||
if (is.null(well.eval(fitted.well)))
|
||||
return(NA)
|
||||
else{
|
||||
inoc.time = fitted.well@screen.data$Time[fitted.well@start.index]
|
||||
inoc.log.OD = well.eval(fitted.well, inoc.time)
|
||||
if (is.na(inoc.log.OD)) inoc.log.OD = fitted.well@fit.par$b # need this in a special case: loess fits with start.index = 1
|
||||
return(round(inoc.log.OD, digits))
|
||||
}
|
||||
}
|
||||
|
||||
max.log.OD = function(fitted.well, digits = Inf, ...){
|
||||
########################################################################
|
||||
# Calculate max log.OD from model fit #
|
||||
########################################################################
|
||||
|
||||
# Evaluated the fitted model at the final timepoint (just the last valid timepoint in the experiment)
|
||||
if (is.null(well.eval(fitted.well)))
|
||||
return(NA)
|
||||
else{
|
||||
return(round(max(well.eval(fitted.well),na.rm=T), digits))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
projected.growth = function(fitted.well,digits=Inf) {
|
||||
########################################################################
|
||||
# Calculate projected growth: plateau minus the inoculated log.OD #
|
||||
########################################################################
|
||||
plateau(fitted.well,digits) - inoc.log.OD(fitted.well,digits)
|
||||
}
|
||||
|
||||
projected.growth.OD = function(fitted.well,constant.added,digits=Inf) {
|
||||
########################################################################
|
||||
# Calculate projected growth: plateau minus the inoculated log.OD #
|
||||
########################################################################
|
||||
value = unlog(plateau(fitted.well),constant.added) - unlog(inoc.log.OD(fitted.well),constant.added)
|
||||
round(value,digits)
|
||||
}
|
||||
|
||||
|
||||
achieved.growth = function(fitted.well,digits=Inf) {
|
||||
########################################################################
|
||||
# Calculate achieved growth: max.log.OD minus the inoculated log.OD #
|
||||
########################################################################
|
||||
max.log.OD(fitted.well,digits) - inoc.log.OD(fitted.well,digits)
|
||||
}
|
||||
|
||||
achieved.growth.OD = function(fitted.well,constant.added,digits=Inf) {
|
||||
########################################################################
|
||||
# Calculate projected growth: plateau minus the inoculated log.OD #
|
||||
########################################################################
|
||||
value = unlog(max.log.OD(fitted.well),constant.added) - unlog(inoc.log.OD(fitted.well),constant.added)
|
||||
round(value,digits)
|
||||
}
|
||||
|
||||
reach.plateau = function(fitted.well, cutoff = 0.75){
|
||||
########################################################################
|
||||
# Did the curve come close to the plateau OD during the experiment? #
|
||||
########################################################################
|
||||
|
||||
plat = plateau(fitted.well)
|
||||
inoc = inoc.log.OD(fitted.well)
|
||||
final = max.log.OD(fitted.well)
|
||||
|
||||
if (!is.na(final)){
|
||||
# If the plateau is the same as the OD at inoculation, return TRUE
|
||||
if ((plat - inoc) == 0)
|
||||
return(T)
|
||||
# If the difference between the final OD and inoculation OD is at least a certain proportion
|
||||
# <cutoff> of the difference between the plateau and inoculated ODs, return TRUE.
|
||||
else
|
||||
return((final - inoc) / (plat - inoc) > cutoff)
|
||||
}
|
||||
else
|
||||
return(T)
|
||||
# If no final OD was calculated (if curve was not fit properly) just return T.
|
||||
}
|
||||
|
||||
|
||||
lag.time = function(fitted.well, digits = Inf, ...){
|
||||
########################################################################
|
||||
# Calculate the lag time from the fitted OD #
|
||||
########################################################################
|
||||
if(length(fitted.well@fit.par) == 0)
|
||||
return(NA)
|
||||
|
||||
fitted.well@fit.par$lam
|
||||
}
|
||||
|
||||
# new params for GCAT 4.0
|
||||
|
||||
amplitude = function(fitted.well){
|
||||
if(length(fitted.well@fit.par) == 0)
|
||||
return(NA)
|
||||
|
||||
return(fitted.well@fit.par$A)
|
||||
}
|
||||
|
||||
shape.par = function(fitted.well){
|
||||
if(length(fitted.well@fit.par) == 0)
|
||||
return(NA)
|
||||
ifelse(is.null(fitted.well@fit.par$v), NA, fitted.well@fit.par$v)
|
||||
}
|
||||
|
||||
max.spec.growth.rate.SE = function(fitted.well, ...){
|
||||
if(length(fitted.well@fit.std.err) == 0)
|
||||
return(NA)
|
||||
ifelse(is.null(fitted.well@fit.std.err$u), NA, fitted.well@fit.std.err$u)
|
||||
}
|
||||
|
||||
lag.time.SE = function(fitted.well, ...){
|
||||
if(length(fitted.well@fit.std.err) == 0)
|
||||
return(NA)
|
||||
ifelse(is.null(fitted.well@fit.std.err$lam), NA, fitted.well@fit.std.err$lam)
|
||||
}
|
||||
|
||||
shape.par.SE = function(fitted.well){
|
||||
if(length(fitted.well@fit.std.err) == 0)
|
||||
return(NA)
|
||||
ifelse(is.null(fitted.well@fit.std.err$v), NA, fitted.well@fit.std.err$v)
|
||||
}
|
||||
|
||||
amplitude.SE = function(fitted.well){
|
||||
if(length(fitted.well@fit.std.err) == 0)
|
||||
return(NA)
|
||||
ifelse(is.null(fitted.well@fit.std.err$A), NA, fitted.well@fit.std.err$A)
|
||||
}
|
||||
|
||||
baseline.SE = function(fitted.well){
|
||||
if(length(fitted.well@fit.std.err) == 0)
|
||||
return(NA)
|
||||
ifelse(is.null(fitted.well@fit.std.err$b), NA, fitted.well@fit.std.err$b)
|
||||
}
|
||||
|
||||
# used to calulate the inflection.time value
|
||||
inflection.time = function(well){
|
||||
if (length(well@loess) == 0 && length(well@nls) == 0) return(NA) # can' compute inflection time in the absence of a fit
|
||||
data = data.from(well)
|
||||
Time = data[,1]
|
||||
t = seq(from = min(Time), to = max(Time), by = (max(Time)-min(Time))/1000)
|
||||
y = well.eval(well,t)
|
||||
if (is.null(y)) return(NA)
|
||||
delta.t = diff(t)
|
||||
dydt = diff(y)/delta.t
|
||||
infl.index = which.max(dydt)
|
||||
t[infl.index]
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
#Copyright 2012 The Board of Regents of the University of Wisconsin System.
|
||||
#Contributors: Jason Shao, James McCurdy, Enhai Xie, Adam G.W. Halstead,
|
||||
#Michael H. Whitney, Nathan DiPiazza, Trey K. Sato and Yury V. Bukhman
|
||||
#
|
||||
#This file is part of GCAT.
|
||||
#
|
||||
#GCAT is free software: you can redistribute it and/or modify
|
||||
#it under the terms of the GNU Lesser General Public License as published by
|
||||
#the Free Software Foundation, either version 3 of the License, or
|
||||
#(at your option) any later version.
|
||||
#
|
||||
#GCAT is distributed in the hope that it will be useful,
|
||||
#but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
#GNU Lesser General Public License for more details.
|
||||
#
|
||||
#You should have received a copy of the GNU Lesser General Public License
|
||||
#along with GCAT. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
# Wrapper for sapply to use lapply over an array, conserving the dimensions.
|
||||
aapply = function(x, FUN,...){
|
||||
dim.values = dim(x)
|
||||
dim.names = dimnames(x)
|
||||
x = lapply(x, function(x){FUN(x,...)})
|
||||
dim(x) = dim.values
|
||||
dimnames(x) = dim.names
|
||||
return(x)
|
||||
}
|
||||
|
||||
# A function to manually create an unchecked exception.
|
||||
exception = function(class, msg)
|
||||
{
|
||||
cond <- simpleError(msg)
|
||||
class(cond) <- c(class, "MyException", class(cond))
|
||||
stop(cond)
|
||||
}
|
@ -0,0 +1,198 @@
|
||||
#Copyright 2012 The Board of Regents of the University of Wisconsin System.
|
||||
#Contributors: Jason Shao, James McCurdy, Enhai Xie, Adam G.W. Halstead,
|
||||
#Michael H. Whitney, Nathan DiPiazza, Trey K. Sato and Yury V. Bukhman
|
||||
#
|
||||
#This file is part of GCAT.
|
||||
#
|
||||
#GCAT is free software: you can redistribute it and/or modify
|
||||
#it under the terms of the GNU Lesser General Public License as published by
|
||||
#the Free Software Foundation, either version 3 of the License, or
|
||||
#(at your option) any later version.
|
||||
#
|
||||
#GCAT is distributed in the hope that it will be useful,
|
||||
#but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
#GNU Lesser General Public License for more details.
|
||||
#
|
||||
#You should have received a copy of the GNU Lesser General Public License
|
||||
#along with GCAT. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
########################################################################
|
||||
# #
|
||||
# Normalize OD readings for an entire array of well objects #
|
||||
# #
|
||||
########################################################################
|
||||
#
|
||||
# Note: This function does not write any new OD values to the well objects in the array - it only
|
||||
# fills the "norm" slot of each well object in the array with a value that will be subtracted
|
||||
# from all OD measurements when returning data from the wells using the function <data.from> (see well.class.R)
|
||||
#
|
||||
# These functions make use of <raw.data> which simply returns the raw time and OD of a well (also see well.class.R)
|
||||
#
|
||||
# well.array: an array of well objects. note this is the only normalization function that acts on an entire array instead of an individual well.
|
||||
# normalize.method:
|
||||
# - (default): subtracts the blank OD (either specified by <blank.value> or taken from the first timepoint as default) of each well from all timepoints in that well
|
||||
# - average.blank: subtracts the mean of all first OD timepoints on a plate from all timepoints in all wells on that plate
|
||||
# - average.first: takes the mean of the difference between the OD of the specified <start> timepoint and the first timepoint of all wells on a plate
|
||||
# and subtracts this value from all timepoints in all wells on that plate
|
||||
# - anything else: do nothing
|
||||
# blank.value - user can enter a blank OD measurement for uninoculated wells. if NULL, defaults to the value of the first OD measurement of each well.
|
||||
# start.index - which timepoint should be used as the first one after inoculation (defaults to the 2th one)
|
||||
# add.constant: add a numeric constant to all timepoints in all wells.
|
||||
normalize.ODs = function(well.array, normalize.method = "default", blank.value = NULL, start.index = 2, add.constant = 1){
|
||||
|
||||
if (normalize.method == "default"){
|
||||
well.array = aapply(well.array, function(well, blank.value){
|
||||
# Use the blank OD value if specified; otherwise, get it from the first OD timepoint.
|
||||
if(is.null(blank.value)) blank.value = raw.data(well)[1,2]
|
||||
# Set the blank OD (minus the constant to be added) to the "norm" slot of each well.
|
||||
well@norm = blank.value - add.constant
|
||||
return(well)}, blank.value)
|
||||
}
|
||||
else if (normalize.method == "average.blank"){
|
||||
# Use the blank OD value if specified; otherwise, get it from the first OD timepoint.
|
||||
blank.ODs = unlist(aapply(well.array, function(well, blank.value){
|
||||
if(is.null(blank.value)) blank.value = raw.data(well)[1,2]
|
||||
return(blank.value)}, blank.value))
|
||||
plate.IDs = unlist(aapply(well.array, plate.name))
|
||||
blank.averages = tapply(blank.ODs, plate.IDs, mean)
|
||||
# Set this value (minus the constant to be added) to the "norm" slot of each well.
|
||||
well.array = aapply(well.array, function(well){
|
||||
well@norm = blank.averages[plate.name(well)] - add.constant
|
||||
return(well)})
|
||||
}
|
||||
else if (normalize.method == "average.first"){
|
||||
# Find the mean difference between starting OD (timepoint specified by <start>) and blank OD (first timepoint) for each plate
|
||||
# Use the blank OD value if specified; otherwise, get it from the first OD timepoint.
|
||||
blank.ODs = unlist(aapply(well.array, function(well, blank.value){
|
||||
if(is.null(blank.value)) blank.value = raw.data(well)[1,2]
|
||||
return(blank.value)}, blank.value))
|
||||
first.ODs = unlist(aapply(well.array, function(well) raw.data(well)[start.index,2]))
|
||||
plate.IDs = unlist(aapply(well.array, plate.name))
|
||||
blank.averages = tapply(first.ODs-blank.ODs,plate.IDs,mean)
|
||||
# Set this value (minus the constant to be added) to the "norm" slot of each well.
|
||||
well.array = aapply(well.array, function(well){
|
||||
well@norm = raw.data(well)[start,2] - blank.averages[plate.name(well)] - add.constant
|
||||
return(well)})
|
||||
}
|
||||
else{
|
||||
# Simply set the negative constant to be added to the "norm" slot of each well.
|
||||
well.array = aapply(well.array, function(well){
|
||||
well@norm = - add.constant
|
||||
return(well)})
|
||||
}
|
||||
if(is.null(blank.value))
|
||||
well.array = aapply(well.array, remove.points, 1)
|
||||
return(well.array)
|
||||
}
|
||||
|
||||
########################################################################
|
||||
# #
|
||||
# Log-transform OD readings for a single well object #
|
||||
# #
|
||||
########################################################################
|
||||
|
||||
# Must include this so that the checking process will not complain about
|
||||
# inconsistency S3 generic/method. Though I don't know why.
|
||||
transform <- function(input.well, ...) {
|
||||
UseMethod("transform")
|
||||
}
|
||||
|
||||
#' Transform.Ods
|
||||
#'
|
||||
#' This function adds a "log.OD" column to the "screen.data" slot of a well object with log-transformed data.
|
||||
#' The raw data is kept intact.
|
||||
#' It also checks to see if any of the raw OD values (before a certain timepoint) is below the blank OD.
|
||||
#' This can be disastrous for the log(OD) transform.
|
||||
#' @param input.well an object of class well
|
||||
#' @param use.log gets added to the "use.log" slot of the well object. this will determine whether the log-transformed data
|
||||
#' or raw normalized data is returned using the function \code{data.from}.
|
||||
#' @param blank.value user can enter a blank OD measurement for uninoculated wells. if NULL, defaults to the value of the first OD measurement of each well.
|
||||
#' @param start.index which timepoint should be used as the first one after inoculation (defaults to the 2th one)
|
||||
#' @param negative.OD.cutoff if any ODs below the specified blank value are detected before this index timepoint, the entire well is discarded.
|
||||
transform.ODs = function(input.well, use.log = T, blank.value = NULL, start.index = 2, negative.OD.cutoff = 10, constant.added = 1.0, ...){
|
||||
|
||||
# The default value for the log-transformed ODs will be NA. Valid values will be filled in.
|
||||
log.OD = rep(NA, length(input.well))
|
||||
OD = raw.data(input.well)[,2]
|
||||
|
||||
# Use the blank OD value if specified; otherwise, get it from the first OD timepoint.
|
||||
if(is.null(blank.value))
|
||||
blank.value = OD[1]
|
||||
|
||||
# Remove any points from the analysis that weren't already removed and fall below the blank value (using <remove.points> below)
|
||||
OD[input.well@screen.data$Remove] = NA
|
||||
|
||||
negative.points = which(OD + 0.2 * constant.added < blank.value)
|
||||
if(length(negative.points) > 0)
|
||||
input.well = remove.points(input.well, negative.points)
|
||||
|
||||
# If any points fall below the blank value by more than 0.2 * <constant.added> and before the cutoff index <negative.OD.cutoff>, remove the well from analysis.
|
||||
# First adjust the cutoff to compensate for curves that don't start at timepoint 1
|
||||
negative.OD.cutoff = negative.OD.cutoff + start.index - 1
|
||||
|
||||
if(any(negative.points <= negative.OD.cutoff)){
|
||||
input.well = remove.points(input.well, rep(T,length(input.well)))
|
||||
input.well@add.info = paste("ODs at timepoint(s)", paste(negative.points[negative.points <= negative.OD.cutoff],collapse=" "), "were below blank OD; well discarded")
|
||||
}
|
||||
|
||||
# Take the natural log of the rest of the OD values (after subtracting the normalization value)
|
||||
log.OD[which(OD > input.well@norm)] = log(OD[which(OD > input.well@norm)] - input.well@norm)
|
||||
|
||||
# Add a column to the "screen.data" slot of the well
|
||||
input.well@screen.data$log.OD = log.OD
|
||||
# Update the "use.log" slot of the well
|
||||
input.well@use.log = use.log
|
||||
|
||||
return(input.well)
|
||||
}
|
||||
|
||||
########################################################################
|
||||
# #
|
||||
# Remove timepoints from the analysis but not from the raw data #
|
||||
# #
|
||||
########################################################################
|
||||
#
|
||||
# Removes timepoints from further analysis. Does not remove them from the raw data;
|
||||
# instead, this function creates or updates the Remove column in slot "screen.data" of the well which dictates whether
|
||||
# individual timepoints are returned using the <load.data> function.
|
||||
#
|
||||
# <points> can be a vector containing:
|
||||
# - any combination of positive and negative integers
|
||||
# the timepoints at indices corresponding to positive integers will be set to be removed.
|
||||
# the timepoints at indices corresponding to negative integers will be be re-added if they were previously set to be removed.
|
||||
# - a single zero, which resets all timepoints (nothing will be removed)
|
||||
# - a logical vector to replace the Remove column and which will be cycled along the length of the timepoints.
|
||||
|
||||
remove.points = function(input.well, points){
|
||||
# Copy the Remove column or create a new one if it doesn't yet exist
|
||||
if (is.null(input.well@screen.data$Remove))
|
||||
Remove = rep(F, length(input.well))
|
||||
else
|
||||
Remove = input.well@screen.data$Remove
|
||||
|
||||
# If <points> is a logical vector, recycle it along the length of Remove
|
||||
if (length(points[!is.na(points)]) != 0){
|
||||
# Separate positive and negative integers
|
||||
if (is.logical(points) & !any(is.na(points)))
|
||||
Remove = rep(points,length.out=nrow(input.well@screen.data))
|
||||
else{
|
||||
pos = points[points > 0]
|
||||
neg = -points[points < 0]
|
||||
Remove[pos] = T
|
||||
Remove[neg] = F
|
||||
|
||||
# If <points> contains only zeros, reset the Remove vector to all F
|
||||
if (all(points == 0))
|
||||
Remove[1:length(Remove)] = F
|
||||
}
|
||||
}
|
||||
# replace the Remove column
|
||||
input.well@screen.data$Remove = Remove
|
||||
input.well
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -0,0 +1,664 @@
|
||||
#Copyright 2012 The Board of Regents of the University of Wisconsin System.
|
||||
#Contributors: Jason Shao, James McCurdy, Enhai Xie, Adam G.W. Halstead,
|
||||
#Michael H. Whitney, Nathan DiPiazza, Trey K. Sato and Yury V. Bukhman
|
||||
#
|
||||
#This file is part of GCAT.
|
||||
#
|
||||
#GCAT is free software: you can redistribute it and/or modify
|
||||
#it under the terms of the GNU Lesser General Public License as published by
|
||||
#the Free Software Foundation, either version 3 of the License, or
|
||||
#(at your option) any later version.
|
||||
#
|
||||
#GCAT is distributed in the hope that it will be useful,
|
||||
#but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
#GNU Lesser General Public License for more details.
|
||||
#
|
||||
#You should have received a copy of the GNU Lesser General Public License
|
||||
#along with GCAT. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
require(pheatmap)
|
||||
require(gplots)
|
||||
|
||||
########################################################################
|
||||
# #
|
||||
# Graphic output functions for fitted well objects. The functions are #
|
||||
# fairly complicated and intertwined and may need revision. #
|
||||
# #
|
||||
########################################################################
|
||||
|
||||
# S3 Generic.
|
||||
plot <- function(input.well, ...) {
|
||||
UseMethod("plot")
|
||||
}
|
||||
|
||||
########################################################################
|
||||
# Basic function plots time vs. OD from a well object #
|
||||
########################################################################
|
||||
#' plot.data
|
||||
#'
|
||||
#' Basic function plots time vs. OD from a well object
|
||||
#'
|
||||
#' @param input.well The well object that need to be plottedd
|
||||
#' @param unlog should data be plotted on a linear (vs. logarithmic) scale?
|
||||
#' @param view.raw.data should the raw data be plotted? (
|
||||
#' @param number.points should points be labeled with numeric indices?
|
||||
#' @param scale determines the font scale for the entire graph. all cex values are calculated from this.
|
||||
#' @param draw.symbols - should <check.slopes> be called on the well and markings drawn on the graph?
|
||||
#' @param ... additional arguments passed to plot()
|
||||
plot.data = function(input.well, view.raw.data = F, unlog = F, scale = 1,
|
||||
main = paste(plate.name(input.well), well.name(input.well)), number.points = T,
|
||||
draw.symbols = F, constant.added, ylim, ...){
|
||||
|
||||
# Get data as well as a vector showing which points were removed.
|
||||
input.data = data.from(input.well, remove = F, remove.tanking = F, raw.data=view.raw.data)
|
||||
removed.points = !(rownames(input.data) %in% rownames(data.from(input.well, remove = T, remove.tanking = T)))
|
||||
point.colors = as.character(factor(removed.points,levels=c(F,T),labels=c("black","gray80")))
|
||||
|
||||
# Draw the axes and all text labels first.
|
||||
par(mar = c(5, 4, 4, 5)+0.1)
|
||||
plot(input.data, main = main, xlab = "Time(hours)", ylab = "log(OD - blank + const)",
|
||||
mex = scale, cex.main = 1.5*scale, cex.axis = 1.2*scale, cex.lab = 1.2*scale, type ="n",...)
|
||||
|
||||
# Draw a second vertical axis, showing unlogged OD scale
|
||||
# - Determine the range of the labels: from min.OD to max.OD
|
||||
if (class(try(ylim,silent=T)) == "try-error") {
|
||||
OD = unlog(input.data[,2],constant.added)
|
||||
baseline.OD = unlog(baseline(input.well),constant.added)
|
||||
min.OD = min(min(OD,na.rm=T),baseline.OD,na.rm=T)
|
||||
plateau.OD = unlog(plateau(input.well),constant.added)
|
||||
max.OD = max(max(OD,na.rm=T),plateau.OD,na.rm=T)
|
||||
} else {
|
||||
min.OD = unlog(ylim[1],constant.added)
|
||||
max.OD = unlog(ylim[2],constant.added)
|
||||
}
|
||||
# - Compute labels and their positions
|
||||
OD.labels = seq(from = min.OD, to = max.OD, length.out = 5)
|
||||
OD.labels = signif(OD.labels,2)
|
||||
OD.at = log(OD.labels+constant.added)
|
||||
# - Draw the axis
|
||||
axis(side=4, at=OD.at, labels=OD.labels, cex.axis = 1.2*scale, cex.lab = 1.2*scale)
|
||||
mtext(4, text = "OD - blank", line = 3, cex=1.2)
|
||||
|
||||
# If <number.points> is true, then label each point with the index of its timepoint and plot removed points in grey, others in black.
|
||||
if (number.points)
|
||||
text(input.data$Time, input.data[,2], rownames(input.data), col = point.colors, cex = 0.5*scale)
|
||||
# Otherwise plot all points, using a different plotting character for removed points.
|
||||
else
|
||||
points(input.data$Time, input.data[,2], pch = 1 + removed.points*15)
|
||||
|
||||
# If <check.slopes> is set to T, then draw all the markings that <check.slopes> makes to determine curve parameters.
|
||||
if (draw.symbols & !view.raw.data)
|
||||
check.slopes(input.well, draw = T)
|
||||
return()
|
||||
}
|
||||
|
||||
########################################################################
|
||||
# Plots the fitted model curve from a well object if it exists #
|
||||
########################################################################
|
||||
#
|
||||
# time: specify which points (in units of time) to plot fitted OD values for. if not specifies, plot all timepoints in range of well.
|
||||
|
||||
plot.model = function(input.well, col = 1, scale = 1, lty = 1, time = NULL, unlog = F, constant.added=1, ...){
|
||||
|
||||
#input.data = data.from(input.well)
|
||||
#growth = input.data[,2]
|
||||
|
||||
# If no list of timepoints is specified, get a list of 360 timepoints (should be smooth enough) from the well's range.
|
||||
if (is.null(time)){
|
||||
time.fin = max(data.from(input.well, raw.data = T, remove = F, remove.tanking = F)$Time)
|
||||
time = seq(0, time.fin, length.out = 360)
|
||||
}
|
||||
|
||||
# Evaluate the predicted OD at the specified timepoints based on the fitted model.
|
||||
predicted.OD = well.eval(input.well, time)
|
||||
# If any values were returned, plot the lines on the current graph. Otherwise, just return without doing anything.
|
||||
if (is.numeric(predicted.OD))
|
||||
lines(time, predicted.OD, col = col, lty = lty, lw = 2 * scale)
|
||||
else
|
||||
return()
|
||||
|
||||
}
|
||||
|
||||
########################################################################
|
||||
# Put various parameters and info in text form on the graphs #
|
||||
########################################################################
|
||||
#
|
||||
draw.text = function(input.well, scale = 0.5, xlim = 0, ylim = 0,...){
|
||||
|
||||
#input.data = data.from(input.well, remove = F, remove.tanking = F)
|
||||
#fit = input.well@fit.par
|
||||
|
||||
# <text2> - fit information (fit status, model name if available, jump detection output, fit parameters if available) from well
|
||||
# color = red if no fit, blue if fit, green if skipped
|
||||
# <text1> - empty or inoculated well.
|
||||
# color = green if empty, blue if inoculated, red if inoculated but has no growth or empty but has growth.
|
||||
|
||||
col2 = "blue"
|
||||
text2 = paste(input.well@fit.info, input.well@model.name, input.well@add.info, "\n", parameter.text(input.well))
|
||||
|
||||
if (length(input.well@fit.par) == 0) # no fit
|
||||
col2 = "red"
|
||||
|
||||
if (is.empty(input.well)){
|
||||
text1 = "empty well"
|
||||
if(!lacks.growth(input.well) | length(input.well@fit.par) == 0) # growth curve fit for an empty well
|
||||
col1 = "red"
|
||||
else
|
||||
col1 = "forestgreen"
|
||||
if (length(input.well@model.name) == 0) # well was skipped
|
||||
col1 = col2 = "forestgreen"
|
||||
}
|
||||
else{
|
||||
text1 = "inoculated well"
|
||||
if(lacks.growth(input.well) | length(input.well@fit.par) == 0) # failure to fit an inoculated well
|
||||
col1 = "red"
|
||||
else
|
||||
col1 = "forestgreen"
|
||||
}
|
||||
|
||||
# <text1.5> - goodness of fit metric.
|
||||
# color = red if below 2, yellow if between 2 and 2.72, and green if above 2.72.
|
||||
|
||||
if(!is.na(model.good.fit(input.well))){
|
||||
#if (model.good.fit(input.well, unlog = F) > 2.72)
|
||||
# col1.5 = "forestgreen"
|
||||
#else if (model.good.fit(input.well, unlog = F)> 2.0)
|
||||
# col1.5 = "gold2"
|
||||
#else
|
||||
# col1.5 = "red"
|
||||
col1.5 = "forestgreen"
|
||||
text1.5 = paste("R squared:", round(model.good.fit(input.well),3))
|
||||
}
|
||||
else
|
||||
col1.5 = text1.5 = NULL
|
||||
|
||||
# Print all text at the top of the graph with approprate positions and scaling
|
||||
text(x = xlim[1] + 0.50 * diff(xlim), y = ylim[2] - 0.025 * diff(ylim),
|
||||
text1.5, cex = 1.5*scale, col = col1.5)
|
||||
|
||||
text(x = xlim[1] + 0.50 * diff(xlim), y = ylim[2] - 0 * diff(ylim),
|
||||
text1, cex = 1.5*scale, col = col1)
|
||||
|
||||
text(x = xlim[1] + 0.50 * diff(xlim), y = ylim[2] - 0.03 * diff(ylim),
|
||||
text2, pos = 1, cex = 1.5*scale, col = col2)
|
||||
}
|
||||
|
||||
########################################################################
|
||||
# Draw lines on graph denoting calculated parameters #
|
||||
########################################################################
|
||||
#
|
||||
# <show.num> - should curve parameters be labeled?
|
||||
|
||||
draw.calc.par = function(input.well, scale = 0.5, unlog = F, constant.added, show.num = T){
|
||||
|
||||
# Don't do anything if well was not fit.
|
||||
if (is.null(well.eval(input.well)))
|
||||
return()
|
||||
|
||||
# Collect values for various curve parameters.
|
||||
baseline = baseline(input.well)
|
||||
inoc.log.OD = inoc.log.OD(input.well)
|
||||
max.log.OD = max.log.OD(input.well)
|
||||
plateau = plateau(input.well)
|
||||
inflection.time = input.well@inflection.time # was a param in model
|
||||
fin.time = (inflection.time+max(data.from(input.well)[,1]))/2
|
||||
|
||||
# <inflection.time> = timepoint at greatest growth
|
||||
# <max.y> = OD measurement at <inflection.time>, minus the constant added before taking the log (if reversing the transformation)
|
||||
# <max.slope> = slope (on log scale) at <inflection.time> (specific growth)
|
||||
# had to add the unlog code. was calculated differently before NWD 7/21/14
|
||||
max.slope = max.spec.growth.rate(input.well)
|
||||
max.y = well.eval(input.well, inflection.time)
|
||||
lag.x = lag.time(input.well)
|
||||
lag.y = baseline
|
||||
|
||||
# ---- Specific growth rate ---- #
|
||||
lines(c(lag.x, inflection.time), c(lag.y, max.y), lty = 2, col = "red")
|
||||
|
||||
|
||||
# Blue dotted line at time of maximum growth, with text label for specific growth rate.
|
||||
abline(v = inflection.time, lty = 2, lw = (scale^2)*2, col = "blue")
|
||||
if(show.num) text(inflection.time, max.y, round(max.slope,3), col = "blue", cex = 1.5*scale, pos = 2)
|
||||
|
||||
# inoculation OD and baseline of the fitted model
|
||||
abline(h = inoc.log.OD, lw = scale*2, lty = 3)
|
||||
abline(h = baseline, col = "red", lw = (scale^2)*2, lty = 2)
|
||||
if(show.num) {
|
||||
text(fin.time, inoc.log.OD, paste(round(inoc.log.OD,3),"\n",sep="") , col = "black", cex = 1.5*scale, pos = 2)
|
||||
text(fin.time, baseline, paste("\n\n", round(baseline,3), sep="") , col = "red", cex = 1.5*scale, pos = 2)
|
||||
}
|
||||
|
||||
# ---- Lag time ---- #
|
||||
# Do not draw a horizontal line to lag time if it is 0 or negative.
|
||||
# Otherwise draw a red line from the starting point to the lag time, and label with the lag time
|
||||
if (lag.time(input.well) == 0){
|
||||
if(show.num) text(0, inoc.log.OD, "\n\n0.000", col = "red", cex = 1.5*scale, pos = 4)
|
||||
}
|
||||
else{
|
||||
lines(c(0, lag.x), c(baseline, baseline), col = "red", lw = (scale^2)*2, lty = 2)
|
||||
if(show.num) text(lag.x, lag.y, paste("\n\n", round(lag.time(input.well),3)), col = "red", cex = 1.5*scale, pos = 2)
|
||||
}
|
||||
|
||||
# ---- Total growth ---- #
|
||||
|
||||
# Draw horizontal lines for the max.log.OD in black, the plateau in green and the initial OD in black.
|
||||
abline(h = max.log.OD, lty = 3, lw = scale*2)
|
||||
abline(h = plateau, lty = 2, lw = (scale^2)*2, col = "forestgreen")
|
||||
|
||||
# Draw a vertical line from the initial OD to the final OD in black, and then to the plateau in gray.
|
||||
lines(c(fin.time, fin.time), c(inoc.log.OD, max.log.OD), lw = (scale^2)*2, lty = 3)
|
||||
lines(c(fin.time, fin.time), c(max.log.OD, plateau), lw = (scale^2)*2, lty = 3, col = "grey")
|
||||
|
||||
# Text: plateau and initial ODs (on left), difference between initial and final OD on right
|
||||
if(show.num){
|
||||
text(fin.time, plateau, paste(round(plateau,3),"\n",sep="") , col = "forestgreen", cex = 1.5*scale, pos = 2)
|
||||
text(fin.time, max.log.OD, paste("\n\n\n",round(max.log.OD,3),sep="") , col = "black", cex = 1.5*scale, pos = 2)
|
||||
text(fin.time, .5*(max.log.OD-inoc.log.OD)+inoc.log.OD, round(max.log.OD - inoc.log.OD,3), cex = 1.5*scale, pos = 4)
|
||||
# difference between final and plateau OD (if large enough)
|
||||
if (!reach.plateau(input.well))
|
||||
text(fin.time, .5*(plateau-max.log.OD)+max.log.OD, paste("(", round(plateau - max.log.OD,3), ")", sep = ""), col = "grey", cex = 1.5*scale, pos = 2)
|
||||
}
|
||||
}
|
||||
|
||||
########################################################################
|
||||
# Draw residuals from the nonlinear fit with option for lowess line #
|
||||
########################################################################
|
||||
#
|
||||
plot.residuals = function(input.well, xlim = NULL, lowess = T, ...){
|
||||
well = input.well
|
||||
data = data.from(well, remove = F, remove.tanking = F)
|
||||
|
||||
if (is.null(xlim))
|
||||
xlim = c(min(data$Time, 0)-1, max(data$Time))
|
||||
|
||||
plot(data.from(well)[,1], model.residuals(well), main = paste(plate.name(well), well.name(well), "\n[Residuals]"),
|
||||
xlab = "Time(hours)", ylab = paste("Residual", names(data)[2]), xlim = xlim)
|
||||
|
||||
abline(0,0, lty = 2)
|
||||
|
||||
if (lowess)
|
||||
lines(lowess(data.from(well)[,1], model.residuals(well)), lw = 2, col = "red")
|
||||
}
|
||||
|
||||
##############################################################################
|
||||
# This function is used to create a heatmap using:
|
||||
# specific growth, total growth, and lag time
|
||||
# for each well on a plate.
|
||||
#
|
||||
# @params
|
||||
# fitted.well.array: matrix containing well array object data
|
||||
# attribute: the data type we should use to create a heatmap
|
||||
# @returns
|
||||
# path of heatmap pdf file
|
||||
##############################################################################
|
||||
create.heatmap = function(fitted.well.array, attribute, unlog=NULL){
|
||||
attr.name <- deparse(substitute(attribute))
|
||||
pdf.name <- ""
|
||||
if(class(fitted.well.array) == "matrix"){
|
||||
#We may want to sub() out periods from plate.ID if it causes problems
|
||||
plate.ID = unique(unlist(aapply(fitted.well.array,plate.name)))[1]
|
||||
if(is.null(unlog)) {
|
||||
spec.growth = unlist(aapply(fitted.well.array, attribute))
|
||||
}
|
||||
# currently only total growth needs to be unlogged if unlog == T
|
||||
else {
|
||||
spec.growth = unlist(aapply(fitted.well.array, attribute))
|
||||
}
|
||||
num.dig = 3 #how many digits should be put on pdf?
|
||||
max = round(max(spec.growth, na.rm=T), digits=num.dig)
|
||||
min = round(min(spec.growth, na.rm=T), digits=num.dig)
|
||||
avg = round(mean(spec.growth, na.rm=T), digits=num.dig)
|
||||
heat.text = paste(toupper(sub("\\.", " ", attr.name)), ":\n", plate.ID, "\n",
|
||||
paste("Max:",max ,"Min:" ,min ,"Avg:", avg, sep=""))
|
||||
|
||||
attr.name <- sub("\\.", "_", attr.name) #do not want periods in file path
|
||||
letters <- attr(fitted.well.array, "dimnames")[[1]]
|
||||
for(i in 1:length(letters)) letters[i] = paste(" ", letters[i], " ")
|
||||
nums <- attr(fitted.well.array, "dimnames")[[2]]
|
||||
for(i in 1:length(nums)) nums[i] = paste(" ", nums[i], " ")
|
||||
heat <- matrix(spec.growth, nrow=dim(fitted.well.array)[1], ncol=dim(fitted.well.array)[2], dimnames=list(letters,nums))
|
||||
pdf.name <- paste(getwd(), "/", plate.ID, "_", attr.name, ".pdf", sep="")
|
||||
pdf(pdf.name)
|
||||
#heatmap(heat, Rowv=NA, Colv=NA, revC=T, scale="none", na.rm=T, main=plate.ID, col=rainbow(100), margins=c(6,6))
|
||||
#mtext(paste("Max:", round(max(spec.growth, na.rm=T), digits=4),"Min:", round(min(spec.growth, na.rm=T), digits=4), "Avg:", round(mean(spec.growth, na.rm=T), digits=4)), side=1, line=3)
|
||||
pheatmap(heat, color=colorpanel(100, "red", "orange", "yellow"),
|
||||
border_color="black", cell_width=2, cell_height=3,
|
||||
cluster_rows=F, cluster_cols=F, scale='none', main=heat.text, fontsize=16)
|
||||
dev.off()
|
||||
}
|
||||
else {
|
||||
return("Error")
|
||||
}
|
||||
return(pdf.name)
|
||||
}
|
||||
|
||||
########################################################################
|
||||
# Draw grids of 96 points as a visual representation of fit status, #
|
||||
# and other info for an array of fitted well objects, plate by plate #
|
||||
########################################################################
|
||||
#
|
||||
|
||||
plate.overview = function(fitted.well.array, scale = 1, plate.ncol = 12, plate.nrow = 8){
|
||||
|
||||
|
||||
# Start with a list of the unique plate names in the fitted well array
|
||||
# and an appropriately-sized grid of coordinates to plot wells on.
|
||||
plates = unique(unlist(aapply(fitted.well.array,plate.name)))
|
||||
|
||||
grid = data.frame(x = rep(rep(1:plate.ncol, each = plate.nrow), length(plates)),
|
||||
y = rep( rep(-(1:plate.nrow), times = plate.ncol), length(plates)))
|
||||
|
||||
|
||||
# Gather information on each well to display on each of the coordinates in <grid>:
|
||||
# - was it marked as empty in the plate layout?
|
||||
# - did the program find it to contain no growth ("dead")?
|
||||
# - was the fitting procedure successful?
|
||||
# - did the curve tank? if so, at what timepoint? if not, or if the curve was marked as dead anyway, do not display the value.
|
||||
# - does the "additional info" slot indicate that any points were removed or the whole well discarded?
|
||||
|
||||
empty = unlist(aapply(fitted.well.array, is.empty))
|
||||
dead = unlist(aapply(fitted.well.array, lacks.growth))
|
||||
fit = unlist(aapply(fitted.well.array, contains.fit))
|
||||
|
||||
tanking = unlist(aapply(fitted.well.array, tanking.start))
|
||||
tanking[is.na(tanking) | tanking == 1 | dead] = ""
|
||||
|
||||
errors = unlist(aapply(fitted.well.array, function(well){
|
||||
if (length(well@add.info) == 0)
|
||||
""
|
||||
else if (grepl("removed", well@add.info))
|
||||
"-"
|
||||
else if (grepl("detected", well@add.info))
|
||||
"+"
|
||||
else if (grepl("discarded", well@add.info))
|
||||
"!"
|
||||
else
|
||||
""
|
||||
}))
|
||||
|
||||
# Color and plotting character vectors (length = the number of wells in the array)
|
||||
# Default = 1 (open point, black)
|
||||
colors = char = rep(1, length(tanking))
|
||||
|
||||
# Desired colors
|
||||
colors[empty & dead] = "green3" # Empty well with no growth.
|
||||
colors[!empty & fit] = "blue" # Inoculated well with successfully fitted growth curve.
|
||||
|
||||
# Undesired colors
|
||||
colors[empty & !dead] = "darkolivegreen4" # Inoculated well with some growth.
|
||||
colors[!empty & !fit] = "red" # Inoculated well with no successfully fit (either no growth or unsuccessful fit).
|
||||
|
||||
char[!dead & fit] = 19 # Filled points for non-empty wells with successful fits
|
||||
char[!dead & !fit] = 4 # an X for non-empty wells with failed fits.
|
||||
|
||||
char[errors == "!"] = 8 # Asterisk for discarded wells.
|
||||
char[errors == "-" & dead ] = 5 # Open diamond for empty wells (after removing points).
|
||||
char[errors == "-" & !dead & fit] = 23 # Filled diamond for non-empty wells with removed points and successful fits.
|
||||
char[errors == "-" & !dead & !fit] = 8 # Asterisk for wells with removed points and failed fits.
|
||||
|
||||
|
||||
for (plate in 1:length(plates)){
|
||||
|
||||
indices = (plate - 1) * plate.nrow*plate.ncol + 1:(plate.nrow*plate.ncol)
|
||||
|
||||
# Plot the grid using colors and plotting characters determined above.
|
||||
plot(grid[indices,], col = colors[indices], bg = colors[indices], pch = char[indices],
|
||||
main = plates[plate], mex = scale, cex = scale, cex.main = 1.5*scale, cex.axis = 1.2*scale,
|
||||
xaxt = "n", yaxt = "n", xlim = c(-0.5,plate.ncol + 0.5), ylim = c(-(plate.nrow + 1.5), 0.5), xlab = "", ylab = "")
|
||||
|
||||
# Symbol legends
|
||||
|
||||
legend.xpos = (c(-1,2.75,6.5,6.86,10.25)+0.5)*(plate.ncol+1)/13 - 0.5
|
||||
legend.ypos = -(plate.nrow + 0.5)
|
||||
|
||||
legend(x=legend.xpos[1], y= legend.ypos, cex = 0.7 * scale, y.intersp = 1.5, bty="n",
|
||||
legend=c("Empty, no growth","Empty with growth"),
|
||||
pch = c(1,19),
|
||||
pt.bg = c("green3","darkolivegreen4"),
|
||||
col = c("green3","darkolivegreen4")
|
||||
)
|
||||
legend(x=legend.xpos[2], y= legend.ypos, cex = 0.7 * scale, y.intersp = 1.5, bty="n",
|
||||
legend=c("Inoculated with growth", "Inoculated, no growth"),
|
||||
pch = c(19,1),
|
||||
pt.bg = c("blue","red"),
|
||||
col = c("blue","red")
|
||||
)
|
||||
legend(x=legend.xpos[3], y= legend.ypos, cex = 0.7 * scale, y.intersp = 1.5, bty="n",
|
||||
legend=c("Well tanks at specified index", "Some points removed"),
|
||||
pch = c(21,23),
|
||||
pt.bg = c("grey","grey"),
|
||||
col = c("black","black")
|
||||
)
|
||||
|
||||
text(x=legend.xpos[4], y=legend.ypos - 0.29,"#",cex=0.5*scale)
|
||||
|
||||
legend(x=legend.xpos[5], y=legend.ypos, cex = 0.7 * scale, y.intersp = 1.5, bty="n",
|
||||
legend=c("Model fitting failed", "Well discarded"),
|
||||
pch = c(4,8),
|
||||
pt.bg = c("black","black"),
|
||||
col = c("black","black")
|
||||
)
|
||||
|
||||
# Add tanking indices if any were found.
|
||||
text(grid[indices,] + 0.30, cex = 0.75*scale,
|
||||
labels = tanking[indices], col = colors[indices])
|
||||
|
||||
# Label rows and columns
|
||||
text(-1, -1:-plate.nrow, pos = 4, LETTERS[1:plate.nrow], cex = scale)
|
||||
text( 1:plate.ncol, 0 , 1:plate.ncol, cex = scale)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
########################################################################
|
||||
# Draw each well in an array of fitted well objects in succession. #
|
||||
# Include options for adding notations, text info and fit parameters. #
|
||||
########################################################################
|
||||
#
|
||||
|
||||
view.fit = function(fitted.data, indices = 1:length(fitted.data),
|
||||
unlog = F, constant.added, xlim = NULL, ylim = NULL, display.legend = T,
|
||||
show.text = T, show.calc = T, draw.guess = NULL, draw.symbols = F, number.points = T,
|
||||
user.advance = T, show.residuals = F, scale = 1,...){
|
||||
|
||||
if(!is.array(fitted.data))
|
||||
fitted.data = list(fitted.data)
|
||||
|
||||
# Determine the boundaries for the axes (if user did not specify them)
|
||||
if(is.null(ylim)){
|
||||
min.y = min(unlist(aapply(fitted.data, function(well){
|
||||
if (unlog) well@use.log = F
|
||||
min.y = min(data.from(well, remove = F, remove.tanking = F)[,2], na.rm = T)
|
||||
min(min.y, well@fit.par$b)
|
||||
})))
|
||||
max.y = max(unlist(aapply(fitted.data, function(well){
|
||||
if (unlog) well@use.log = F
|
||||
max.y = max(data.from(well, remove = F, remove.tanking = F)[,2], na.rm = T)
|
||||
max(max.y, well@fit.par$b + well@fit.par$A)
|
||||
})))
|
||||
ylim = c(min.y, min.y + (max.y-min.y)*1.15) - unlog*constant.added
|
||||
}
|
||||
if(is.null(xlim)){
|
||||
min.x = min(unlist(aapply(fitted.data, function(well){
|
||||
min(data.from(well, remove = F, remove.tanking = F)[,1], na.rm = T)
|
||||
})))
|
||||
max.x = max(unlist(aapply(fitted.data, function(well){
|
||||
max(data.from(well, remove = F, remove.tanking = F)[,1], na.rm = T)
|
||||
})))
|
||||
xlim = c(min.x - 0.05 * (max.x-min.x), max.x)
|
||||
}
|
||||
|
||||
# Display a figure legend
|
||||
if(display.legend){
|
||||
well.fit.legend(xlim=xlim,ylim=ylim,scale=scale,constant.added=constant.added)
|
||||
if(user.advance){
|
||||
prompt = readline("<Enter> to continue or Q to quit >>")
|
||||
if (toupper(prompt) == "Q") break
|
||||
}
|
||||
}
|
||||
# Start to cycle through the wells
|
||||
well.number = 1
|
||||
while (well.number <= length(fitted.data)) {
|
||||
# Only show wells specified by <indices> (default all wells)
|
||||
if (well.number %in% indices){
|
||||
# plot the well
|
||||
fitted.well = fitted.data[[well.number]]
|
||||
plot(x=fitted.well, constant.added = constant.added, xlim = xlim, ylim = ylim,
|
||||
unlog = unlog, well.number = well.number, scale = scale, number.points = T, draw.symbols = F, show.text = T, show.calc = T, draw.guess = NULL, ...)
|
||||
|
||||
if(user.advance)
|
||||
cat("\n[", well.number, "] ", plate.name(fitted.well), " ", well.name(fitted.well), ".", sep = "")
|
||||
|
||||
if (show.residuals & is.numeric(model.residuals(fitted.well))){
|
||||
if(user.advance)
|
||||
if (toupper(readline("<Enter> for residuals >>")) == "Q") break
|
||||
plot.residuals(fitted.well)
|
||||
}
|
||||
|
||||
# Allow user to advance the currently shown well if specified.
|
||||
if (user.advance){
|
||||
|
||||
prompt = readline("<Enter> to continue, or type # of next well or Q to quit >>")
|
||||
if (toupper(prompt) == "Q") break
|
||||
|
||||
user.input = suppressWarnings(try(as.numeric(prompt),silent=T))
|
||||
|
||||
# Go onto the next well unless input is a number.
|
||||
if (is.numeric(user.input) & !is.na(user.input) & length(user.input) > 0)
|
||||
well.number = user.input - 1
|
||||
}
|
||||
}
|
||||
# Advance the loop
|
||||
well.number = well.number + 1
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
well.fit.legend = function(xlim, ylim, scale = 1, constant.added){
|
||||
par(mar = c(5, 4, 4, 5)+0.1)
|
||||
plot(0,0, main = "[Index] <Plate Name> <Well Position>\n<Strain Name>; <Media Definition>",
|
||||
xlim = xlim, ylim = ylim, xlab = "Time", ylab = "log(OD - blank + const)",
|
||||
mex = scale, cex.main = 1.5*scale, cex.axis = 1.2*scale, cex.lab = 1.2*scale, type = "n")
|
||||
|
||||
# Draw a second vertical axis, showing unlogged OD scale
|
||||
min.OD = unlog(ylim[1],constant.added)
|
||||
max.OD = unlog(ylim[2],constant.added)
|
||||
OD.labels = seq(from = min.OD, to = max.OD, length.out = 5)
|
||||
OD.labels = round(OD.labels,1)
|
||||
OD.at = log(OD.labels+constant.added)
|
||||
axis(side=4, at=OD.at, labels=OD.labels, cex.axis = 1.2*scale, cex.lab = 1.2*scale)
|
||||
mtext(4, text = "OD - blank", line = 3, cex=1.2)
|
||||
|
||||
# Sample max. slope line
|
||||
abline(v=min(xlim)+0.5*max(xlim), col="blue", lty=2)
|
||||
text(mean(xlim),min(ylim)+0.4*diff(ylim),labels="Maximum specific\ngrowth rate",col="blue",pos=2,cex=0.75*scale)
|
||||
|
||||
# Sample plateau line
|
||||
abline(h=min(ylim)+0.8*diff(ylim),col="forestgreen",lty=2)
|
||||
text(min(xlim)+0.9*diff(xlim),ylim+0.8*diff(ylim),labels="Growth plateau",col="forestgreen",pos=3,cex=0.75*scale)
|
||||
|
||||
# Sample max.log.OD line
|
||||
abline(h=min(ylim)+0.7*diff(ylim),col="black",lty=3)
|
||||
text(min(xlim)+0.9*diff(xlim),ylim+0.7*diff(ylim),labels="max.log.OD",col="black",pos=1,cex=0.75*scale)
|
||||
|
||||
# Sample inoc.log.OD
|
||||
abline(h=min(ylim)+0.1*diff(ylim),col="black",lty=3)
|
||||
text(min(xlim)+0.1*diff(xlim),min(ylim)+0.1*diff(ylim),labels="Fitted growth\nat inoculation",col="black",pos=3,cex=0.75*scale)
|
||||
|
||||
# Sample baseline
|
||||
abline(h=min(ylim)+0.05*diff(ylim),col="red",lty=2)
|
||||
text(min(xlim)+0.1*diff(xlim),min(ylim)+0.05*diff(ylim),labels="Baseline",col="red",pos=1,cex=0.75*scale)
|
||||
|
||||
# Sample lag time
|
||||
lines(min(xlim)+c(0.1,0.25,0.50)*max(xlim),min(ylim)+c(0.05,0.05,0.4)*diff(ylim),col="red",lty=2)
|
||||
text(min(xlim)+0.25*max(xlim),min(ylim)+0.05*diff(ylim),labels="Lag time",col="red",pos=1,cex=0.75*scale)
|
||||
|
||||
# Sample achieved growth
|
||||
lines(min(xlim)+c(0.75,0.75)*max(xlim),min(ylim)+c(0.1,0.7)*diff(ylim),col="black",lty=3)
|
||||
text(min(xlim)+0.75*max(xlim),min(ylim)+0.3*diff(ylim),labels="Achieved growth",col="black",cex=0.75*scale)
|
||||
|
||||
# Sample plateau - achieved growth
|
||||
lines(min(xlim)+c(0.75,0.75)*max(xlim),min(ylim)+c(0.7,0.8)*diff(ylim),col="grey",lty=3)
|
||||
text(min(xlim)+0.75*max(xlim),min(ylim)+0.75*diff(ylim),labels="Projected minus achieved growth",col="grey",cex=0.75*scale)
|
||||
|
||||
# Symbol legend
|
||||
legend(x="right", title = "Timepoint Symbols", legend = c("Normal point", "Ignored point"),
|
||||
cex = 0.75*scale, pt.cex = c(0.6,0.6)*scale, pch = c(35,35), col=c("black","gray80"),
|
||||
x.intersp=1, xjust = 1, y.intersp=1.5)
|
||||
}
|
||||
|
||||
pdf.by.plate = function(fitted.data, out.prefix = "", upload.timestamp = NULL,
|
||||
out.dir = getwd(), unlog = F, constant.added, silent = T, overview.jpgs = T, plate.ncol = 12, plate.nrow = 8,...){
|
||||
|
||||
# Prepare timestamp for addition to output file names.
|
||||
filename.timestamp = strftime(upload.timestamp, format="_%Y-%m-%d_%H.%M.%S")
|
||||
|
||||
# Start file list with the overview pdf
|
||||
file.list.out = paste(out.dir,"/",out.prefix, "_overview", filename.timestamp, ".pdf",sep="")
|
||||
|
||||
# Call <plate.overview> to draw a graphic representation of each plate in this file.
|
||||
pdf(file.list.out, title = paste(out.prefix, "plate overview"))
|
||||
plate.overview.out = try(plate.overview(fitted.data),silent=T)
|
||||
if(class(plate.overview.out) == "try-error")
|
||||
stop("Error in <plate.overview>: ", plate.overview.out)
|
||||
|
||||
# Close devices
|
||||
while(dev.cur() != 1)
|
||||
dev.off()
|
||||
|
||||
# Cycle through each plate
|
||||
for(i in 1:dim(fitted.data)[3]){
|
||||
|
||||
# Get plate ID and position in data array.
|
||||
plate.ID = dimnames(fitted.data)[[3]][i]
|
||||
plate.indices = (i-1) * plate.nrow*plate.ncol + 1:(plate.nrow*plate.ncol)
|
||||
if(overview.jpgs){
|
||||
# most be > 1 to partition value breaks for heatmap
|
||||
well.matrix <- aapply(fitted.data[,,i], max.spec.growth.rate)
|
||||
num.wells <- length(well.matrix[!sapply(well.matrix, is.na)])
|
||||
if(num.wells > 1){
|
||||
#Heatmap block##########################################################
|
||||
#alongside the jpgs file create 3 heatmaps for each plate. NWD
|
||||
spec.heat.file = create.heatmap(fitted.data[,,i], max.spec.growth.rate)
|
||||
if(spec.heat.file == "Error")
|
||||
stop("Error in <create.heatmap> for specific growth")
|
||||
lag.heat.file = create.heatmap(fitted.data[,,i], lag.time)
|
||||
if(lag.heat.file == "Error")
|
||||
stop("Error in <create.heatmap> for lag time")
|
||||
total.heat.file = create.heatmap(fitted.data[,,i], achieved.growth)
|
||||
if(total.heat.file == "Error")
|
||||
stop("Error in <create.heatmap> for total growth")
|
||||
# Add name of file if successfully written to file list output. Including heatmap files NWD
|
||||
file.list.out = c(file.list.out, spec.heat.file, lag.heat.file, total.heat.file)
|
||||
########################################################################
|
||||
}
|
||||
jpg.name = paste(out.dir, "/", plate.ID, "_overview", ".jpg", sep="")
|
||||
jpeg(jpg.name, quality = 90, width = 600, height = 480)
|
||||
plate.overview.out = try(plate.overview(fitted.data[,,i]),silent = T)
|
||||
if(class(plate.overview.out) == "try-error")
|
||||
stop("Error in <plate.overview>: ", plate.overview.out)
|
||||
}
|
||||
else
|
||||
jpg.name = c()
|
||||
|
||||
# Open a separate PDF for each plate.
|
||||
if(!silent) cat("\nprinting PDF for", plate.ID)
|
||||
pdf.name = paste(out.dir, "/", plate.ID, "_plots", filename.timestamp, ".pdf", sep="")
|
||||
pdf(pdf.name, title = paste("R Graphics output for plate", plate.ID))
|
||||
|
||||
# Call <view.fit> to draw each well on the plate to the pdf.
|
||||
view.fit.out = try(view.fit(fitted.data, indices = plate.indices, unlog=unlog, constant.added=constant.added, user.advance=F,...),silent=T)
|
||||
|
||||
if(class(view.fit.out) == "try-error")
|
||||
stop("Error in <view.fit>: ", view.fit.out)
|
||||
|
||||
# Close all devices
|
||||
while(dev.cur() != 1)
|
||||
dev.off()
|
||||
|
||||
if(!silent) cat("...done!\n\twritten to", pdf.name, "\n")
|
||||
file.list.out = c(file.list.out, jpg.name , pdf.name)
|
||||
}
|
||||
return(file.list.out)
|
||||
}
|
@ -0,0 +1,419 @@
|
||||
#Copyright 2012 The Board of Regents of the University of Wisconsin System.
|
||||
#Contributors: Jason Shao, James McCurdy, Enhai Xie, Adam G.W. Halstead,
|
||||
#Michael H. Whitney, Nathan DiPiazza, Trey K. Sato and Yury V. Bukhman
|
||||
#
|
||||
#This file is part of GCAT.
|
||||
#
|
||||
#GCAT is free software: you can redistribute it and/or modify
|
||||
#it under the terms of the GNU Lesser General Public License as published by
|
||||
#the Free Software Foundation, either version 3 of the License, or
|
||||
#(at your option) any later version.
|
||||
#
|
||||
#GCAT is distributed in the hope that it will be useful,
|
||||
#but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
#GNU Lesser General Public License for more details.
|
||||
#
|
||||
#You should have received a copy of the GNU Lesser General Public License
|
||||
#along with GCAT. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
########################################################################
|
||||
# #
|
||||
# Estimate the growth curve slope at each timepoint of a well #
|
||||
# #
|
||||
########################################################################
|
||||
#
|
||||
# uses the functions <data.from> and <well.name> (see well.class.R)
|
||||
# adds estimated slopes as a new column to the "screen.data" slot
|
||||
|
||||
calculate.slopes = function(input.well, silent = T){
|
||||
# Get the growth curve data (excluding removed points, but not excluding points marked as tanking)
|
||||
growth.data = data.from(input.well, remove = T, remove.tanking = F)
|
||||
x = growth.data[,1]
|
||||
y = growth.data[,2]
|
||||
|
||||
# Get a list of timepoint indices
|
||||
indices = as.numeric(rownames(growth.data))
|
||||
|
||||
# Default slope is NA, values will be filled in as they are calculated
|
||||
slopes = rep(NA, length(input.well))
|
||||
|
||||
for (i in 1:length(x)){
|
||||
if (i == 1)
|
||||
slopes[indices[i]] = NA
|
||||
# Calculate the slope of the line drawn from each point to the point preceding it.
|
||||
else
|
||||
slopes[indices[i]] = (y[i] - y[i-1])/(x[i] - x[i-1])
|
||||
}
|
||||
# Add a Slope column to the "screen.data" slot
|
||||
input.well@screen.data$Slope = slopes
|
||||
if (!silent)
|
||||
cat("slopes filled for", input.well@position[1], well.name(input.well), "\n")
|
||||
return(input.well)
|
||||
}
|
||||
|
||||
|
||||
########################################################################
|
||||
# #
|
||||
# Use slope estimates to check growth curves for tanking and OD jumps #
|
||||
# #
|
||||
########################################################################
|
||||
#
|
||||
# uses the functions <data.from> and <well.name> (see well.class.R)
|
||||
# Arguments:
|
||||
# ----- stringency parameters ----
|
||||
# remove.jumps - should the program remove OD jumps? default F (just report them) -
|
||||
# should be set to T if data contains distinct jumps in OD that need to be eliminated
|
||||
# otherwise, this might be too stringent and will result in loss of data.
|
||||
# check.start - which timepoint should checking for jumps and tanking start at? this is included because early timepoints can be unstable.
|
||||
# fall.cutoff - what downward slope should constitute a fall in OD?
|
||||
# jump.cutoffs - multipliers to determine whether a curve jumps up or down (see methods 1 and 2, below)
|
||||
# tank.limit - how many timepoints in a row can have falling slopes until the curve is marked as tanking?
|
||||
# tank.cutoff - what proportion of the maximum OD can the curve go below until it is considered tanking?
|
||||
|
||||
# ---- input/output ----
|
||||
# silent - output to R console?
|
||||
# draw - plot growth curve with curve checking details?
|
||||
#
|
||||
# Fills the "curve.par" slot in the well with the starting index of tanking (NA if none is found)
|
||||
#
|
||||
|
||||
#check.slopes = function(input.well, check.start = 8, fall.cutoff = -.0025, remove.jumps = F,
|
||||
# jump.multipliers = -c(15, 500, 10), tank.cutoff = 1.0, tank.limit = 3, silent = T, draw = T){
|
||||
|
||||
#changed default values to parameters to account for settling
|
||||
check.slopes = function(input.well, check.start = 22, fall.cutoff = -.0025, remove.jumps = F,
|
||||
jump.multipliers = -c(15, 500, 10), tank.cutoff = 1.0, tank.limit = 6, silent = T, draw = T){
|
||||
|
||||
if (!silent)
|
||||
cat("\nNow checking slopes for", plate.name(input.well), well.name(input.well))
|
||||
|
||||
# Get estimated slopes and untransformed points from the well
|
||||
slopes = input.well@screen.data$Slope
|
||||
x = data.from(input.well, remove=F, remove.tanking=F)[,1]
|
||||
y = data.from(input.well, remove=F, remove.tanking=F)[,2]
|
||||
|
||||
# Get a list of indices with valid slope estimates
|
||||
indices = (1:length(input.well))[!is.na(slopes)]
|
||||
|
||||
# Do not report tanking or check for jumps if there are fewer valid points than the number needed to detect it
|
||||
if (length(indices) < tank.limit){
|
||||
input.well@curve.par$tanking.start = NA
|
||||
if (!silent)
|
||||
cat("...does not have enough points to check.\n")
|
||||
return(input.well)
|
||||
}
|
||||
|
||||
#######################################################################################
|
||||
# Create indicator variables and recalculate cutoffs based on timepoint density. #
|
||||
#######################################################################################
|
||||
#
|
||||
|
||||
# Create <slope.indicator>, a vector of indicator variables for each timepoint with a valid slope estimate.
|
||||
slope.indicator = rep(NA, length(slopes))
|
||||
|
||||
# Calculate the mean time difference between two timepoints (this typically doesn't vary too much)
|
||||
time.diff = mean(diff(x[-1]))
|
||||
|
||||
# Use the mean time difference to recalculate what should constitute a fall in OD using <fall.cutoff> (which should be a proportion)
|
||||
# Honestly I don't remember why the fifth root thing is in here...this is probably going to be revised later.
|
||||
fall.cutoff = fall.cutoff * time.diff ^ (1/5) / 0.9506785
|
||||
|
||||
# Recalculate stringency parameters for jump detection based on spread of timepoints
|
||||
jump.cutoffs = jump.multipliers* fall.cutoff
|
||||
|
||||
# Recalculate tanking limit based on spread of timepoints
|
||||
tank.limit = round(tank.limit / time.diff ^ (1/5) * 0.9506785)
|
||||
|
||||
# Cycle through the indices of input.wells with valid slope estimate
|
||||
counter = 0
|
||||
|
||||
for(j in 1:length(indices)){
|
||||
#######################################################################################
|
||||
# Method #1 for finding OD jumps: compare the slope estimate of each point to the #
|
||||
# ones for the closest surrounding points. #
|
||||
#######################################################################################
|
||||
# Get indices of the two closest surrounding timepoints with valid slope estimates.
|
||||
if (j == 1)
|
||||
prev.i = indices[2]
|
||||
else
|
||||
prev.i = indices[j-1]
|
||||
if (j == length(indices))
|
||||
next.i = indices[length(indices) - 1]
|
||||
else
|
||||
next.i = indices[j+1]
|
||||
i = indices[j]
|
||||
|
||||
# How the program determines a jump up:
|
||||
# If slope estimate of current timepoint is larger than <jump.cutoffs[2]> times the highest surrounding slope estimate plus <jump.cutoffs[1]>
|
||||
# Add a "2" to the indicator variable
|
||||
# How the program determines a fall:
|
||||
# If slope estimate of current timepoint is more negative than <fall.cutoff>
|
||||
# Add a "5" to the indicator variable
|
||||
# How the program determines a jump down:
|
||||
# If slope estimate is lower than <fall.cutoff> AND is smaller than <jump.cutoffs[2]> times the lowest surrounding slope estimate minus <jump.cutoffs[1]>
|
||||
# Add a "6" to the slope indicator variable
|
||||
#
|
||||
# If none of these are true, add a "0" to the indicator variable
|
||||
|
||||
if (slopes[i] > jump.cutoffs[2] * max(c(slopes[next.i],slopes[prev.i]),0) + jump.cutoffs[1])
|
||||
slope.indicator[i] = 2
|
||||
else if (slopes[i] < fall.cutoff){
|
||||
slope.indicator[i] = 5
|
||||
if (slopes[i] < jump.cutoffs[2] * min(c(slopes[next.i],slopes[prev.i], 0)) - jump.cutoffs[1])
|
||||
slope.indicator[i] = 6
|
||||
}
|
||||
else
|
||||
slope.indicator[i] = 0
|
||||
|
||||
|
||||
#######################################################################################
|
||||
# Method #2 for finding OD jumps: see if each point lies close to a line drawn #
|
||||
# between the closest surrounding points. #
|
||||
#######################################################################################
|
||||
#
|
||||
# Use <counter> variable to track the location of each point. If two subsequent points lie farther
|
||||
# away than the cutoff from their respectively drawn lines AND are on different sides, then count that as a jump.
|
||||
|
||||
if (j > 1 & j < length(indices)){
|
||||
|
||||
# Make equation (y=mx+b) for line drawn between two surrounding points
|
||||
m = (y[next.i] - y[prev.i])/(x[next.i] - x[prev.i])
|
||||
b = y[prev.i] - m * x[prev.i]
|
||||
|
||||
# Estimate y from that line. Points will be judged by how much their true y value deviate from this estimate.
|
||||
|
||||
# calculate b for perpendicular line from observed point to drawn line (slope is -1/m)
|
||||
b2 = y[i] + x[i]/m
|
||||
|
||||
# solve equation for intersection to determine the shortest Euclidean distance between the point and line.
|
||||
# assign a sign to the distance based on the vertical distance.
|
||||
est.x = (b2 - b) / (m + 1/m)
|
||||
est.y = est.x * m + b
|
||||
#est.y = m * x[i] + b
|
||||
#est.x = x[i]
|
||||
|
||||
if(m != 0)
|
||||
point.distance = sqrt((y[i]-est.y)^2 + (x[i]-est.x)^2) * sign(y[i]-est.y)
|
||||
else # horizontal case
|
||||
point.distance = y[i] - b
|
||||
|
||||
#print(paste(i, point.distance, slopes[i], jump.cutoffs[2] * max(c(slopes[next.i],slopes[prev.i]),0) + jump.cutoffs[1], point.distance > jump.cutoffs[3]))
|
||||
|
||||
color = "gray30"
|
||||
# If the true point exceeds that estimate by more than <jump.cutoffs[3]>, update <counter> to positive.
|
||||
# if the counter weas previously negative, mark this as a jump up.
|
||||
if (point.distance > jump.cutoffs[3]){
|
||||
if (counter == -1){
|
||||
slope.indicator[i] = 2
|
||||
color = "red"
|
||||
}
|
||||
counter = 1
|
||||
}
|
||||
# If the true point is under that estimate by more than <jump.cutoffs[3]>, update <counter> to negative.
|
||||
# if the counter was previously positive, mark this as a jump down.
|
||||
else if (point.distance < -jump.cutoffs[3]){
|
||||
if (counter == 1){
|
||||
slope.indicator[i] = 6
|
||||
color = "red"
|
||||
}
|
||||
counter = -1
|
||||
}
|
||||
# If the true point lies within <jump.cutoffs[3]> of that estimate, update <counter> to zero.
|
||||
else
|
||||
counter = 0
|
||||
|
||||
if(draw)
|
||||
# Graphic representation: draw each line used in Method #2 as a dotted line,
|
||||
# and highlight in red if a jump was detected
|
||||
lines(x[c(prev.i, next.i)], y[c(prev.i, next.i)], lty = 2, col = color)
|
||||
}
|
||||
}
|
||||
|
||||
#######################################################################################
|
||||
# Check for tanking by looking for unbroken series of points with falling slopes. #
|
||||
#######################################################################################
|
||||
#
|
||||
# Cycle through <slope.indicator>, adding to <tank> until the end of the curve or until <tank> reaches the <tank.limit>
|
||||
|
||||
tank = 0
|
||||
i = 1
|
||||
|
||||
while(i < length(slope.indicator) & tank < tank.limit){
|
||||
# If a fall was not detected, reset <tank> to 0.
|
||||
if (is.na(slope.indicator[i]))
|
||||
tank = 0
|
||||
# If a fall was detected at a point index greater than <check.start>, add 1 to <tank> .
|
||||
else if (slope.indicator[i] >= 5 & i > check.start)
|
||||
tank = tank + 1
|
||||
else
|
||||
tank = 0
|
||||
|
||||
i = i + 1
|
||||
}
|
||||
|
||||
# If the above loop was terminated because <tank> reached <tank.limit>, update the "curve.par"
|
||||
# slot to denote the first point at which tanking started (should be the last index checked minus <tank.limit>)
|
||||
# also truncate <slope.indicator> so that it does not include the timepoints after tanking.
|
||||
|
||||
if (tank == tank.limit){
|
||||
input.well@curve.par$tanking.start = i - tank.limit
|
||||
slope.indicator = slope.indicator[1:i]
|
||||
if (!silent)
|
||||
cat("...tanks at timepoint", i - tank.limit, ".\n")
|
||||
}
|
||||
else{
|
||||
input.well@curve.par$tanking.start = NA
|
||||
if (!silent)
|
||||
cat("...does not tank.\n")
|
||||
}
|
||||
|
||||
#######################################################################################
|
||||
# Method #2 of checking for tanking: see if OD falls below cutoff #
|
||||
# (as a proportion of max OD) without recovery (according to <tank.limit>) #
|
||||
#######################################################################################
|
||||
#
|
||||
i = check.start
|
||||
tanking.start = NA
|
||||
while(i < length(y) & is.na(tanking.start)){
|
||||
# If the <tank.limit> next ODs beyond i do not reach the cutoff, then mark i as tanking.
|
||||
if (all(y[i+(1:tank.limit)] < max(y,na.rm=T)*tank.cutoff, na.rm=T))
|
||||
tanking.start = i
|
||||
i = i+1
|
||||
}
|
||||
|
||||
# Graphic representation: draw the indicators used in Method #1 using the pch symbols in <slope.indicator>
|
||||
# slope index = 2: an upward-pointing traingle for an upward jump
|
||||
# slope index = 5: a diamond for a fall
|
||||
# slope index = 6: a downward-pointing triangle for downward jump
|
||||
if (draw){
|
||||
points(data.from(input.well, remove = F, remove.tanking = F)[which(slope.indicator != 0),],
|
||||
col = 2, bg = 2, cex = 1.3, pch = slope.indicator[which(slope.indicator != 0)])
|
||||
}
|
||||
|
||||
#######################################################################################
|
||||
# Decide what to do about any remaining jumps in OD #
|
||||
#######################################################################################
|
||||
|
||||
jump.up = which(slope.indicator == 2)
|
||||
jump.down = which(slope.indicator == 6)
|
||||
# <jump.all> is a variable which keeps track of all the jumps, whether up or down.
|
||||
jump.all = sort(c(match(jump.down, indices), match(jump.up, indices)))
|
||||
# commented out; jump not working
|
||||
# if (length(jump.all) > 0)
|
||||
# add.info = paste("Jump(s) detected at timepoint(s)",paste(indices[jump.all],collapse=" "))
|
||||
# else
|
||||
add.info = ""
|
||||
|
||||
# If <remove.jumps> is true, use the following automated process to try and remove OD jumps by selectively removing points from analysis.
|
||||
# if not, just return the well with the above slot filled.
|
||||
|
||||
if (!remove.jumps)
|
||||
input.well@add.info = add.info
|
||||
else{
|
||||
# Cycle through first few jumps (before <check.start>). <remove.initial.jump> is a logical that controls this loop.
|
||||
remove.initial.jump = T
|
||||
while (length(jump.all) > 0 & jump.all[1] < check.start & remove.initial.jump){
|
||||
|
||||
# If any other jumps are also before <check.start>...
|
||||
if (any(jump.all[-1] < check.start)){
|
||||
# ...and the next jump is in a different direction, stop the loop and don't remove the first one.
|
||||
if(slope.indicator[indices[min(jump.all[-1])]] != slope.indicator[indices[jump.all[1]]])
|
||||
remove.initial.jump = F
|
||||
# ...or if the next two jumps are different, stop the loop and don't remove the first one.
|
||||
else if(length(jump.all[-1]) > 1 &
|
||||
slope.indicator[indices[jump.all[2]]] != slope.indicator[indices[jump.all[3]]])
|
||||
remove.initial.jump = F
|
||||
# ...otherwise, remove the jump and keep looping.
|
||||
else
|
||||
remove.initial.jump = T
|
||||
}
|
||||
# If no jumps other than the first one are before <check.start>, remove it and keep looping.
|
||||
else
|
||||
remove.initial.jump = T
|
||||
|
||||
# If the initial jump is to be removed, remove all points before the jump from analysis.
|
||||
# also delete the initial jump from <jump.all>
|
||||
if (remove.initial.jump){
|
||||
input.well = remove.points(input.well, 1:(indices[jump.all[1]] - 1))
|
||||
input.well@add.info = paste(add.info, "and removed.")
|
||||
jump.all = jump.all[-1]
|
||||
}
|
||||
}
|
||||
# If greater than 3 jumps remain, discard the curve as uninterpretable
|
||||
if (length(jump.all) >= 4){
|
||||
input.well = remove.points(input.well, 1:length(input.well))
|
||||
input.well@add.info = paste(add.info, " - data was discarded.")
|
||||
}
|
||||
else{
|
||||
# If there are 3 jumps, remove all points after the last one from analysis and delete the last jump from <jump.all>
|
||||
if(length(jump.all) == 3){
|
||||
input.well = remove.points(input.well, indices[jump.all[3]]:length(input.well))
|
||||
input.well@add.info = paste(add.info, "and removed.")
|
||||
jump.all = jump.all[-3]
|
||||
}
|
||||
|
||||
# If there are now 2 jumps...
|
||||
if(length(jump.all) == 2){
|
||||
# ...and they are different (one up, one down), remove the points in between them from analysis.
|
||||
if (diff(slope.indicator[indices[jump.all]]) != 0 ){
|
||||
input.well = remove.points(input.well, indices[jump.all[1]:(jump.all[2] - 1)])
|
||||
input.well@add.info = paste(add.info, "and removed.")
|
||||
}
|
||||
# ...and they are in the same direction, remove all the points after the first one from analysis.
|
||||
else{
|
||||
input.well = remove.points(input.well, indices[jump.all[1]]:length(input.well))
|
||||
input.well@add.info = paste(add.info, "and removed.")
|
||||
}
|
||||
}
|
||||
# If there is only one jump, remove all points after it from analysis.
|
||||
else if (length(jump.all == 1)){
|
||||
input.well = remove.points(input.well, indices[jump.all[1]]:length(input.well))
|
||||
input.well@add.info = paste(add.info, "and removed.")
|
||||
jump.all = jump.all[-1]
|
||||
}
|
||||
}
|
||||
}
|
||||
if(!silent)
|
||||
cat("\t", input.well@add.info)
|
||||
return(input.well)
|
||||
}
|
||||
|
||||
########################################################################
|
||||
# #
|
||||
# Check wells for growth, remove from analysis if OD is too low #
|
||||
# #
|
||||
########################################################################
|
||||
#
|
||||
# The well will be tagged with no.growth = T in the slot "curve.par" if raw OD values (except for <points.to.remove>)
|
||||
# do not increase beyond <growth.cutoff> above the specified time of inoculation for that well (<start.index>)
|
||||
|
||||
check.growth = function(input.well, growth.cutoff, start.index = 2){
|
||||
|
||||
# Get raw ODs (not including <points.to.remove>) and slope estimates from the well
|
||||
# as well as OD at inoculation timepoint <start.index>
|
||||
raw.ODs = raw.data(input.well)[,2]
|
||||
start.OD = raw.ODs[start.index]
|
||||
|
||||
raw.ODs[input.well@screen.data$Remove] = NA
|
||||
slope.estimates = slopes(input.well, remove.tanking = T, na.rm = T)
|
||||
|
||||
# If fewer than 3 points remain in the analysis with valid slope estimates, discard the well.
|
||||
if (length(slope.estimates) < 3 | all(is.na(slope.estimates)))
|
||||
input.well@curve.par$no.growth= T
|
||||
else{
|
||||
# If there are no points at all in the raw ODs
|
||||
if(all(is.na(raw.ODs)))
|
||||
input.well@curve.par$no.growth = T
|
||||
else if(max(raw.ODs, na.rm=T) - start.OD < growth.cutoff) # See if OD increases by at least <growth.cutoff> above
|
||||
input.well@curve.par$no.growth = T
|
||||
else
|
||||
input.well@curve.par$no.growth = F
|
||||
}
|
||||
if(all(raw.data(input.well)[,2] - raw.data(input.well)[start.index,2] < growth.cutoff))
|
||||
input.well@add.info = "" # This is simply to reduce the amount of unnecessary info in the output.
|
||||
# If the well is below growth cutoff anyway, don't bother reporting other errors.
|
||||
return(input.well)
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,210 @@
|
||||
#Copyright 2012 The Board of Regents of the University of Wisconsin System.
|
||||
#Contributors: Jason Shao, James McCurdy, Enhai Xie, Adam G.W. Halstead,
|
||||
#Michael H. Whitney, Nathan DiPiazza, Trey K. Sato and Yury V. Bukhman
|
||||
#
|
||||
#This file is part of GCAT.
|
||||
#
|
||||
#GCAT is free software: you can redistribute it and/or modify
|
||||
#it under the terms of the GNU Lesser General Public License as published by
|
||||
#the Free Software Foundation, either version 3 of the License, or
|
||||
#(at your option) any later version.
|
||||
#
|
||||
#GCAT is distributed in the hope that it will be useful,
|
||||
#but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
#GNU Lesser General Public License for more details.
|
||||
#
|
||||
#You should have received a copy of the GNU Lesser General Public License
|
||||
#along with GCAT. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
########################################################################
|
||||
# #
|
||||
# Populate an output table with parameters and other useful info for #
|
||||
# each well in a fitted dataset. #
|
||||
# #
|
||||
########################################################################
|
||||
#
|
||||
# unlog - Should OD values be returned on the linear scale instead of log-transformed scale?
|
||||
# constant.added - For returning values on linear scale, what constant was added to ODs before the log transform?
|
||||
# reach.cutoff - what proportion of the plateau OD must tbe reached by the last valid timepoint for the curve to be marked as reaching its plateau OD?
|
||||
#
|
||||
|
||||
table.out = function(fitted.data.set, unlog = F, constant.added, reach.cutoff = 0.90, filename.timestamp = NULL,use.linear.param=F, use.loess=F){
|
||||
|
||||
# The idea is basically to use <unlist> and <aapply> on the fitted data array in order
|
||||
# to get one vector for each column of the output table.
|
||||
|
||||
# Get identifying information (plate, well, media and strain names)
|
||||
plate.ID = unlist(aapply(fitted.data.set,plate.name))
|
||||
well.ID = unlist(aapply(fitted.data.set,well.name))
|
||||
media.ID = unlist(aapply(fitted.data.set,media.name))
|
||||
strain.ID = unlist(aapply(fitted.data.set,strain.name))
|
||||
# Get fit information for each well
|
||||
# - was it marked as empty in the plate layout?
|
||||
# - did the program find it to contain no growth ("dead")?
|
||||
# - was the fitting procedure successful?
|
||||
# - did the curve tank? if so, at what timepoint? if not, set value to "-"
|
||||
|
||||
empty = unlist(aapply(fitted.data.set, is.empty))
|
||||
dead = unlist(aapply(fitted.data.set, lacks.growth))
|
||||
fit = unlist(aapply(fitted.data.set, contains.fit))
|
||||
tanking = unlist(aapply(fitted.data.set, tanking.start))
|
||||
tanking[is.na(tanking) | tanking == 1 | dead] = "-"
|
||||
|
||||
# Get calculated values for each well: specific growth, final and initial OD, fitted plateau and baseline OD, lag time, etc.
|
||||
inflection.time = unlist(aapply(fitted.data.set, inflection.time))
|
||||
max.spec.growth.rate = unlist(aapply(fitted.data.set, max.spec.growth.rate))
|
||||
max.log.OD = unlist(aapply(fitted.data.set, max.log.OD))
|
||||
inoc.log.OD = unlist(aapply(fitted.data.set, inoc.log.OD))
|
||||
projected.growth = unlist(aapply(fitted.data.set, projected.growth))
|
||||
projected.growth.OD = unlist(aapply(fitted.data.set, projected.growth.OD, constant.added))
|
||||
achieved.growth = unlist(aapply(fitted.data.set, achieved.growth))
|
||||
achieved.growth.OD = unlist(aapply(fitted.data.set, achieved.growth.OD, constant.added))
|
||||
lag.time = unlist(aapply(fitted.data.set, lag.time))
|
||||
shape.par = unlist(aapply(fitted.data.set, shape.par))
|
||||
RSS = unlist(aapply(fitted.data.set, rss))
|
||||
baseline = unlist(aapply(fitted.data.set, baseline))
|
||||
amplitude = unlist(aapply(fitted.data.set, amplitude))
|
||||
plateau = unlist(aapply(fitted.data.set, plateau))
|
||||
########################3h#############################################
|
||||
max.spec.growth.rate.SE = unlist(aapply(fitted.data.set, max.spec.growth.rate.SE))
|
||||
shape.par.SE = unlist(aapply(fitted.data.set, shape.par.SE))
|
||||
lag.time.SE = unlist(aapply(fitted.data.set, lag.time.SE))
|
||||
amplitude.SE = unlist(aapply(fitted.data.set, amplitude.SE)) # a.k.a amplitude error
|
||||
baseline.SE = unlist(aapply(fitted.data.set, baseline.SE)) # a.k.a baseline error
|
||||
#######################################################################
|
||||
|
||||
# If the curve falls short of 90% of plateau OD by the final timepoint.
|
||||
no.reach.plateau = !unlist(aapply(fitted.data.set, reach.plateau, cutoff = 0.9))
|
||||
# If the fitted baseline is below zero on linear scale
|
||||
no.reach.baseline = unlog(baseline,constant.added) < 0
|
||||
|
||||
# If any of these are NA as a result of failed fits, change them to false: they don't need to be reported.
|
||||
no.reach.plateau[is.na(no.reach.plateau)] = F
|
||||
no.reach.baseline[is.na(no.reach.baseline)] = F
|
||||
# What percent of the total growth does the curve actually reach?
|
||||
# (in case of total growth being 0, change this to 100%)
|
||||
percent.reach = 100*((max.log.OD - inoc.log.OD) / (projected.growth))
|
||||
percent.reach[is.infinite(percent.reach)] = 100
|
||||
|
||||
# Return the name of the model (if any) that was successfully fit to the well.
|
||||
model.used = unlist(aapply(fitted.data.set, function(well)well@model.name))
|
||||
|
||||
# "Goodness of fit" metric
|
||||
good.fit = unlist(aapply(fitted.data.set, model.good.fit))
|
||||
|
||||
# Code the two flags:
|
||||
flag1 = flag2 = rep("-", length(tanking))
|
||||
|
||||
for(i in 1:length(tanking)){
|
||||
# Flag 1 (empty/inoculated flag) possible values:
|
||||
# well was empty and no growth was found (E)
|
||||
# well was empty, but growth was found (E*)
|
||||
# well was inoculated but no growth was found (!)
|
||||
# well was inoculated and growth was found (I)
|
||||
|
||||
if(empty[i] & !fit[i])
|
||||
flag1[i] = "E "
|
||||
if(empty[i] & fit[i])
|
||||
flag1[i] = "E*"
|
||||
if(!empty[i] & dead[i])
|
||||
flag1[i] = "! "
|
||||
if(!empty[i] & !dead[i])
|
||||
flag1[i] = "I "
|
||||
|
||||
# Flag 2 (lower/upper asymptotes) possible values:
|
||||
# well did not reach lower asymptote (baseline OD) (L)
|
||||
# well did not reach upper asymptote (plateau OD) (U)
|
||||
# well did not reach either asymptote (L/U)
|
||||
# well reached both asymptotes (-)
|
||||
|
||||
if(no.reach.baseline[i]){
|
||||
if (no.reach.plateau[i])
|
||||
flag2[i] = "L/U"
|
||||
else
|
||||
flag2[i] = "L"
|
||||
}
|
||||
else{
|
||||
if (no.reach.plateau[i])
|
||||
flag2[i] = "U"
|
||||
else
|
||||
flag2[i] = "-"
|
||||
}
|
||||
# Also use the <dead> and <empty> and <fit> to provie more info about why model fitting failed in some cases.
|
||||
if(dead[i])
|
||||
model.used[i] = "<NA>: skipped"
|
||||
else if(!empty[i] & !fit[i])
|
||||
model.used[i] = "<NA>: failed"
|
||||
}
|
||||
|
||||
# Flag 3: return the additional info slot.
|
||||
flag3 = unlist(aapply(fitted.data.set, function(well){
|
||||
if (length(well@add.info) > 0)
|
||||
return(well@add.info)
|
||||
else
|
||||
return("")
|
||||
}))
|
||||
|
||||
# If something is amiss with the data table use this to check on the arguments...
|
||||
#cat("plate ", length(plate.ID)," well ", length(well.ID)," media ", length(media.ID)," strain ", length(strain.ID),
|
||||
#" model ", length(model.used)," max.spec.growth.rate", length(max.spec.growth.rate), "projected.growth", length(projected.growth),
|
||||
#"lag.time", length(lag.time), "inoc.log.OD", length(inoc.log.OD), "good.fit",
|
||||
#length(good.fit),"empty", length(flag1),"asymp", length(flag2)," tank ", length(tanking)," reach ", length(percent.reach)," other ", length(flag3), sep = "\n")
|
||||
# 06.28.11: Add a row number identifier for output perusal
|
||||
row.number = 1:length(plate.ID)
|
||||
|
||||
pdf.file = page.no = c()
|
||||
# 06.29.11: Add pdf file name and page number references. Prepare timestamp for addition to output file names (for file references in last column)
|
||||
for(i in 1:length(plate.ID)){
|
||||
pdf.file[i] = paste(plate.ID[i], "_plots", filename.timestamp, ".pdf", sep="")
|
||||
page.no[i] = (i-1) %% 96 + 2
|
||||
}
|
||||
# Slap it all together into a data frame.
|
||||
if(use.loess){
|
||||
output.core = data.frame(row = row.number, plate = plate.ID, well = well.ID, media = media.ID, strain = strain.ID,
|
||||
model = model.used, lag.time, inflection.time, max.spec.growth.rate,
|
||||
baseline, amplitude, plateau, inoc.log.OD, max.log.OD, achieved.growth,
|
||||
baseline.OD = unlog(baseline,constant.added), amplitude.OD = unlog(amplitude,constant.added),
|
||||
plateau.OD = unlog(plateau,constant.added), inoc.OD = unlog(inoc.log.OD,constant.added),
|
||||
max.OD = unlog(max.log.OD,constant.added), achieved.growth.OD = achieved.growth.OD,
|
||||
R.squared = good.fit, RSS = RSS, empty = flag1, asymp.not.reached = flag2, tank = tanking, other = flag3, pdf.file = pdf.file, page.no = page.no)
|
||||
} else {
|
||||
output.core = data.frame(row = row.number, plate = plate.ID, well = well.ID, media = media.ID, strain = strain.ID,
|
||||
model = model.used, lag.time = lag.time, lag.time.SE, inflection.time, max.spec.growth.rate, max.spec.growth.rate.SE,
|
||||
baseline, baseline.SE, amplitude, amplitude.SE, plateau, inoc.log.OD, max.log.OD, projected.growth, achieved.growth,
|
||||
baseline.OD = unlog(baseline,constant.added), amplitude.OD = unlog(amplitude,constant.added),
|
||||
plateau.OD = unlog(plateau,constant.added), inoc.OD = unlog(inoc.log.OD,constant.added),
|
||||
max.OD = unlog(max.log.OD,constant.added), projected.growth.OD = projected.growth.OD, achieved.growth.OD = achieved.growth.OD,
|
||||
shape.par = shape.par, shape.par.SE,
|
||||
R.squared = good.fit, RSS = RSS, empty = flag1, asymp.not.reached = flag2, tank = tanking, other = flag3, pdf.file = pdf.file, page.no = page.no)
|
||||
}
|
||||
|
||||
# Add units to column names
|
||||
names2 = names(output.core)
|
||||
names2[grep("time",names2)] = sub("$",", hrs", names2[grep("time",names2)])
|
||||
names2[grep("rate",names2)] = sub("$",", log.OD/hr", names2[grep("rate",names2)])
|
||||
log.OD.fields = c("baseline", "baseline.SE", "amplitude", "amplitude.SE", "plateau", "projected.growth", "achieved.growth")
|
||||
names2[names2 %in% log.OD.fields] = sub("$", ", log.OD", names2[names2 %in% log.OD.fields])
|
||||
names(output.core) = names2
|
||||
|
||||
# Add on any additional fields found in the plate layout.
|
||||
all.layout.fields = sapply(fitted.data.set, function(well) unlist(well@well.info))
|
||||
all.layout.fields = as.data.frame(t(all.layout.fields))
|
||||
|
||||
|
||||
addl.info = all.layout.fields[,!(names(all.layout.fields) %in% c("Strain", "Media"))]
|
||||
if(!is.data.frame(addl.info)){
|
||||
addl.info = data.frame(addl.info)
|
||||
names(addl.info) = names(all.layout.fields)[!(names(all.layout.fields) %in% c("Strain", "Media"))]
|
||||
}
|
||||
|
||||
output = cbind(output.core,addl.info)
|
||||
|
||||
return(output)
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -0,0 +1,427 @@
|
||||
#Copyright 2012 The Board of Regents of the University of Wisconsin System.
|
||||
#Contributors: Jason Shao, James McCurdy, Enhai Xie, Adam G.W. Halstead,
|
||||
#Michael H. Whitney, Nathan DiPiazza, Trey K. Sato and Yury V. Bukhman
|
||||
#
|
||||
#This file is part of GCAT.
|
||||
#
|
||||
#GCAT is free software: you can redistribute it and/or modify
|
||||
#it under the terms of the GNU Lesser General Public License as published by
|
||||
#the Free Software Foundation, either version 3 of the License, or
|
||||
#(at your option) any later version.
|
||||
#
|
||||
#GCAT is distributed in the hope that it will be useful,
|
||||
#but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
#GNU Lesser General Public License for more details.
|
||||
#
|
||||
#You should have received a copy of the GNU Lesser General Public License
|
||||
#along with GCAT. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
# Notes by Jason
|
||||
# 9/07/11
|
||||
|
||||
|
||||
########################################################################
|
||||
# #
|
||||
# Function for loading data from tabular format into an object array #
|
||||
# #
|
||||
########################################################################
|
||||
#' Load tabular data
|
||||
#'
|
||||
#' This function handles loading data from tabular format (.csv, tab-delimited text or R data frame object)
|
||||
#' and returns an array of well objects, each filled with raw Time vs. OD data.
|
||||
#' It takes single-plate or multiple-plate format data. For single-plate data,
|
||||
#'it calls on the function \code{gcat.reorganize.single.plate.data} to rearrange the table before creating the output object.
|
||||
#'
|
||||
#' @param file.name Complete path and file name of a comma-separated values (.csv) file containing growth curve data
|
||||
#' in the multiple-plate (long) format.
|
||||
#' @param input.data A list of tables representing input files read with \code{read.table}. Used to save time in cases
|
||||
#' of running multiple analyses on the same dataset. If used, the function will ignore \code{file.name} entirely.
|
||||
#' @param load.type .csv by default.
|
||||
#' @param plate.laout Specifies the layout of the given plate.
|
||||
#' @param single.plate.ID specifies a plate name for a single-plate read. If NULL, this is derived from the file name.
|
||||
#' @param blank.value Blank OD measurement for uninoculated wells. By default(NULL), the value of the first OD
|
||||
#' measurement in each well is used.
|
||||
#' @param add.constant A value for r in the log(OD + r) transformation.
|
||||
#' @param plate.nrow The number of rows in the input files.
|
||||
#' @param plate.ncol The number of columns in the input files.
|
||||
#' @param input.skip.lines specifies a plate name for a single-plate read. If NULL, this is derived from the file name.
|
||||
#' @param multi.column.headers The headers of the column when analyzing multiple plates.
|
||||
#' @param single.column.headers The headers of the column when analyzing a single plate.
|
||||
#' @param layout.sheet.headers The headers of the layout file.
|
||||
#' @param silent Surpress all messages.
|
||||
#' @param verbose Display all messages when analyzing each well.
|
||||
#'
|
||||
#' @return A list of well objects.
|
||||
gcat.load.data = function(file.name = NULL, load.type = "csv", input.data = NULL, single.plate.ID = NULL,
|
||||
plate.layout = NULL,plate.nrow = 8, plate.ncol = 12, input.skip.lines = 0,
|
||||
multi.column.headers = c("Plate.ID", "Well", "OD", "Time"), single.column.headers = c("","A1"),
|
||||
layout.sheet.headers = c("Strain", "Media Definition"),
|
||||
blank.value = NULL, start.index = 2, single.plate = F, silent = T){
|
||||
|
||||
########################################################################
|
||||
# Read from .csv, tab-delimited text file or data frame object #
|
||||
########################################################################
|
||||
|
||||
if(is.null(input.data)){
|
||||
# Either read from .csv.
|
||||
input.data = read.csv(file.name, stringsAsFactors=F, skip = input.skip.lines, fileEncoding='UTF-8')
|
||||
|
||||
# Determine single plate name if not specified.
|
||||
if (is.null(single.plate.ID)){
|
||||
# Split the file name by "." and discard the last member (file extension).
|
||||
single.plate.ID = strsplit(basename(file.name),"\\.")[[1]]
|
||||
single.plate.ID = paste(single.plate.ID[-length(single.plate.ID)],collapse=".")
|
||||
}
|
||||
}
|
||||
|
||||
# Call <gcat.reorganize.single.plate.data> to arrange data from a single plate format file
|
||||
if(single.plate)
|
||||
input.data = gcat.reorganize.single.plate.data(input.data = input.data, single.column.headers,
|
||||
blank.value = blank.value, single.plate.ID = single.plate.ID, plate.nrow = plate.nrow, plate.ncol = plate.ncol, silent=silent)
|
||||
|
||||
########################################################################
|
||||
# Search for and standardize column headers in input data #
|
||||
########################################################################
|
||||
|
||||
# Go through the specified column headers, determining what their positions are in the
|
||||
# input data frame and if any are missing.
|
||||
|
||||
# Get names of column headers in input data
|
||||
input.colnames = colnames(input.data)
|
||||
|
||||
# Create a list denoting the column numbers in input data that match each of the specified column names,
|
||||
# and a separate list for any missing columns.
|
||||
|
||||
column.matches = c()
|
||||
missing.list = NULL
|
||||
|
||||
for(i in 1:length(multi.column.headers)){
|
||||
if (multi.column.headers[i] %in% input.colnames)
|
||||
column.matches[i] = min(which(input.colnames == multi.column.headers[i]))
|
||||
# Take the first column in input file that matches a specified column header.
|
||||
else{
|
||||
missing.list = c(missing.list, i)
|
||||
}
|
||||
}
|
||||
|
||||
# If any columns are missing, stop and report error with missing column names
|
||||
if (is.vector(missing.list)){
|
||||
message = "The following columns:"
|
||||
for (i in missing.list)
|
||||
message = paste(message, paste(" ", multi.column.headers[i]), sep = "\n")
|
||||
stop(message, "\n were not found in the data file.")
|
||||
}
|
||||
|
||||
# Reorder and rename the columns, using the list of matching column numbers from above.
|
||||
input.data = input.data[,column.matches]
|
||||
names(input.data)[1:4] = c("Plate.ID", "Well", "OD", "Time")
|
||||
|
||||
# Use 'substring' to split the alphanumeric "Well" field into row (letters) and column (numbers)
|
||||
input.data$Well.row = substring(input.data$Well, 0,1)
|
||||
input.data$Well.col = as.numeric(substring(input.data$Well, 2))
|
||||
|
||||
|
||||
########################################################################
|
||||
# Create an array of well objects with the Time and OD data #
|
||||
########################################################################
|
||||
#
|
||||
# Use the by function to split up the data frame into shorter segments by well (row, column and plate)
|
||||
|
||||
well.array = by(data = input.data[,c("OD", "Time")],
|
||||
INDICES = list(input.data$Well.row,input.data$Well.col,input.data$Plate.ID),
|
||||
FUN = function(x){data.frame(Time=x$Time, OD=x$OD,stringsAsFactors = F)}, simplify = F)
|
||||
|
||||
|
||||
# Then apply the function <well> (found in well.class) to each member to create a well object
|
||||
well.array = aapply(well.array,function(x){well(x$Time,x$OD)})
|
||||
|
||||
# Differentiate any duplicate plate names in the array's dimnames
|
||||
new.dimnames = dimnames(well.array)
|
||||
for (i in length(new.dimnames[[3]]):1){
|
||||
if (any(new.dimnames[[3]][-i] == new.dimnames[[3]][i]))
|
||||
new.dimnames[[3]][i] = paste("another_", new.dimnames[[3]][i], sep = "")
|
||||
}
|
||||
dimnames(well.array) = new.dimnames
|
||||
|
||||
# Copy the plate/row/column names found in the dimnames into the array objects themselves (use "position" slot)
|
||||
for(plate in unique(dimnames(well.array)[[3]])){
|
||||
for (col in unique(dimnames(well.array)[[2]])){
|
||||
for(row in unique(dimnames(well.array)[[1]])){
|
||||
well.array[[row,col,plate]]@position = c(plate=plate,row=row,col=col)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
########################################################################
|
||||
# Add plate layout information to well array #
|
||||
########################################################################
|
||||
|
||||
# Use the <plate.layout> object to add media and strain information to the "well.info" slot of each well
|
||||
# Also set the value of the parameter <empty.well> in slot "curve.par" to T for empty wells.
|
||||
########################################################################
|
||||
# Add plate layout information to well array #
|
||||
########################################################################
|
||||
|
||||
# Use the <plate.layout> object to add media and strain information to the "well.info" slot of each well
|
||||
# Also set the value of the parameter <empty.well> in slot "curve.par" to T for empty wells.
|
||||
|
||||
|
||||
# If <plate.layout> is not provided, do not add strain information, and assume all wells are inoculated.
|
||||
if(is.null(plate.layout)){
|
||||
plate.layout = data.frame(Row=rep(PLATE.LETTERS[1:plate.nrow],plate.ncol),Column=rep(1:plate.ncol,each=plate.nrow),rep("Unknown Strain",96),rep("Unknown Media",96))
|
||||
colnames(plate.layout) = c("Row", "Column", layout.sheet.headers)
|
||||
}
|
||||
else
|
||||
if(!silent) cat("\n\t\tusing plate layout to fill well info.")
|
||||
|
||||
for(plate in unique(dimnames(well.array)[[3]])){
|
||||
for (col in unique(dimnames(well.array)[[2]])){
|
||||
for(row in unique(dimnames(well.array)[[1]])){
|
||||
well = well.array[[row,col,plate]]
|
||||
# For each well on each plate, find the corresponding row in <plate.layout>.
|
||||
# If <plate.layout> refers to specific plates, then use those to find the correct row.
|
||||
# Otherwise, generalize across all plates.
|
||||
if ("Plate.ID" %in% names(plate.layout))
|
||||
layout.row.number = which(plate.layout$Column==well@position["col"] &
|
||||
plate.layout$Row==well@position["row"] &
|
||||
plate.layout$Plate.ID==well@position["plate"] )
|
||||
else
|
||||
layout.row.number = which(plate.layout$Column==well@position["col"] &
|
||||
plate.layout$Row==well@position["row"])
|
||||
|
||||
# Error if either no rows or more than one row matches the well
|
||||
if (length(layout.row.number) != 1)
|
||||
stop("incorrectly formatted plate layout! check names of columns, rows, and plates (if applicable).")
|
||||
|
||||
# Add any additional columns to the well's "well.info" slot
|
||||
well.info = plate.layout[layout.row.number,!(names(plate.layout) %in% c("Row","Column","Plate.ID",layout.sheet.headers))]
|
||||
|
||||
# Fix the column name issue if there is only one additional entry.
|
||||
if(length(well.info) == 1){
|
||||
well.info = data.frame(well.info,stringsAsFactors=F)
|
||||
names(well.info) = names(plate.layout)[!(names(plate.layout) %in% c("Row","Column","Plate.ID",layout.sheet.headers))]
|
||||
}
|
||||
well@well.info = as.list(well.info)
|
||||
|
||||
well@well.info$Strain = plate.layout[layout.row.number, layout.sheet.headers[1]]
|
||||
well@well.info$Media = plate.layout[layout.row.number, layout.sheet.headers[2]]
|
||||
|
||||
# Set <empty.well> parameter in slot "curve.par" accordingly
|
||||
well@curve.par$empty.well = (plate.layout$Strain[layout.row.number] == "Empty")
|
||||
well.array[[row,col,plate]] = well
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Set start index value in each well
|
||||
well.array = aapply(well.array, function(x,start.index) { x@start.index = start.index; x }, start.index)
|
||||
|
||||
########################################################################
|
||||
# Return values to R #
|
||||
########################################################################
|
||||
#
|
||||
# Console output if desired, return the completed well array.
|
||||
if (!silent)
|
||||
cat("\n\t", dim(well.array)[[3]], "plates added to array from", file.name)
|
||||
return(well.array)
|
||||
}
|
||||
|
||||
|
||||
|
||||
########################################################################
|
||||
# #
|
||||
# Reorganize data from single-plate input format before reading #
|
||||
# #
|
||||
########################################################################
|
||||
#
|
||||
# This function reorganizes the data frame from a single-plate format file.
|
||||
# input.data - data frame read straight from a single-plate format data file.
|
||||
# single.plate.ID - specifies a plate name for a single-plate read, since none is given in the single-plate format
|
||||
# The plate will be named Plate_1 unless otherwise specified.
|
||||
|
||||
gcat.reorganize.single.plate.data = function(input.data, blank.value = NULL, single.column.headers, single.plate.ID = "Plate_1",
|
||||
plate.nrow = 8, plate.ncol = 12, silent=T){
|
||||
|
||||
########################################################################
|
||||
# Standardize the formatting and search for specified column names #
|
||||
########################################################################
|
||||
#
|
||||
# Locate the first and last rows from the table and return errors if not defined
|
||||
# Note: this only works if the time column is the first column
|
||||
|
||||
header.row = min(which(input.data[,1] == single.column.headers[1]))
|
||||
if (length(header.row) != 1 | is.infinite(header.row))
|
||||
stop("could not locate header row in input file!")
|
||||
|
||||
# The last row: where column 2 starts to be blank, or the total number of rows, whichever is smaller
|
||||
extra.rows.start = min(which(input.data[-(1:header.row),2] == ""), which(is.na(input.data[-(1:header.row),2])), nrow(input.data[-(1:header.row),]))
|
||||
if (length(extra.rows.start) != 1 & is.infinite(extra.rows.start))
|
||||
stop("could not locate last row in input file!")
|
||||
|
||||
# Use header row to rename the columns, then cut off extra rows (including the ones above header)
|
||||
names(input.data) = as.character(unlist(input.data[header.row,]))
|
||||
input.data = input.data[(header.row+1):(header.row+extra.rows.start-1),]
|
||||
|
||||
# Time column: allow for multiple matches to the name (since it's usually blank) but assume it's the first one
|
||||
Time.column = which(names(input.data) == single.column.headers[1])
|
||||
if (length(Time.column) != 1){
|
||||
if(!silent) cat("No unique time column in input.data file! Using the first one encountered.")
|
||||
Time.column = min(Time.column)
|
||||
}
|
||||
# First well column (default A1): only allow for one match.
|
||||
Well.column.start = which(names(input.data) == single.column.headers[2])
|
||||
if (length(Well.column.start) != 1)
|
||||
stop("No unique start point for well columns in input.data file!")
|
||||
|
||||
# If the time column was found, rename it "Time" and reformat it into a numeric value
|
||||
# Adjust the blank measurement timestamp to -1 seconds if there is one
|
||||
|
||||
names(input.data)[Time.column] = "Time"
|
||||
|
||||
# Note: Some single plate screens have timepoints ending with "s" for seconds.
|
||||
# This line removes the "s" while maintaining general compatibility.
|
||||
input.data$Time = unlist(strsplit(input.data$Time, "s"))
|
||||
|
||||
# If <blank.value> is NULL (default - takes the first OD as the blank reading), then the first timepoint can labeled something non-numeric.
|
||||
# In that case, rename it to match the first real timepoint minus one.
|
||||
# when user input blank value, Blank timepoint i.e. input.data$Time[1] == Blank, labeled as "Blank" from data input file
|
||||
# It also should rename it to match the first real timepoint minus one.
|
||||
if(is.null(blank.value) || is.na(as.numeric(input.data$Time[1])))
|
||||
input.data$Time[1] = as.numeric(input.data$Time[2]) - 1
|
||||
|
||||
########################################################################
|
||||
# Start to fill the reformatted data frame #
|
||||
########################################################################
|
||||
|
||||
# If all columns are present, make a list of all the wells.
|
||||
well.list = paste(rep(PLATE.LETTERS[1:plate.nrow], each = plate.ncol), rep(formatC(1:plate.ncol, digits = log(plate.ncol, 10), flag = "0"), plate.nrow), sep = "")
|
||||
|
||||
# Duplicate the well names times the number of time measurements in each well
|
||||
Well = rep(well.list, each = length(input.data[,Time.column]))
|
||||
|
||||
# Duplicate <plate.name> times the length of the entire output
|
||||
Plate.ID = rep(single.plate.ID, length(Well))
|
||||
|
||||
# Duplicate the time column times the number of wells and convert to numeric
|
||||
Time = as.numeric(rep(input.data[,Time.column], times = length(Well.column.start:ncol(input.data))))
|
||||
|
||||
# Append OD measurements from each well together and convert to numeric
|
||||
OD = c()
|
||||
for (i in Well.column.start:ncol(input.data)){
|
||||
OD = as.numeric(c(OD, input.data[,i]))
|
||||
OD = unlist(OD)
|
||||
}
|
||||
|
||||
# Fill and return the data frame containing the above four vectors.
|
||||
output = data.frame(Plate.ID, Well, OD, Time)
|
||||
|
||||
# Include any extra columns that were not Time or OD measurements?
|
||||
for(i in (1:length(names(input.data)))[-c(Time.column,Well.column.start:ncol(input.data))]){
|
||||
new.column = data.frame(rep(input.data[,i], length(Well.column.start:ncol(input.data))))
|
||||
names(new.column) = names(input.data)[i]
|
||||
output = cbind(output, new.column)
|
||||
}
|
||||
return(output)
|
||||
}
|
||||
|
||||
|
||||
########################################################################
|
||||
# #
|
||||
# Function to combine two well array datasets by plate #
|
||||
# #
|
||||
########################################################################
|
||||
# ----------------------------------------------------------
|
||||
# This function can append together arrays created using <load.data>
|
||||
# Arguments: any number of array objects as long as they are all output straight from <load.data>
|
||||
|
||||
gcat.append.arrays = function(...){
|
||||
|
||||
# Transfer arrays to a list
|
||||
args.arrays = list(...)
|
||||
first.array = args.arrays[[1]]
|
||||
first.dims = dim(first.array)
|
||||
plate.nrow = args.arrays[[4]]
|
||||
plate.ncol = args.arrays[[3]]
|
||||
input.arrays = list(args.arrays[[1]], args.arrays[[2]])
|
||||
for (i in 2:length(input.arrays)){
|
||||
next.array = input.arrays[[i]]
|
||||
next.dims = dim(next.array)
|
||||
|
||||
# Check to make sure the arrays have proper dimensions for 96-well plate data
|
||||
if (!(all(c(first.dims[1], next.dims[1]) == plate.nrow) & all(c(first.dims[2], next.dims[2]) == plate.ncol)))
|
||||
stop("Data should have dimensions (",plate.nrow,",",plate.ncol,",n)!")
|
||||
|
||||
# If dimensions are alright, append dimensions and dimension names
|
||||
new.dims = c(plate.nrow,plate.ncol,first.dims[3]+next.dims[3])
|
||||
new.names = dimnames(first.array)
|
||||
new.names[[3]] = c(new.names[[3]], dimnames(next.array)[[3]])
|
||||
|
||||
# Differentiate duplicate names
|
||||
for (i in length(new.names[[3]]):1){
|
||||
if (any(new.names[[3]][-i] == new.names[[3]][i]))
|
||||
new.names[[3]][i] = paste("another_", new.names[[3]][i], sep = "")
|
||||
}
|
||||
|
||||
# Create a new array
|
||||
new.array = c(first.array, next.array)
|
||||
dim(new.array) = new.dims
|
||||
dimnames(new.array) = new.names
|
||||
|
||||
# Update plate name in well objects
|
||||
for (i in 1:length(unlist(new.array)))
|
||||
new.array[[i]]@position[1] = new.names[[3]][floor((i-1)/96)+1]
|
||||
|
||||
# Loop until complete
|
||||
first.array = new.array
|
||||
first.dims = dim(first.array)
|
||||
}
|
||||
return(new.array)
|
||||
}
|
||||
|
||||
|
||||
########################################################################
|
||||
# #
|
||||
# Convert timestamps to hours from start and sort timepoints #
|
||||
# #
|
||||
########################################################################
|
||||
#
|
||||
# This function acts on a single well and modifies the raw data stored in slot "screen.data"
|
||||
#
|
||||
# input.well - an object of class well
|
||||
# time.format - specifies the time format. allowed values are "%S", for seconds, "%d", for days, or anything complying with ISO C / POSIX standards; see <strptime>
|
||||
# note: reading directly from excel to R results in timestamps being converted to days.
|
||||
# start.index - which timepoint should be used as the starting time at inoculation?
|
||||
|
||||
gcat.start.times = function(input.well, time.input, start.index = 2) {
|
||||
|
||||
if(start.index > length(input.well))
|
||||
stop("Start index is greater than length of well!")
|
||||
|
||||
# If using a numeric time format, simply multiply times by the appropriate conversion factor
|
||||
# Conversion factor should be supplied to convert timestamps to hours. For example,
|
||||
# <time.format> should be equal to 1/3600 if "time" is in seconds, 24 if "time" is in days, etc.
|
||||
|
||||
time.format = time.input # Set default constant from rails user input
|
||||
|
||||
if (is.numeric(time.format))
|
||||
input.well@screen.data$Time = (input.well@screen.data$Time - min(input.well@screen.data$Time)) * time.format
|
||||
else{
|
||||
# Otherwise, convert timestamps from ISO C / POSIX to numeric values representing seconds (since the dawn of time?) and subtract out the initial value.
|
||||
rtimes = input.well@screen.data$Time
|
||||
ptimes = strptime(as.character(rtimes),time.format)
|
||||
ctimes = as.POSIXct(ptimes)
|
||||
int.times = unclass(ctimes)
|
||||
# Time will be in seconds, convert to hours by dividing by 3600
|
||||
input.well@screen.data$Time = (int.times - min(int.times))/3600
|
||||
}
|
||||
# Sort raw data by timestamp and return the input.well
|
||||
input.well@screen.data = input.well@screen.data[order(input.well@screen.data$Time),]
|
||||
|
||||
input.well@screen.data$Time = input.well@screen.data$Time - input.well@screen.data$Time[start.index]
|
||||
|
||||
if(all(is.na(input.well@screen.data$Time)))
|
||||
stop("Error in <time.format>.")
|
||||
rownames(input.well@screen.data) = NULL
|
||||
return(input.well)
|
||||
}
|
|
Binary file not shown.
@ -0,0 +1,141 @@
|
||||
"row" "plate" "well" "media" "strain" "model" "lag.time, hrs" "lag.time.SE, hrs" "inflection.time, hrs" "max.spec.growth.rate, log.OD/hr" "max.spec.growth.rate.SE, log.OD/hr" "baseline, log.OD" "baseline.SE, log.OD" "amplitude, log.OD" "amplitude.SE, log.OD" "plateau, log.OD" "inoc.log.OD" "max.log.OD" "projected.growth, log.OD" "achieved.growth, log.OD" "baseline.OD" "amplitude.OD" "plateau.OD" "inoc.OD" "max.OD" "projected.growth.OD" "achieved.growth.OD" "shape.par" "shape.par.SE" "R.squared" "RSS" "empty" "asymp.not.reached" "tank" "other" "pdf.file" "page.no"
|
||||
1 "YPDAFEXglucoseTests_2-25-10" "A01" "Unknown Media" "Unknown Strain" "<NA>: skipped" NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA "! " "-" "-" "" "YPDAFEXglucoseTests_2-25-10_plots_2014-11-14_15.24.29.pdf" 2
|
||||
2 "YPDAFEXglucoseTests_2-25-10" "B01" "Unknown Media" "Unknown Strain" "<NA>: skipped" NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA "! " "-" "-" "" "YPDAFEXglucoseTests_2-25-10_plots_2014-11-14_15.24.29.pdf" 3
|
||||
3 "YPDAFEXglucoseTests_2-25-10" "C01" "Unknown Media" "Unknown Strain" "<NA>: skipped" NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA "! " "-" "-" "" "YPDAFEXglucoseTests_2-25-10_plots_2014-11-14_15.24.29.pdf" 4
|
||||
4 "YPDAFEXglucoseTests_2-25-10" "D01" "Unknown Media" "Unknown Strain" "<NA>: skipped" NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA "! " "-" "-" "" "YPDAFEXglucoseTests_2-25-10_plots_2014-11-14_15.24.29.pdf" 5
|
||||
5 "YPDAFEXglucoseTests_2-25-10" "E01" "Unknown Media" "Unknown Strain" "<NA>: skipped" NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA "! " "-" "-" "" "YPDAFEXglucoseTests_2-25-10_plots_2014-11-14_15.24.29.pdf" 6
|
||||
6 "YPDAFEXglucoseTests_2-25-10" "F01" "Unknown Media" "Unknown Strain" "<NA>: skipped" NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA "! " "-" "-" "" "YPDAFEXglucoseTests_2-25-10_plots_2014-11-14_15.24.29.pdf" 7
|
||||
7 "YPDAFEXglucoseTests_2-25-10" "G01" "Unknown Media" "Unknown Strain" "<NA>: skipped" NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA "! " "-" "-" "" "YPDAFEXglucoseTests_2-25-10_plots_2014-11-14_15.24.29.pdf" 8
|
||||
8 "YPDAFEXglucoseTests_2-25-10" "H01" "Unknown Media" "Unknown Strain" "<NA>: skipped" NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA "! " "-" "-" "" "YPDAFEXglucoseTests_2-25-10_plots_2014-11-14_15.24.29.pdf" 9
|
||||
9 "YPDAFEXglucoseTests_2-25-10" "A02" "Unknown Media" "Unknown Strain" "<NA>: skipped" NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA "! " "-" "-" "" "YPDAFEXglucoseTests_2-25-10_plots_2014-11-14_15.24.29.pdf" 10
|
||||
10 "YPDAFEXglucoseTests_2-25-10" "B02" "Unknown Media" "Unknown Strain" "gompertz sigmoid" 0 1.75346968441508 9.00872222222222 0.00387129153696364 0.000169526629036836 0.106012627625114 0.00533333077366909 0.0949774510885174 0.0112054835606438 0.200990078713631 0.112280003072039 0.184252861638202 0.0887100756415919 0.0719728585661627 0.111835916265025 0.0996340592954781 0.222612641873017 0.1188260915329 0.202319805217563 0.103786550340117 0.083493713684663 NA NA 0.955970181896241 0.00271004795972451 "I " "U" "-" "" "YPDAFEXglucoseTests_2-25-10_plots_2014-11-14_15.24.29.pdf" 11
|
||||
11 "YPDAFEXglucoseTests_2-25-10" "C02" "Unknown Media" "Unknown Strain" "richards sigmoid" 2.40987742434362 0.0533048027754095 4.21822222222222 0.0460029547745148 0.000724535892211916 0.0730406535194956 0.00147448055623566 0.201954494843009 0.00148223223518411 0.274995148362504 0.0732663157203884 0.274994927952796 0.201728832642116 0.201728612232407 0.0757742700360047 0.223792317982719 0.31652428755353 0.0760170590185625 0.316523997378827 0.240507228534967 0.240506938360264 0.265874614443588 0.100707923111372 0.997917404710366 0.00135388203716735 "I " "-" "-" "" "YPDAFEXglucoseTests_2-25-10_plots_2014-11-14_15.24.29.pdf" 12
|
||||
12 "YPDAFEXglucoseTests_2-25-10" "D02" "Unknown Media" "Unknown Strain" "logistic sigmoid." 3.07823370582446 0.0432348265726729 5.36222222222222 0.0732442032057736 0.000833850358526795 0.0859165025402299 0.00136428307371176 0.336085738207293 0.00149532024021089 0.422002240747523 0.0889959965972815 0.42200220627278 0.333006244150242 0.333006209675498 0.089715336043938 0.399459006773759 0.525011941846182 0.0930762802930187 0.525011889271788 0.431935661553164 0.431935608978769 NA NA 0.99892015420286 0.00211931922664645 "I " "-" "-" "" "YPDAFEXglucoseTests_2-25-10_plots_2014-11-14_15.24.29.pdf" 13
|
||||
13 "YPDAFEXglucoseTests_2-25-10" "E02" "Unknown Media" "Unknown Strain" "richards sigmoid" 3.31104933734427 0.0428738853375245 6.24405555555555 0.0874988597365696 0.000646229450327621 0.0670789147198683 0.00264084519286054 0.496808439056947 0.00261152547593285 0.563887353776815 0.0759549208448961 0.563886450736804 0.487932432931919 0.487931529891908 0.0693798646573409 0.643467664348464 0.757491228469676 0.0789139365323319 0.757489641385495 0.678577291937345 0.678575704853163 1.2232332690843 0.0913419753453248 0.999523017751576 0.00210815425649168 "I " "-" "-" "" "YPDAFEXglucoseTests_2-25-10_plots_2014-11-14_15.24.29.pdf" 14
|
||||
14 "YPDAFEXglucoseTests_2-25-10" "F02" "Unknown Media" "Unknown Strain" "richards sigmoid" 3.16160949001608 0.0130132793917631 5.69588888888889 0.0871403273784542 0.000229647034986262 0.0873771888050847 0.000697694045768953 0.569725535280617 0.000706582800205296 0.657102724085702 0.0877050601525881 0.65691395601709 0.569397663933114 0.569208895864502 0.0913082313448255 0.767781791110135 0.929194819859989 0.0916660987091995 0.928830683849576 0.837528721150789 0.837164585140376 0.128377120300513 0.0158490160700108 0.999930578411107 0.000418173571721339 "I " "-" "-" "" "YPDAFEXglucoseTests_2-25-10_plots_2014-11-14_15.24.29.pdf" 15
|
||||
15 "YPDAFEXglucoseTests_2-25-10" "G02" "Unknown Media" "Unknown Strain" "gompertz sigmoid" 1.97362815105853 0.16021845812197 6.10105555555556 0.0637129441648277 0.000882845698725157 0.0636642130548074 0.00677504484433783 0.715651375245064 0.00877835069042374 0.779315588299871 0.0726054460832097 0.769574984837188 0.706710142216661 0.696969538753978 0.0657344789473957 1.04551864861753 1.17997975116158 0.0753061869379306 1.1588485154191 1.10467356422365 1.08354232848117 NA NA 0.996368548540555 0.0284187363816129 "I " "-" "-" "" "YPDAFEXglucoseTests_2-25-10_plots_2014-11-14_15.24.29.pdf" 16
|
||||
16 "YPDAFEXglucoseTests_2-25-10" "H02" "Unknown Media" "Unknown Strain" "<NA>: skipped" NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA "! " "-" "-" "" "YPDAFEXglucoseTests_2-25-10_plots_2014-11-14_15.24.29.pdf" 17
|
||||
17 "YPDAFEXglucoseTests_2-25-10" "A03" "Unknown Media" "Unknown Strain" "<NA>: skipped" NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA "! " "-" "-" "" "YPDAFEXglucoseTests_2-25-10_plots_2014-11-14_15.24.29.pdf" 18
|
||||
18 "YPDAFEXglucoseTests_2-25-10" "B03" "Unknown Media" "Unknown Strain" "gompertz sigmoid" 0 6.85707463811534 22.1408888888889 0.00240032501380818 0.000622808650861115 0.183471251012776 0.0241038297960887 0.144528358183154 0.243573937919412 0.32799960919593 0.19300839349323 0.240674524266226 0.134991215702699 0.0476661307729958 0.201380426444684 0.155494462222733 0.388188429779618 0.21289297388536 0.272106927985118 0.175295455894257 0.0592139540997572 NA NA 0.790451631963757 0.00713078905920276 "I " "U" "-" "" "YPDAFEXglucoseTests_2-25-10_plots_2014-11-14_15.24.29.pdf" 19
|
||||
19 "YPDAFEXglucoseTests_2-25-10" "C03" "Unknown Media" "Unknown Strain" "gompertz sigmoid" 1.9906115314917 0.0691975321280808 3.47938888888889 0.049037411407282 0.00113344209515939 0.113611335404073 0.00175358526967256 0.199753898839363 0.00189317967878135 0.313365234243436 0.113618320794987 0.313364980342489 0.199746913448449 0.199746659547502 0.120316612851937 0.221102206508354 0.368021087941464 0.120324438728759 0.36802074059966 0.247696649212706 0.247696301870901 NA NA 0.993990129878449 0.00350258662967145 "I " "-" "-" "" "YPDAFEXglucoseTests_2-25-10_plots_2014-11-14_15.24.29.pdf" 20
|
||||
20 "YPDAFEXglucoseTests_2-25-10" "D03" "Unknown Media" "Unknown Strain" "logistic sigmoid." 2.74248926505973 0.035437954480672 4.43272222222222 0.0945867703490634 0.00125702159386047 0.120482088812658 0.00134117833543308 0.321778875148931 0.0014434874516871 0.442260963961589 0.122204770400314 0.442260963921188 0.320056193561275 0.320056193520873 0.128040536239446 0.379579682874746 0.556221805255072 0.129985465667426 0.556221805192198 0.426236339587646 0.426236339524771 NA NA 0.998757902847438 0.00205103195615211 "I " "-" "-" "" "YPDAFEXglucoseTests_2-25-10_plots_2014-11-14_15.24.29.pdf" 21
|
||||
21 "YPDAFEXglucoseTests_2-25-10" "E03" "Unknown Media" "Unknown Strain" "richards sigmoid" 3.06558694902111 0.0312092215590165 5.36222222222222 0.121127558762234 0.000999219508000457 0.0914412473879785 0.00245736134720504 0.492484371503167 0.00245078828605803 0.583925618891146 0.100902026458548 0.583925618815027 0.483023592432598 0.483023592356479 0.0957523964858846 0.636376541441498 0.793063516837805 0.106168261232303 0.793063516701319 0.686895255605501 0.686895255469016 1.8099614528835 0.11749762404479 0.999544726321194 0.00181967924857281 "I " "-" "-" "" "YPDAFEXglucoseTests_2-25-10_plots_2014-11-14_15.24.29.pdf" 22
|
||||
22 "YPDAFEXglucoseTests_2-25-10" "F03" "Unknown Media" "Unknown Strain" "richards sigmoid" 2.77641828785608 0.0527034560581212 5.62438888888889 0.129882569921262 0.00113584993704318 0.0943645335434394 0.00505890981001432 0.678399516685425 0.00501032094392126 0.772764050228865 0.114848054862814 0.77276399900153 0.657915995366051 0.657915944138716 0.0989602807937964 0.970721100596954 1.16574421407829 0.121702987308433 1.16574410313299 1.04404122676985 1.04404111582455 1.58781631519902 0.131684418310394 0.999371589849353 0.0046402268216646 "I " "-" "-" "" "YPDAFEXglucoseTests_2-25-10_plots_2014-11-14_15.24.29.pdf" 23
|
||||
23 "YPDAFEXglucoseTests_2-25-10" "G03" "Unknown Media" "Unknown Strain" "richards sigmoid" 2.62155169712258 0.0528519100875045 5.64822222222222 0.120898389380839 0.00085666747705881 0.106939410004678 0.00473823141471648 0.792250605021815 0.00464150388859163 0.899190015026493 0.119165060075358 0.899150108989174 0.780024954951135 0.779985048913817 0.112866823840885 1.20836098585375 1.45761167622119 0.126555852336668 1.45751360463476 1.33105582388452 1.33095775229809 0.651987068135623 0.0715475087316549 0.999508942394936 0.00516491712891765 "I " "-" "-" "" "YPDAFEXglucoseTests_2-25-10_plots_2014-11-14_15.24.29.pdf" 24
|
||||
24 "YPDAFEXglucoseTests_2-25-10" "H03" "Unknown Media" "Unknown Strain" "<NA>: skipped" NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA "! " "-" "-" "" "YPDAFEXglucoseTests_2-25-10_plots_2014-11-14_15.24.29.pdf" 25
|
||||
25 "YPDAFEXglucoseTests_2-25-10" "A04" "Unknown Media" "Unknown Strain" "<NA>: skipped" NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA "! " "-" "-" "" "YPDAFEXglucoseTests_2-25-10_plots_2014-11-14_15.24.29.pdf" 26
|
||||
26 "YPDAFEXglucoseTests_2-25-10" "B04" "Unknown Media" "Unknown Strain" "gompertz sigmoid" 0 5.07805229649163 14.0137222222222 0.00262196440444693 0.000184379038247711 0.128373352119061 0.0113746218267311 0.0999846427550281 0.0508219597027302 0.228357994874089 0.134971142309161 0.189191274790955 0.0933868525649285 0.0542201324817943 0.136977416391989 0.105153945825447 0.256535078040028 0.144503756139199 0.208272042363683 0.11203132190083 0.0637682862244842 NA NA 0.85538308083977 0.00575026814684176 "I " "U" "-" "" "YPDAFEXglucoseTests_2-25-10_plots_2014-11-14_15.24.29.pdf" 27
|
||||
27 "YPDAFEXglucoseTests_2-25-10" "C04" "Unknown Media" "Unknown Strain" "gompertz sigmoid" 0.891438191034907 0.0875315881492886 2.31155555555556 0.0535113239026645 0.00124573543576505 0.0881434967648596 0.0030430726219828 0.207061852626777 0.00316468237828018 0.295205349391636 0.0894254269730997 0.295205293002666 0.205779922418537 0.205779866029567 0.0921448300342507 0.230058651786557 0.343402197187588 0.0935457812526346 0.343402121434524 0.249856415934954 0.24985634018189 NA NA 0.991724253334925 0.00363563892033064 "I " "-" "-" "" "YPDAFEXglucoseTests_2-25-10_plots_2014-11-14_15.24.29.pdf" 28
|
||||
28 "YPDAFEXglucoseTests_2-25-10" "D04" "Unknown Media" "Unknown Strain" "logistic sigmoid." 1.64713495094778 0.0412877819867957 3.38405555555556 0.0931935829948414 0.00118142555796191 0.0808528951164181 0.00187894207024751 0.326765479915366 0.00196420645231437 0.407618375031784 0.0874704777516756 0.407618375007183 0.320147897280109 0.320147897255508 0.084211392044496 0.386476282514334 0.503233380301545 0.0914100430890148 0.503233380264563 0.41182333721253 0.411823337175548 NA NA 0.998561073647885 0.00184537988196708 "I " "-" "-" "" "YPDAFEXglucoseTests_2-25-10_plots_2014-11-14_15.24.29.pdf" 29
|
||||
29 "YPDAFEXglucoseTests_2-25-10" "E04" "Unknown Media" "Unknown Strain" "richards sigmoid" 2.00035125190919 0.0281455448570578 4.31355555555556 0.124952395006035 0.000705710861425023 0.066176309959304 0.00266242496712618 0.497003217265191 0.00264805326268335 0.563179527224495 0.0884800687678949 0.563179527222079 0.4746994584566 0.474699458454184 0.0684150727790216 0.643787807212848 0.756247669676583 0.0925124772737131 0.756247669672339 0.66373519240287 0.663735192398626 2.09745467815794 0.104168282542748 0.999771040591133 0.000720981102550124 "I " "-" "-" "" "YPDAFEXglucoseTests_2-25-10_plots_2014-11-14_15.24.29.pdf" 30
|
||||
30 "YPDAFEXglucoseTests_2-25-10" "F04" "Unknown Media" "Unknown Strain" "richards sigmoid" 2.04900717766187 0.066224854828332 4.76638888888889 0.133067446429845 0.00129515567063011 0.0751622402050358 0.00684502426879832 0.656973010100056 0.00678618679816553 0.732135250305092 0.103854789208097 0.732135243310908 0.628280461096995 0.628280454102811 0.0780590412170139 0.92894459254016 1.07951615799459 0.109439340652877 1.07951614345007 0.970076817341713 0.970076802797194 1.62672188639015 0.161151123608519 0.999229593966034 0.00459582695233034 "I " "-" "-" "" "YPDAFEXglucoseTests_2-25-10_plots_2014-11-14_15.24.29.pdf" 31
|
||||
31 "YPDAFEXglucoseTests_2-25-10" "G04" "Unknown Media" "Unknown Strain" "logistic sigmoid." 1.9862918042278 0.0661342206052662 5.19538888888889 0.122957281401382 0.00117607965873161 0.0764858915144976 0.00452433434411634 0.79385835220941 0.00487921872529871 0.870344243723908 0.106676772171339 0.8703364785556 0.763667471552569 0.763659706384262 0.0794869603035999 1.21191432769022 1.38773267405029 0.112574581288131 1.38771413297619 1.27515809276216 1.27513955168806 NA NA 0.998885750680601 0.0103824045406079 "I " "-" "-" "" "YPDAFEXglucoseTests_2-25-10_plots_2014-11-14_15.24.29.pdf" 32
|
||||
32 "YPDAFEXglucoseTests_2-25-10" "H04" "Unknown Media" "Unknown Strain" "<NA>: skipped" NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA "! " "-" "-" "" "YPDAFEXglucoseTests_2-25-10_plots_2014-11-14_15.24.29.pdf" 33
|
||||
33 "YPDAFEXglucoseTests_2-25-10" "A05" "Unknown Media" "Unknown Strain" "<NA>: skipped" NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA "! " "-" "-" "" "YPDAFEXglucoseTests_2-25-10_plots_2014-11-14_15.24.29.pdf" 34
|
||||
34 "YPDAFEXglucoseTests_2-25-10" "B05" "Unknown Media" "Unknown Strain" "gompertz sigmoid" 0 3.37960858365283 11.4873888888889 0.00260114802439224 0.000171113343666121 0.0996380868853665 0.00702344409232819 0.0812678741827026 0.0218737361493502 0.180905961068069 0.105000794280007 0.157379079130282 0.075905166788062 0.0523782848502749 0.104771014596006 0.084661410443271 0.198302486908548 0.110711492571287 0.17043921889605 0.0875909943372608 0.0597277263247633 NA NA 0.906033844889986 0.00328284811832969 "I " "U" "-" "" "YPDAFEXglucoseTests_2-25-10_plots_2014-11-14_15.24.29.pdf" 35
|
||||
35 "YPDAFEXglucoseTests_2-25-10" "C05" "Unknown Media" "Unknown Strain" "gompertz sigmoid" 0.983948331255506 0.112859781965525 2.47838888888889 0.0501739427160517 0.0014420089652692 0.0661469394856897 0.00364271174491049 0.205919620008399 0.00380546097157685 0.272066559494088 0.0672650611064177 0.272066409690128 0.204801498387671 0.204801348583711 0.0683836933831337 0.22865444079244 0.312674369345416 0.0695789443834065 0.312674172701612 0.24309542496201 0.243095228318206 NA NA 0.987488271024712 0.00577672548033435 "I " "-" "-" "" "YPDAFEXglucoseTests_2-25-10_plots_2014-11-14_15.24.29.pdf" 36
|
||||
36 "YPDAFEXglucoseTests_2-25-10" "D05" "Unknown Media" "Unknown Strain" "richards sigmoid" 1.86398043856721 0.0558531671153862 3.55088888888889 0.0944346386187149 0.00150539512391036 0.0602064636566113 0.00349724747100135 0.368213530469543 0.00348116509707638 0.428419994126155 0.0619674060244801 0.428419978432962 0.366452588101675 0.366452572408482 0.0620557998346221 0.445150589714197 0.534830565440387 0.0639276665305688 0.534830541353995 0.470902898909819 0.470902874823426 0.412410289167828 0.120556335197892 0.997911612798025 0.0038575229887498 "I " "-" "-" "" "YPDAFEXglucoseTests_2-25-10_plots_2014-11-14_15.24.29.pdf" 37
|
||||
37 "YPDAFEXglucoseTests_2-25-10" "E05" "Unknown Media" "Unknown Strain" "logistic sigmoid." 1.99006793199662 0.0351079466631901 4.12288888888889 0.121142575318895 0.00106707300014084 0.0644342398512972 0.00208740707850082 0.517632133390329 0.00221049024230705 0.582066373241626 0.0750837824145655 0.582066368204037 0.506982590827061 0.506982585789472 0.0665554390942191 0.67804954426084 0.789732868500974 0.0779744624046204 0.789732859485036 0.711758406096354 0.711758397080416 NA NA 0.999269039916925 0.00268951955610802 "I " "-" "-" "" "YPDAFEXglucoseTests_2-25-10_plots_2014-11-14_15.24.29.pdf" 38
|
||||
38 "YPDAFEXglucoseTests_2-25-10" "F05" "Unknown Media" "Unknown Strain" "logistic sigmoid." 1.9843141430209 0.0344438897925297 4.48038888888889 0.130673511255828 0.0009102976624566 0.0736708018228489 0.00232986504593521 0.655420765590931 0.00247952512560695 0.72909156741378 0.0914028198920642 0.729091436236412 0.637688747521716 0.637688616344348 0.0764523809998565 0.925952721546378 1.07319639280175 0.0957102902741691 1.07319612084532 0.977486102527583 0.977485830571155 NA NA 0.999493885845309 0.00307265449990921 "I " "-" "-" "" "YPDAFEXglucoseTests_2-25-10_plots_2014-11-14_15.24.29.pdf" 39
|
||||
39 "YPDAFEXglucoseTests_2-25-10" "G05" "Unknown Media" "Unknown Strain" "logistic sigmoid." 2.10388607337831 0.0485609573830706 5.24305555555556 0.128060724390908 0.000947720098512415 0.0637480626845324 0.00338335492162949 0.806179689300295 0.00365527291991514 0.869927751984827 0.0914242899489073 0.869921741897374 0.77850346203592 0.778497451948466 0.0658238441354071 1.23933666272802 1.38673841018214 0.0957338154889276 1.38672406571867 1.29100459469321 1.29099025022974 NA NA 0.999357534856407 0.00631075803154067 "I " "-" "-" "" "YPDAFEXglucoseTests_2-25-10_plots_2014-11-14_15.24.29.pdf" 40
|
||||
40 "YPDAFEXglucoseTests_2-25-10" "H05" "Unknown Media" "Unknown Strain" "<NA>: skipped" NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA "! " "-" "-" "" "YPDAFEXglucoseTests_2-25-10_plots_2014-11-14_15.24.29.pdf" 41
|
||||
41 "YPDAFEXglucoseTests_2-25-10" "A06" "Unknown Media" "Unknown Strain" "<NA>: skipped" NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA "! " "-" "-" "" "YPDAFEXglucoseTests_2-25-10_plots_2014-11-14_15.24.29.pdf" 42
|
||||
42 "YPDAFEXglucoseTests_2-25-10" "B06" "Unknown Media" "Unknown Strain" "<NA>: skipped" NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA "! " "-" "-" "" "YPDAFEXglucoseTests_2-25-10_plots_2014-11-14_15.24.29.pdf" 43
|
||||
43 "YPDAFEXglucoseTests_2-25-10" "C06" "Unknown Media" "Unknown Strain" "<NA>: skipped" NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA "! " "-" "-" "" "YPDAFEXglucoseTests_2-25-10_plots_2014-11-14_15.24.29.pdf" 44
|
||||
44 "YPDAFEXglucoseTests_2-25-10" "D06" "Unknown Media" "Unknown Strain" "<NA>: skipped" NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA "! " "-" "-" "" "YPDAFEXglucoseTests_2-25-10_plots_2014-11-14_15.24.29.pdf" 45
|
||||
45 "YPDAFEXglucoseTests_2-25-10" "E06" "Unknown Media" "Unknown Strain" "<NA>: skipped" NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA "! " "-" "-" "" "YPDAFEXglucoseTests_2-25-10_plots_2014-11-14_15.24.29.pdf" 46
|
||||
46 "YPDAFEXglucoseTests_2-25-10" "F06" "Unknown Media" "Unknown Strain" "logistic sigmoid." 9.73707676235984 0.0985970534035122 14.6810555555556 0.0827678160106198 0.00119202041680005 -0.000880352187845948 0.00297599235645004 0.821196181129969 0.00723578636175851 0.820315828942123 0.00130662737972163 0.800169424333775 0.819009201562402 0.798862796954054 -0.000879964791548726 1.27321739161308 1.27121704034493 0.00130748138919312 1.22591802122501 1.26990955895573 1.22461053983581 NA NA 0.997343483064722 0.0337108649740509 "I " "L" "-" "" "YPDAFEXglucoseTests_2-25-10_plots_2014-11-14_15.24.29.pdf" 47
|
||||
47 "YPDAFEXglucoseTests_2-25-10" "G06" "Unknown Media" "Unknown Strain" "<NA>: skipped" NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA "! " "-" "-" "" "YPDAFEXglucoseTests_2-25-10_plots_2014-11-14_15.24.29.pdf" 48
|
||||
48 "YPDAFEXglucoseTests_2-25-10" "H06" "Unknown Media" "Unknown Strain" "<NA>: skipped" NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA "! " "-" "-" "" "YPDAFEXglucoseTests_2-25-10_plots_2014-11-14_15.24.29.pdf" 49
|
||||
49 "YPDAFEXglucoseTests_2-25-10" "A07" "Unknown Media" "Unknown Strain" "<NA>: skipped" NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA "! " "-" "-" "" "YPDAFEXglucoseTests_2-25-10_plots_2014-11-14_15.24.29.pdf" 50
|
||||
50 "YPDAFEXglucoseTests_2-25-10" "B07" "Unknown Media" "Unknown Strain" "richards sigmoid" 3.77043529571833 0.0360628420623705 7.69788888888889 0.0922143076926756 0.000396448198824364 0.0415079420521979 0.0024939806880155 0.670137254811387 0.00244318035757864 0.711645196863585 0.0610249600071162 0.711620409501757 0.650620236856469 0.650595449494641 0.0423814404664091 0.954505567519456 1.03734032887055 0.0629254444827541 1.03728982920453 0.974414884387793 0.974364384721773 1.4963619113461 0.0645035995742297 0.999821079386736 0.00149128792010239 "I " "-" "-" "" "YPDAFEXglucoseTests_2-25-10_plots_2014-11-14_15.24.29.pdf" 51
|
||||
51 "YPDAFEXglucoseTests_2-25-10" "C07" "Unknown Media" "Unknown Strain" "richards sigmoid" 3.81401381522114 0.0414172657437824 7.84088888888889 0.0912912499034691 0.000430847219978935 0.0416798125769253 0.00284816950320603 0.691432841148329 0.00278081561800945 0.733112653725254 0.0607785100182575 0.733056393446629 0.672334143706997 0.672277883428372 0.0425606105081318 0.996574258457647 1.08154967782242 0.0626635187959206 1.0814325725518 1.0188861590265 1.01876905375588 1.38211645759186 0.0684414244741087 0.999776277423773 0.00199878407126499 "I " "-" "-" "" "YPDAFEXglucoseTests_2-25-10_plots_2014-11-14_15.24.29.pdf" 52
|
||||
52 "YPDAFEXglucoseTests_2-25-10" "D07" "Unknown Media" "Unknown Strain" "richards sigmoid" 4.10969518950279 0.0412228728953147 8.43672222222222 0.088704008575966 0.000394405519889003 0.0340862871852733 0.00276975744049372 0.70953425865252 0.00269646155006053 0.743620545837793 0.0553702984483679 0.743521928172232 0.688250247389426 0.688151629723864 0.034673881973359 1.03304416538455 1.10353769882172 0.0569319224716098 1.10333026307303 1.04660577635011 1.04639834060142 1.51337756529933 0.0684110320188058 0.999797902728699 0.00192728932795895 "I " "-" "-" "" "YPDAFEXglucoseTests_2-25-10_plots_2014-11-14_15.24.29.pdf" 53
|
||||
53 "YPDAFEXglucoseTests_2-25-10" "E07" "Unknown Media" "Unknown Strain" "richards sigmoid" 4.24887938478086 0.0432115804682178 8.81805555555556 0.0859527182536688 0.000375029677532563 0.0356447291331235 0.00283858615006587 0.73054813412698 0.00274599571528213 0.766192863260103 0.0570847530989374 0.765947840867417 0.709108110161166 0.70886308776848 0.0362876182839384 1.07621834195843 1.15155936062553 0.0587455385584554 1.15103224498319 1.09281382206707 1.09228670642473 1.43679374016896 0.0664148624074164 0.999795584571703 0.00207184898977108 "I " "-" "-" "" "YPDAFEXglucoseTests_2-25-10_plots_2014-11-14_15.24.29.pdf" 54
|
||||
54 "YPDAFEXglucoseTests_2-25-10" "F07" "Unknown Media" "Unknown Strain" "richards sigmoid" 4.18007395312142 0.0466407712716441 8.81805555555556 0.0839684557491972 0.000369759976738274 0.0335662062693272 0.00302321128563783 0.761208315309071 0.00289043060904211 0.794774521578398 0.0523578981772083 0.794000059837111 0.74241662340119 0.741642161659902 0.0341359077403089 1.14086149398729 1.21394174443082 0.0537528112436063 1.2122277950321 1.16018893318721 1.1584749837885 1.13197496403506 0.0608907017398173 0.999775581271097 0.00245341232352347 "I " "-" "-" "" "YPDAFEXglucoseTests_2-25-10_plots_2014-11-14_15.24.29.pdf" 55
|
||||
55 "YPDAFEXglucoseTests_2-25-10" "G07" "Unknown Media" "Unknown Strain" "richards sigmoid" 4.31631143939288 0.0375067727591517 9.10405555555556 0.0746869165825098 0.000251011197158741 0.0449034108817944 0.00217539445550943 0.811374095379108 0.0020199780410581 0.856277506260903 0.0531730592633562 0.847610695599428 0.803104446997546 0.794437636336071 0.0459268298793891 1.25099894980635 1.35438019563279 0.054612139727737 1.33406339635061 1.29976805590506 1.27945125662287 0.475355220605967 0.03549891791103 0.99984356158066 0.00187490302158906 "I " "-" "-" "" "YPDAFEXglucoseTests_2-25-10_plots_2014-11-14_15.24.29.pdf" 56
|
||||
56 "YPDAFEXglucoseTests_2-25-10" "H07" "Unknown Media" "Unknown Strain" "<NA>: skipped" NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA "! " "-" "-" "" "YPDAFEXglucoseTests_2-25-10_plots_2014-11-14_15.24.29.pdf" 57
|
||||
57 "YPDAFEXglucoseTests_2-25-10" "A08" "Unknown Media" "Unknown Strain" "<NA>: skipped" NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA "! " "-" "-" "" "YPDAFEXglucoseTests_2-25-10_plots_2014-11-14_15.24.29.pdf" 58
|
||||
58 "YPDAFEXglucoseTests_2-25-10" "B08" "Unknown Media" "Unknown Strain" "richards sigmoid" 2.71231715323206 0.0513772236677379 6.24405555555555 0.114869797815563 0.000679522300954349 0.0686814145642472 0.00460568296459795 0.729956501400163 0.00454362083736724 0.79863791596441 0.100996399779546 0.798636815323626 0.697641516184865 0.697640415544081 0.0710949195446084 1.07499034653627 1.22251161827911 0.106272658930799 1.22250917209352 1.11623895934831 1.11623651316272 1.70292228067724 0.101795481685622 0.999686879664103 0.00266681050440395 "I " "-" "-" "" "YPDAFEXglucoseTests_2-25-10_plots_2014-11-14_15.24.29.pdf" 59
|
||||
59 "YPDAFEXglucoseTests_2-25-10" "C08" "Unknown Media" "Unknown Strain" "richards sigmoid" 3.01070189963687 0.0455540489565291 6.55388888888889 0.115107998390645 0.000641488550406568 0.0614813761638786 0.00401667583803556 0.743382938664491 0.00395687845960871 0.80486431482837 0.088530666535353 0.804861736471092 0.716333648293017 0.716331069935739 0.0634106915579287 1.10303794255036 1.23639303286004 0.0925677573644961 1.23638726664722 1.14382527549554 1.14381950928273 1.57881075668526 0.0887320004643622 0.999717695034928 0.00263054987530886 "I " "-" "-" "" "YPDAFEXglucoseTests_2-25-10_plots_2014-11-14_15.24.29.pdf" 60
|
||||
60 "YPDAFEXglucoseTests_2-25-10" "D08" "Unknown Media" "Unknown Strain" "richards sigmoid" 2.97864250922658 0.0440943282069485 6.55388888888889 0.114576828300042 0.000592514310191339 0.0574375614416587 0.00388756856149796 0.7604944481012 0.00382450809353859 0.817932009542859 0.0846335573654363 0.817926981782412 0.733298452177423 0.733293424416975 0.059119138718029 1.13933374853871 1.26580931718273 0.0883181874358308 1.2657979252649 1.1774911297469 1.17747973782907 1.48473853768196 0.0802727742184424 0.999751240782926 0.0024285821665204 "I " "-" "-" "" "YPDAFEXglucoseTests_2-25-10_plots_2014-11-14_15.24.29.pdf" 61
|
||||
61 "YPDAFEXglucoseTests_2-25-10" "E08" "Unknown Media" "Unknown Strain" "richards sigmoid" 2.92985461402822 0.0457749753910733 6.57772222222222 0.113561152700099 0.000574978172033136 0.060472124586291 0.00402516603178239 0.782067831917711 0.00395231332100131 0.842539956504002 0.0880742342619773 0.84252871547194 0.754465722242024 0.754454481209962 0.0623379840467781 1.18598785060288 1.32225792636021 0.0920691879694222 1.32223182193112 1.23018873839079 1.2301626339617 1.37581261172662 0.0764095565221835 0.999754748600533 0.00252958095458288 "I " "-" "-" "" "YPDAFEXglucoseTests_2-25-10_plots_2014-11-14_15.24.29.pdf" 62
|
||||
62 "YPDAFEXglucoseTests_2-25-10" "F08" "Unknown Media" "Unknown Strain" "richards sigmoid" 3.04342229734717 0.0449382703508806 6.81605555555555 0.111344220804687 0.000532114828111489 0.0556626629934722 0.00387136842702 0.80721451235666 0.00378851479664982 0.862877175350132 0.0817091171508141 0.862843943432654 0.781168058199318 0.78113482628184 0.0572409770684312 1.24165517935791 1.36996971207487 0.0851401152682132 1.3698909547456 1.28482959680665 1.28475083947739 1.25155543832615 0.0687282577051449 0.999773222693453 0.00254586287935125 "I " "-" "-" "" "YPDAFEXglucoseTests_2-25-10_plots_2014-11-14_15.24.29.pdf" 63
|
||||
63 "YPDAFEXglucoseTests_2-25-10" "G08" "Unknown Media" "Unknown Strain" "richards sigmoid" 3.4098419642861 0.0273360221329334 7.17355555555555 0.104909950287556 0.000320509634067564 0.0670946887166673 0.00214797636037448 0.835221165471032 0.00207744953517517 0.902315854187699 0.0807525020864334 0.901946971291666 0.821563352101265 0.821194469205233 0.0693967331849445 1.30532384994483 1.46530579406434 0.0841025502412753 1.46439655263553 1.38120324382306 1.38029400239426 0.753286735551893 0.0336141513817103 0.999897955876558 0.00130605700907157 "I " "-" "-" "" "YPDAFEXglucoseTests_2-25-10_plots_2014-11-14_15.24.29.pdf" 64
|
||||
64 "YPDAFEXglucoseTests_2-25-10" "H08" "Unknown Media" "Unknown Strain" "<NA>: skipped" NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA "! " "-" "-" "" "YPDAFEXglucoseTests_2-25-10_plots_2014-11-14_15.24.29.pdf" 65
|
||||
65 "YPDAFEXglucoseTests_2-25-10" "A09" "Unknown Media" "Unknown Strain" "<NA>: skipped" NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA "! " "-" "-" "" "YPDAFEXglucoseTests_2-25-10_plots_2014-11-14_15.24.29.pdf" 66
|
||||
66 "YPDAFEXglucoseTests_2-25-10" "B09" "Unknown Media" "Unknown Strain" "richards sigmoid" 2.43102440854542 0.045460599271 5.50522222222222 0.126842367700522 0.00078809068382565 0.0539690230506907 0.00446798151426212 0.690558562302537 0.00442509765211851 0.744527585353228 0.0857310637664198 0.744527554769708 0.658796521586808 0.658796491003288 0.0554519069684636 0.994829458651344 1.10544655621043 0.0895132793033759 1.10544649181846 1.01593327690705 1.01593321251509 1.86325174031776 0.111013994653246 0.999682108231503 0.0022617847845379 "I " "-" "-" "" "YPDAFEXglucoseTests_2-25-10_plots_2014-11-14_15.24.29.pdf" 67
|
||||
67 "YPDAFEXglucoseTests_2-25-10" "C09" "Unknown Media" "Unknown Strain" "richards sigmoid" 2.48092970936734 0.0462358382066653 5.62438888888889 0.126022327910869 0.000766265150014104 0.0498912361992905 0.00451231718259913 0.714630509324354 0.00446315297026109 0.764521745523645 0.0803254378903323 0.764521612683065 0.684196307633313 0.684196174792733 0.0511567623538203 1.04343151386262 1.14796685420359 0.0836396677044799 1.14796656886645 1.06432718649911 1.06432690116197 1.68924161205464 0.102428342637296 0.999685472160361 0.00245503448373934 "I " "-" "-" "" "YPDAFEXglucoseTests_2-25-10_plots_2014-11-14_15.24.29.pdf" 68
|
||||
68 "YPDAFEXglucoseTests_2-25-10" "D09" "Unknown Media" "Unknown Strain" "richards sigmoid" 2.4240864159307 0.0532786610411069 5.62438888888889 0.124384377213099 0.000823105141045872 0.0492950122622815 0.00516311817880534 0.727641420786466 0.00510226526603821 0.776936433048748 0.0803276494249522 0.776936115957329 0.696608783623795 0.696608466532377 0.0505302243276007 1.07019213288015 1.17479940575581 0.0836420642137705 1.17479871614569 1.09115734154204 1.09115665193192 1.58714595722847 0.108898702801139 0.999619231516236 0.00307919508939744 "I " "-" "-" "" "YPDAFEXglucoseTests_2-25-10_plots_2014-11-14_15.24.29.pdf" 69
|
||||
69 "YPDAFEXglucoseTests_2-25-10" "E09" "Unknown Media" "Unknown Strain" "richards sigmoid" 2.35160838405737 0.0596596610215118 5.69588888888889 0.122918277169901 0.000825310470715047 0.0456238028839663 0.00577234379276726 0.757677923379007 0.0056971886786291 0.803301726262973 0.0794802278099073 0.803300765573587 0.723821498453066 0.72382053776368 0.0466805786671931 1.13331673965171 1.23290119953907 0.0827241514900563 1.23289905441561 1.15017704804901 1.15017490292556 1.50943194471365 0.109906081597383 0.999597425228284 0.00351671862436227 "I " "-" "-" "" "YPDAFEXglucoseTests_2-25-10_plots_2014-11-14_15.24.29.pdf" 70
|
||||
70 "YPDAFEXglucoseTests_2-25-10" "F09" "Unknown Media" "Unknown Strain" "richards sigmoid" 2.52360102190548 0.0587446527958999 5.93422222222222 0.120073445296037 0.00078330497794479 0.0450247442396835 0.00549978755377369 0.786911440525391 0.00540921386567027 0.831936184765074 0.0732958506922422 0.831929765410992 0.758640334072832 0.75863391471875 0.0460537433930304 1.19660160385529 1.29776333045596 0.0760488396214321 1.29774858034688 1.22171449083452 1.22169974072545 1.23976303548348 0.0944772275219821 0.999601760903923 0.003945474202229 "I " "-" "-" "" "YPDAFEXglucoseTests_2-25-10_plots_2014-11-14_15.24.29.pdf" 71
|
||||
71 "YPDAFEXglucoseTests_2-25-10" "G09" "Unknown Media" "Unknown Strain" "richards sigmoid" 2.58690525353267 0.0503605395754859 6.17255555555556 0.109989495082239 0.000552298605536815 0.0475039668950725 0.00430649430288473 0.830681449075495 0.0041905877903163 0.878185415970567 0.0684271069666917 0.878046704757166 0.809758309003876 0.809619597790474 0.0486503609989841 1.29488205279799 1.40652889311671 0.0708225666010445 1.40619510372456 1.33570632651566 1.33537253712351 0.776030036332651 0.0590321056856611 0.999743045862095 0.00295407387389302 "I " "-" "-" "" "YPDAFEXglucoseTests_2-25-10_plots_2014-11-14_15.24.29.pdf" 72
|
||||
72 "YPDAFEXglucoseTests_2-25-10" "H09" "Unknown Media" "Unknown Strain" "<NA>: skipped" NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA "! " "-" "-" "" "YPDAFEXglucoseTests_2-25-10_plots_2014-11-14_15.24.29.pdf" 73
|
||||
73 "YPDAFEXglucoseTests_2-25-10" "A10" "Unknown Media" "Unknown Strain" "<NA>: skipped" NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA "! " "-" "-" "" "YPDAFEXglucoseTests_2-25-10_plots_2014-11-14_15.24.29.pdf" 74
|
||||
74 "YPDAFEXglucoseTests_2-25-10" "B10" "Unknown Media" "Unknown Strain" "richards sigmoid" 2.17498330293522 0.050279837635597 5.12388888888889 0.122218804745147 0.000784428647033225 0.0435682252869189 0.00476512067527676 0.699692212082884 0.00470444888749683 0.743260437369803 0.0678435113392866 0.743259718768562 0.675416926030517 0.675416207429275 0.0445312553256874 1.0131329940941 1.10278033345866 0.0701978215504209 1.10277882239865 1.03258251190824 1.03258100084823 1.18141836933351 0.0894530547512188 0.999633683586648 0.00265620405353139 "I " "-" "-" "" "YPDAFEXglucoseTests_2-25-10_plots_2014-11-14_15.24.29.pdf" 75
|
||||
75 "YPDAFEXglucoseTests_2-25-10" "C10" "Unknown Media" "Unknown Strain" "richards sigmoid" 2.51277041012627 0.038507563353684 5.50522222222222 0.124302687021946 0.00066257956155985 0.0363365047244458 0.0036365878373532 0.715682301835976 0.00358889795068784 0.752018806560422 0.0575296221367186 0.752017909485812 0.694489184423703 0.694488287349094 0.0370047447805615 1.04558191051421 1.12127814704052 0.0592166464503368 1.12127624409661 1.06206150059019 1.06205959764628 1.22124195072666 0.0728117489699227 0.999746251949321 0.00205128571327075 "I " "-" "-" "" "YPDAFEXglucoseTests_2-25-10_plots_2014-11-14_15.24.29.pdf" 76
|
||||
76 "YPDAFEXglucoseTests_2-25-10" "D10" "Unknown Media" "Unknown Strain" "richards sigmoid" 2.53563261500299 0.0376782239481082 5.60055555555556 0.122775491121767 0.000617718902119621 0.0383224027816064 0.00352849521278669 0.723989555733905 0.00348019906626899 0.762311958515511 0.0604113495090868 0.762310653527533 0.701900609006425 0.701899304018446 0.0390661767078291 1.06264585795333 1.14322554552581 0.0622734223356722 1.14322274864406 1.08095212319014 1.08094932630839 1.22916204620621 0.0694532726806568 0.999772141364762 0.00189783824442064 "I " "-" "-" "" "YPDAFEXglucoseTests_2-25-10_plots_2014-11-14_15.24.29.pdf" 77
|
||||
77 "YPDAFEXglucoseTests_2-25-10" "E10" "Unknown Media" "Unknown Strain" "logistic sigmoid." 2.60565520615734 0.0279148181724273 5.67205555555555 0.122180167584985 0.000572646126517836 0.0367511555402461 0.00173132032241477 0.755101749186329 0.00189799852175128 0.791852904726575 0.0552120643770304 0.791846881053104 0.736640840349544 0.736634816676074 0.0374348288051571 1.12782801711047 1.20748289465781 0.0567646930614347 1.20746959754171 1.15071820159638 1.15070490448028 NA NA 0.999760229166242 0.00222986115644152 "I " "-" "-" "" "YPDAFEXglucoseTests_2-25-10_plots_2014-11-14_15.24.29.pdf" 78
|
||||
78 "YPDAFEXglucoseTests_2-25-10" "F10" "Unknown Media" "Unknown Strain" "logistic sigmoid." 2.59552092151026 0.0233507553372593 5.79122222222222 0.123112398187359 0.000459924956636787 0.0376321525320693 0.00147723902213235 0.788206013375021 0.0016231663999626 0.825838165907091 0.0581595525580899 0.825828102856854 0.767678613349001 0.767668550298764 0.0383492084922821 1.19944710611067 1.28379416175066 0.059884089438009 1.28377117993091 1.22391007231265 1.2238870904929 NA NA 0.999844012469462 0.00158372380662875 "I " "-" "-" "" "YPDAFEXglucoseTests_2-25-10_plots_2014-11-14_15.24.29.pdf" 79
|
||||
79 "YPDAFEXglucoseTests_2-25-10" "G10" "Unknown Media" "Unknown Strain" "richards sigmoid" 2.65619332794927 0.0304232773418221 6.00572222222222 0.113927548251521 0.00039401531514436 0.0448535113624544 0.00262903461356949 0.830698452659732 0.00255902384555125 0.875551964022187 0.059612603657046 0.875406838426976 0.815939360365141 0.81579423476993 0.0458746399354508 1.29492107435005 1.40019975231613 0.0614252746181767 1.39985144717306 1.33877447769796 1.33842617255488 0.630436882604844 0.0359660464050951 0.999878122228538 0.00142471670120544 "I " "-" "-" "" "YPDAFEXglucoseTests_2-25-10_plots_2014-11-14_15.24.29.pdf" 80
|
||||
80 "YPDAFEXglucoseTests_2-25-10" "H10" "Unknown Media" "Unknown Strain" "<NA>: skipped" NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA "! " "-" "-" "" "YPDAFEXglucoseTests_2-25-10_plots_2014-11-14_15.24.29.pdf" 81
|
||||
81 "YPDAFEXglucoseTests_2-25-10" "A11" "Unknown Media" "Unknown Strain" "<NA>: skipped" NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA "! " "-" "-" "" "YPDAFEXglucoseTests_2-25-10_plots_2014-11-14_15.24.29.pdf" 82
|
||||
82 "YPDAFEXglucoseTests_2-25-10" "B11" "Unknown Media" "Unknown Strain" "<NA>: skipped" NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA "! " "-" "-" "" "YPDAFEXglucoseTests_2-25-10_plots_2014-11-14_15.24.29.pdf" 83
|
||||
83 "YPDAFEXglucoseTests_2-25-10" "C11" "Unknown Media" "Unknown Strain" "<NA>: skipped" NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA "! " "-" "-" "" "YPDAFEXglucoseTests_2-25-10_plots_2014-11-14_15.24.29.pdf" 84
|
||||
84 "YPDAFEXglucoseTests_2-25-10" "D11" "Unknown Media" "Unknown Strain" "<NA>: skipped" NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA "! " "-" "-" "" "YPDAFEXglucoseTests_2-25-10_plots_2014-11-14_15.24.29.pdf" 85
|
||||
85 "YPDAFEXglucoseTests_2-25-10" "E11" "Unknown Media" "Unknown Strain" "<NA>: skipped" NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA "! " "-" "-" "" "YPDAFEXglucoseTests_2-25-10_plots_2014-11-14_15.24.29.pdf" 86
|
||||
86 "YPDAFEXglucoseTests_2-25-10" "F11" "Unknown Media" "Unknown Strain" "richards sigmoid" 14.4916170721585 0.0217082788822816 18.6612222222222 0.0889624212709417 0.000433184593667829 0.00193467537358108 0.000448535254389812 0.976169160121559 0.0129779368057855 0.97810383549514 0.00193467537359373 0.752023541644887 0.976169160121546 0.750088866271293 0.0019365480654705 1.65426866265479 1.65940878149869 0.00193654806548316 1.1212881914955 1.65747223343321 1.11935164343002 0.07 0.0304920969087024 0.999799864971328 0.0015636072090697 "I " "U" "-" "" "YPDAFEXglucoseTests_2-25-10_plots_2014-11-14_15.24.29.pdf" 87
|
||||
87 "YPDAFEXglucoseTests_2-25-10" "G11" "Unknown Media" "Unknown Strain" "<NA>: skipped" NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA "! " "-" "-" "" "YPDAFEXglucoseTests_2-25-10_plots_2014-11-14_15.24.29.pdf" 88
|
||||
88 "YPDAFEXglucoseTests_2-25-10" "H11" "Unknown Media" "Unknown Strain" "<NA>: skipped" NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA "! " "-" "-" "" "YPDAFEXglucoseTests_2-25-10_plots_2014-11-14_15.24.29.pdf" 89
|
||||
89 "YPDAFEXglucoseTests_2-25-10" "A12" "Unknown Media" "Unknown Strain" "<NA>: skipped" NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA "! " "-" "-" "" "YPDAFEXglucoseTests_2-25-10_plots_2014-11-14_15.24.29.pdf" 90
|
||||
90 "YPDAFEXglucoseTests_2-25-10" "B12" "Unknown Media" "Unknown Strain" "<NA>: skipped" NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA "! " "-" "-" "" "YPDAFEXglucoseTests_2-25-10_plots_2014-11-14_15.24.29.pdf" 91
|
||||
91 "YPDAFEXglucoseTests_2-25-10" "C12" "Unknown Media" "Unknown Strain" "<NA>: skipped" NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA "! " "-" "-" "" "YPDAFEXglucoseTests_2-25-10_plots_2014-11-14_15.24.29.pdf" 92
|
||||
92 "YPDAFEXglucoseTests_2-25-10" "D12" "Unknown Media" "Unknown Strain" "<NA>: skipped" NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA "! " "-" "-" "" "YPDAFEXglucoseTests_2-25-10_plots_2014-11-14_15.24.29.pdf" 93
|
||||
93 "YPDAFEXglucoseTests_2-25-10" "E12" "Unknown Media" "Unknown Strain" "<NA>: skipped" NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA "! " "-" "-" "" "YPDAFEXglucoseTests_2-25-10_plots_2014-11-14_15.24.29.pdf" 94
|
||||
94 "YPDAFEXglucoseTests_2-25-10" "F12" "Unknown Media" "Unknown Strain" "<NA>: skipped" NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA "! " "-" "-" "" "YPDAFEXglucoseTests_2-25-10_plots_2014-11-14_15.24.29.pdf" 95
|
||||
95 "YPDAFEXglucoseTests_2-25-10" "G12" "Unknown Media" "Unknown Strain" "<NA>: skipped" NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA "! " "-" "-" "" "YPDAFEXglucoseTests_2-25-10_plots_2014-11-14_15.24.29.pdf" 96
|
||||
96 "YPDAFEXglucoseTests_2-25-10" "H12" "Unknown Media" "Unknown Strain" "<NA>: skipped" NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA "! " "-" "-" "" "YPDAFEXglucoseTests_2-25-10_plots_2014-11-14_15.24.29.pdf" 97
|
||||
|
||||
# Raw OD values are adjusted and log-transformed before fitting a growth curve as follows: log.OD = log(OD - blank + const) where blank is OD of blank medium and const is specified by the user (1 by default)
|
||||
# Values are reported on the above 'log.OD' scale unless otherwise specified.
|
||||
# .SE columns report standard errors of those values that are estimated directly as parameters of global sigmoid models.
|
||||
# .OD columns report values back-transformed to the linear 'OD - blank' scale.
|
||||
|
||||
# -- Explanation of columns --
|
||||
# - model: Name of the model the well was successfully fit with (if any)
|
||||
# - lag.time: Lag time estimate inferred from the fitted model
|
||||
# - inflection.time: inflection time point of the growth curve when drawn on the log scale
|
||||
# - max.spec.growth.rate: maximum specific growth rate estimate inferred from the fitted model. Estimated as the first derivative of the growth curve at inflection time point
|
||||
# - baseline: growth curve baseline. Global sigmoid model: baseline is parameter 'b' of the model. LOESS: baseline is the same as the lowest predicted log.OD value
|
||||
# - amplitude: difference between upper plateau and baseline values. Global sigmoid model: amplitude is parameter 'A' of the model. LOESS: amplitude = max.log.OD - min.log.OD
|
||||
# - plateau: upper asymptote value of the fitted model. Global sigmoid model: plateau = b + A. LOESS: plateau = max.log.OD
|
||||
# - inoc.log.OD: log.OD value at inoculation. Estimated value from the fitted model is used, rather than the actual measurement
|
||||
# - max.log.OD: maximal log.OD value reached during the experiment. Estimated value from the fitted model is used rather than the actual measurement
|
||||
# - projected.growth: maximal projected growth over inoculation value. Global sigmoid model: projected.growth = plateau - inoc.log.OD. LOESS: not reported
|
||||
# - achieved.growth: maximal growth over inoculation value actually achieved during the experiment. achieved.growth = max.log.OD - inoc.log.OD
|
||||
# - shape.par: shape parameter of the Richard equation
|
||||
# - R.squared: goodness of fit metric. Also known as coefficient of determination. R.squared is usually between 0 and 1. A value close to 1 indicates good fit.
|
||||
# - RSS: residual sum of squares. Another goodness of fit metric. Smaller values indicate better fits.
|
||||
# - empty: (Well indicator)
|
||||
# - an 'E' indicates that the well was empty and no growth was detected.
|
||||
# - an 'I' indicates that the well was inoculated and growth was detected above the threshold.
|
||||
# - an 'E*' indicates that the well was empty and growth was detected (possible contamination).
|
||||
# - an '!' indicates that the well was inoculated and no growth was detected.
|
||||
# - asymp.not.reached: shows “L” if the bottom asymptote (baseline) was not reached and “U” if the upper asymptote (plateau) was not reached.
|
||||
# - tank: (Tanking indicator) If a number is present then the growth trend was determined to tank at that timepoint index.
|
||||
# - other: Additional flag column. Displays information about whether jumps in OD were detected and what was done about them.
|
||||
# - pdf.file and page.no: location of the figure for this well in the output .pdf files.
|
||||
#
|
||||
# -- Source file information--
|
||||
# YPDAFEXglucoseTests_2-25-10.csv
|
||||
# analyzed using GCAT v 4.5
|
||||
# request sent: 2014-11-14 15:24:29
|
||||
# completed: 2014-11-14 15:24:36
|
||||
#
|
||||
# -- Parameters used in current analysis --
|
||||
# - Constant added to log(OD + n) transformation: 1
|
||||
# - Blank OD value: First timepoint in well
|
||||
# - Index of inoculation timepoint 2
|
||||
# - Minimum growth threshold: 0.05
|
||||
# - Removed points: 0
|
||||
# - Jump detection: FALSE
|
@ -0,0 +1,35 @@
|
||||
% Generated by roxygen2 (4.0.2): do not edit by hand
|
||||
\name{fit.model}
|
||||
\alias{fit.model}
|
||||
\title{fit.model}
|
||||
\usage{
|
||||
fit.model(input.well, growth.model, backup.growth.model = NULL,
|
||||
fit.if.no.growth = F, use.linear.param = F, use.loess = F, smooth.param,
|
||||
silent = T)
|
||||
}
|
||||
\arguments{
|
||||
\item{input.well}{The well needed to be fitted with the given model.}
|
||||
|
||||
\item{growth.model}{What growth model should be used?}
|
||||
|
||||
\item{backup.growth.model}{If \code{gowth.mode} fails, this model will be used.}
|
||||
|
||||
\item{fit.if.no.growth}{should the function attempt to fit a well even if there was no growth detected? default is F}
|
||||
|
||||
\item{silent}{output back to R console?}
|
||||
|
||||
\item{use.linear.param:}{Should an additional linear parameter (c) be used when fitting the data to the model?}
|
||||
|
||||
\item{use.loess:}{Should Local Polynomial Regression Fitting (loess function) be used instead of nls?}
|
||||
|
||||
\item{smooth.param:}{If loess is used, an optional smoothing parameter. Default is .6}
|
||||
}
|
||||
\description{
|
||||
This function will use the function stored in the "guess" slot of \code{growth.model} to calculate initial guesses
|
||||
for growth.model parameters, then it will use the "formula" slot with \code{nls} to fit a non-linear least squares
|
||||
\code{growth.model} or Local Polynomial Regression Fitting to the data. Richards model is first fitted.
|
||||
If the shape parameter is statisticaly significant then Richards is used. If it is within 2 SE of 1 or Zero than
|
||||
a simpler model is preferred. If the Richards fit fails, then Logistic is tried. If it fails, Gompertz is tried.
|
||||
Model fit failure is reported if none of the models can sucessfully fit the data
|
||||
}
|
||||
|
@ -0,0 +1,30 @@
|
||||
\name{GCAT}
|
||||
\alias{GCAT}
|
||||
\title{
|
||||
Growth Curve Analysis Tool
|
||||
}
|
||||
\description{
|
||||
Mathematical modeling and parameter estimation of high volume microbial growth data.
|
||||
}
|
||||
\details{
|
||||
GCAT utilizes the \code{\link{nls}} function in the R base package to fit logistic and Richards models to
|
||||
growth curve data. Input is in .csv format and analysis is accessed using \code{\link{gcat.analysis.main}}
|
||||
or \code{\link{gcat.fit.main}}. Output is in .txt and .pdf format, and is accessed using \code{\link{gcat.analysis.main}}
|
||||
or \code{\link{gcat.output.main}}.
|
||||
|
||||
\tabular{ll}{
|
||||
Version: \tab 5.0\cr
|
||||
Depends: \tab pheatmap, gplots\cr
|
||||
License: \tab LGPL-3\cr
|
||||
Date: \tab 2014-02-10\cr
|
||||
}
|
||||
|
||||
}
|
||||
\author{
|
||||
Jason Shao\cr
|
||||
Nate DiPiazza\cr
|
||||
Yury Bukhman\cr
|
||||
Minh Bui\cr
|
||||
|
||||
Maintainer: Yury Bukhman
|
||||
}
|
@ -0,0 +1,72 @@
|
||||
% Generated by roxygen2 (4.0.2): do not edit by hand
|
||||
\name{gcat.analysis.main}
|
||||
\alias{gcat.analysis.main}
|
||||
\title{Analyze screening growth data from the given .csv files.}
|
||||
\usage{
|
||||
gcat.analysis.main(file.list, single.plate, layout.file = NULL,
|
||||
out.dir = getwd(), graphic.dir = paste(out.dir, "/pics", sep = ""),
|
||||
add.constant = 0.1, blank.value = NULL, start.index = 2,
|
||||
growth.cutoff = 0.05, use.linear.param = F, use.loess = F,
|
||||
smooth.param = 0.1, points.to.remove = 0, remove.jumps = F,
|
||||
time.input = NA, plate.nrow = 8, plate.ncol = 12,
|
||||
input.skip.lines = 0, multi.column.headers = c("Plate.ID", "Well", "OD",
|
||||
"Time"), single.column.headers = c("", "A1"),
|
||||
layout.sheet.headers = c("Strain", "Media Definition"), silent = T,
|
||||
verbose = F, return.fit = F, overview.jpgs = T)
|
||||
}
|
||||
\arguments{
|
||||
\item{file.list}{A list of full paths to .csv files. all files must be in the same format (see <single.plate>)}
|
||||
|
||||
\item{single.plate}{The file in the single plate (wide) format vs. the multi-plate (long) format?}
|
||||
|
||||
\item{layout.file}{Full path to a layout file with strain and media definitions (applies to all files in list)}
|
||||
|
||||
\item{out.dir}{A directory to output the table of curve parameters to (defaults to working directory)}
|
||||
|
||||
\item{graphic.dir}{A directory to output the images of the fitted curves to (defaults to subdirectory "pics" of <out.dir> above)}
|
||||
|
||||
\item{add.constant}{A numeric constant that will be added to each curve before the log transform (defaults to 1)}
|
||||
|
||||
\item{blank.value}{User can enter a blank OD measurement for uninoculated wells. if NULL, defaults to the value of the first OD measurement of each well.}
|
||||
|
||||
\item{start.index}{Which timepoint should be used as the first one after inoculation (defaults to the 2th one)}
|
||||
|
||||
\item{growth.cutoff}{Minimum threshold for curve growth.}
|
||||
|
||||
\item{use.linear.param}{Whether to use linear parameters or not?}
|
||||
|
||||
\item{use.loess}{Whether to use LOESS model or not?}
|
||||
|
||||
\item{smooth.param}{Smoothing parameter for LOESS model.}
|
||||
|
||||
\item{points.to.remove}{A list of numbers referring to troublesome points that should be removed across all wells.}
|
||||
|
||||
\item{remove.jumps}{Should the slope checking function be on the lookout for large jumps in OD?}
|
||||
|
||||
\item{time.input}{The time setting in which the current system is running?}
|
||||
|
||||
\item{plate.nrow}{The number of rows in a plate.}
|
||||
|
||||
\item{plate.ncol}{The number of columns in a plate.}
|
||||
|
||||
\item{input.skip.lines}{If specified, this number of lines shall be skipped from the top when reading the input file with read.csv}
|
||||
|
||||
\item{multi.column.headers}{The headers of the result tabular data when analyzing multiple plates at once.}
|
||||
|
||||
\item{single.column.headers}{The headers of the result tebaular data when analyzaing a single plate.}
|
||||
|
||||
\item{layout.sheet.headers}{The headers of the layout file?}
|
||||
|
||||
\item{silent}{Shoulde messages be returned to the console?}
|
||||
|
||||
\item{verbose}{Should sub-functions return messages to console? (when I say verbose, I mean it!)}
|
||||
|
||||
\item{overview.jpgs}{Should GCAT enable an overview image?}
|
||||
}
|
||||
\value{
|
||||
A list of the output files.
|
||||
}
|
||||
\description{
|
||||
Top-level GCAT function
|
||||
}
|
||||
|
@ -0,0 +1,88 @@
|
||||
% Generated by roxygen2 (4.0.2): do not edit by hand
|
||||
\name{gcat.fit.main}
|
||||
\alias{gcat.fit.main}
|
||||
\title{Main analysis function for GCAT}
|
||||
\usage{
|
||||
gcat.fit.main(file.name, input.data = NULL, load.type = "csv",
|
||||
layout.file = NULL, single.plate = F, blank.value = NULL,
|
||||
start.index = 2, time.input = NA, normalize.method = "default",
|
||||
add.constant = 1, use.log = T, points.to.remove = 0,
|
||||
use.linear.param = F, use.loess = F, smooth.param = 0.1,
|
||||
fall.cutoff = -0.0025, growth.cutoff = 0.05, remove.jumps = F,
|
||||
plate.nrow = 8, plate.ncol = 12, input.skip.lines = 0,
|
||||
multi.column.headers = c("Plate.ID", "Well", "OD", "Time"),
|
||||
single.column.headers = c("", "A1"), layout.sheet.headers = c("Strain",
|
||||
"Media Definition"), growth.model = NA, backup.growth.model = NA,
|
||||
silent = F, verbose = F)
|
||||
}
|
||||
\arguments{
|
||||
\item{file.name}{Complete path and file name of a comma-separated values (.csv) file containing growth curve data
|
||||
in the multiple-plate (long) format.}
|
||||
|
||||
\item{input.data}{A list of tables representing input files read with \code{read.table}. Used to save time in cases
|
||||
of running multiple analyses on the same dataset. If used, the function will ignore \code{file.name} entirely.}
|
||||
|
||||
\item{load.type}{.csv by default.}
|
||||
|
||||
\item{layout.file}{Specifies the location of a layout file containing identifying information.}
|
||||
|
||||
\item{single.plate}{Whether the GCAT is analyzing a single plate or not.}
|
||||
|
||||
\item{blank.value}{Blank OD measurement for uninoculated wells. By default(NULL), the value of the first OD
|
||||
measurement in each well is used.}
|
||||
|
||||
\item{start.index}{Which timepoint should be used as the first one after inoculation?}
|
||||
|
||||
\item{time.input}{Either a character describing the format used to convert timestamps in the input to numbers
|
||||
representing number of seconds (see \code{strptime}), or a factor to divide entries in the Time column by to get the
|
||||
numbers of hours.}
|
||||
|
||||
\item{normalize.method}{Describes the method used by \code{normalize.ODs} to normalize cell density values using blank reads.}
|
||||
|
||||
\item{add.constant}{A value for r in the log(OD + r) transformation.}
|
||||
|
||||
\item{use.log}{Should the analysis use log on all values.}
|
||||
|
||||
\item{points.to.remove}{A vector of integers specifying which timepoints should be removed across all wells.
|
||||
By default(0) none are marked for removal.}
|
||||
|
||||
\item{use.linear.param}{Should the linear parameter be used or not.}
|
||||
|
||||
\item{use.loess}{Should the loess model be used or not.}
|
||||
|
||||
\item{smooth.param}{If loess model is used, this parameter define the smoothing parameter for the loess model.}
|
||||
|
||||
\item{fall.cutoff}{A cutoff used by \code{check.slopes} to decide on thresholds for jumps and tanking.}
|
||||
|
||||
\item{growth.cutoff}{A threshold used by check.growth to decide whether a well displays growth.}
|
||||
|
||||
\item{remove.jumps}{Should jumps in OD detected by the subfunction \code{check.slopes}?}
|
||||
|
||||
\item{plate.nrow}{The number of rows in the input files.}
|
||||
|
||||
\item{plate.ncol}{The number of columns in the input files.}
|
||||
|
||||
\item{input.skip.lines}{If specified, this number of lines shall be skipped from the top when reading the input file with read.csv}
|
||||
|
||||
\item{multi.column.headers}{The headers of the column when analyzing multiple plates.}
|
||||
|
||||
\item{single.column.headers}{The headers of the column when analyzing a single plate.}
|
||||
|
||||
\item{growth.model}{What growth model should be used?}
|
||||
|
||||
\item{backup.growth.model}{If the main growth model fails, the back up model will be used.}
|
||||
|
||||
\item{silent}{Surpress all messages.}
|
||||
|
||||
\item{verbose}{Display all messages when analyzing each well.}
|
||||
|
||||
\item{layour.sheet.headers}{The headers of the layout file.}
|
||||
}
|
||||
\value{
|
||||
An array of well objects
|
||||
}
|
||||
\description{
|
||||
This is the main function that handles all the analyses for data files in both single and multiple plate formats.
|
||||
It is called by the top level function \code{gcat.analysis.main} along with \code{gcat.output.main}.
|
||||
}
|
||||
|
@ -0,0 +1,57 @@
|
||||
% Generated by roxygen2 (4.0.2): do not edit by hand
|
||||
\name{gcat.load.data}
|
||||
\alias{gcat.load.data}
|
||||
\title{Load tabular data}
|
||||
\usage{
|
||||
gcat.load.data(file.name = NULL, load.type = "csv", input.data = NULL,
|
||||
single.plate.ID = NULL, plate.layout = NULL, plate.nrow = 8,
|
||||
plate.ncol = 12, input.skip.lines = 0,
|
||||
multi.column.headers = c("Plate.ID", "Well", "OD", "Time"),
|
||||
single.column.headers = c("", "A1"), layout.sheet.headers = c("Strain",
|
||||
"Media Definition"), blank.value = NULL, start.index = 2,
|
||||
single.plate = F, silent = T)
|
||||
}
|
||||
\arguments{
|
||||
\item{file.name}{Complete path and file name of a comma-separated values (.csv) file containing growth curve data
|
||||
in the multiple-plate (long) format.}
|
||||
|
||||
\item{load.type}{.csv by default.}
|
||||
|
||||
\item{input.data}{A list of tables representing input files read with \code{read.table}. Used to save time in cases
|
||||
of running multiple analyses on the same dataset. If used, the function will ignore \code{file.name} entirely.}
|
||||
|
||||
\item{single.plate.ID}{specifies a plate name for a single-plate read. If NULL, this is derived from the file name.}
|
||||
|
||||
\item{plate.nrow}{The number of rows in the input files.}
|
||||
|
||||
\item{plate.ncol}{The number of columns in the input files.}
|
||||
|
||||
\item{input.skip.lines}{specifies a plate name for a single-plate read. If NULL, this is derived from the file name.}
|
||||
|
||||
\item{multi.column.headers}{The headers of the column when analyzing multiple plates.}
|
||||
|
||||
\item{single.column.headers}{The headers of the column when analyzing a single plate.}
|
||||
|
||||
\item{layout.sheet.headers}{The headers of the layout file.}
|
||||
|
||||
\item{blank.value}{Blank OD measurement for uninoculated wells. By default(NULL), the value of the first OD
|
||||
measurement in each well is used.}
|
||||
|
||||
\item{silent}{Surpress all messages.}
|
||||
|
||||
\item{plate.laout}{Specifies the layout of the given plate.}
|
||||
|
||||
\item{add.constant}{A value for r in the log(OD + r) transformation.}
|
||||
|
||||
\item{verbose}{Display all messages when analyzing each well.}
|
||||
}
|
||||
\value{
|
||||
A list of well objects.
|
||||
}
|
||||
\description{
|
||||
This function handles loading data from tabular format (.csv, tab-delimited text or R data frame object)
|
||||
and returns an array of well objects, each filled with raw Time vs. OD data.
|
||||
It takes single-plate or multiple-plate format data. For single-plate data,
|
||||
it calls on the function \code{gcat.reorganize.single.plate.data} to rearrange the table before creating the output object.
|
||||
}
|
||||
|
@ -0,0 +1,51 @@
|
||||
% Generated by roxygen2 (4.0.2): do not edit by hand
|
||||
\name{gcat.output.main}
|
||||
\alias{gcat.output.main}
|
||||
\title{Output function for generating files from fitted data.}
|
||||
\usage{
|
||||
gcat.output.main(fitted.well.array, out.prefix = "", source.file.list,
|
||||
upload.timestamp = NULL, add.constant, blank.value, start.index,
|
||||
growth.cutoff, points.to.remove, remove.jumps, out.dir = getwd(),
|
||||
graphic.dir = paste(out.dir, "/pics", sep = ""), overview.jpgs = T,
|
||||
use.linear.param = F, use.loess = F, plate.nrow = 8, plate.ncol = 12,
|
||||
unlog = F, silent = T)
|
||||
}
|
||||
\arguments{
|
||||
\item{fitted.well.array}{A list of fitted well objects.}
|
||||
|
||||
\item{out.prefix}{Prefix that is in the name of output files.}
|
||||
|
||||
\item{blank.value}{User can enter a blank OD measurement for uninoculated wells.
|
||||
If NULL, defaults to the value of the first OD measurement of each well.}
|
||||
|
||||
\item{start.index}{Which timepoint should be used as the first one after inoculation (defaults to the 2th one)}
|
||||
|
||||
\item{growth.cutoff}{Minimum threshold for curve growth.}
|
||||
|
||||
\item{points.to.remove}{A list of numbers referring to troublesome points that should be removed across all wells.}
|
||||
|
||||
\item{remove.jumps}{Should the slope checking function be on the lookout for large jumps in OD?}
|
||||
|
||||
\item{out.dir}{name a directory to output the table of curve parameters to (defaults to working directory)}
|
||||
|
||||
\item{graphic.dir}{name a directory to output the images of the fitted curves to
|
||||
(defaults to subdirectory "pics" of <out.dir> above)}
|
||||
|
||||
\item{overview.jpgs}{should jpgs be generated for each plate with the overview graphic?
|
||||
This is for backwards compatibility with the old web server.}
|
||||
|
||||
\item{unlog}{should exported graphics be transformed back to the OD scale?}
|
||||
|
||||
\item{silent}{should messages be returned to the console?}
|
||||
|
||||
\item{constant.added}{(should be the same value as add.constant above) -
|
||||
used to readjust for the constant added during the log transform when plotting ODs.}
|
||||
}
|
||||
\value{
|
||||
A list of output files if success.
|
||||
}
|
||||
\description{
|
||||
Handles files and directories, calls \code{table.out}, \code{plate.overview} and \code{view.fit}
|
||||
to generate output tables and graphics.
|
||||
}
|
||||
|
@ -0,0 +1,53 @@
|
||||
\name{gcat.set.constants}
|
||||
\alias{gcat.set.constants}
|
||||
\title{
|
||||
Set global constants for GCAT analysis package
|
||||
}
|
||||
\description{
|
||||
Sets global constants, mostly regarding issues in input file format, for GCAT analysis.
|
||||
}
|
||||
\usage{
|
||||
gcat.set.constants(plate.nrow = 8, plate.ncol = 12, input.skip.lines = 0, time.format = "\%Y-\%m-\%d \%H:\%M:\%S",
|
||||
multi.column.headers = c("Plate ID", "Well", "OD", "Time"), single.column.headers = c("", "A1"),
|
||||
xlsx.data.headers = c("Plate ID", "Well positions"), xlsx.layout.sheet = "Plate layout",
|
||||
layout.sheet.headers = c("Strain", "Media Definition"))
|
||||
}
|
||||
\arguments{
|
||||
\item{plate.nrow}{
|
||||
Number of rows present in each plate of input data. Default 8 (A-H)
|
||||
}
|
||||
\item{plate.ncol}{
|
||||
Number of columns present in each plate of input data. Default 12 (1-12)
|
||||
}
|
||||
\item{input.skip.lines}{
|
||||
Number of lines to skip at the top when reading input data files.
|
||||
}
|
||||
\item{time.format}{
|
||||
Either a character describing the format used to convert timestamps
|
||||
in the input to numbers representing number of seconds (see \code{\link{strptime}}), or a
|
||||
factor to divide entries in the \code{Time} column by to get the number of hours.
|
||||
}
|
||||
\item{multi.column.headers}{
|
||||
A character vector describing the names of the columns for
|
||||
Plate ID, Well ID, Cellular density measurements and Time, respectively, in the multi-plate (long) format.
|
||||
}
|
||||
\item{single.column.headers}{
|
||||
A character vector describing the name of the Time column and the first well data in the single plate (wide) format.
|
||||
}
|
||||
\item{xlsx.data.headers}{
|
||||
For .xlsx data only, a vector describing possible entries in the upper left cell marking worksheets in each
|
||||
workbook as containing data. .csv files don't have multiple worksheets and are assumed to contain useable data.
|
||||
}
|
||||
\item{xlsx.layout.sheet}{
|
||||
For .xlsx data only, the name of the worksheet containing plate layout information. .csv files use a separate layout file.
|
||||
}
|
||||
\item{layout.sheet.headers}{
|
||||
A character vector describing the name of the Strain and Media definiton columns, respectively, in the plate layout file.
|
||||
}
|
||||
}
|
||||
\value{
|
||||
NULL
|
||||
}
|
||||
\author{
|
||||
Jason Shao
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
% Generated by roxygen2 (4.0.2): do not edit by hand
|
||||
\name{model}
|
||||
\alias{model}
|
||||
\title{Model}
|
||||
\usage{
|
||||
model(name, expression, formula, guess)
|
||||
}
|
||||
\arguments{
|
||||
\item{name}{The name of the model}
|
||||
|
||||
\item{expression}{Expression of the model}
|
||||
|
||||
\item{formula}{The formula of this model}
|
||||
|
||||
\item{guess}{The guess of this model}
|
||||
}
|
||||
\value{
|
||||
The new model
|
||||
}
|
||||
\description{
|
||||
Function to create a new model
|
||||
}
|
||||
|
@ -0,0 +1,28 @@
|
||||
% Generated by roxygen2 (4.0.2): do not edit by hand
|
||||
\name{plot.data}
|
||||
\alias{plot.data}
|
||||
\title{plot.data}
|
||||
\usage{
|
||||
\method{plot}{data}(input.well, view.raw.data = F, unlog = F, scale = 1,
|
||||
main = paste(plate.name(input.well), well.name(input.well)),
|
||||
number.points = T, draw.symbols = F, constant.added, ylim, ...)
|
||||
}
|
||||
\arguments{
|
||||
\item{input.well}{The well object that need to be plottedd}
|
||||
|
||||
\item{view.raw.data}{should the raw data be plotted? (}
|
||||
|
||||
\item{unlog}{should data be plotted on a linear (vs. logarithmic) scale?}
|
||||
|
||||
\item{scale}{determines the font scale for the entire graph. all cex values are calculated from this.}
|
||||
|
||||
\item{number.points}{should points be labeled with numeric indices?}
|
||||
|
||||
\item{draw.symbols}{- should <check.slopes> be called on the well and markings drawn on the graph?}
|
||||
|
||||
\item{...}{additional arguments passed to plot()}
|
||||
}
|
||||
\description{
|
||||
Basic function plots time vs. OD from a well object
|
||||
}
|
||||
|
@ -0,0 +1,27 @@
|
||||
% Generated by roxygen2 (4.0.2): do not edit by hand
|
||||
\name{transform.ODs}
|
||||
\alias{transform.ODs}
|
||||
\title{Transform.Ods}
|
||||
\usage{
|
||||
\method{transform}{ODs}(input.well, use.log = T, blank.value = NULL,
|
||||
start.index = 2, negative.OD.cutoff = 10, constant.added = 1, ...)
|
||||
}
|
||||
\arguments{
|
||||
\item{input.well}{an object of class well}
|
||||
|
||||
\item{use.log}{gets added to the "use.log" slot of the well object. this will determine whether the log-transformed data
|
||||
or raw normalized data is returned using the function \code{data.from}.}
|
||||
|
||||
\item{blank.value}{user can enter a blank OD measurement for uninoculated wells. if NULL, defaults to the value of the first OD measurement of each well.}
|
||||
|
||||
\item{start.index}{which timepoint should be used as the first one after inoculation (defaults to the 2th one)}
|
||||
|
||||
\item{negative.OD.cutoff}{if any ODs below the specified blank value are detected before this index timepoint, the entire well is discarded.}
|
||||
}
|
||||
\description{
|
||||
This function adds a "log.OD" column to the "screen.data" slot of a well object with log-transformed data.
|
||||
The raw data is kept intact.
|
||||
It also checks to see if any of the raw OD values (before a certain timepoint) is below the blank OD.
|
||||
This can be disastrous for the log(OD) transform.
|
||||
}
|
||||
|
@ -0,0 +1,30 @@
|
||||
# Regression testing script for GCAT.
|
||||
# Yury V Bukhman, 17 Nov 2014
|
||||
# This script tests outputs generated from the example dataset "YPDAFEXglucoseTests_2-25-10" with default GCAT settings.
|
||||
|
||||
INPUT.DIR = system.file("extdata/YPDAFEXglucoseTests_2-25-10",package="GCAT")
|
||||
OUTPUT.DIR = paste(INPUT.DIR,"temp",sep="/")
|
||||
INPUT.FILE = "YPDAFEXglucoseTests_2-25-10.csv"
|
||||
|
||||
# Run GCAT
|
||||
library(GCAT)
|
||||
setwd(INPUT.DIR)
|
||||
time.input=1/3600
|
||||
out = gcat.analysis.main(file.list = INPUT.FILE, single.plate = T, layout.file = NULL,
|
||||
out.dir = OUTPUT.DIR, graphic.dir = OUTPUT.DIR,
|
||||
add.constant = 1, blank.value = NULL, start.index = 2, growth.cutoff = 0.05,
|
||||
use.linear.param=F, use.loess=F, smooth.param=0.1,
|
||||
points.to.remove = 0, remove.jumps = F, time.input=time.input,
|
||||
silent = F, verbose = T, return.fit = T, overview.jpgs = T)
|
||||
|
||||
# Read in old and new output spreadsheets
|
||||
old.output.table = read.table("default_output.txt",header=T,sep="\t")
|
||||
new.output.file = list.files(path=OUTPUT.DIR, pattern = "^output_gcat\\.fit_.+\\.txt$")
|
||||
new.output.table = read.table(paste("temp",new.output.file,sep="/"),header=T,sep="\t")
|
||||
|
||||
# Remove "pdf.file" column
|
||||
old.output.table = old.output.table[names(old.output.table) != "pdf.file"]
|
||||
new.output.table = new.output.table[names(new.output.table) != "pdf.file"]
|
||||
|
||||
# Verify that output spreadsheets are identical within rounding error
|
||||
stopifnot(all.equal(new.output.table,old.output.table))
|
@ -0,0 +1,23 @@
|
||||
===What's in this package===
|
||||
R - R code. Sub-folder GCAT contains the GCAT package
|
||||
Rails - Rails code
|
||||
Testing - testing code, data and documents, outside of any regression tests that may be incorporated directly into R packages or Rails applications
|
||||
|
||||
===Getting started===
|
||||
First you will need to install Ruby and Ruby on Rails. I suggest using RVM to
|
||||
install them. Documentation for RVM can be found at: http://rvm.io.
|
||||
|
||||
You will need: Ruby version 1.9.3p194 and Rails 3.2.15
|
||||
|
||||
The R package is in subfolder R. To install, do the following:
|
||||
Open a terminal in the R folder
|
||||
$ sudo R CMD REMOVE GCAT # do this if an older version of GCAT has been installed
|
||||
$ sudo R CMD INSTALL GCAT
|
||||
It works with R version 3.0.2 (2013-09-25) -- "Frisbee Sailing".
|
||||
|
||||
The rails application is in subfolder Rails. It runs under Rails 3.2.15. To run it locally using the default Rails WEBrick web server do the following:
|
||||
Open a terminal in the Rails folder
|
||||
$ bundle install
|
||||
$ rails s
|
||||
Open http://0.0.0.0:3000 in a web browser
|
||||
|
@ -0,0 +1,5 @@
|
||||
.bundle
|
||||
db/*.sqlite3
|
||||
log/*.log
|
||||
tmp/
|
||||
.sass-cache/
|
@ -0,0 +1,42 @@
|
||||
source 'http://rubygems.org'
|
||||
|
||||
# gem 'rails', '3.1.0' #no longer supporting security updates
|
||||
gem 'rails', '3.2.15'
|
||||
|
||||
# Bundle edge Rails instead:
|
||||
# gem 'rails', :git => 'git://github.com/rails/rails.git'
|
||||
|
||||
gem 'sqlite3'
|
||||
|
||||
|
||||
# Gems used only for assets and not required
|
||||
# in production environments by default.
|
||||
group :assets do
|
||||
gem 'sass-rails', '~> 3.2.3'
|
||||
#gem 'coffee-rails', "~> 3.1.0"
|
||||
gem 'uglifier'
|
||||
|
||||
# See https://github.com/sstephenson/execjs#readme for more supported runtimes
|
||||
gem 'therubyracer'
|
||||
|
||||
end
|
||||
|
||||
gem 'jquery-rails'
|
||||
|
||||
# Use unicorn as the web server
|
||||
# gem 'unicorn'
|
||||
|
||||
# Deploy with Capistrano
|
||||
# gem 'capistrano'
|
||||
|
||||
# To use debugger
|
||||
gem 'debugger'
|
||||
|
||||
group :test do
|
||||
# Pretty printed test output
|
||||
gem 'turn', :require => false
|
||||
end
|
||||
|
||||
gem 'rinruby'
|
||||
|
||||
gem 'rubyzip'
|
@ -0,0 +1,124 @@
|
||||
GEM
|
||||
remote: http://rubygems.org/
|
||||
specs:
|
||||
actionmailer (3.2.15)
|
||||
actionpack (= 3.2.15)
|
||||
mail (~> 2.5.4)
|
||||
actionpack (3.2.15)
|
||||
activemodel (= 3.2.15)
|
||||
activesupport (= 3.2.15)
|
||||
builder (~> 3.0.0)
|
||||
erubis (~> 2.7.0)
|
||||
journey (~> 1.0.4)
|
||||
rack (~> 1.4.5)
|
||||
rack-cache (~> 1.2)
|
||||
rack-test (~> 0.6.1)
|
||||
sprockets (~> 2.2.1)
|
||||
activemodel (3.2.15)
|
||||
activesupport (= 3.2.15)
|
||||
builder (~> 3.0.0)
|
||||
activerecord (3.2.15)
|
||||
activemodel (= 3.2.15)
|
||||
activesupport (= 3.2.15)
|
||||
arel (~> 3.0.2)
|
||||
tzinfo (~> 0.3.29)
|
||||
activeresource (3.2.15)
|
||||
activemodel (= 3.2.15)
|
||||
activesupport (= 3.2.15)
|
||||
activesupport (3.2.15)
|
||||
i18n (~> 0.6, >= 0.6.4)
|
||||
multi_json (~> 1.0)
|
||||
ansi (1.4.3)
|
||||
arel (3.0.3)
|
||||
builder (3.0.4)
|
||||
columnize (0.3.6)
|
||||
debugger (1.6.6)
|
||||
columnize (>= 0.3.1)
|
||||
debugger-linecache (~> 1.2.0)
|
||||
debugger-ruby_core_source (~> 1.3.2)
|
||||
debugger-linecache (1.2.0)
|
||||
debugger-ruby_core_source (1.3.2)
|
||||
erubis (2.7.0)
|
||||
execjs (2.0.2)
|
||||
hike (1.2.3)
|
||||
i18n (0.6.9)
|
||||
journey (1.0.4)
|
||||
jquery-rails (3.1.0)
|
||||
railties (>= 3.0, < 5.0)
|
||||
thor (>= 0.14, < 2.0)
|
||||
json (1.8.1)
|
||||
libv8 (3.16.14.3)
|
||||
mail (2.5.4)
|
||||
mime-types (~> 1.16)
|
||||
treetop (~> 1.4.8)
|
||||
mime-types (1.25.1)
|
||||
multi_json (1.9.0)
|
||||
polyglot (0.3.4)
|
||||
rack (1.4.5)
|
||||
rack-cache (1.2)
|
||||
rack (>= 0.4)
|
||||
rack-ssl (1.3.3)
|
||||
rack
|
||||
rack-test (0.6.2)
|
||||
rack (>= 1.0)
|
||||
rails (3.2.15)
|
||||
actionmailer (= 3.2.15)
|
||||
actionpack (= 3.2.15)
|
||||
activerecord (= 3.2.15)
|
||||
activeresource (= 3.2.15)
|
||||
activesupport (= 3.2.15)
|
||||
bundler (~> 1.0)
|
||||
railties (= 3.2.15)
|
||||
railties (3.2.15)
|
||||
actionpack (= 3.2.15)
|
||||
activesupport (= 3.2.15)
|
||||
rack-ssl (~> 1.3.2)
|
||||
rake (>= 0.8.7)
|
||||
rdoc (~> 3.4)
|
||||
thor (>= 0.14.6, < 2.0)
|
||||
rake (10.1.1)
|
||||
rdoc (3.12.2)
|
||||
json (~> 1.4)
|
||||
ref (1.0.5)
|
||||
rinruby (2.0.3)
|
||||
rubyzip (1.1.0)
|
||||
sass (3.2.14)
|
||||
sass-rails (3.2.6)
|
||||
railties (~> 3.2.0)
|
||||
sass (>= 3.1.10)
|
||||
tilt (~> 1.3)
|
||||
sprockets (2.2.2)
|
||||
hike (~> 1.2)
|
||||
multi_json (~> 1.0)
|
||||
rack (~> 1.0)
|
||||
tilt (~> 1.1, != 1.3.0)
|
||||
sqlite3 (1.3.9)
|
||||
therubyracer (0.12.1)
|
||||
libv8 (~> 3.16.14.0)
|
||||
ref
|
||||
thor (0.18.1)
|
||||
tilt (1.4.1)
|
||||
treetop (1.4.15)
|
||||
polyglot
|
||||
polyglot (>= 0.3.1)
|
||||
turn (0.9.6)
|
||||
ansi
|
||||
tzinfo (0.3.38)
|
||||
uglifier (2.4.0)
|
||||
execjs (>= 0.3.0)
|
||||
json (>= 1.8.0)
|
||||
|
||||
PLATFORMS
|
||||
ruby
|
||||
|
||||
DEPENDENCIES
|
||||
debugger
|
||||
jquery-rails
|
||||
rails (= 3.2.15)
|
||||
rinruby
|
||||
rubyzip
|
||||
sass-rails (~> 3.2.3)
|
||||
sqlite3
|
||||
therubyracer
|
||||
turn
|
||||
uglifier
|
@ -0,0 +1,18 @@
|
||||
Copyright 2012 The Board of Regents of the University of Wisconsin System.
|
||||
Contributors: Jason Shao, James McCurdy, Enhai Xie, Adam G.W. Halstead,
|
||||
Michael H. Whitney, Nathan DiPiazza, Trey K. Sato and Yury V. Bukhman
|
||||
|
||||
This file is part of GCAT.
|
||||
|
||||
GCAT is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
GCAT is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with GCAT. If not, see <http://www.gnu.org/licenses/>.
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue