--- title: "Basic example" output: rmarkdown::html_vignette vignette: > %\VignetteIndexEntry{Basic example} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} --- ```{r, include = FALSE} knitr::opts_chunk$set( collapse = TRUE, comment = "#>" ) ``` ```{r setup} library(designit) library(ggplot2) library(dplyr) library(tidyr) ``` # Plate layout with two factors ## The samples Samples of a 2-condition in-vivo experiment are to be placed on 48 well plates. These are the conditions ```{r} # conditions to use conditions <- data.frame( group = c(1, 2, 3, 4, 5), treatment = c( "vehicle", "TRT1", "TRT2", "TRT1", "TRT2" ), dose = c(0, 25, 25, 50, 50) ) gt::gt(conditions) ``` We will have 3 animals per groups with 4 replicates each ```{r} # sample table (2 animals per group with 3 replicates) n_reps <- 4 n_animals <- 3 animals <- bind_rows(replicate(n_animals, conditions, simplify = FALSE), .id = "animal" ) samples <- bind_rows(replicate(n_reps, animals, simplify = FALSE), .id = "replicate" ) |> mutate( SampleID = paste0(treatment, "_", animal, "_", replicate), AnimalID = paste0(treatment, "_", animal) ) |> mutate(dose = factor(dose)) samples |> head(10) |> gt::gt() ``` ## Plate layout requirements Corner wells of the plates should be left empty. This means on a 48 well plate we can place 44 samples. Since we have `r nrow(samples)` samples, they will fit on `r ceiling(nrow(samples)/44)` plates ```{r} n_samp <- nrow(samples) n_loc_per_plate <- 48 - 4 n_plates <- ceiling(n_samp / n_loc_per_plate) exclude_wells <- expand.grid(plate = seq(n_plates), column = c(1, 8), row = c(1, 6)) ``` ## Setting up a Batch container Create a BatchContainer object that provides all possible locations ```{r} bc <- BatchContainer$new( dimensions = c("plate" = n_plates, "column" = 8, "row" = 6), exclude = exclude_wells ) bc bc$n_locations bc$exclude bc$get_locations() |> head() ``` ## Moving samples Use random assignment function to place samples to plate locations ```{r} bc <- assign_random(bc, samples) bc$get_samples() bc$get_samples(remove_empty_locations = TRUE) ``` Plot of the result using the `plot_plate` function ```{r, fig.width=6, fig.height=3.5} plot_plate(bc, plate = plate, column = column, row = row, .color = treatment, .alpha = dose ) ``` To not show empty wells, we can directly plot the sample table as well ```{r, fig.width=6, fig.height=3.5} plot_plate(bc$get_samples(remove_empty_locations = TRUE), plate = plate, column = column, row = row, .color = treatment, .alpha = dose ) ``` To move individual samples or manually assigning all locations we can use the `batchContainer$move_samples()` method To swap two or more samples use: **Warning**: This will change your BatchContainer in-place. ```{r, fig.width=6, fig.height=3.5} bc$move_samples(src = c(1L, 2L), dst = c(2L, 1L)) plot_plate(bc$get_samples(remove_empty_locations = TRUE), plate = plate, column = column, row = row, .color = treatment, .alpha = dose ) ``` To assign all samples in one go, use the option `location_assignment`. **Warning**: This will change your BatchContainer in-place. The example below orders samples by ID and adds the empty locations afterwards ```{r, fig.width=6, fig.height=3.5} bc$move_samples( location_assignment = c( 1:nrow(samples), rep(NA, (bc$n_locations - nrow(samples))) ) ) plot_plate(bc$get_samples(remove_empty_locations = TRUE, include_id = TRUE), plate = plate, column = column, row = row, .color = .sample_id ) ``` ## Run an optimization The optimization procedure is invoked with e.g. `optimize_design`. Here we use a simple shuffling schedule: swap 10 samples for 100 times, then swap 2 samples for 400 times. To evaluate how good a layout is, we need a scoring function. This function will assess how well treatment and dose are balanced across the two plates. ```{r} bc <- optimize_design(bc, scoring = osat_score_generator( batch_vars = "plate", feature_vars = c("treatment", "dose") ), # shuffling schedule n_shuffle = c(rep(10, 200), rep(2, 400)) ) ``` Development of the score can be viewed with ```{r, fig.width=3.5, fig.height=3} bc$plot_trace() ``` The layout after plate batching looks the following ```{r, fig.width=6, fig.height=3.5} plot_plate(bc$get_samples(remove_empty_locations = TRUE), plate = plate, column = column, row = row, .color = treatment, .alpha = dose ) ``` Looking at treatment, we see it's evenly distributed across the plates ```{r, fig.width=4, fig.height=3.5} ggplot( bc$get_samples(remove_empty_locations = TRUE), aes(x = treatment, fill = treatment) ) + geom_bar() + facet_wrap(~plate) ``` ## Customizing the plate layout To properly distinguish between empty and excluded locations one can do the following. * Supply the BatchContainer directly * set `add_excluded = TRUE`, set `rename_empty = TRUE` * supply a custom color palette * excluded wells have NA values and can be colored with `na.value` ```{r, fig.width=6, fig.height=3.5} color_palette <- c( TRT1 = "blue", TRT2 = "purple", vehicle = "orange", empty = "white" ) plot_plate(bc, plate = plate, column = column, row = row, .color = treatment, .alpha = dose, add_excluded = TRUE, rename_empty = TRUE ) + scale_fill_manual(values = color_palette, na.value = "darkgray") ``` To remove all empty wells from the plot, hand the pruned sample list. to plot_plate rather than the whole BatchContainer. You can still assign your own colors. ```{r, fig.width=6, fig.height=3.5} plot_plate(bc$get_samples(remove_empty_locations = TRUE), plate = plate, column = column, row = row, .color = treatment, .alpha = dose ) + scale_fill_viridis_d() ``` Note: removing all empty and excluded wells will lead to omitting completely empty rows or columns! ```{r, fig.width=6, fig.height=3.5} plot_plate(bc$get_samples(remove_empty_locations = TRUE) |> filter(column != 2), plate = plate, column = column, row = row, .color = treatment, .alpha = dose ) + scale_fill_viridis_d() ```