{ "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 .\n\n# GCAT version 5.00\n# Notes by Jason\n# 08/18/2011\n\n# Initialization\n\n\nPLATE.LETTERS = paste(rep(c(\"\", LETTERS), each = 26), rep(LETTERS, 26), sep=\"\")\nglobal.version.number = packageDescription(pkg=\"GCAT\")$Version \n\n########################################################################\n# #\n# Top-level functions for analysis of screening data from .csv files. #\n# #\n########################################################################\n# This functions is called directly by the user interface.\n# They in turn call the main function (below) multiple times for each data file provided in . \n\n# Arguments:\n# file.list - a list of full paths to .csv files. all files must be in the same format (see )\n# single.plate - are the file in the single plate (wide) format vs. the multi-plate (long) format?\n# layout.file - (optional) provide full path to a layout file with strain and media definitions (applies to all files in list)\n\n# out.dir - name a directory to output the table of curve parameters to (defaults to working directory) \n# graphic.dir - name a directory to output the images of the fitted curves to (defaults to subdirectory \"pics\" of above)\n\n\n# add.constant- should be a numeric constant that will be added to each curve before the log transform (defaults to 1) \n# 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. \n# start.index - which timepoint should be used as the first one after inoculation (defaults to the 2th one)\n# growth.cutoff - minimum threshold for curve growth. \n# points.to.remove - a list of numbers referring to troublesome points that should be removed across all wells.\n# remove.jumps - should the slope checking function be on the lookout for large jumps in OD?\n \n# silent - should messages be returned to the console?\n# verbose - should sub-functions return messages to console? (when I say verbose, I mean it!)\n\n# Returns:\n# if = F (default), avector of full paths to all the files generated by the function.\n# otherwise, the fitted array of well objects. \n\n# Use this function to analyze any set of .csv files using the same plate layout info. \n\n#' Analyze screening growth data from the given .csv files.\n#' \n#' Top-level GCAT function \n#' \n#' @param file.list A list of full paths to .csv files. all files must be in the same format (see )\n#' @param single.plate The file in the single plate (wide) format vs. the multi-plate (long) format?\n#' @param layout.file Full path to a layout file with strain and media definitions (applies to all files in list)\n#' @param out.dir A directory to output the table of curve parameters to (defaults to working directory) \n#' @param graphic.dir A directory to output the images of the fitted curves to (defaults to subdirectory \"pics\" of above)\n#' @param use.linear.param Whether to use linear parameters or not?\n#' @param use.loess Whether to use LOESS model or not?\n#' @param smooth.param Smoothing parameter for LOESS model.\n#' @param add.constant A numeric constant that will be added to each curve before the log transform (defaults to 1) \n#' @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. \n#' @param start.index Which timepoint should be used as the first one after inoculation (defaults to the 2th one)\n#' @param growth.cutoff Minimum threshold for curve growth. \n#' @param points.to.remove A list of numbers referring to troublesome points that should be removed across all wells.\n#' @param remove.jumps Should the slope checking function be on the lookout for large jumps in OD?\n#' @param time.input The time setting in which the current system is running?\n#' @param plate.nrow The number of rows in a plate.\n#' @param plate.ncol The number of columns in a plate.\n#' @param input.skip.lines If specified, this number of lines shall be skipped from the top when reading the input file with read.csv \n#' @param multi.column.headers The headers of the result tabular data when analyzing multiple plates at once.\n#' @param single.column.headers The headers of the result tebaular data when analyzaing a single plate.\n#' @param layout.sheet.headers The headers of the layout file?\n#' @param silent Shoulde messages be returned to the console?\n#' @param verbose Should sub-functions return messages to console? (when I say verbose, I mean it!)\n#' @param overview.jpgs Should GCAT enable an overview image?\n#' \n#' @return A list of the output files.\ngcat.analysis.main = function(file.list, single.plate, layout.file = NULL, \n out.dir = getwd(), graphic.dir = paste(out.dir, \"/pics\", sep = \"\"), \n add.constant = 0.1, blank.value = NULL, start.index = 2, growth.cutoff = 0.05,\n use.linear.param = F, use.loess = F, 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 = T, verbose = F, return.fit = F, overview.jpgs = T){\n\n # MB: Prototyping system unwanted argument guarding. Proper function \n # will be added in the future.\n # Not the best solution.\n if (is.na(time.input)) {\n if (single.plate)\n time.input = 1/3600\n else\n exception(\"Error: \", \"time.input is NA.\")\n }\n \n if (add.constant < 0)\n exception(\"Error: \", \"The constant r should not be negative.\")\n # End prototyping temporary solution.\n \n upload.timestamp = strftime(Sys.time(), format=\"%Y-%m-%d %H:%M:%S\") # Get a timestamp for the time of upload. \n fitted.well.array.master = list()\n source.file.list = c()\n \n dim(fitted.well.array.master) = c(plate.nrow,plate.ncol,0)\n dimnames(fitted.well.array.master) = list(PLATE.LETTERS[1:plate.nrow], 1:plate.ncol, c())\n \n for(file.name in file.list){\n \n # Call on the file with single plate options\n \tfitted.well.array = try(gcat.fit.main(file.name = file.name, load.type = \"csv\", \n single.plate = single.plate, layout.file = layout.file, start.index = start.index, \n time.input = time.input, add.constant = add.constant, blank.value = blank.value, \n growth.cutoff = growth.cutoff, points.to.remove = points.to.remove, remove.jumps = remove.jumps,\n \t use.linear.param=use.linear.param, use.loess=use.loess, smooth.param=smooth.param,\n plate.nrow = plate.nrow, plate.ncol = plate.ncol, multi.column.headers = multi.column.headers, \n single.column.headers = single.column.headers, layout.sheet.headers = layout.sheet.headers,\n input.skip.lines = input.skip.lines, silent = silent, verbose = verbose), silent = T)\n \n # Return error message if the function fails.\n if(class(fitted.well.array) == \"try-error\")\n return(as.character(fitted.well.array)) \n }\n \n # Add fitted well array onto existing fitted wells\n fitted.well.array.master = gcat.append.arrays(fitted.well.array.master, fitted.well.array, plate.ncol, plate.nrow)\n \n # Remove the \"processed_\" tag from file names and add to the list of source files.\n source.file.list = c(source.file.list, basename(paste(strsplit(file.name, \"processed_\")[[1]],collapse=\"/\"))) \n\n out.files = try(gcat.output.main(fitted.well.array.master, out.prefix = \"output\", \n source.file.list = source.file.list, upload.timestamp = upload.timestamp, \n growth.cutoff = growth.cutoff, add.constant = add.constant, blank.value = blank.value, start.index = start.index, \n points.to.remove = points.to.remove, remove.jumps = remove.jumps, \n out.dir = out.dir, graphic.dir = graphic.dir, overview.jpgs=overview.jpgs,\n use.linear.param=use.linear.param, use.loess=use.loess, plate.ncol = plate.ncol, plate.nrow = plate.nrow,\n silent = silent), silent = T)\n \n # Return file list or error message otherwise return \"successful analysis\" message (?)\n\n # file.list = c(\"Data was successfully analyzed.\", file.list) # <--- yet to be implemented. causes errors downstream right now \n if(class(out.files) == \"try-error\") return(as.character(out.files)) \n \n if(return.fit) return(fitted.well.array.master)\n else return(out.files) \n}\n\n########################################################################\n# #\n# Main function for analysis of screening data from input tables. #\n# #\n########################################################################\n# This is the main function that handles all the analyses for files in both single and multiple plate formats. \n# It is called by the top level function \n#\n# It then calls the following functions on each member of the array: \n# - curve normalization and standardization: , , , , \n# - curve shape analysis before model fitting: , , \n# - to fit a nonlinear model to the growth data: \n# Finally, it returns the fitted array of well objects.\n\n#' Main analysis function for GCAT \n#' \n#' This is the main function that handles all the analyses for data files in both single and multiple plate formats. \n#' It is called by the top level function \\code{gcat.analysis.main} along with \\code{gcat.output.main}.\n#' \n#' @param file.name Complete path and file name of a comma-separated values (.csv) file containing growth curve data \n#' in the multiple-plate (long) format. \n#' @param input.data A list of tables representing input files read with \\code{read.table}. Used to save time in cases\n#' of running multiple analyses on the same dataset. If used, the function will ignore \\code{file.name} entirely.\n#' @param load.type .csv by default. \n#' @param layout.file Specifies the location of a layout file containing identifying information.\n#' @param single.plate Whether the GCAT is analyzing a single plate or not.\n#' @param blank.value Blank OD measurement for uninoculated wells. By default(NULL), the value of the first OD\n#'measurement in each well is used.\n#' @param start.index Which timepoint should be used as the first one after inoculation?\n#' @param time.input Either a character describing the format used to convert timestamps in the input to numbers\n#' representing number of seconds (see \\code{strptime}), or a factor to divide entries in the Time column by to get the \n#' numbers of hours.\n#' @param normalize.method Describes the method used by \\code{normalize.ODs} to normalize cell density values using blank reads.\n#' @param add.constant A value for r in the log(OD + r) transformation.\n#' @param use.log Should the analysis use log on all values.\n#' @param points.to.remove A vector of integers specifying which timepoints should be removed across all wells. \n#' By default(0) none are marked for removal.\n#' @param use.linear.param Should the linear parameter be used or not.\n#' @param use.loess Should the loess model be used or not.\n#' @param smooth.param If loess model is used, this parameter define the smoothing parameter for the loess model.\n#' @param fall.cutoff A cutoff used by \\code{check.slopes} to decide on thresholds for jumps and tanking.\n#' @param growth.cutoff A threshold used by check.growth to decide whether a well displays growth.\n#' @param remove.jumps Should jumps in OD detected by the subfunction \\code{check.slopes}?\n#' @param plate.nrow The number of rows in the input files.\n#' @param plate.ncol The number of columns in the input files.\n#' @param input.skip.lines If specified, this number of lines shall be skipped from the top when reading the input file with read.csv \n#' @param multi.column.headers The headers of the column when analyzing multiple plates.\n#' @param single.column.headers The headers of the column when analyzing a single plate.\n#' @param layour.sheet.headers The headers of the layout file.\n#' @param growth.model What growth model should be used?\n#' @param backup.growth.model If the main growth model fails, the back up model will be used.\n#' @param silent Surpress all messages.\n#' @param verbose Display all messages when analyzing each well.\n#' \n#' @return An array of well objects \ngcat.fit.main = function(file.name, input.data = NULL, load.type = \"csv\", layout.file = NULL, \n single.plate = F, blank.value = NULL, start.index = 2, time.input = NA,\n normalize.method = \"default\", add.constant = 1, use.log = T, points.to.remove = 0,\n use.linear.param=F, use.loess=F, smooth.param=0.1,\n fall.cutoff = -0.0025, growth.cutoff = 0.05, remove.jumps = F, \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 growth.model = NA, backup.growth.model = NA, \n silent = F, verbose = F){\n \n # Explanation of arguments:\n \n # ---File Handling---\n # file.name - full path to an excel spreadsheet, .csv or tab-delimited text file, in either the single or multiple-plate format\n # input.data - use pre-loaded data set (output from function only). will override if not NULL \n # load.type - supports \"csv.\" \n # layout.file - full path to a file containing the plate layout in the same format as . will not be used if is \"xlsx\"\n\n # ---Input file format---\n # single.plate - true denotes data in single-plate format, i.e. simple OD output. false denotes multiple-plate robotic screening output. \n # note: reading directly from excel to R results in timestamps being converted to days.\n\n # ---Normalization and Transforms---\n # 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. \n # start.index - which timepoint should be used as the first one after inoculation (defaults to the 2th one)\n # normalize.method - how should each growth curve be normalized? allowed values are:\n # \"first\": subtracts the first OD, assumed to be the blank, from all ODs\n # \"none\": does nothing, assumes no blank. highly recommend log(OD+1) transform in this case.\n # \"average.first\": forces all filled wells on each plate to match the average value at (after subtracting the first OD) \n # add.constant - a numeric constant that will be added to each curve before the log transform (defaults to 1)\n # use.log - should a log transform be applied to the data after normalization? \n # points.to.remove - a list of numbers referring to troublesome points that should be removed across all wells.\n \n # ---Pre-fitting processing---\n # fall.cutoff - a cutoff value for determining whether OD falls significantly between two timepoints. see in prefit.processing.R for details. \n # growth.cutoff - a cutoff value for determining whether a well contains a successfully growing culture or not.\n # remove.jumps - should the slope checking function be on the lookout for large jumps in OD?\n \n # ---Model fitting---\n # 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\"\n # backup.model - which model should be used if fitting using fails? should ideally be simpler than the main model (less parameters)\n \n # ---Miscellanous input/output preferences---\n # silent - should messages be returned to the console?\n # verbose - should sub-functions return messages to console? (when I say verbose, I mean it!) \n # unlog - should exported graphics be transformed back to the OD scale? \n # return.fit - should the function return an array of wells? if not, it will return a list of generated files. \n \n \t\n ########################################################################\n # Read from .csv file #\n ########################################################################\n #\n # The functions used here are found in table2well.R\n \n if(!silent) cat(\"\\nReading input files...\")\n # Read from .csv or tab-delimited text file using (in load.R)\n # if is provided, it will be used here. \n \n plate.layout = NULL \n # Read layout file if it is specified. \n if(!is.null(layout.file)){\n if(load.type==\"csv\") plate.layout = read.csv(layout.file,header=T,stringsAsFactors=F)\n else plate.layout = read.table(layout.file,header=T,sep=\"\\t\",stringsAsFactors=F) \n if(!silent) cat(\"\\n\\tAdded plate layout information from\", layout.file, \"\\n\")\n }\n \n # Load the data \n\t\twell.array = try(gcat.load.data(file.name = file.name, input.data = input.data, \n plate.layout = plate.layout, plate.nrow = plate.nrow, plate.ncol = plate.ncol, \n input.skip.lines = input.skip.lines, multi.column.headers = multi.column.headers, \n single.column.headers = single.column.headers, layout.sheet.headers = layout.sheet.headers,\n blank.value = blank.value, start.index = start.index, single.plate = single.plate, \n load.type = load.type, silent=silent),silent=silent)\n\n # Return an error if there is a problem with file loading. \n if (class(well.array) == \"try-error\")\n \tstop(\"Error in : \", well.array)\n\t\t\n\n # !---At this point, is an array of well objects, each containing raw data and media/strain information if provided--- \n \n # Attempt to apply time formatting to all wells in array \n well.array = try(aapply(well.array, gcat.start.times, start.index = start.index, time.input = time.input),silent=silent)\n \n # Return an error if there is a problem with time formatting\n if (class(well.array) == \"try-error\")\n \tstop(\"Error in : \", well.array)\n \t\n ########################################################################\n # Perform normalization and transformation of raw data #\n ######################################################################## \n #\n # The functions used here are found in normalize.and.transform.R \n \n if(!silent) cat(\"\\nProcessing raw data...\")\n \n # Set all timepoints to active for now using \"points.to.remove=0\" argument with \n # adds an extra column to the \"well.array\" slot of each well specifying which points to remove when data is retrieved from the well\n well.array = aapply(well.array, remove.points, points = 0)\n \n # Normalize ODs using specified method and adding a constant if desired. \n # sets the \"norm\" slot of each well to a value to be subtracted from OD values whenever data is retrieved from the well\n well.array = try(normalize.ODs(well.array, normalize.method = normalize.method, \n start.index = start.index, blank.value = blank.value, add.constant = add.constant),silent=silent)\n \n # Return an error if there is a problem with normalization\n if (class(well.array) == \"try-error\")\n \tstop(\"Error in : \", well.array)\n \n # Transform ODs on the logarithmic scale, regardless of whether is true \n # an extra column of log-transformed values is added to the \"well.array\" slot of each well \n # 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.\n 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)\n \n # Return an error if there is a problem with transformation\n if (class(well.array) == \"try-error\")\n \tstop(\"Error in : \", well.array)\n \n # Remove specified timepoints across wells (use \"points.to.remove=NULL\" if no points to remove) \n well.array = try(aapply(well.array, remove.points, points = points.to.remove),silent=silent)\n \n # Return an error if there is a problem with point removal\n if (class(well.array) == \"try-error\")\n stop(\"Error in : \", well.array) \n \n \n \n ########################################################################\n # Pre-fitting data processing (analysis of curve shapes) #\n ######################################################################## \n #\n # The functions used here are found in slope.analysis.R\n \n # Estimate slope at each timepoint \n # add a column to the \"well.array\" slot of each well with the local slope at each timepoint \n \n well.array = try(aapply(well.array, calculate.slopes, silent=!verbose),silent=silent)\n \n # Return an error if there is a problem with slope calculation\n if (class(well.array) == \"try-error\")\n \tstop(\"Error in : \", well.array)\n \n # Check slopes for tanking and/or jumping behavior\n # fills the \"curve.par\" slot of each well with , denoting the timepoint at which tanking starts (if none, value is NA) \n # uses to remove all points after \n # It will also fill the \"jump.error\" slot with a status message, and try to use an automated process to remove the \n # erroneous points if is true (default false). \n \n well.array = try(aapply(well.array, check.slopes, fall.cutoff = fall.cutoff, remove.jumps = remove.jumps, silent=!verbose, draw = F),silent=silent)\n \n # Return an error if there is a problem with slope analysis\n if (class(well.array) == \"try-error\")\n \tstop(\"Error in : \", well.array)\n \t\n \t\n # Check curves for growth above cutoff\n # fills the \"curve.par\" slot of each well with , denoting whether the well has no detectable growth. \n well.array = try(aapply(well.array, check.growth, growth.cutoff = growth.cutoff, start.index = start.index),silent=silent)\n \n # Return an error if there is a problem with growth.check\n if (class(well.array) == \"try-error\")\n \tstop(\"Error in : \", well.array)\n \t\n ########################################################################\n # Fit parameterized models to data #\n ######################################################################## \n #\n # The functions used here are found in fit.model.R \n \n # Fit each well with the selected model and attempt to catch failed fittings with the backup model \n # skips wells designated as above\n # fills the \"fit.info\" slot of each well with \"success,\" \"failed,\" or \"skipped\"\n # if fit was successful:\n # fills the \"equation\" and \"model.name\" slots with the relevant info for the successful model \n # fills the \"fit.par\" slot with fitted parameters if fit is successful \n \n if(!silent) cat(\"\\nFitting models to data...\")\n well.array = aapply(well.array, fit.model, growth.model=growth.model,\n backup.growth.model = backup.growth.model, use.linear.param=use.linear.param,\n use.loess=use.loess, smooth.param=smooth.param, silent=!verbose)\n \n # Return an error if there is a problem with model fitting\n if (class(well.array) == \"try-error\")\n \tstop(\"Error in : \", well.array)\n \n if(!silent) cat(\"\\ndone!\\n\") \n return(well.array) \n } \n \n \n########################################################################\n# #\n# Output function for generating files from fitted data. #\n# #\n######################################################################## \n#' Output function for generating files from fitted data.\n#' \n#' Handles files and directories, calls \\code{table.out}, \\code{plate.overview} and \\code{view.fit} \n#' to generate output tables and graphics.\n#' \n#' @param fitted.well.array A list of fitted well objects.\n#' @param out.prefix Prefix that is in the name of output files.\n#' @param blank.value User can enter a blank OD measurement for uninoculated wells. \n#' If NULL, defaults to the value of the first OD measurement of each well.\n#' @param start.index Which timepoint should be used as the first one after inoculation (defaults to the 2th one)\n#' @param growth.cutoff Minimum threshold for curve growth.\n#' @param points.to.remove A list of numbers referring to troublesome points that should be removed across all wells.\n#' @param remove.jumps Should the slope checking function be on the lookout for large jumps in OD?\n#' @param out.dir name a directory to output the table of curve parameters to (defaults to working directory) \n#' @param graphic.dir name a directory to output the images of the fitted curves to \n#' (defaults to subdirectory \"pics\" of above)\n#' @param overview.jpgs should jpgs be generated for each plate with the overview graphic? \n#' This is for backwards compatibility with the old web server. \n#' @param silent should messages be returned to the console?\n#' @param unlog should exported graphics be transformed back to the OD scale?\n#' @param constant.added (should be the same value as add.constant above) - \n#' used to readjust for the constant added during the log transform when plotting ODs. \n#' @return A list of output files if success.\n\ngcat.output.main = function(fitted.well.array, out.prefix = \"\", source.file.list, upload.timestamp = NULL, \n add.constant, blank.value, start.index, growth.cutoff, points.to.remove, remove.jumps, \n out.dir = getwd(), graphic.dir = paste(out.dir,\"/pics\",sep = \"\"), overview.jpgs = T,\n use.linear.param=F, use.loess=F, plate.nrow = 8, plate.ncol = 12,\n unlog = F, silent = T){ \n \n # Prepare timestamp for addition to output file names. \n filename.timestamp = strftime(upload.timestamp, format=\"_%Y-%m-%d_%H.%M.%S\")\n \t\n ########################################################################\n # Prepare to write to output files #\n ######################################################################## \t\n\t if(is.null(blank.value)) blank.value = \"First timepoint in well\"\n\t \n if(!silent) cat(\"\\nFinding/creating new output directories...\")\n \n old.wd = getwd() \n # Create output directory if it doesn't exist\n if(class(try(setwd(out.dir), silent = T)) == \"try-error\"){\n \tif(!silent) cat(\"\\ncreating new output directory\")\n \tif (class(try(dir.create(out.dir))) == \"try-error\")\n \t\tstop(\"Error creating new output directory!\")\n \t}\n \n # Create graphics directory if it doesn't exist\n if(class(try(setwd(graphic.dir), silent = T)) == \"try-error\"){\n \tif(!silent) cat(\"\\ncreating new graphics directory\")\n \tif (class(try(dir.create(graphic.dir))) == \"try-error\")\n \t\tstop(\"Error creating new graphics directory!\")\n \t}\n \t\n ########################################################################\n # Populate a data table with fit results and write to file #\n ######################################################################## \n # \n # The functions used here are found in table.output.R \n \n # Creates a table with a row for each well and a column for each of various identifiers and fitted and calculated parameters. \n \n if(!silent) cat(\"\\nPopulating data table...\")\n 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))\n \n # Return an error if there is a problem with returning the table\n if (class(fitted.well.array) == \"try-error\")\n \tstop(\"Error in : \", fitted.well.array)\n \t\n \t\n # Set working directory to \n\tif (class(try(setwd(out.dir))) == \"try-error\")\n\t\tstop(\"Error setting directory for table output\")\n\t\t\n\t# Write output table to file in \n table.filename = paste(out.dir, \"/\", out.prefix, \"_gcat.fit\", filename.timestamp, \".txt\", sep = \"\")\n if (class(try(write.table(table.fit, table.filename, sep = \"\\t\", row.names = F))) == \"try-error\")\n\t\tstop(\"Error writing tabular output\")\n\t\t\n \t# ---If successfully written, add postscript and start a list of generated files.\t\n generated.files = table.filename\n\n ########################################################################\n # Write individual fit and overview graphics to file #\n ######################################################################## \n # \n # The functions used here are found in graphic.output.R\n \n if(!silent) cat(\"\\nDrawing graphics...\")\n \n # Set working directory to \n\tif (class(try(setwd(graphic.dir))) == \"try-error\")\n\t\tstop(\"Error setting directory for graphic output\")\n\t# Use function to write fit graphics to file. \n \n\tgraphic.files = try(pdf.by.plate(fitted.well.array, out.prefix=out.prefix, upload.timestamp = upload.timestamp, \n unlog=unlog,constant.added=add.constant,overview.jpgs=overview.jpgs, plate.ncol = plate.ncol, plate.nrow = plate.nrow),silent=silent)\n \n if (class(graphic.files) == \"try-error\")\n\t\tstop(\"Error in : \", graphic.files)\n \n # If successfully written, add to the list of generated files.\t\n generated.files = c(generated.files, graphic.files)\n \n ########################################################################\n # Add a postscript to the output table with legend and file info. #\n ######################################################################## \n # \t\n sink(table.filename, append = T)\n analysis.timestamp = strftime(Sys.time(), format=\"%Y-%m-%d %H:%M:%S\")\n 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 \"\\n# Values are reported on the above 'log.OD' scale unless otherwise specified.\",\n \"\\n# .SE columns report standard errors of those values that are estimated directly as parameters of global sigmoid models.\",\n \"\\n# .OD columns report values back-transformed to the linear 'OD - blank' scale.\",\n \"\\n\")\n \n cat(\"\\n# -- Explanation of columns --\",\n \"\\n# - model: Name of the model the well was successfully fit with (if any)\",\n \"\\n# - lag.time: Lag time estimate inferred from the fitted model\",\n \"\\n# - inflection.time: inflection time point of the growth curve when drawn on the log scale\",\n \"\\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 \"\\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 \"\\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 \"\\n# - plateau: upper asymptote value of the fitted model. Global sigmoid model: plateau = b + A. LOESS: plateau = max.log.OD\",\n \"\\n# - inoc.log.OD: log.OD value at inoculation. Estimated value from the fitted model is used, rather than the actual measurement\", \n \"\\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 \"\\n# - projected.growth: maximal projected growth over inoculation value. Global sigmoid model: projected.growth = plateau - inoc.log.OD. LOESS: not reported\",\n \"\\n# - achieved.growth: maximal growth over inoculation value actually achieved during the experiment. achieved.growth = max.log.OD - inoc.log.OD\",\n \"\\n# - shape.par: shape parameter of the Richard equation\",\n \"\\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 \"\\n# - RSS: residual sum of squares. Another goodness of fit metric. Smaller values indicate better fits.\",\n \"\\n# - empty: (Well indicator)\", \n \"\\n# - an 'E' indicates that the well was empty and no growth was detected. \",\n \"\\n# - an 'I' indicates that the well was inoculated and growth was detected above the threshold. \",\n \"\\n# - an 'E*' indicates that the well was empty and growth was detected (possible contamination). \",\n \"\\n# - an '!' indicates that the well was inoculated and no growth was detected. \",\n \"\\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 \"\\n# - tank: (Tanking indicator) If a number is present then the growth trend was determined to tank at that timepoint index.\", \n \"\\n# - other: Additional flag column. Displays information about whether jumps in OD were detected and what was done about them.\",\n \"\\n# - pdf.file and page.no: location of the figure for this well in the output .pdf files.\"\n )\n \n\t # Analysis information \n \n cat(\"\\n#\\n# -- Source file information--\",\n \"\\n# \", paste(source.file.list, collapse = \"\\n# \"), \n \"\\n# analyzed using GCAT v\", global.version.number, \n \"\\n# request sent: \", upload.timestamp, \n \"\\n# completed: \", analysis.timestamp, \n \"\\n#\\n# -- Parameters used in current analysis --\",\n \"\\n# - Constant added to log(OD + n) transformation:\", add.constant,\n \"\\n# - Blank OD value: \", blank.value,\n \"\\n# - Index of inoculation timepoint\", start.index,\n \"\\n# - Minimum growth threshold:\", growth.cutoff, \n \"\\n# - Removed points:\", paste(points.to.remove, collapse = \" \"),\n \"\\n# - Jump detection:\", remove.jumps) \n sink()\n \n ########################################################################\n # Return values to R #\n ######################################################################## \n # \n\n if(!silent) cat(\"\\ndone!\") \n setwd(old.wd)\n # Return list of generated files\n\treturn(generated.files)\n }\n \n", "created" : 1425413277808.000, "dirty" : false, "encoding" : "UTF-8", "folds" : "", "hash" : "1165231602", "id" : "3DC2D3DA", "lastKnownWriteTime" : 1428438949, "path" : "~/Documents/GCAT4/trunk/R/GCAT/R/GCAT.main.R", "project_path" : "R/GCAT.main.R", "properties" : { }, "source_on_save" : false, "type" : "r_source" }