# generateDesign generic and methods
#' @include DREList.R SynergyScreen.R
NULL
#### generateDesign generic ####
#' Generate design of microtiter plate-based synergy screening experiments.
#'
#' Design specifies compound treatments, untreated controls and blanks that go in each well of a set of
#' microtiter plates.
#'
#' @param object an object of supported type, e.g. \code{DREList} or \code{SynergyScreen}
#' @param ... method-specific arguments: see below
#' @param type design type. Supported types include "5 doses exp", "8 doses linear", "12 doses exp",
#' and "custom". See Details.
#' @param dre.orientation character. Must be set if \code{type}="custom".
#' Specifies if dose-response experiments are to be in rows or columns.
#' Supported values are "rows" and "columns"
#' @param control.orientation character. Must be set if \code{type}="custom".
#' Specifies if untreated controls are to be in rows or columns.
#' Supported values are "rows" and "columns"
#' @param dose.series.type character type of dose series. Must be set if \code{type}="custom".
#' Supported values are "linear" and "exp".
#' @param use.edge logical. Must be set if \code{type}="custom".
#' Specifies if wells at the edge of the plate, e.g. rows "A" and "H" and columns "1" and "12",
#' are to be used for dose series and untreated controls or left blank.
#' @param singles logical: if singles = T, include dose-response experiments for individual compounds
#' (\code{SynergyScreen} method)
#' @param pairs logical: if pairs = T, include dose-response experiments for compound pairs
#' (\code{SynergyScreen} method)
#' @param digits number of decimal places in dose values
#'
#' @return
#' \describe{
#' \item{SynergyScreen method}{returns a SynergyScreen object with populated @@design, @@dre_list and,
#' if \code{pairs=T}, @@synergy_experiment_list slots}
#' \item{DREList method}{returns a data frame that represents experimental design}
#' }
#'
#' @details
#' Screen design is represented as a data frame. A \code{\linkS4class{SynergyScreen}} object has slots
#' @@design for a design data frame, @@dre_list for a \code{\linkS4class{DREList}} object
#' and @@synergy_experiment_list for a \code{\linkS4class{SynergyExperimentList}} object.
#' The SynergyScreen method populates all of these based on data in its @@compound_list slot, i.e. max
#' and min doses of each compound, and the desired design type.
#'
#' A \code{\linkS4class{DREList}} object contains a list of dose-response experiment objects (of class
#' \code{\linkS4class{DRE}}). The DREList method produces a design data frame based on the contents of
#' a DREList object.
#'
#' Plate layout is determined by parameter \emph{type}. If \code{type="custom"}, the user must manually
#' set parameters \emph{dre.orientation, control.orientation, dose.series.type, and use.edge}. These
#' settings determine how many dose-response experiments can fit on a [96-well] plate.
#' \emph{generateDesign} computes the minimum necessary number of plates. Each plate must contain at
#' least one row or column of untreated controls, where cell cultures are allowed to grow on media
#' without any of the drugs or toxins beign investigated in the dose-response experiments. If there is
#' space for more than one row or column of controls per plate, \emph{generateDesign} distributes them
#' evenly amongst the plates.
#'
#' The following pre-configured plate layout types are supported:
#' \describe{
#' \item{5 doses exp}{
#' generates a 96-well plate design where border rows and columns are left blank (e.g. filled with
#' buffer), row B is untreated controls and the rest of the plate contains 10 dose-response experiments.
#' Each dose-response experiment contains 5 doses of a compound or mixture.
#' These 5 doses are in the same column, in wells C-G. The doses form exponential series,
#' e.g. 1,2,4,8,16.
#' This design corresponds to \code{dre.orientation="columns"; control.orientation="rows";
#' dose.series.type="exp"; use.edge=FALSE}
#' }
#' \item{8 doses linear}{
#' generates a 96-well plate design where each column from 1 to 11 contains a dose-response experiment.
#' Each experiment has 8 doses of a compound or mixture. The doses form linear series, e.g.
#' 1,2,3,4,5,6,7,8. The last column (12) contains 8 untreated control wells.
#' This design corresponds to \code{dre.orientation="columns"; control.orientation="columns";
#' dose.series.type="linear"; use.edge=TRUE}
#' }
#' \item{12 doses exp}{
#' generates a 96-well plate design where each row from A to G contains a dose-response experiment.
#' Each experiment has 12 doses of a compound or mixture. The doses form exponential series,
#' e.g. 1,2,4,8,16,32,64,128,256,512,1024,2048.
#' The last row (H) contains 12 untreated control wells.
#' This design corresponds to \code{dre.orientation="rows"; control.orientation="rows";
#' dose.series.type="exp"; use.edge=TRUE}
#' }
#' }
#'
#' The current implementation supports mixtures of no more than 2 compounds and no replicates. However,
#' if replicates are desired, the user may simply run the same design more than once.
#'
#' @seealso \code{\linkS4class{SynergyScreen}}, \code{\linkS4class{DREList}}, \code{\linkS4class{DRE}},
#' \code{\linkS4class{SynergyExperimentList}}, \code{\linkS4class{SynergyExperiment}}
#'
setGeneric("generateDesign", function(object,...) standardGeneric("generateDesign"))
#### DREList generateDesign method ####
#' @describeIn generateDesign Generate design from a \code{DREList} object
#'
#' Taking a \code{DREList} object as input, generate a microtiter plate design showing what to put in
#' each well.
#'
setMethod("generateDesign", "DREList",
function(object, dre.orientation, control.orientation, use.edge, digits=3) {
# Debug
#browser()
# Check validity of arguments
stopifnot(dre.orientation %in% c("rows","columns"),
control.orientation %in% c("rows","columns"),
is.logical(use.edge),
is.numeric(digits), digits>0
)
# compute the max number of dose-response experiments that can fit on one plate
max.dres.per.plate = ifelse(dre.orientation == "rows",8,12)
if (dre.orientation == control.orientation) max.dres.per.plate = max.dres.per.plate - 1
if (!use.edge) max.dres.per.plate = max.dres.per.plate - 2
# compute the number of plates needed for the screen
num.plates = length(object)/max.dres.per.plate
# number of plates must be an integer
num.plates = ceiling(num.plates)
# compute the number of dose-response experiments per plate. Some plates will have one
# dre more if the number of dres is not a multiple of the number of plates
dres.per.plate = floor(length(object)/num.plates)
num.extra.dres = length(object)%%num.plates
# initialize design
design = data.frame(plate = rep(1:num.plates,each=96),
column = rep(rep(1:12,each=8),num.plates),
row = rep(rep(LETTERS[1:8],12),num.plates)
)
# fill out experiments, compounds and doses
# - initialize all wells to untreated controls
design$experiment = "untreated"
# - if not using plate edges, overwrite them with blanks
if (!use.edge) {
design$experiment[design$column %in% c(1,12) | design$row %in% c("A","H")] = "blank"
}
# - place compounds and doses
design$cpd1 = as.character(NA)
design$dose1 = as.numeric(NA)
design$cpd2 = as.character(NA)
design$dose2 = as.numeric(NA)
counter = 0 # dose-response experiment counter
if (dre.orientation == "columns") {
# -- dose-response experiments in columns
for (plate in 1:num.plates) {
# -- compute first and last dose-response experiment columns
first.dre.col = 1
if (!use.edge) first.dre.col = 2
last.dre.col = first.dre.col + dres.per.plate - 1
if (plate <= num.extra.dres) last.dre.col = last.dre.col + 1
# - compute rows occupied by dose-response experiments
first.dre.row = 1
if (!use.edge) first.dre.row = 2
if (control.orientation == "rows") first.dre.row = first.dre.row + 1
last.dre.row = 8
if (!use.edge) last.dre.row = 7
dre.rows = LETTERS[first.dre.row:last.dre.row]
# -- Set up dose-response experiments one by one
for (column in first.dre.col:last.dre.col) {
counter = counter + 1
filt = design$plate == plate & design$column == column & design$row %in% dre.rows
if (counter <= length(object)){
dre = object[[counter]]
design$experiment[filt] = dre@name
design$cpd1[filt] = dre@compound.name[1]
design$dose1[filt] = round(dre@fraction[1] * dre@dose, digits)
if (length(dre@compound.name)==2) {
design$cpd2[filt] = dre@compound.name[2]
design$dose2[filt] = round(dre@fraction[2] * dre@dose, digits)
}
}
}
}
} else if (dre.orientation == "rows") {
# -- dose-response experiments in rows
for (plate in 1:num.plates) {
# -- compute first and last dose-response experiment rows
first.dre.row = 1
if (!use.edge) first.dre.row = 2
last.dre.row = first.dre.row + dres.per.plate - 1
if (plate <= num.extra.dres) last.dre.row = last.dre.row + 1
# - compute columns occupied by dose-response experiments
first.dre.column = 1
if (!use.edge) first.dre.column = 2
if (control.orientation == "columns") first.dre.column = first.dre.column + 1
last.dre.column = 12
if (!use.edge) last.dre.column = 11
dre.columns = first.dre.column:last.dre.column
# -- Set up dose-response experiments one by one
for (row in LETTERS[first.dre.row:last.dre.row]) {
counter = counter + 1
filt = design$plate == plate & design$row == row & design$column %in% dre.columns
if (counter <= length(object)){
dre = object[[counter]]
design$experiment[filt] = dre@name
design$cpd1[filt] = dre@compound.name[1]
design$dose1[filt] = round(dre@fraction[1] * dre@dose, digits)
if (length(dre@compound.name)==2) {
design$cpd2[filt] = dre@compound.name[2]
design$dose2[filt] = round(dre@fraction[2] * dre@dose, digits)
}
}
}
}
} else {
stop("Unsupported dre.orientation value", dre.orientation)
}
return(design)
})
#### SynergyScreen generateDesign method ####
#' @describeIn generateDesign Taking a \code{SynergyScreen} object as input, generate a microtiter plate
#' design showing what to put in each well.
#'
#' This method also sets up dose-response experiment objects in object@@dre_list
#' and synergy experiment objects in object@@synergy_experiment_list
#'
setMethod("generateDesign", "SynergyScreen",
function(object, type="5 doses exp", dre.orientation=NULL, control.orientation=NULL,
dose.series.type=NULL, use.edge=NULL, singles=T, pairs=T, digits=3) {
# Verify validity of arguments
stopifnot(type %in% c("5 doses exp","8 doses linear","12 doses exp","custom"))
stopifnot(is.logical(singles))
stopifnot(is.logical(pairs))
stopifnot(is.numeric(digits), digits>0)
# Set parameters for pre-configured design types
if (type=="5 doses exp") {
dre.orientation="columns"
control.orientation="rows"
dose.series.type="exp"
use.edge=FALSE
} else if (type=="8 doses linear") {
dre.orientation="columns"
control.orientation="columns"
dose.series.type="linear"
use.edge=TRUE
} else if (type=="12 doses exp") {
dre.orientation="rows"
control.orientation="rows"
dose.series.type="exp"
use.edge=TRUE
}
# Verify design parameters
stopifnot(dre.orientation %in% c("rows","columns"),
control.orientation %in% c("rows","columns"),
dose.series.type %in% c("exp","linear"),
is.logical(use.edge)
)
# Compute number of doses in a dose-response experiment
if (dre.orientation == "rows") {
num.doses = 12
} else if (dre.orientation == "columns") {
num.doses = 8
} else {
stop("Unsupported dre.orientation value: ", dre.orientation)
}
if (!use.edge) num.doses = num.doses - 2
if (dre.orientation != control.orientation) num.doses = num.doses - 1
# Create dose-response experiment objects
dre_list = list()
if (singles) {
# Create single-compound dose-response experiments
dre_list_s = lapply(object@compound_list,
function(x) new("DRE", compound.name = x@name,
compound=object@compound_list, num.doses = num.doses,
dose.series.type = dose.series.type)
)
dre_list = c(dre_list,dre_list_s)
}
if (pairs) {
# Create dose-response experiments for pairs of compounds
dre_list_p = list()
for (i in 1:(length(object@compound_list)-1)) {
for (j in (i+1):length(object@compound_list)) {
dre = new("DRE", compound.name=names(object@compound_list)[c(i,j)],
compound=object@compound_list,
num.doses = num.doses, dose.series.type = dose.series.type)
dre_list_p = c(dre_list_p,dre)
}
}
dre_list = c(dre_list,dre_list_p)
}
# Assign names to the dre_list members and populate object@dre_list
names(dre_list) = sapply(dre_list, function(x) x@name)
object@dre_list = as(dre_list,"DREList")
# Generate design
design = generateDesign(object@dre_list,
dre.orientation=dre.orientation,
control.orientation=control.orientation,
use.edge=use.edge,
digits=digits)
object@design = as(design,"ScreenDesign")
# Create SynergyExperiment objects
if (pairs) {
synergy_experiment_list = list()
for (dre in dre_list_p) {
exp1 = new("SynergyExperiment",
mixture.dre.name=dre@name, compound.dre.name=dre@compound.name, dre.list = dre_list)
synergy_experiment_list = c(synergy_experiment_list,exp1)
}
names(synergy_experiment_list) = sapply(synergy_experiment_list, function(x) x@name)
object@synergy_experiment_list = as(synergy_experiment_list,"SynergyExperimentList")
}
# All done
return(object)
})
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.