R/is_well_on_edge.R

Defines functions is_well_on_edge

Documented in is_well_on_edge

# WARNING - Generated by {fusen} from dev/flat_utils.Rmd: do not edit by hand

#' Identify the wells on the plate's edge
#'
#'
#' @details
#' Flag the wells located on the edges of a 96- or 384-well plate, based on the following well numbering:
#'
#' * Well numbers start at 1
#' * Well are numbered from left to right and then top to bottom of the plate.
#'
#' @param well_number A vector of positive numeric well identifier
#' @param plate_layout An integer indicating the maximum number of well on the plate
#' @param edges A character vector pointing which plate edges should be considered
#' @param details A logical controlling whether a [data.frame] with more details should be returned
#'
#' @return A logical vector, the same length as `well_number` indicating whether the well is on the edge. If `details = TRUE`, the function returns a [data.frame] that complements the logical vector with the `well_number`, row and column positions.
#' @export
#'
#' @examples
#' # Logical vector indicating whether the wells are on the four edges
#' is_well_on_edge(1:96, plate_layout = 96)
#' # More details can be obtained to verify the results
#' well_df <- is_well_on_edge(1:96, plate_layout = 96, details = TRUE)
#' # And the resulting prediction displayed
#' matrix(well_df$is_edge, ncol = max(well_df$col), byrow = TRUE)
is_well_on_edge <- function(
    well_number,
    plate_layout = c(96, 384),
    edges = c("top", "bottom", "left", "right"),
    details = FALSE) {
  if (!is.numeric(well_number)) {
    stop("The well number is not an numeric vector")
  }
  if (any(well_number <= 0)) {
    stop("The well number is not a positive only vector")
  }
  if (plate_layout != 96 & plate_layout != 384) {
    stop(
      "The expected plate layouts are 96 or 384 wells."
    )
  }
  if (any(max(well_number, plate_layout) > plate_layout)) {
    stop(
      "The well number vector has elements that exceeds the expected maximum",
      " well number for a plate layout of ", plate_layout, " wells."
    )
  }
  well_number <- as.integer(well_number)

  row_col_max <- c("row" = 8, "col" = 12)
  if (plate_layout == 384) {
    row_col_max <- 2 * row_col_max
  }

  # Convert well number to
  #   row identifier with the integer part of the division
  #     shifted by 1 (because 1-index in plates)
  #   col identifier with the modulo(remaining) of the division
  row_positions <- ((well_number - 1) %/% row_col_max["col"]) + 1 # modulo
  col_positions <- ((well_number - 1) %% row_col_max["col"]) + 1 # integer div

  mat <- cbind(row_positions, col_positions)
  colnames(mat) <- c("row", "col")
  # Being on the edge:
  #   top: row 1; all columns
  #   left: all rows; col 1
  #   bottom: last row; all columns
  #   right: all rows; last col

  edge_type <- list(
    "top" = apply(mat, 1, function(coord) {
      coord[1] == 1 & coord[2] <= row_col_max["col"]
    }),
    "bottom" = apply(mat, 1, function(coord) {
      coord[1] == row_col_max["row"] & coord[2] <= row_col_max["col"]
    }),
    "left" = apply(mat, 1, function(coord) {
      coord[1] <= row_col_max["row"] & coord[2] == 1
    }),
    "right" = apply(mat, 1, function(coord) {
      coord[1] <= row_col_max["row"] & coord[2] == row_col_max["col"]
    })
  )
  # Keep only the wanted edges and combine logical with OR
  edges <- match.arg(edges, several.ok = TRUE)
  edge_type <- edge_type[edges]
  is_edge <- Reduce(`|`, edge_type)

  if (isTRUE(details)) {
    return(data.frame(well_number, mat, is_edge, row.names = NULL))
  }
  return(unname(is_edge))
}

Try the maldipickr package in your browser

Any scripts or data that you put into this service are public.

maldipickr documentation built on Sept. 13, 2024, 1:12 a.m.