diff --git a/.nojekyll b/.nojekyll new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/.nojekyll @@ -0,0 +1 @@ + diff --git a/404.html b/404.html new file mode 100644 index 00000000..03d99437 --- /dev/null +++ b/404.html @@ -0,0 +1,149 @@ + + + + + + + +Page not found (404) • designit + + + + + + + + + + + + + + + + + + +
+
+ + + + +
+
+ + +Content not found. Please use links in the navbar. + +
+ + + +
+ + + + +
+ + + + + + + + diff --git a/CODE_OF_CONDUCT.html b/CODE_OF_CONDUCT.html new file mode 100644 index 00000000..3748845d --- /dev/null +++ b/CODE_OF_CONDUCT.html @@ -0,0 +1,122 @@ + +Contributor Code of Conduct • designit + + +
+
+ + + +
+
+ + +
+ +

As contributors and maintainers of this project, we pledge to respect all people who contribute through reporting issues, posting feature requests, updating documentation, submitting pull requests or patches, and other activities.

+

We are committed to making participation in this project a harassment-free experience for everyone, regardless of level of experience, gender, gender identity and expression, sexual orientation, disability, personal appearance, body size, race, ethnicity, age, or religion.

+

Examples of unacceptable behavior by participants include the use of sexual language or imagery, derogatory comments or personal attacks, trolling, public or private harassment, insults, or other unprofessional conduct.

+

Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct. Project maintainers who do not follow the Code of Conduct may be removed from the project team.

+

Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by opening an issue or contacting one or more of the project maintainers.

+

This Code of Conduct is adapted from the Contributor Covenant (https://www.contributor-covenant.org), version 1.0.0, available at https://contributor-covenant.org/version/1/0/0/.

+
+ +
+ + + +
+ + + +
+ + + + + + + + diff --git a/ISSUE_TEMPLATE.html b/ISSUE_TEMPLATE.html new file mode 100644 index 00000000..9fc5a041 --- /dev/null +++ b/ISSUE_TEMPLATE.html @@ -0,0 +1,121 @@ + +NA • designit + + +
+
+ + + +
+
+ + + +

Please DO NOT use any confidential data when submitting an issue. For Roche internal data use code.roche.com.

+

Please briefly describe your problem and what output you expect. If you have a question, please don’t use this form. Instead, ask in the Discussions.

+

When possible, please include a minimal reproducible example (AKA a reprex). If you’ve never heard of a reprex before, start by reading https://www.tidyverse.org/help/#reprex.

+

Brief description of the problem

+
+# insert reprex here
+ + +
+ + + +
+ + + +
+ + + + + + + + diff --git a/LICENSE-text.html b/LICENSE-text.html new file mode 100644 index 00000000..8a45bfb9 --- /dev/null +++ b/LICENSE-text.html @@ -0,0 +1,116 @@ + +License • designit + + +
+
+ + + +
+
+ + +
YEAR: 2022
+COPYRIGHT HOLDER: Iakov I. Davydov, Juliane Siebourg-Polster, Guido Steiner, Balazs Banfai, F. Hoffman-La Roche
+
+ +
+ + + +
+ + + +
+ + + + + + + + diff --git a/LICENSE.html b/LICENSE.html new file mode 100644 index 00000000..68ed86d8 --- /dev/null +++ b/LICENSE.html @@ -0,0 +1,120 @@ + +MIT License • designit + + +
+
+ + + +
+
+ + +
+ +

Copyright (c) 2022 Iakov I. Davydov, Juliane Siebourg-Polster, Guido Steiner, Balazs Banfai, F. Hoffman-La Roche

+

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

+

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

+

THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

+
+ +
+ + + +
+ + + +
+ + + + + + + + diff --git a/apple-touch-icon-120x120.png b/apple-touch-icon-120x120.png new file mode 100644 index 00000000..2eb0292f Binary files /dev/null and b/apple-touch-icon-120x120.png differ diff --git a/apple-touch-icon-152x152.png b/apple-touch-icon-152x152.png new file mode 100644 index 00000000..1ef8fa06 Binary files /dev/null and b/apple-touch-icon-152x152.png differ diff --git a/apple-touch-icon-180x180.png b/apple-touch-icon-180x180.png new file mode 100644 index 00000000..4a93ae13 Binary files /dev/null and b/apple-touch-icon-180x180.png differ diff --git a/apple-touch-icon-60x60.png b/apple-touch-icon-60x60.png new file mode 100644 index 00000000..1cae2d51 Binary files /dev/null and b/apple-touch-icon-60x60.png differ diff --git a/apple-touch-icon-76x76.png b/apple-touch-icon-76x76.png new file mode 100644 index 00000000..b480c4d5 Binary files /dev/null and b/apple-touch-icon-76x76.png differ diff --git a/apple-touch-icon.png b/apple-touch-icon.png new file mode 100644 index 00000000..ee61604a Binary files /dev/null and b/apple-touch-icon.png differ diff --git a/articles/NCS22_talk.html b/articles/NCS22_talk.html new file mode 100644 index 00000000..1c30f5fe --- /dev/null +++ b/articles/NCS22_talk.html @@ -0,0 +1,1478 @@ + + + + + + + +designit: a flexible engine to generate experiment layouts • designit + + + + + + + + + + + + + + + + + + + +
+
+ + + + +
+
+ + + + +
+

Introduction +

+

Examples in this vignette are used were used in our presentation.

+

It uses a subset of the longitudinal_subject_samples +dataset.

+
+data("longitudinal_subject_samples")
+
+dat <- longitudinal_subject_samples |>
+  filter(Group %in% 1:5, Week %in% c(1, 4)) |>
+  select(SampleID, SubjectID, Group, Sex, Week)
+
+# for simplicity: remove two subjects that don't have both visits
+dat <- dat |>
+  filter(SubjectID %in%
+    (dat |> count(SubjectID) |> filter(n == 2) |> pull(SubjectID)))
+
+
+subject_data <- dat |>
+  select(SubjectID, Group, Sex) |>
+  unique()
+
+

Batch effects matter +

+

Here’s an example of plate effect. Here both top and bottom rows of +the plate are used as controls.

+

This is the experiment design:

+

+

These are the readouts:

+

+

Due to the plate effect, the control rows are affected differently. +It is virtually impossible to normalize readouts in a meaningful +way.

+
+
+

Go fully random? +

+
    +
  • Could it be sufficient to randomly distribute samples across +batches?
  • +
  • Not necessarily! +
      +
    • Often sample sizes are too small to avoid grouping by change
    • +
    • Experimental constraints might not allow for a fully random +layout
    • +
    +
  • +
+

Gone wrong: Random distribution of 31 grouped subjects into 3 batches +turns out unbalanced:

+

+

Block what you can and randomize +what you cannot.” (G. Box, 1978)

+
+
+

designit +

+
+

To avoid batch or gradient effects in complex +experiments, designit is an R package that offers flexible +ways to allocate a given set of samples to experiment +layouts. It’s strength is that it implements a very general +framework that can easily be customized and extended to fit specific +constrained layouts.

+
+
    +
  • Data structure: BatchContainer class +
      +
    • R6 object storing: +
        +
      • Experiment dimensions (cages, plates…)
      • +
      • Sample annotation
      • +
      • Scoring functions for sample distribution
      • +
      +
    • +
    +
  • +
  • Main function: optimize_design() +
      +
    • Optimizes the layout with user defined +
        +
      • Scores for sample distribution
      • +
      • Optimization protocols
      • +
      • Sample shuffling functions
      • +
      +
    • +
    • Returns improved design and optimization trace
    • +
    +
  • +
+
+
+
+

Sample Batching +

+
+

Setup +

+
    +
  • Assign 31 samples to 3 equally sized batches
  • +
  • Balance by: +
      +
    • treatment group (higher priority)
    • +
    • sex (lower priority)
    • +
    +
  • +
+
+bc <- BatchContainer$new(
+  dimensions = list("batch" = 3, "location" = 11)
+) |>
+  assign_random(subject_data)
+

Batch composition before optimization

+

+
+bc$get_samples()
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
batchlocationSubjectIDGroupSex
11NANANA
12P325M
13P103F
... ............
39P313F
310P335M
311P245F
+
+
+
+

Optimization +

+
    +
  • Assign 31 samples to 3 equally sized batches
  • +
  • Balance by: +
      +
    • treatment group (higher priority)
    • +
    • sex (lower priority)
    • +
    +
  • +
+
+bc <- optimize_design(
+  bc,
+  scoring = list(
+    group = osat_score_generator(
+      batch_vars = "batch",
+      feature_vars = "Group"
+    ),
+    sex = osat_score_generator(
+      batch_vars = "batch",
+      feature_vars = "Sex"
+    )
+  ),
+  n_shuffle = 1,
+  acceptance_func =
+    ~ accept_leftmost_improvement(..., tolerance = 0.01),
+  max_iter = 150,
+  quiet = TRUE
+)
+

Batch composition after optimization

+

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
batchlocationSubjectIDGroupSex
11NANANA
12P011F
13P103F
... ............
39P295F
310P335M
311P123F
+
+
+
+
+

Plate layouts +

+
+

Continuous confounding +

+

Assays are often performed in well plates (24, 96, 384)

+

Observed effects

+
    +
  • Edge effects (bad plate sealing)
  • +
  • Gradients (non-equal temperature distribution)
  • +
  • Row / column effects (pipetting issues)
  • +
+

Since plate effects often cannot be avoided, we aim to distribute +sample groups of interest evenly across the plate and adjust for the +effect computationally.

+
+
+

Setup +

+
    +
  • Assume previous batches are 24-well plates
  • +
  • Within plate optimization & across plate blocking
  • +
  • Balanced by: +
      +
    • treatment group (higher priority)
    • +
    • sex (lower priority)
    • +
    +
  • +
+
+set.seed(4)
+
+bc <- BatchContainer$new(
+  dimensions = list("plate" = 3, "row" = 4, "col" = 6)
+) |>
+  assign_in_order(dat)
+
+plot_plate(bc,
+  plate = plate, row = row, column = col,
+  .color = Group, title = "Initial layout by Group"
+)
+plot_plate(bc,
+  plate = plate, row = row, column = col,
+  .color = Sex, title = "Initial layout by Sex"
+)
+

+
+
+

2-step optimization +

+
+

Across plate optimization using osat score as before +

+
+bc1 <- optimize_design(
+  bc,
+  scoring = list(
+    group = osat_score_generator(
+      batch_vars = "plate",
+      feature_vars = "Group"
+    ),
+    sex = osat_score_generator(
+      batch_vars = "plate",
+      feature_vars = "Sex"
+    )
+  ),
+  n_shuffle = 1,
+  acceptance_func =
+    ~ accept_leftmost_improvement(..., tolerance = 0.01),
+  max_iter = 150,
+  quiet = TRUE
+)
+

+
+
+

Within plate optimization using distance based sample scoring +function +

+
+bc2 <- optimize_design(
+  bc1,
+  scoring = mk_plate_scoring_functions(
+    bc1,
+    plate = "plate", row = "row", column = "col",
+    group = "Group"
+  ),
+  shuffle_proposal_func = shuffle_with_constraints(dst = plate == .src$plate),
+  max_iter = 150,
+  quiet = TRUE
+)
+

+
+
+
+

2-step optimization multi_plate_layout() +

+

We are performing the same optimization as before, but using the +multi_plate_layout() function to combine the two steps.

+
+bc <- optimize_multi_plate_design(
+  bc,
+  across_plates_variables = c("Group", "Sex"),
+  within_plate_variables = c("Group"),
+  plate = "plate", row = "row", column = "col",
+  n_shuffle = 2,
+  max_iter = 500 # 2000
+)
+#> 1 ... 2 ... 3 ...
+

+
#> Warning: Removed 4509 rows containing missing values (`geom_line()`).
+#> Warning: Removed 4509 rows containing missing values (`geom_point()`).
+

+
+
+
+

Glimpse on more complex application +

+

Goal:

+
    +
  • Assign 3 treatment conditions to 59 animals, representing 2 relevant +strains
  • +
  • Avoid confounding by sex, weight and age
  • +
+

Constraints:

+
    +
  • Cages host ideally 3 animals (preferably 2-5)
  • +
  • Strain, Sex and Treatment must be homogeneous within a cage
  • +
  • Don’t put males from different litters same cage; litter mixing is +possible for females!
  • +
  • Average weight and age composition comparable between treatment +groups and cages
  • +
  • Avoid animals with identical ear markings in same cage (if +possible)
  • +
  • Treatment distribution across animal subgroups (if specified) has to +be respected
  • +
+

see vignette invivo_study_design for the full story.

+
+
+

Conclusion +

+
    +
  • designit aims to be general and adaptable +
      +
    • One framework to address simple batching as well as complex +multi-step procedures
    • +
    • Easy add-ons: custom scoring-functions, acceptance-criteria and +shuffling-procedures can be passed to optimize_design by the user
    • +
    +
  • +
  • Includes functions and vignettes for frequently used layouts such as +plates.
  • +
+

Acknowledgements

+
    +
  • Martha Serrano
  • +
  • Sabine Wilson
  • +
  • David Jitao Zhang
  • +
  • Fabian Birzele
  • +
  • PMDA group for feedback?
  • +
+

+
+
+ + + +
+ + + + +
+ + + + + + + + diff --git a/articles/NCS22_talk_files/figure-html/unnamed-chunk-12-1.png b/articles/NCS22_talk_files/figure-html/unnamed-chunk-12-1.png new file mode 100644 index 00000000..bbcf6381 Binary files /dev/null and b/articles/NCS22_talk_files/figure-html/unnamed-chunk-12-1.png differ diff --git a/articles/NCS22_talk_files/figure-html/unnamed-chunk-16-1.png b/articles/NCS22_talk_files/figure-html/unnamed-chunk-16-1.png new file mode 100644 index 00000000..491595bf Binary files /dev/null and b/articles/NCS22_talk_files/figure-html/unnamed-chunk-16-1.png differ diff --git a/articles/NCS22_talk_files/figure-html/unnamed-chunk-18-1.png b/articles/NCS22_talk_files/figure-html/unnamed-chunk-18-1.png new file mode 100644 index 00000000..c70d44ae Binary files /dev/null and b/articles/NCS22_talk_files/figure-html/unnamed-chunk-18-1.png differ diff --git a/articles/NCS22_talk_files/figure-html/unnamed-chunk-2-1.png b/articles/NCS22_talk_files/figure-html/unnamed-chunk-2-1.png new file mode 100644 index 00000000..da4435e5 Binary files /dev/null and b/articles/NCS22_talk_files/figure-html/unnamed-chunk-2-1.png differ diff --git a/articles/NCS22_talk_files/figure-html/unnamed-chunk-20-1.png b/articles/NCS22_talk_files/figure-html/unnamed-chunk-20-1.png new file mode 100644 index 00000000..17203669 Binary files /dev/null and b/articles/NCS22_talk_files/figure-html/unnamed-chunk-20-1.png differ diff --git a/articles/NCS22_talk_files/figure-html/unnamed-chunk-22-1.png b/articles/NCS22_talk_files/figure-html/unnamed-chunk-22-1.png new file mode 100644 index 00000000..07c468ec Binary files /dev/null and b/articles/NCS22_talk_files/figure-html/unnamed-chunk-22-1.png differ diff --git a/articles/NCS22_talk_files/figure-html/unnamed-chunk-23-1.png b/articles/NCS22_talk_files/figure-html/unnamed-chunk-23-1.png new file mode 100644 index 00000000..493b0dfa Binary files /dev/null and b/articles/NCS22_talk_files/figure-html/unnamed-chunk-23-1.png differ diff --git a/articles/NCS22_talk_files/figure-html/unnamed-chunk-24-1.png b/articles/NCS22_talk_files/figure-html/unnamed-chunk-24-1.png new file mode 100644 index 00000000..ae63e34c Binary files /dev/null and b/articles/NCS22_talk_files/figure-html/unnamed-chunk-24-1.png differ diff --git a/articles/NCS22_talk_files/figure-html/unnamed-chunk-3-1.png b/articles/NCS22_talk_files/figure-html/unnamed-chunk-3-1.png new file mode 100644 index 00000000..dcb481c1 Binary files /dev/null and b/articles/NCS22_talk_files/figure-html/unnamed-chunk-3-1.png differ diff --git a/articles/NCS22_talk_files/figure-html/unnamed-chunk-5-1.png b/articles/NCS22_talk_files/figure-html/unnamed-chunk-5-1.png new file mode 100644 index 00000000..84a03703 Binary files /dev/null and b/articles/NCS22_talk_files/figure-html/unnamed-chunk-5-1.png differ diff --git a/articles/NCS22_talk_files/figure-html/unnamed-chunk-8-1.png b/articles/NCS22_talk_files/figure-html/unnamed-chunk-8-1.png new file mode 100644 index 00000000..5ba017b2 Binary files /dev/null and b/articles/NCS22_talk_files/figure-html/unnamed-chunk-8-1.png differ diff --git a/articles/basic_examples.html b/articles/basic_examples.html new file mode 100644 index 00000000..09fcb3bc --- /dev/null +++ b/articles/basic_examples.html @@ -0,0 +1,1465 @@ + + + + + + + +Basic example • designit + + + + + + + + + + + + + + + + + + + +
+
+ + + + +
+
+ + + + +
+library(designit)
+library(ggplot2)
+library(dplyr)
+#> 
+#> Attaching package: 'dplyr'
+#> The following objects are masked from 'package:stats':
+#> 
+#>     filter, lag
+#> The following objects are masked from 'package:base':
+#> 
+#>     intersect, setdiff, setequal, union
+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

+
+# 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)
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
grouptreatmentdose
1vehicle0
2TRT125
3TRT225
4TRT150
5TRT250
+
+

We will have 3 animals per groups with 4 replicates each

+
+# 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()
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
replicateanimalgrouptreatmentdoseSampleIDAnimalID
111vehicle0vehicle_1_1vehicle_1
112TRT125TRT1_1_1TRT1_1
113TRT225TRT2_1_1TRT2_1
114TRT150TRT1_1_1TRT1_1
115TRT250TRT2_1_1TRT2_1
121vehicle0vehicle_2_1vehicle_2
122TRT125TRT1_2_1TRT1_2
123TRT225TRT2_2_1TRT2_2
124TRT150TRT1_2_1TRT1_2
125TRT250TRT2_2_1TRT2_2
+
+
+
+

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 60 samples, they will +fit on 2 plates

+
+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

+
+bc <- BatchContainer$new(
+  dimensions = c("plate" = n_plates, "column" = 8, "row" = 6),
+  exclude = exclude_wells
+)
+bc
+#> Batch container with 88 locations.
+#>   Dimensions: plate, column, row
+
+bc$n_locations
+#> [1] 88
+bc$exclude
+#> NULL
+bc$get_locations() %>% head()
+#> # A tibble: 6 × 3
+#>   plate column   row
+#>   <int>  <int> <int>
+#> 1     1      1     2
+#> 2     1      1     3
+#> 3     1      1     4
+#> 4     1      1     5
+#> 5     1      2     1
+#> 6     1      2     2
+
+
+

Moving samples +

+

Use random assignment function to place samples to plate +locations

+
+bc <- assign_random(bc, samples)
+
+bc$get_samples()
+#> # A tibble: 88 × 10
+#>    plate column   row replicate animal group treatment dose  SampleID   AnimalID
+#>    <int>  <int> <int> <chr>     <chr>  <dbl> <chr>     <fct> <chr>      <chr>   
+#>  1     1      1     2 NA        NA        NA NA        NA    NA         NA      
+#>  2     1      1     3 2         2          5 TRT2      50    TRT2_2_2   TRT2_2  
+#>  3     1      1     4 3         2          4 TRT1      50    TRT1_2_3   TRT1_2  
+#>  4     1      1     5 3         3          1 vehicle   0     vehicle_3… vehicle…
+#>  5     1      2     1 NA        NA        NA NA        NA    NA         NA      
+#>  6     1      2     2 NA        NA        NA NA        NA    NA         NA      
+#>  7     1      2     3 2         2          2 TRT1      25    TRT1_2_2   TRT1_2  
+#>  8     1      2     4 1         1          1 vehicle   0     vehicle_1… vehicle…
+#>  9     1      2     5 1         1          2 TRT1      25    TRT1_1_1   TRT1_1  
+#> 10     1      2     6 NA        NA        NA NA        NA    NA         NA      
+#> # ℹ 78 more rows
+bc$get_samples(remove_empty_locations = TRUE)
+#> # A tibble: 60 × 10
+#>    plate column   row replicate animal group treatment dose  SampleID   AnimalID
+#>    <int>  <int> <int> <chr>     <chr>  <dbl> <chr>     <fct> <chr>      <chr>   
+#>  1     1      1     3 2         2          5 TRT2      50    TRT2_2_2   TRT2_2  
+#>  2     1      1     4 3         2          4 TRT1      50    TRT1_2_3   TRT1_2  
+#>  3     1      1     5 3         3          1 vehicle   0     vehicle_3… vehicle…
+#>  4     1      2     3 2         2          2 TRT1      25    TRT1_2_2   TRT1_2  
+#>  5     1      2     4 1         1          1 vehicle   0     vehicle_1… vehicle…
+#>  6     1      2     5 1         1          2 TRT1      25    TRT1_1_1   TRT1_1  
+#>  7     1      3     2 2         1          3 TRT2      25    TRT2_1_2   TRT2_1  
+#>  8     1      3     3 2         3          1 vehicle   0     vehicle_3… vehicle…
+#>  9     1      3     4 2         3          3 TRT2      25    TRT2_3_2   TRT2_3  
+#> 10     1      3     5 3         1          3 TRT2      25    TRT2_1_3   TRT2_1  
+#> # ℹ 50 more rows
+

Plot of the result using the plot_plate function

+
+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

+
+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.

+
+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

+
+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.

+
+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))
+)
+#> Warning in osat_score(bc, batch_vars = batch_vars, feature_vars = feature_vars,
+#> : NAs in features / batch columns; they will be excluded from scoring
+#> Checking variances of 1-dim. score vector.
+#> ... (247.342) - OK
+#> Initial score: 80
+#> Achieved score: 72 at iteration 1
+#> Achieved score: 58 at iteration 2
+#> Achieved score: 52 at iteration 3
+#> Achieved score: 18 at iteration 4
+#> Achieved score: 16 at iteration 6
+#> Achieved score: 14 at iteration 9
+#> Achieved score: 12 at iteration 10
+#> Achieved score: 8 at iteration 11
+#> Achieved score: 4 at iteration 17
+#> Achieved score: 2 at iteration 35
+#> Achieved score: 0 at iteration 58
+

Development of the score can be viewed with

+
+bc$plot_trace()
+

+

The layout after plate batching looks the following

+
+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

+
+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 +
  • +
+
+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.

+
+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!

+
+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()
+

+
+
+
+ + + +
+ + + + +
+ + + + + + + + diff --git a/articles/basic_examples_files/figure-html/unnamed-chunk-10-1.png b/articles/basic_examples_files/figure-html/unnamed-chunk-10-1.png new file mode 100644 index 00000000..2556a32f Binary files /dev/null and b/articles/basic_examples_files/figure-html/unnamed-chunk-10-1.png differ diff --git a/articles/basic_examples_files/figure-html/unnamed-chunk-12-1.png b/articles/basic_examples_files/figure-html/unnamed-chunk-12-1.png new file mode 100644 index 00000000..7fe14903 Binary files /dev/null and b/articles/basic_examples_files/figure-html/unnamed-chunk-12-1.png differ diff --git a/articles/basic_examples_files/figure-html/unnamed-chunk-13-1.png b/articles/basic_examples_files/figure-html/unnamed-chunk-13-1.png new file mode 100644 index 00000000..55b2a3e0 Binary files /dev/null and b/articles/basic_examples_files/figure-html/unnamed-chunk-13-1.png differ diff --git a/articles/basic_examples_files/figure-html/unnamed-chunk-14-1.png b/articles/basic_examples_files/figure-html/unnamed-chunk-14-1.png new file mode 100644 index 00000000..fb5ad783 Binary files /dev/null and b/articles/basic_examples_files/figure-html/unnamed-chunk-14-1.png differ diff --git a/articles/basic_examples_files/figure-html/unnamed-chunk-15-1.png b/articles/basic_examples_files/figure-html/unnamed-chunk-15-1.png new file mode 100644 index 00000000..a264da8b Binary files /dev/null and b/articles/basic_examples_files/figure-html/unnamed-chunk-15-1.png differ diff --git a/articles/basic_examples_files/figure-html/unnamed-chunk-16-1.png b/articles/basic_examples_files/figure-html/unnamed-chunk-16-1.png new file mode 100644 index 00000000..5952f462 Binary files /dev/null and b/articles/basic_examples_files/figure-html/unnamed-chunk-16-1.png differ diff --git a/articles/basic_examples_files/figure-html/unnamed-chunk-17-1.png b/articles/basic_examples_files/figure-html/unnamed-chunk-17-1.png new file mode 100644 index 00000000..89555c88 Binary files /dev/null and b/articles/basic_examples_files/figure-html/unnamed-chunk-17-1.png differ diff --git a/articles/basic_examples_files/figure-html/unnamed-chunk-7-1.png b/articles/basic_examples_files/figure-html/unnamed-chunk-7-1.png new file mode 100644 index 00000000..2dbec1e6 Binary files /dev/null and b/articles/basic_examples_files/figure-html/unnamed-chunk-7-1.png differ diff --git a/articles/basic_examples_files/figure-html/unnamed-chunk-8-1.png b/articles/basic_examples_files/figure-html/unnamed-chunk-8-1.png new file mode 100644 index 00000000..2af4f693 Binary files /dev/null and b/articles/basic_examples_files/figure-html/unnamed-chunk-8-1.png differ diff --git a/articles/basic_examples_files/figure-html/unnamed-chunk-9-1.png b/articles/basic_examples_files/figure-html/unnamed-chunk-9-1.png new file mode 100644 index 00000000..ddb14955 Binary files /dev/null and b/articles/basic_examples_files/figure-html/unnamed-chunk-9-1.png differ diff --git a/articles/custom_shuffle.html b/articles/custom_shuffle.html new file mode 100644 index 00000000..357133aa --- /dev/null +++ b/articles/custom_shuffle.html @@ -0,0 +1,374 @@ + + + + + + + +Using custom shuffle schedule • designit + + + + + + + + + + + + + + + + + + + +
+
+ + + + +
+
+ + + + +
+library(designit)
+library(tidyverse)
+#> ── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
+#>  dplyr     1.1.3      readr     2.1.4
+#>  forcats   1.0.0      stringr   1.5.0
+#>  ggplot2   3.4.4      tibble    3.2.1
+#>  lubridate 1.9.3      tidyr     1.3.0
+#>  purrr     1.0.2     
+#> ── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
+#>  dplyr::filter() masks stats::filter()
+#>  dplyr::lag()    masks stats::lag()
+#>  Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors
+

In this example we would like to distribute animals among cages with +constraints:

+
    +
  • There should be not more than one male per cage.
  • +
  • Number of treatment/control animals should be comparable per +cage
  • +
  • Average weight per cage should be comparable between cages
  • +
+
+set.seed(43)
+samples <- tibble(
+  id = 1:params$n_samples,
+  sex = sample(c("F", "M"), params$n_samples, replace = TRUE, prob = c(0.8, 0.2)),
+  group = sample(c("treatment", "control"), params$n_samples, replace = TRUE),
+  weight = runif(params$n_samples, 20, 30)
+)
+samples %>%
+  head()
+#> # A tibble: 6 × 4
+#>      id sex   group     weight
+#>   <int> <chr> <chr>      <dbl>
+#> 1     1 F     treatment   26.2
+#> 2     2 M     treatment   26.1
+#> 3     3 F     control     26.6
+#> 4     4 F     control     25.4
+#> 5     5 F     treatment   24.3
+#> 6     6 F     treatment   21.5
+
+samples %>%
+  count(sex)
+#> # A tibble: 2 × 2
+#>   sex       n
+#>   <chr> <int>
+#> 1 F        42
+#> 2 M         8
+

We create a BatchContainer with 11 cages and 5 positions +per cage. Note that positions do not actually matter; this is just to +limit the number of animals per cage.

+

We start by assigning samples randomly.

+
+set.seed(42)
+bc <- BatchContainer$new(
+  dimensions = c("cage" = 11, "position" = 5)
+) %>%
+  assign_random(samples)
+bc
+#> Batch container with 55 locations and 50 samples (assigned).
+#>   Dimensions: cage, position
+

Functions to plot number of males per cage, weights per cage and +treatment/control ratios.

+
+males_per_cage <- function(bc) {
+  bc$get_samples() %>%
+    filter(sex == "M") %>%
+    count(cage) %>%
+    ggplot(aes(cage, n)) +
+    geom_col()
+}
+
+weight_d <- function(bc) {
+  bc$get_samples() %>%
+    ggplot(aes(factor(cage), weight)) +
+    geom_violin() +
+    geom_point() +
+    stat_summary(fun = mean, geom = "point", size = 2, shape = 23, color = "red")
+}
+
+group_d <- function(bc) {
+  bc$get_samples(remove_empty_locations = TRUE) %>%
+    ggplot(aes(factor(cage), fill = group)) +
+    geom_bar(position = "fill")
+}
+
+males_per_cage(bc)
+

+
+weight_d(bc)
+#> Warning: Removed 5 rows containing non-finite values
+#> (`stat_ydensity()`).
+#> Warning: Removed 5 rows containing non-finite values (`stat_summary()`).
+#> Warning: Removed 5 rows containing missing values (`geom_point()`).
+

+
+group_d(bc)
+

+

First, we use OSAT scoring function to ensure even distribution of +males among cages. Only cage and sex +interactions are considered in the scoring function. We only use 10 +iterations, since shuffling is limited to locations with males and +enforces change of cage on every iteration.

+
+set.seed(10)
+
+bc <- optimize_design(
+  bc,
+  scoring = osat_score_generator(
+    "cage",
+    "sex"
+  ),
+  shuffle_proposal_func = shuffle_with_constraints(
+    sex == "M",
+    cage != .src$cage
+  ),
+  max_iter = 10
+)
+#> Warning in osat_score(bc, batch_vars = batch_vars, feature_vars = feature_vars,
+#> : NAs in features / batch columns; they will be excluded from scoring
+#> Checking variances of 1-dim. score vector.
+#> ... (21.451) - OK
+#> Initial score: 15.818
+#> Achieved score: 11.818 at iteration 1
+#> Achieved score: 9.818 at iteration 10
+
+bc$plot_trace()
+

+We expect the distribution of males become even, while other variables +are not significantly affected.

+
+males_per_cage(bc)
+

+
+weight_d(bc)
+#> Warning: Removed 5 rows containing non-finite values
+#> (`stat_ydensity()`).
+#> Warning: Removed 5 rows containing non-finite values (`stat_summary()`).
+#> Warning: Removed 5 rows containing missing values (`geom_point()`).
+

+
+group_d(bc)
+

+

Here we only define our custom scoring function which ensures even +distribution of weights and treatment/control groups. Only female +samples are shuffled and male samples are kept in their locations. We +also ensure that on every iteration the cage number is changed; we do +this because position dimension does affect actual animal +allocation.

+
+scoring_f <- function(bc) {
+  samples <- bc$get_samples(include_id = TRUE, as_tibble = FALSE)
+  avg_w <- samples[, mean(weight, na.rm = TRUE)]
+  avg_w_per_cage <- samples[!is.na(weight), mean(weight), by = cage]$V1
+  trt_per_cage <- samples[!is.na(group), sum(group == "treatment") / .N, by = cage]$V1
+
+  w_score <- mean((avg_w - avg_w_per_cage)**2)
+  trt_score <- mean((trt_per_cage - 0.5)**2)
+  w_score + 10 * trt_score
+}
+
+set.seed(12)
+bc <- optimize_design(bc,
+  scoring = scoring_f,
+  shuffle_proposal = shuffle_with_constraints(
+    sex == "F",
+    cage != .src$cage & (is.na(sex) | sex != "M")
+  ),
+  n_shuffle = c(rep(10, 20), rep(5, 20), rep(3, 20), rep(1, 140)),
+  max_iter = 200
+)
+#> Checking variances of 1-dim. score vector.
+#> ... (0.457) - OK
+#> Initial score: 2.657
+#> Achieved score: 1.916 at iteration 2
+#> Achieved score: 1.835 at iteration 5
+#> Achieved score: 1.289 at iteration 9
+#> Achieved score: 1.225 at iteration 10
+#> Achieved score: 1.089 at iteration 11
+#> Achieved score: 1.074 at iteration 16
+#> Achieved score: 1.033 at iteration 18
+#> Achieved score: 0.875 at iteration 19
+#> Achieved score: 0.574 at iteration 22
+#> Achieved score: 0.523 at iteration 23
+#> Achieved score: 0.522 at iteration 32
+#> Achieved score: 0.483 at iteration 41
+#> Achieved score: 0.394 at iteration 49
+#> Achieved score: 0.379 at iteration 67
+#> Achieved score: 0.372 at iteration 73
+#> Achieved score: 0.365 at iteration 84
+#> Achieved score: 0.361 at iteration 90
+#> Achieved score: 0.348 at iteration 96
+#> Achieved score: 0.322 at iteration 102
+#> Achieved score: 0.302 at iteration 131
+#> Achieved score: 0.302 at iteration 141
+#> Achieved score: 0.246 at iteration 165
+#> Achieved score: 0.245 at iteration 166
+#> Achieved score: 0.241 at iteration 184
+#> Achieved score: 0.241 at iteration 191
+#> Achieved score: 0.237 at iteration 196
+bc$plot_trace()
+

+
+scoring_f(bc)
+#> [1] 0.2370109
+

Now we have a much more even distribution of weights and +treatment/control balance.

+
+males_per_cage(bc)
+

+
+weight_d(bc)
+#> Warning: Removed 5 rows containing non-finite values
+#> (`stat_ydensity()`).
+#> Warning: Removed 5 rows containing non-finite values (`stat_summary()`).
+#> Warning: Removed 5 rows containing missing values (`geom_point()`).
+

+
+group_d(bc)
+

+
+ + + +
+ + + + +
+ + + + + + + + diff --git a/articles/custom_shuffle_files/figure-html/unnamed-chunk-10-1.png b/articles/custom_shuffle_files/figure-html/unnamed-chunk-10-1.png new file mode 100644 index 00000000..feb120c3 Binary files /dev/null and b/articles/custom_shuffle_files/figure-html/unnamed-chunk-10-1.png differ diff --git a/articles/custom_shuffle_files/figure-html/unnamed-chunk-10-2.png b/articles/custom_shuffle_files/figure-html/unnamed-chunk-10-2.png new file mode 100644 index 00000000..4fadb7ef Binary files /dev/null and b/articles/custom_shuffle_files/figure-html/unnamed-chunk-10-2.png differ diff --git a/articles/custom_shuffle_files/figure-html/unnamed-chunk-10-3.png b/articles/custom_shuffle_files/figure-html/unnamed-chunk-10-3.png new file mode 100644 index 00000000..b10179b4 Binary files /dev/null and b/articles/custom_shuffle_files/figure-html/unnamed-chunk-10-3.png differ diff --git a/articles/custom_shuffle_files/figure-html/unnamed-chunk-6-1.png b/articles/custom_shuffle_files/figure-html/unnamed-chunk-6-1.png new file mode 100644 index 00000000..8a3b1217 Binary files /dev/null and b/articles/custom_shuffle_files/figure-html/unnamed-chunk-6-1.png differ diff --git a/articles/custom_shuffle_files/figure-html/unnamed-chunk-6-2.png b/articles/custom_shuffle_files/figure-html/unnamed-chunk-6-2.png new file mode 100644 index 00000000..53258003 Binary files /dev/null and b/articles/custom_shuffle_files/figure-html/unnamed-chunk-6-2.png differ diff --git a/articles/custom_shuffle_files/figure-html/unnamed-chunk-6-3.png b/articles/custom_shuffle_files/figure-html/unnamed-chunk-6-3.png new file mode 100644 index 00000000..687d33dc Binary files /dev/null and b/articles/custom_shuffle_files/figure-html/unnamed-chunk-6-3.png differ diff --git a/articles/custom_shuffle_files/figure-html/unnamed-chunk-7-1.png b/articles/custom_shuffle_files/figure-html/unnamed-chunk-7-1.png new file mode 100644 index 00000000..031475e9 Binary files /dev/null and b/articles/custom_shuffle_files/figure-html/unnamed-chunk-7-1.png differ diff --git a/articles/custom_shuffle_files/figure-html/unnamed-chunk-8-1.png b/articles/custom_shuffle_files/figure-html/unnamed-chunk-8-1.png new file mode 100644 index 00000000..feb120c3 Binary files /dev/null and b/articles/custom_shuffle_files/figure-html/unnamed-chunk-8-1.png differ diff --git a/articles/custom_shuffle_files/figure-html/unnamed-chunk-8-2.png b/articles/custom_shuffle_files/figure-html/unnamed-chunk-8-2.png new file mode 100644 index 00000000..4dc3364d Binary files /dev/null and b/articles/custom_shuffle_files/figure-html/unnamed-chunk-8-2.png differ diff --git a/articles/custom_shuffle_files/figure-html/unnamed-chunk-8-3.png b/articles/custom_shuffle_files/figure-html/unnamed-chunk-8-3.png new file mode 100644 index 00000000..94beea9b Binary files /dev/null and b/articles/custom_shuffle_files/figure-html/unnamed-chunk-8-3.png differ diff --git a/articles/custom_shuffle_files/figure-html/unnamed-chunk-9-1.png b/articles/custom_shuffle_files/figure-html/unnamed-chunk-9-1.png new file mode 100644 index 00000000..f5999ad1 Binary files /dev/null and b/articles/custom_shuffle_files/figure-html/unnamed-chunk-9-1.png differ diff --git a/articles/index.html b/articles/index.html new file mode 100644 index 00000000..a3d97a87 --- /dev/null +++ b/articles/index.html @@ -0,0 +1,131 @@ + +Articles • designit + + +
+
+ + + +
+ +
+ + +
+ + + + + + + + diff --git a/articles/invivo_study_design.html b/articles/invivo_study_design.html new file mode 100644 index 00000000..e31b2692 --- /dev/null +++ b/articles/invivo_study_design.html @@ -0,0 +1,2652 @@ + + + + + + + +In-vivo study design • designit + + + + + + + + + + + + + + + + + + + +
+
+ + + + +
+
+ + + + +
+

Purpose of vignette +

+

This example demonstrates how recurring complex design problems of +similar structure may be handled by writing dedicated wrappers that use +designIt functionality in the background while presenting a simplified +interface to the user. These wrapper functions may completely hide the +construction of batch containers, scoring functions and other +fundamental package concepts from the user, allowing to focus on the +correct specification of the concrete design task at hand.

+

We are using the very specific design constraints of certain in +vivo studies as an example. The implementation of the respective +wrapper functions won’t be discussed here, but code may be inspected in +the .Rmd file of the vignette if desired.

+
+
+

Dataset and design task +

+

We would like to assign 3 treatment conditions to a cohort of 59 +animals, representing 2 relevant strains. There are a few concrete user +specified constraints for the study, on top we have to avoid confounding +by common variables such as animal sex, body weight and age.

+

The animal information is provided in a sample sheet, the treatment +list has to be stored separately. The example data we are looking at is +included in the package.

+
+data("invivo_study_samples")
+data("invivo_study_treatments")
+
+

The animal (sample) sheet +

+
+str(invivo_study_samples)
+#> 'data.frame':    59 obs. of  8 variables:
+#>  $ AnimalID           : chr  "F1" "F2" "F3" "F4" ...
+#>  $ Strain             : chr  "Strain B" "Strain B" "Strain B" "Strain B" ...
+#>  $ Sex                : chr  "F" "F" "F" "F" ...
+#>  $ BirthDate          : Date, format: "2021-05-24" "2021-03-01" ...
+#>  $ Earmark            : chr  "R" "2L" "2L1R" "L" ...
+#>  $ ArrivalWeight      : num  19.4 26.5 20.8 22.1 22.9 ...
+#>  $ Arrival.weight.Unit: chr  "g" "g" "g" "g" ...
+#>  $ Litter             : chr  "Litter 1" "Litter 2" "Litter 2" "Litter 2" ...
+
+invivo_study_samples %>%
+  dplyr::count(Strain, Sex, BirthDate) %>%
+  gt::gt()
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
StrainSexBirthDaten
Strain AFNA7
Strain AMNA22
Strain BF2021-03-014
Strain BF2021-04-122
Strain BF2021-05-241
Strain BM2021-02-224
Strain BM2021-03-158
Strain BM2021-04-125
Strain BM2021-05-173
Strain BM2021-05-243
+
+

A simple data summary reveals that the cohort is almost equally +composed of Strains A and B. There are male and female animals in quite +different proportions, with a noticeable excess of the males. Birth +dates are available for Strain A, but missing completely for Strain +B.

+

Initial body weights (arrival weights), identifying ear marks and +litter information are available for all animals. The litter is nested +within the strain and all individuals within one litter naturally share +one birth date.

+
+invivo_study_samples %>%
+  dplyr::count(Strain, Litter, BirthDate) %>%
+  gt::gt()
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
StrainLitterBirthDaten
Strain ALitter 10NA5
Strain ALitter 11NA7
Strain ALitter 12NA7
Strain ALitter 13NA4
Strain ALitter 14NA6
Strain BLitter 12021-05-244
Strain BLitter 22021-03-014
Strain BLitter 32021-04-127
Strain BLitter 42021-03-154
Strain BLitter 52021-02-224
Strain BLitter 62021-03-154
Strain BLitter 72021-05-173
+
+
+
+

Treatment list +

+
+str(invivo_study_treatments)
+#> 'data.frame':    59 obs. of  3 variables:
+#>  $ Treatment: chr  "Treatment 1" "Treatment 1" "Treatment 1" "Treatment 1" ...
+#>  $ Strain   : chr  "Strain A" "Strain A" "Strain A" "Strain A" ...
+#>  $ Sex      : chr  "M" "M" "M" "M" ...
+
+invivo_study_treatments %>%
+  dplyr::count(Treatment, Strain, Sex) %>%
+  gt::gt()
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TreatmentStrainSexn
Treatment 1Strain AM10
Treatment 1Strain BM10
Treatment 2Strain AF5
Treatment 2Strain AM5
Treatment 2Strain BF5
Treatment 2Strain BM5
Treatment 3Strain AM6
Treatment 3Strain BM6
untreatedStrain AF2
untreatedStrain AM1
untreatedStrain BF2
untreatedStrain BM2
+
+

We have 3 treatments that should each be administered to a defined +number of animals. In addition, some satellite animals of either strain +will not receive any treatment at all, which is specified by a fourth +(‘untreated’) condition.

+

In most cases the treatment list could be reduced to the first +column, i.e. repeating each label for the right number of times so that +the total length matches the sample sheet.

+

However, additional study specific constraints may be specified by +adding columns that also appear in the animal list and indicate how the +treatments should be assigned to subgroups of the cohort. In this +example, a different number of animals is used for each of the +treatments, balanced across strains. However, female animals are only to +be used for treatment 2.

+
+
+

Design constraints and data preparation +

+

The specific constraints for our type of in vivo study may +be summarized as follows:

+
    +
  • We want to form cages, each hosting ideally 3 animals (preferred +range from 2-5)
  • +
  • Strain, Sex and Treatment must be homogeneous within a cage
  • +
  • Males from different litters must not be put into the same cage; +litter mixing is possible however for female animals!
  • +
  • Average body weight and age composition should be comparable between +treatment groups and cages
  • +
  • If at all possible, we avoid putting animals with identical ear +markings into the same cage
  • +
  • The distribution of treatments across animal subgroups (if specified +by the treatment list!) has to be respected
  • +
+

The very special and intricate nature of these requirements motivate +th creation of dedicated functionality on top of this package, as +demonstrated by this vignette.

+

Before using these functions, we add two auxiliary columns to the +sample sheet:

+
    +
  • +AgeGroup represents the different birth dates as an +integer variable, where unknown (NA) values get their own code.
  • +
  • +Litter_combine_females groups all female animals in +a pseudo litter, facilitating the assignment of animals to cages at +which point only the females can be freely combined (co-housed).
  • +
+
+invivo_study_samples <- dplyr::mutate(invivo_study_samples,
+  AgeGroup = as.integer(factor(BirthDate, exclude = NULL)),
+  Litter_combine_females = ifelse(Sex == "F", "female_all", Litter)
+)
+
+invivo_study_samples %>%
+  dplyr::count(Strain, Litter_combine_females, BirthDate, AgeGroup) %>%
+  gt::gt()
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
StrainLitter_combine_femalesBirthDateAgeGroupn
Strain ALitter 10NA73
Strain ALitter 11NA74
Strain ALitter 12NA75
Strain ALitter 13NA74
Strain ALitter 14NA76
Strain Afemale_allNA77
Strain BLitter 12021-05-2463
Strain BLitter 32021-04-1245
Strain BLitter 42021-03-1534
Strain BLitter 52021-02-2214
Strain BLitter 62021-03-1534
Strain BLitter 72021-05-1753
Strain Bfemale_all2021-03-0124
Strain Bfemale_all2021-04-1242
Strain Bfemale_all2021-05-2461
+
+
+
+
+

Design steps +

+

The process of solving the design problem can be divided into 3 +successive steps, each of which is addressed by a specific in +vivo-specific wrapper function.

+
    +
  1. Assign treatments to individuals animals (function +InVivo_assignTreatments())

  2. +
  3. Allocate animals to cages (function +Invivo_assignCages())

  4. +
  5. Arrange cages in one or more racks of given dimension (function +Invivo_arrangeCages())

  6. +
+

Dedicated constraints have to be handled at each step, as is +reflected in the interface of those wrappers.

+

As stated above, implementation details are beyond the scope of this +example. We will instead just show the interfaces of the three wrappers, +run the example case and visualize the resulting design.

+
+

Assign treatments to animal list +

+
+InVivo_assignTreatments <- function(animal_list, treatments,
+                                    balance_treatment_vars = c(),
+                                    form_cages_by = c(),
+                                    n_shuffle = c(rep(5, 100), rep(3, 200), rep(2, 500), rep(1, 20000)),
+                                    quiet_process = FALSE, quiet_optimize = TRUE) {
+  (...)
+}
+

The function works with the initial animal and treatment lists.

+

Most importantly, balance_treatment_vars lists the +variables that should be balanced across treatments (e.g. strain, sex, +body weight, age, litter). Different scoring functions will be created +for categorical and numerical covariates.

+

form_cages_by is not mandatory, but gives important +clues regarding the variables that will later be homogeneous within each +cage (e.g. strain, sex, litter). Providing this may be crucial for +finding good solutions with a low number of single-housed animals that +don’t fit into any other cage.

+

It is also possible to modify the shuffling protocol and toggle +messaging on the level of processing steps as well as optimization +iterations.

+
+
+

Populate cages +

+
+Invivo_assignCages <- function(design_trt,
+                               cagegroup_vars,
+                               unique_vars = c(),
+                               balance_cage_vars = c(),
+                               n_min = 2, n_max = 5, n_ideal = 2, prefer_big_groups = TRUE, strict = TRUE,
+                               maxiter = 5e3,
+                               quiet_process = FALSE, quiet_optimize = TRUE) {
+  (...)
+}
+

This wrapper takes the output of the previous step (‘design_trt’) as +input.

+
    +
  • +cagegroup_vars is a list of variables that must be +uniform within each cage (e.g. treatment”, strain, sex, litter).
  • +
  • +unique_vars is a list of variables whose values +should be unique per cage (e.g. ear marking). This constraint will be +relaxed in a stepwise way if no solution can be found under strict +adherence.
  • +
  • +balance_cage_vars lists variables which should be +evenly distributed across cages, as far as possible (e.g. age, body +weight).
  • +
  • +n_min, n_max and +n_ideal specify the minimal, maximal and ideal cage +sizes, respectively. It is often necessary to release the +strict criterion to find any solution at all or reduce +the number of remaining single-housed animals.
  • +
+
+
+

Arrange cages in rack(s) +

+
+Invivo_arrangeCages <- function(design_cage,
+                                distribute_cagerack_vars = "Treatment",
+                                rack_size_x = 4,
+                                rack_size_y = 4,
+                                n_shuffle = c(rep(5, 100), rep(3, 400), rep(2, 500), rep(1, 4000)),
+                                quiet_process = FALSE, quiet_optimize = TRUE) {
+  (...)
+}
+

This wrapper takes the output of the previous step (‘design_cage’) as +input.

+

distribute_cagerack_vars is a list of variables that +should be evenly spaced out across the rows and columns of a rack (or +several racks, if needed). Typical cases may include treatment, strain +and sex of the animals.

+

rack_size_x and rack_size_y specify +the number of cages that fit into the rows and columns of a grid like +rack, respectively. Depending on the actual number of cages, one or more +racks are automatically assigned. Only rectangular sub-grids may be used +of any rack to accommodate the cages.

+
+

+Calculating the design + +

+

+A full run of the three wrapper functions is executed below, printing +messages on the level of processing steps, but not the iterations within +every optimization. +

+
set.seed(44)
+
+# Assign treatments to animals, respecting user provided as well as passed constraints
+design_trt <- InVivo_assignTreatments(invivo_study_samples, invivo_study_treatments,
+  form_cages_by = c("Strain", "Sex", "Litter_combine_females"),
+  balance_treatment_vars = c("Strain", "Sex", "ArrivalWeight", "AgeGroup"),
+  n_shuffle = c(rep(5, 200), rep(3, 300), rep(2, 500), rep(1, 3000)),
+  quiet_process = FALSE,
+  quiet_optimize = TRUE
+)
+#> Performing treatment assignment with constrained animal selection.
+#> Using constraints in variables: Strain, Sex
+#> Checking if solution is possible:
+#>    ... Yes!
+#> Setting up batch container.
+#> Constructing scoring functions:
+#>      ... user specified treatment allocation constraint (Treatment-Strain-Sex)
+#>      ... facilitating homogeneity of treatment in cages (CageGroup)
+#>      ... ANOVA -logP for numerical variables balanced across treatment (ArrivalWeight, AgeGroup)
+#> Success. User provided constraints could be fully met.
+
+# Form cages with reasonable animal numbers and compliant with all constraints
+design_cage <- Invivo_assignCages(design_trt,
+  cagegroup_vars = c("Treatment", "Strain", "Sex", "Litter_combine_females"),
+  unique_vars = c("Earmark"),
+  balance_cage_vars = c("ArrivalWeight", "AgeGroup"),
+  n_min = 2, n_max = 5, n_ideal = 2, prefer_big_groups = T, strict = F,
+  maxiter = 1000,
+  quiet_process = FALSE,
+  quiet_optimize = TRUE
+)
+#> Setting up batch container.
+#> 
+#> Formed 22 homogeneous groups using 59 samples.
+#> 27 subgroups needed to satisfy size constraints.
+#> 
+#> Finding possible ways to allocate variable of interest with 1 levels ...
+#> 
+#> Finished with 27 recursive calls.
+#> 1 allocations found.
+#> 
+#> Expecting 27 cages to be created and 4 single-housed animals.
+#> Constructing scoring functions:
+#>      ... ANOVA -logP for numerical variables balanced across cages (ArrivalWeight, AgeGroup)
+#> Adding 4 attributes to samples.
+
+# Arrange cages in sub-grid of one rack (or several racks), avoiding spatial clusters
+design_rack <- Invivo_arrangeCages(design_cage,
+  distribute_cagerack_vars = c("Treatment", "Strain", "Sex"),
+  rack_size_x = 7,
+  rack_size_y = 10,
+  n_shuffle = c(rep(5, 100), rep(3, 200), rep(2, 300), rep(1, 500)),
+  quiet_process = FALSE,
+  quiet_optimize = TRUE
+)
+#> Needing 1 rack with a grid of 4 x 7 cages.
+#> There will be 1 empty position overall.
+#> Setting up batch container.
+#> 
+#> Distributing target variables (Treatment, Strain, Sex) within rack
+#>    ... Rack 1
+#> ... Performing simple mean/stddev adjustment.
+#>    ... final scores: Plate_Treatment: 5.12, Plate_Strain: 5.48, Plate_Sex: 5.72
+
+
+

+Visualization of the study design + +

+
+

+Cage composition + +

+

+There are 27 cages in total. +

+

+Strains and age groups should be evenly split (balanced) across the +treatments. Also,in each cage there should be only animals with the same +treatment, strain and sex. +

+

+Females are exclusively used for treatment 2, as was specified in the +treatment list. +

+

+

+
+
+

+Body weights + +

+

+Body weights should be balanced across treatments as well as possible. +

+

+The plot illustrates that this is true for the overall weight +distribution (box plots). Interestingly, as there are females +(associated with considerable less body weight) involved in treatment 2, +the optimization favored the selection of heavier males in this group to +compensate, achieving better cross-treatment balance of this factor. +

+

+Red diamonds mark the mean values for a specific sex within each +treatment group. +

+

+

+
+
+

+Cage arrangement in rack + +

+

+The following plots show the organization of the cage rack, individual +cages colored by different variables each time. +

+

+

+
+
+

+Individual animals in cages + +

+

+Finally, an overview plot illustrates the placement of animals in the +cages. Notice the distinct earmarks within each cage, a ‘soft’ design +constraint that could be achieved with the given solution. +

+

+

+
+
+
+
+
+ + + +
+ + + + +
+ + + + + + + + diff --git a/articles/nested_dimensions_examples.html b/articles/nested_dimensions_examples.html new file mode 100644 index 00000000..a83cf9e6 --- /dev/null +++ b/articles/nested_dimensions_examples.html @@ -0,0 +1,883 @@ + + + + + + + +Nested dimension example • designit + + + + + + + + + + + + + + + + + + + +
+
+ + + + +
+
+ + + + +
+library(designit)
+library(tidyverse)
+#> ── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
+#>  dplyr     1.1.3      readr     2.1.4
+#>  forcats   1.0.0      stringr   1.5.0
+#>  ggplot2   3.4.4      tibble    3.2.1
+#>  lubridate 1.9.3      tidyr     1.3.0
+#>  purrr     1.0.2     
+#> ── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
+#>  dplyr::filter() masks stats::filter()
+#>  dplyr::lag()    masks stats::lag()
+#>  Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors
+
+

Sample annotation overview +

+
+data("multi_trt_day_samples")
+

Samples are grouped by Treatment and Collection time with the +following group sizes:

+
+multi_trt_day_samples %>%
+  count(Time, Treatment) %>%
+  gt::gt()
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TimeTreatmentn
4CTRL3
4SOC_TRT14
4SOC_TRT1_TRT23
4SOC_TRT1_TRT34
4SOC_TRT1_TRT3_TRT24
8SOC_TRT13
8SOC_TRT1_TRT23
8SOC_TRT1_TRT34
8SOC_TRT1_TRT3_TRT24
+
+

Total number of samples is: 32

+
+
+

Task +

+

Samples are to be blocked in batches for scRNA-seq.

+
    +
  • 8 samples can be processed per day (batch)
  • +
  • Within day they need to be split into 2 parallel runs (4 + 4).
  • +
+
+
+

Optimize batch +

+
+# Setting up the batch container
+bc <- BatchContainer$new(
+  dimensions = c(
+    batch = ceiling(nrow(multi_trt_day_samples) / 8),
+    run = 2, position = 4
+  )
+)
+
+# Initial random assignment
+bc <- assign_in_order(bc, multi_trt_day_samples)
+bc
+#> Batch container with 32 locations and 32 samples (assigned).
+#>   Dimensions: batch, run, position
+

The samples are distributed to 4 batches (processing days). This is +done using osat scoring on sample Treatment and +Time, optimizing by shuffling.

+
+n_shuffle <- rep(c(32, 10, 2), c(100, 80, 20))
+n_iterations <- length(n_shuffle)
+
+set.seed(42) # should we have conventions for this?
+
+scoring_f <- osat_score_generator(c("batch"), c("Treatment", "Time"))
+bc <- optimize_design(
+  bc,
+  scoring = scoring_f,
+  n_shuffle = n_shuffle,
+  max_iter = n_iterations
+) # default is 10000
+#> Re-defined number of swaps to 16 in swapping function.
+#> Checking variances of 1-dim. score vector.
+#> ... (29.235) - OK
+#> Initial score: 75
+#> Achieved score: 25 at iteration 1
+#> Achieved score: 21 at iteration 2
+#> Achieved score: 15 at iteration 4
+#> Achieved score: 13 at iteration 5
+#> Achieved score: 11 at iteration 95
+#> Achieved score: 9 at iteration 112
+#> Achieved score: 5 at iteration 188
+

NOTE: Here the shuffling procedure is short, as it was optimized for +this vignette. I practice you will have to run for a much higher number +of iterations.

+
+

Optimization trace +

+
+qplot(
+  x = bc$trace$scores[[1]]$step,
+  y = bc$trace$scores[[1]]$score_1,
+  color = factor(c(32, n_shuffle)),
+  main = str_glue("Final score={bc$score(scoring_f)}"), geom = "point"
+)
+#> Warning: `qplot()` was deprecated in ggplot2 3.4.0.
+#> This warning is displayed once every 8 hours.
+#> Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
+#> generated.
+

+
+
+

Final batch layout +

+
+bc$get_samples(assignment = TRUE) %>%
+  mutate(batch = factor(batch)) %>%
+  ggplot(aes(x = batch, fill = Treatment, alpha = factor(Time))) +
+  geom_bar()
+#> Warning: Using alpha for a discrete variable is not advised.
+

+
+
+
+

Repeat but use shuffle with contraints +

+
+# copy batch container for second optimization
+bc2 <- assign_in_order(bc)
+
+n_iterations <- 200
+
+set.seed(42) # should we have conventions for this?
+
+bc2 <- optimize_design(
+  bc2,
+  scoring = scoring_f,
+  shuffle_proposal = shuffle_with_constraints(
+    src = TRUE,
+    # batch needs to change for shuffle to be accepted
+    dst = .src$batch != batch
+  ),
+  max_iter = n_iterations
+)
+#> Checking variances of 1-dim. score vector.
+#> ... (26.382) - OK
+#> Initial score: 75
+#> Achieved score: 67 at iteration 1
+#> Achieved score: 63 at iteration 2
+#> Achieved score: 53 at iteration 3
+#> Achieved score: 49 at iteration 4
+#> Achieved score: 47 at iteration 5
+#> Achieved score: 37 at iteration 6
+#> Achieved score: 35 at iteration 9
+#> Achieved score: 33 at iteration 11
+#> Achieved score: 29 at iteration 13
+#> Achieved score: 27 at iteration 14
+#> Achieved score: 25 at iteration 19
+#> Achieved score: 19 at iteration 20
+#> Achieved score: 17 at iteration 25
+#> Achieved score: 15 at iteration 36
+#> Achieved score: 13 at iteration 40
+#> Achieved score: 11 at iteration 49
+#> Achieved score: 9 at iteration 57
+#> Achieved score: 7 at iteration 79
+#> Achieved score: 5 at iteration 126
+#> Achieved score: 3 at iteration 180
+
+qplot(
+  x = bc2$trace$scores[[1]]$step,
+  y = bc2$trace$scores[[1]]$score_1,
+  main = str_glue("Final score={bc2$score(scoring_f)}"), geom = "point"
+)
+

+
+
+bc2$get_samples(assignment = TRUE) %>%
+  mutate(batch = factor(batch)) %>%
+  ggplot(aes(x = batch, fill = Treatment, alpha = factor(Time))) +
+  geom_bar()
+#> Warning: Using alpha for a discrete variable is not advised.
+

+NOTE: It is not possible to calculate the theoretically minimal osat +score, right?

+
+
+

Optimize runs within batch +

+

Using shuffle with constraints

+

Within each day there will be 2 runs (samples processed together) +with 4 samples each. For this we keep the optimized batch +and now only optimize run with constraint.

+
+n_iterations <- 100
+
+# new optimization function
+scoring_f <- osat_score_generator(c("run"), c("Treatment", "Time"))
+# like this the optimization score is wrong because it tries to optimize across Batches.
+# Possible ways to go:
+# - we'd need something like c("batch", batch/run") for optimize by batch and run within batch.
+# - or we add "batch/run" to the constraints somehow.
+bc$score(scoring_f)
+#> score_1 
+#>      16
+
+bc <- optimize_design(
+  bc,
+  scoring = scoring_f,
+  shuffle_proposal = shuffle_with_constraints(
+    src = TRUE,
+    # batch remains the same and run needs to change
+    dst = batch == .src$batch & run != .src$run
+  ),
+  max_iter = n_iterations
+)
+#> Checking variances of 1-dim. score vector.
+#> ... (36.071) - OK
+#> Initial score: 16
+#> Achieved score: 14 at iteration 2
+#> Achieved score: 8 at iteration 4
+#> Achieved score: 6 at iteration 10
+#> Achieved score: 4 at iteration 11
+#> Achieved score: 2 at iteration 16
+
+qplot(
+  x = bc$trace$scores[[1]]$step,
+  y = bc$trace$scores[[1]]$score_1,
+  color = factor(n_iterations),
+  main = str_glue("Final score={bc$score(scoring_f)}"), geom = "point"
+)
+

+
+

Final run layout +

+

This is not giving the expected mix of treatments across runs.

+
+bc$get_samples() %>%
+  mutate(run = factor(run)) %>%
+  ggplot(aes(x = run, fill = Treatment, alpha = factor(Time))) +
+  geom_bar() +
+  facet_wrap(~batch)
+#> Warning: Using alpha for a discrete variable is not advised.
+

+
+
+
+ + + +
+ + + + +
+ + + + + + + + diff --git a/articles/nested_dimensions_examples_files/figure-html/unnamed-chunk-10-1.png b/articles/nested_dimensions_examples_files/figure-html/unnamed-chunk-10-1.png new file mode 100644 index 00000000..24c47eaf Binary files /dev/null and b/articles/nested_dimensions_examples_files/figure-html/unnamed-chunk-10-1.png differ diff --git a/articles/nested_dimensions_examples_files/figure-html/unnamed-chunk-11-1.png b/articles/nested_dimensions_examples_files/figure-html/unnamed-chunk-11-1.png new file mode 100644 index 00000000..78b5bbb0 Binary files /dev/null and b/articles/nested_dimensions_examples_files/figure-html/unnamed-chunk-11-1.png differ diff --git a/articles/nested_dimensions_examples_files/figure-html/unnamed-chunk-6-1.png b/articles/nested_dimensions_examples_files/figure-html/unnamed-chunk-6-1.png new file mode 100644 index 00000000..2b15edaf Binary files /dev/null and b/articles/nested_dimensions_examples_files/figure-html/unnamed-chunk-6-1.png differ diff --git a/articles/nested_dimensions_examples_files/figure-html/unnamed-chunk-7-1.png b/articles/nested_dimensions_examples_files/figure-html/unnamed-chunk-7-1.png new file mode 100644 index 00000000..057a2815 Binary files /dev/null and b/articles/nested_dimensions_examples_files/figure-html/unnamed-chunk-7-1.png differ diff --git a/articles/nested_dimensions_examples_files/figure-html/unnamed-chunk-8-1.png b/articles/nested_dimensions_examples_files/figure-html/unnamed-chunk-8-1.png new file mode 100644 index 00000000..d79f398e Binary files /dev/null and b/articles/nested_dimensions_examples_files/figure-html/unnamed-chunk-8-1.png differ diff --git a/articles/nested_dimensions_examples_files/figure-html/unnamed-chunk-8-2.png b/articles/nested_dimensions_examples_files/figure-html/unnamed-chunk-8-2.png new file mode 100644 index 00000000..4fdfd101 Binary files /dev/null and b/articles/nested_dimensions_examples_files/figure-html/unnamed-chunk-8-2.png differ diff --git a/articles/optimizer_examples.html b/articles/optimizer_examples.html new file mode 100644 index 00000000..021cebbb --- /dev/null +++ b/articles/optimizer_examples.html @@ -0,0 +1,1303 @@ + + + + + + + +Optimizer examples • designit + + + + + + + + + + + + + + + + + + + +
+
+ + + + +
+
+ + + + + +
+

Sample annotation overview +

+
+data("multi_trt_day_samples")
+

Samples are grouped by Treatment and Collection time with the +following group sizes:

+
+multi_trt_day_samples %>%
+  dplyr::count(Time, Treatment) %>%
+  gt::gt()
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TimeTreatmentn
4CTRL3
4SOC_TRT14
4SOC_TRT1_TRT23
4SOC_TRT1_TRT34
4SOC_TRT1_TRT3_TRT24
8SOC_TRT13
8SOC_TRT1_TRT23
8SOC_TRT1_TRT34
8SOC_TRT1_TRT3_TRT24
+
+

Total number of samples is: 32

+
+
+

Task +

+

Samples are to be blocked in batches for scRNA-seq.

+
    +
  • 8 samples can be processed per day (batch)
  • +
  • Within day they need to be split into 2 parallel runs (4 + 4).
  • +
+

This data set is also used in the nested dimensions example. Here, we +focus on using different methods for the optimization.

+
+
+

Setting up batch container +

+

We allocate surplus positions in the batch container and some +excluded positions to check that all optimization methods support empty +container positions.

+
+# Setting up the batch container
+bc <- BatchContainer$new(
+  dimensions = c(
+    batch = ceiling(nrow(multi_trt_day_samples) / 8),
+    run = 2, position = 5
+  ),
+  exclude = tibble::tibble(batch = 4, run = c(1, 2), position = c(5, 5))
+) %>%
+  # Add samples to container
+  assign_in_order(samples = multi_trt_day_samples)
+
+bc
+#> Batch container with 38 locations and 32 samples (assigned).
+#>   Dimensions: batch, run, position
+
+
+

First optimization with fixed shuffling protocol +

+

The samples are distributed to 4 batches (processing days). We use +the osat scoring on sample Treatment and Time, +using first a shuffling protocol with a fixed number of sample swaps on +each iteration.

+

Note that doing 32 swaps on 38 free container positions does not make +sense, since each swapping operation affects two different positions +anyway. The upper limit is reduced to the max number of meaningful swaps +(19) on the fly.

+

Optimization finishes after the list of permutations is +exhausted.

+
+n_shuffle <- rep(c(32, 10, 5, 2, 1), c(20, 40, 40, 50, 50))
+
+scoring_f <- osat_score_generator(c("batch"), c("Treatment", "Time"))
+
+bc1 <- optimize_design(
+  bc,
+  scoring = scoring_f,
+  n_shuffle = n_shuffle # will implicitly generate a shuffling function according to the provided schedule
+)
+#> Re-defined number of swaps to 19 in swapping function.
+#> Warning in osat_score(bc, batch_vars = batch_vars, feature_vars = feature_vars,
+#> : NAs in features / batch columns; they will be excluded from scoring
+#> Checking variances of 1-dim. score vector.
+#> ... (30.986) - OK
+#> Initial score: 73.03
+#> Achieved score: 35.03 at iteration 1
+#> Achieved score: 31.241 at iteration 2
+#> Achieved score: 16.82 at iteration 3
+#> Achieved score: 16.504 at iteration 6
+#> Achieved score: 14.609 at iteration 10
+#> Achieved score: 12.504 at iteration 25
+#> Achieved score: 12.188 at iteration 44
+#> Achieved score: 10.083 at iteration 77
+#> Achieved score: 8.504 at iteration 112
+#> Achieved score: 6.399 at iteration 114
+#> Achieved score: 4.504 at iteration 120
+#> Achieved score: 4.188 at iteration 154
+#> Achieved score: 3.873 at iteration 196
+
+bc1$trace$elapsed
+#> Time difference of 2.15546 secs
+
+

Optimization trace +

+

Custom plot with some colours:

+
+bc1$scores_table() %>%
+  dplyr::mutate(
+    n_shuffle = c(NA, n_shuffle)
+  ) %>%
+  ggplot2::ggplot(
+    ggplot2::aes(step, value, color = factor(n_shuffle))
+  ) +
+  ggplot2::geom_point() +
+  ggplot2::labs(
+    title = "Score 1 tracing",
+    subtitle = stringr::str_glue("Final score = {bc1$score(scoring_f)}"),
+    x = "Iteration",
+    y = "Score",
+    color = "n_shuffle"
+  )
+

+

Using the internal method…

+
+bc1$plot_trace()
+

+

We may safely apply the batch container methods get_samples() and +score() also after using the new optimization code.

+
+
+

Final batch layout +

+
+bc1$score(scoring_f)
+#>  score_1 
+#> 3.872576
+
+bc1$get_samples(assignment = TRUE) %>%
+  dplyr::filter(!is.na(Treatment)) %>%
+  dplyr::mutate(anno = stringr::str_c(Time, " hr")) %>%
+  ggplot2::ggplot(ggplot2::aes(x = batch, y = interaction(position, run), fill = Treatment)) +
+  ggplot2::geom_tile(color = "white") +
+  ggplot2::geom_hline(yintercept = 5.5, size = 1) +
+  ggplot2::geom_text(ggplot2::aes(label = anno)) +
+  ggplot2::labs(x = "Batch", y = "Position . Run")
+#> Warning: Using `size` aesthetic for lines was deprecated in ggplot2 3.4.0.
+#>  Please use `linewidth` instead.
+#> This warning is displayed once every 8 hours.
+#> Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
+#> generated.
+

+
+
+

Perform new iterations on optimized batch container +

+

Further optimization (using a different shuffling protocol maybe) can +be done immediately on the same batch container.

+
+n_shuffle <- rep(c(5, 2, 1), c(30, 30, 30))
+
+bc1 <- optimize_design(
+  bc1,
+  scoring = scoring_f,
+  n_shuffle = n_shuffle
+)
+#> Checking variances of 1-dim. score vector.
+#> ... (20.941) - OK
+#> Initial score: 3.873
+
+
+
+

Optimization with specified stopping criteria +

+

Starting optimization from scratch, we are passing now some stopping +criteria that may terminate optimization before a shuffling protocol has +been exhausted.

+

For demonstration, we use a shuffling function now that will do 3 +sample (position) swaps per iteration and can be called an arbitrary +number of times. Thus, iteration has to be stopped by either the +max_iter criterion or by reaching a specific minimum delta threshold +(score improvement from one selected solution to the next).

+
+bc2 <- optimize_design(
+  bc,
+  scoring = scoring_f,
+  n_shuffle = 3, # will implicitly generate a shuffling function that will do 3 swaps at each iteration
+  max_iter = 2000,
+  min_delta = 0.1
+)
+#> Checking variances of 1-dim. score vector.
+#> ... (26.567) - OK
+#> Initial score: 73.03
+#> Achieved score: 57.03 at iteration 1
+#> Achieved score: 45.452 at iteration 2
+#> Achieved score: 39.452 at iteration 3
+#> Achieved score: 25.767 at iteration 4
+#> Achieved score: 23.662 at iteration 7
+#> Achieved score: 19.662 at iteration 9
+#> Achieved score: 18.083 at iteration 10
+#> Achieved score: 16.399 at iteration 11
+#> Achieved score: 12.399 at iteration 17
+#> Achieved score: 10.82 at iteration 21
+#> Achieved score: 8.82 at iteration 43
+#> Achieved score: 6.82 at iteration 79
+#> Achieved score: 6.504 at iteration 151
+#> Achieved score: 4.504 at iteration 186
+#> Achieved score: 2.609 at iteration 314
+#> Achieved score: 2.294 at iteration 1560
+
+
+

Optimization with multi-variate scoring function +

+

Instead of passing a single scoring function, a list of multiple +scoring functions can be passed to the optimizer, each of which to +return a scalar value on evaluation.

+

By default, a strict improvement rule is applied for classifying a +potential solution as “better”: each of the individual scores has to be +smaller than or equal to its previous value, and one of the scores has +to be changed.

+

However, the user could specify other methods for aggregating the +scores or defining the acceptance criterion. See later examples.

+

The second scoring function used here is by the way rather redundant +and just serves for illustration.

+
+multi_scoring_f <- list(
+  osat_score_generator(c("batch"), c("Treatment", "Time")),
+  osat_score_generator(c("batch"), c("Treatment"))
+)
+
+
+bc3 <- optimize_design(
+  bc,
+  scoring = multi_scoring_f,
+  n_shuffle = 3,
+  max_iter = 200,
+  min_delta = 0.1
+)
+#> Warning in osat_score(bc, batch_vars = batch_vars, feature_vars = feature_vars,
+#> : NAs in features / batch columns; they will be excluded from scoring
+
+#> Warning in osat_score(bc, batch_vars = batch_vars, feature_vars = feature_vars,
+#> : NAs in features / batch columns; they will be excluded from scoring
+#> Checking variances of 2-dim. score vector.
+#> ... (27.797, 55.515) - OK
+#> Initial score: c(73.03, 44.803)
+#> Achieved score: c(49.03, 30.803) at iteration 1
+#> Achieved score: c(43.03, 26.803) at iteration 2
+#> Achieved score: c(35.03, 26.803) at iteration 4
+#> Achieved score: c(25.03, 18.803) at iteration 6
+#> Achieved score: c(19.767, 10.277) at iteration 8
+#> Achieved score: c(18.188, 6.909) at iteration 23
+#> Achieved score: c(16.188, 5.014) at iteration 35
+#> Achieved score: c(16.083, 5.014) at iteration 55
+#> Achieved score: c(15.978, 4.909) at iteration 82
+#> Achieved score: c(12.399, 3.751) at iteration 110
+#> Achieved score: c(6.504, 3.751) at iteration 188
+

Note that the first score tends to yield higher values than the +second one. This could be a problem when trying to select a solution +based on an aggregated, overall score. We repeat the same optimization +now by using the autoscaling functionality of the optimizer.

+
+
+

Auto-scaling scores +

+

We’re just adding the autoscale_scores option here to +estimate the distribution of individual scores on a number of completely +random sample assignments (200 in this case) and then apply a +transformation to rescale each score to a standard normal.

+

Note that by ‘normalizing’ the distribution of the scores we obtain +values centered around zero, thus that the optimized scores are likely +to be negative. We may also want to decrease the delta_min parameter to +match the new numerical range.

+
+bc3_as <- optimize_design(
+  bc,
+  scoring = multi_scoring_f,
+  n_shuffle = 3,
+  max_iter = 200,
+  min_delta = 0.01,
+  autoscale_scores = T,
+  autoscaling_permutations = 200
+)
+#> Checking variances of 2-dim. score vector.
+#> ... (22.658, 51.127) - OK
+#> Creating autoscaling function for 2-dim. score vector. (200 random permutations)
+#> ... Performing boxcox lambda estimation.
+#> Initial score: c(6.795, 3.015)
+#> Achieved score: c(4.466, 1.316) at iteration 1
+#> Achieved score: c(3.179, 1.316) at iteration 2
+#> Achieved score: c(1.064, -0.558) at iteration 4
+#> Achieved score: c(0.705, -0.558) at iteration 7
+#> Achieved score: c(-0.068, -1.221) at iteration 8
+#> Achieved score: c(-1.308, -1.448) at iteration 15
+#> Achieved score: c(-1.815, -1.83) at iteration 18
+#> Achieved score: c(-2.947, -2.158) at iteration 29
+#> Achieved score: c(-3.632, -2.158) at iteration 67
+#> Achieved score: c(-3.671, -2.181) at iteration 108
+#> Achieved score: c(-3.671, -2.645) at iteration 121
+#> Achieved score: c(-4.473, -2.645) at iteration 139
+

Having directly comparable scores, it may be reasonable now to use a +function that somehow aggregates the scores to decide on the best +iteration (instead of looking at the scores individually).

+

An easy way to do this is to use the built-in worst_score function. +This will simply set the aggregated score to whichever of the individual +scores is larger (i.e. ‘worse’ in terms of the optimization).

+
+bc4 <- optimize_design(
+  bc,
+  scoring = multi_scoring_f,
+  n_shuffle = 3,
+  aggregate_scores_func = worst_score,
+  max_iter = 200,
+  autoscale_scores = TRUE,
+  autoscaling_permutations = 200
+)
+#> Checking variances of 2-dim. score vector.
+#> ... (28.257, 67.23) - OK
+#> Creating autoscaling function for 2-dim. score vector. (200 random permutations)
+#> ... Performing boxcox lambda estimation.
+#> Initial score: c(6.361, 2.703)
+#>    Aggregated: 6.361
+#> Achieved score: c(5.444, 1.789) at iteration 1
+#>    Aggregated: 5.444
+#> Achieved score: c(4.836, 1.533) at iteration 2
+#>    Aggregated: 4.836
+#> Achieved score: c(3.009, 0.872) at iteration 3
+#>    Aggregated: 3.009
+#> Achieved score: c(1.679, 0.487) at iteration 4
+#>    Aggregated: 1.679
+#> Achieved score: c(0.705, 0.735) at iteration 7
+#>    Aggregated: 0.735
+#> Achieved score: c(0.705, 0.487) at iteration 9
+#>    Aggregated: 0.705
+#> Achieved score: c(-0.435, -0.345) at iteration 15
+#>    Aggregated: -0.345
+#> Achieved score: c(-0.435, -0.662) at iteration 16
+#>    Aggregated: -0.435
+#> Achieved score: c(-1.228, -0.526) at iteration 17
+#>    Aggregated: -0.526
+#> Achieved score: c(-1.752, -0.875) at iteration 20
+#>    Aggregated: -0.875
+#> Achieved score: c(-1.179, -1.948) at iteration 27
+#>    Aggregated: -1.179
+#> Achieved score: c(-1.643, -1.851) at iteration 33
+#>    Aggregated: -1.643
+#> Achieved score: c(-2.18, -2.893) at iteration 82
+#>    Aggregated: -2.18
+#> Achieved score: c(-2.646, -2.665) at iteration 102
+#>    Aggregated: -2.646
+#> Achieved score: c(-4.081, -2.665) at iteration 146
+#>    Aggregated: -2.665
+#> Achieved score: c(-5.029, -2.76) at iteration 192
+#>    Aggregated: -2.76
+#> Achieved score: c(-4.125, -2.826) at iteration 195
+#>    Aggregated: -2.826
+

Another - more interesting - option would be to aggregate the two +scores by taking their sum. This way both scores will influence the +optimization at every step.

+

For illustration, we omit the n_shuffle parameter here, +which will lead by default to pairwise sample swaps being done on each +iteration.

+
+bc5 <- optimize_design(
+  bc,
+  scoring = multi_scoring_f,
+  aggregate_scores_func = sum_scores,
+  max_iter = 200,
+  autoscale_scores = TRUE,
+  autoscaling_permutations = 200
+)
+

As a final example, we calculate the (squared) L2 norm to actually +aggregate the two scores. Not that this choice is not really motivated +in this case, but it could be used if optimization was carried on +meaningful distance vectors or normalized n-tuples.

+

Note that we don’t use the auto-scaling in this case as the L2-norm +based optimization would force both normalized scores towards zero, not +the minimal (negative) value that would be desired in that case.

+
+bc5_2 <- optimize_design(
+  bc,
+  scoring = multi_scoring_f,
+  aggregate_scores_func = L2s_norm,
+  max_iter = 200,
+)
+
+
+

Passing a customized shuffling function +

+

It is recommended to use the n_shuffle parameter to +steer the optimization protocol. However, you may also provide a +dedicated shuffling function that on each call has to return a shuffling +order (as integer vector) or a list with the source and destination +positions (src and dst) of the sample positions to be swapped.

+

The following example uses a template for creating complete random +shuffles across all available positions in the batch container. Note +that this is usually not a good strategy for converging to a +solution.

+
+bc6 <- optimize_design(
+  bc,
+  scoring = scoring_f,
+  shuffle_proposal_func = complete_random_shuffling,
+  max_iter = 200
+)
+#> Checking variances of 1-dim. score vector.
+#> ... (30.855) - OK
+#> Initial score: 73.03
+#> Achieved score: 21.136 at iteration 1
+#> Achieved score: 18.609 at iteration 4
+#> Achieved score: 16.294 at iteration 5
+#> Achieved score: 16.083 at iteration 9
+#> Achieved score: 14.294 at iteration 16
+#> Achieved score: 13.767 at iteration 40
+#> Achieved score: 10.609 at iteration 42
+
+
+

Using simulated annealing (SA) for optimization +

+

Esp. for very large search spaces, better solutions can be quite +successfully obtained by a SA protocol which allows the optimizer to +jump over ‘energy barriers’ to more likely converge at lower local +minima.

+

The optimizer usually remembers the permutation with the best overall +score to start with, but this behavior can be changed by supplying a +simulated annealing protocol, most simply by generating a ready-made +function template.

+

It is generally recommended for SA to make small changes at each +step, like allowing just 1 sample swap per iteration.

+

Currently the simulated annealing protocol requires a single double +value score to be optimized. Choose an appropriate aggregation function +if you happen to have multiple scores initially.

+
+bc7 <- optimize_design(
+  bc,
+  scoring = scoring_f,
+  n_shuffle = 1,
+  acceptance_func = mk_simanneal_acceptance_func(),
+  max_iter = 200
+)
+#> Checking variances of 1-dim. score vector.
+#> ... (38.114) - OK
+#> Initial score: 73.03
+#> Achieved score: 63.03 at iteration 1
+#> Achieved score: 51.03 at iteration 2
+#> Achieved score: 51.03 at iteration 3
+#> Achieved score: 45.03 at iteration 4
+#> Achieved score: 39.03 at iteration 5
+#> Achieved score: 33.03 at iteration 6
+#> Achieved score: 33.03 at iteration 7
+#> Achieved score: 33.03 at iteration 8
+#> Achieved score: 31.03 at iteration 9
+#> Achieved score: 31.03 at iteration 10
+#> Achieved score: 27.03 at iteration 11
+#> Achieved score: 25.03 at iteration 12
+#> Achieved score: 25.03 at iteration 14
+#> Achieved score: 29.03 at iteration 15
+#> Achieved score: 27.03 at iteration 16
+#> Achieved score: 27.03 at iteration 17
+#> Achieved score: 27.03 at iteration 18
+#> Achieved score: 27.03 at iteration 20
+#> Achieved score: 25.03 at iteration 21
+#> Achieved score: 25.03 at iteration 22
+#> Achieved score: 25.03 at iteration 23
+#> Achieved score: 25.03 at iteration 27
+#> Achieved score: 25.03 at iteration 28
+#> Achieved score: 19.03 at iteration 29
+#> Achieved score: 15.03 at iteration 31
+#> Achieved score: 15.03 at iteration 32
+#> Achieved score: 15.03 at iteration 33
+#> Achieved score: 15.03 at iteration 34
+#> Achieved score: 15.03 at iteration 35
+#> Achieved score: 15.03 at iteration 36
+#> Achieved score: 15.03 at iteration 37
+#> Achieved score: 13.452 at iteration 39
+#> Achieved score: 13.452 at iteration 40
+#> Achieved score: 13.767 at iteration 43
+#> Achieved score: 13.767 at iteration 47
+#> Achieved score: 13.767 at iteration 48
+#> Achieved score: 11.767 at iteration 49
+#> Achieved score: 11.767 at iteration 50
+#> Achieved score: 11.662 at iteration 52
+#> Achieved score: 11.662 at iteration 57
+#> Achieved score: 11.662 at iteration 63
+#> Achieved score: 10.083 at iteration 65
+#> Achieved score: 10.083 at iteration 70
+#> Achieved score: 8.083 at iteration 72
+#> Achieved score: 6.504 at iteration 73
+#> Achieved score: 6.504 at iteration 77
+#> Achieved score: 6.504 at iteration 82
+#> Achieved score: 6.504 at iteration 98
+#> Achieved score: 6.399 at iteration 101
+#> Achieved score: 4.82 at iteration 113
+#> Achieved score: 4.82 at iteration 142
+

The trace may show a non strictly monotonic behavior now, reflecting +the SA protocol at work.

+
+bc7$plot_trace()
+

+

Better results and quicker convergence may be achieved by playing +with the starting temperature (T0) and cooling speed (alpha) in a +specific case.

+
+bc8 <- optimize_design(
+  bc,
+  scoring = scoring_f,
+  n_shuffle = 1,
+  acceptance_func = mk_simanneal_acceptance_func(mk_simanneal_temp_func(T0 = 100, alpha = 2)),
+  max_iter = 150
+)
+#> Checking variances of 1-dim. score vector.
+#> ... (27.125) - OK
+#> Initial score: 73.03
+#> Achieved score: 73.03 at iteration 1
+#> Achieved score: 73.03 at iteration 2
+#> Achieved score: 63.03 at iteration 3
+#> Achieved score: 59.346 at iteration 4
+#> Achieved score: 59.346 at iteration 5
+#> Achieved score: 53.767 at iteration 6
+#> Achieved score: 53.767 at iteration 7
+#> Achieved score: 53.767 at iteration 8
+#> Achieved score: 53.767 at iteration 9
+#> Achieved score: 52.083 at iteration 11
+#> Achieved score: 44.083 at iteration 12
+#> Achieved score: 44.083 at iteration 14
+#> Achieved score: 38.083 at iteration 15
+#> Achieved score: 36.083 at iteration 19
+#> Achieved score: 34.399 at iteration 20
+#> Achieved score: 28.399 at iteration 21
+#> Achieved score: 28.399 at iteration 23
+#> Achieved score: 28.399 at iteration 25
+#> Achieved score: 24.399 at iteration 26
+#> Achieved score: 20.399 at iteration 27
+#> Achieved score: 18.399 at iteration 30
+#> Achieved score: 16.399 at iteration 36
+#> Achieved score: 16.294 at iteration 37
+#> Achieved score: 16.294 at iteration 38
+#> Achieved score: 14.294 at iteration 40
+#> Achieved score: 12.294 at iteration 46
+#> Achieved score: 10.294 at iteration 57
+#> Achieved score: 8.294 at iteration 65
+#> Achieved score: 6.399 at iteration 83
+#> Achieved score: 4.82 at iteration 90
+
+bc8$plot_trace()
+

+
+
+

Full blown example +

+

The following example puts together all possible options to +illustrate the flexibility of the optimization.

+
+n_shuffle <- rep(c(3, 2, 1), c(20, 20, 200))
+
+bc9 <- optimize_design(
+  bc,
+  scoring = list(
+    osat_score_generator(c("batch"), c("Treatment", "Time")),
+    osat_score_generator(c("batch"), c("Treatment")),
+    osat_score_generator(c("batch"), c("Time"))
+  ),
+  n_shuffle = n_shuffle,
+  aggregate_scores_func = sum_scores,
+  acceptance_func = mk_simanneal_acceptance_func(mk_simanneal_temp_func(T0 = 500, alpha = 1)),
+  max_iter = 200,
+  min_delta = 1e-8,
+  autoscale_scores = T
+)
+#> Warning in osat_score(bc, batch_vars = batch_vars, feature_vars = feature_vars,
+#> : NAs in features / batch columns; they will be excluded from scoring
+
+#> Warning in osat_score(bc, batch_vars = batch_vars, feature_vars = feature_vars,
+#> : NAs in features / batch columns; they will be excluded from scoring
+
+#> Warning in osat_score(bc, batch_vars = batch_vars, feature_vars = feature_vars,
+#> : NAs in features / batch columns; they will be excluded from scoring
+#> Checking variances of 3-dim. score vector.
+#> ... (38.61, 61.35, 96.604) - OK
+#> Creating autoscaling function for 3-dim. score vector. (100 random permutations)
+#> ... Performing boxcox lambda estimation.
+#> Initial score: c(6.427, 2.439, 4.104)
+#>    Aggregated: 12.97
+#> Achieved score: c(5.511, 2.217, 3.224) at iteration 1
+#>    Aggregated: 10.953
+#> Achieved score: c(3.358, 1.527, 2.528) at iteration 2
+#>    Aggregated: 7.413
+#> Achieved score: c(2.583, 1.355, 2.528) at iteration 3
+#>    Aggregated: 6.466
+#> Achieved score: c(2.849, 1.846, 2.528) at iteration 4
+#>    Aggregated: 7.224
+#> Achieved score: c(2.309, 1.527, 2.402) at iteration 5
+#>    Aggregated: 6.238
+#> Achieved score: c(1.73, 1.846, 1.433) at iteration 6
+#>    Aggregated: 5.009
+#> Achieved score: c(1.746, 1.854, 0.39) at iteration 7
+#>    Aggregated: 3.99
+#> Achieved score: c(0.424, 0.038, 0.39) at iteration 8
+#>    Aggregated: 0.852
+#> Achieved score: c(0.424, 0.299, -0.016) at iteration 9
+#>    Aggregated: 0.708
+#> Achieved score: c(1.106, 1.172, 1.215) at iteration 10
+#>    Aggregated: 3.493
+#> Achieved score: c(0.809, 0.75, -0.028) at iteration 11
+#>    Aggregated: 1.531
+#> Achieved score: c(1.14, 0.024, 0.855) at iteration 12
+#>    Aggregated: 2.019
+#> Achieved score: c(0.48, 0.081, 0.855) at iteration 13
+#>    Aggregated: 1.417
+#> Achieved score: c(0.116, -1.267, 0.855) at iteration 14
+#>    Aggregated: -0.295
+#> Achieved score: c(0.48, 0.081, 1.821) at iteration 16
+#>    Aggregated: 2.383
+#> Achieved score: c(0.116, 0.795, 1.449) at iteration 18
+#>    Aggregated: 2.36
+#> Achieved score: c(0.48, -0.201, 2.412) at iteration 20
+#>    Aggregated: 2.692
+#> Achieved score: c(-0.268, -0.201, 1.449) at iteration 21
+#>    Aggregated: 0.98
+#> Achieved score: c(0.097, -0.201, 2.194) at iteration 22
+#>    Aggregated: 2.09
+#> Achieved score: c(-0.206, 0.192, 1.619) at iteration 23
+#>    Aggregated: 1.605
+#> Achieved score: c(-0.206, 0.44, 1.083) at iteration 25
+#>    Aggregated: 1.317
+#> Achieved score: c(-0.206, -0.079, 1.083) at iteration 26
+#>    Aggregated: 0.798
+#> Achieved score: c(-0.206, 0.192, 0.67) at iteration 27
+#>    Aggregated: 0.657
+#> Achieved score: c(-0.206, 0.883, 0.134) at iteration 29
+#>    Aggregated: 0.811
+#> Achieved score: c(-0.185, 0.681, 0.134) at iteration 32
+#>    Aggregated: 0.63
+#> Achieved score: c(0.136, 0.828, 0.38) at iteration 33
+#>    Aggregated: 1.344
+#> Achieved score: c(-0.247, 1.031, -0.277) at iteration 36
+#>    Aggregated: 0.507
+#> Achieved score: c(0.48, 1.691, -1.314) at iteration 39
+#>    Aggregated: 0.857
+#> Achieved score: c(0.116, 0.979, -1.314) at iteration 40
+#>    Aggregated: -0.219
+#> Achieved score: c(-0.185, 0.415, -1.343) at iteration 42
+#>    Aggregated: -1.113
+#> Achieved score: c(-0.165, 0.478, -1.466) at iteration 44
+#>    Aggregated: -1.153
+#> Achieved score: c(-0.165, 0.478, -1.466) at iteration 46
+#>    Aggregated: -1.153
+#> Reached min delta in 46 iterations.
+
+bc9$plot_trace()
+

+
+
+bc9$get_samples(assignment = TRUE) %>%
+  dplyr::mutate(batch = factor(batch)) %>%
+  ggplot2::ggplot(ggplot2::aes(x = batch, fill = Treatment, alpha = factor(Time))) +
+  ggplot2::geom_bar()
+#> Warning: Using alpha for a discrete variable is not advised.
+

+
+
+ + + +
+ + + + +
+ + + + + + + + diff --git a/articles/optimizer_examples_files/figure-html/unnamed-chunk-18-1.png b/articles/optimizer_examples_files/figure-html/unnamed-chunk-18-1.png new file mode 100644 index 00000000..0137d24a Binary files /dev/null and b/articles/optimizer_examples_files/figure-html/unnamed-chunk-18-1.png differ diff --git a/articles/optimizer_examples_files/figure-html/unnamed-chunk-19-1.png b/articles/optimizer_examples_files/figure-html/unnamed-chunk-19-1.png new file mode 100644 index 00000000..22ecab98 Binary files /dev/null and b/articles/optimizer_examples_files/figure-html/unnamed-chunk-19-1.png differ diff --git a/articles/optimizer_examples_files/figure-html/unnamed-chunk-20-1.png b/articles/optimizer_examples_files/figure-html/unnamed-chunk-20-1.png new file mode 100644 index 00000000..036257a8 Binary files /dev/null and b/articles/optimizer_examples_files/figure-html/unnamed-chunk-20-1.png differ diff --git a/articles/optimizer_examples_files/figure-html/unnamed-chunk-20-2.png b/articles/optimizer_examples_files/figure-html/unnamed-chunk-20-2.png new file mode 100644 index 00000000..b0c72d20 Binary files /dev/null and b/articles/optimizer_examples_files/figure-html/unnamed-chunk-20-2.png differ diff --git a/articles/optimizer_examples_files/figure-html/unnamed-chunk-6-1.png b/articles/optimizer_examples_files/figure-html/unnamed-chunk-6-1.png new file mode 100644 index 00000000..f85d7758 Binary files /dev/null and b/articles/optimizer_examples_files/figure-html/unnamed-chunk-6-1.png differ diff --git a/articles/optimizer_examples_files/figure-html/unnamed-chunk-7-1.png b/articles/optimizer_examples_files/figure-html/unnamed-chunk-7-1.png new file mode 100644 index 00000000..b7ad23af Binary files /dev/null and b/articles/optimizer_examples_files/figure-html/unnamed-chunk-7-1.png differ diff --git a/articles/optimizer_examples_files/figure-html/unnamed-chunk-8-1.png b/articles/optimizer_examples_files/figure-html/unnamed-chunk-8-1.png new file mode 100644 index 00000000..bc2069b4 Binary files /dev/null and b/articles/optimizer_examples_files/figure-html/unnamed-chunk-8-1.png differ diff --git a/articles/osat.html b/articles/osat.html new file mode 100644 index 00000000..d3b3d364 --- /dev/null +++ b/articles/osat.html @@ -0,0 +1,624 @@ + + + + + + + +OSAT and scoring functions • designit + + + + + + + + + + + + + + + + + + + +
+
+ + + + +
+
+ + + + +
+library(designit)
+library(tidyverse)
+#> ── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
+#>  dplyr     1.1.3      readr     2.1.4
+#>  forcats   1.0.0      stringr   1.5.0
+#>  ggplot2   3.4.4      tibble    3.2.1
+#>  lubridate 1.9.3      tidyr     1.3.0
+#>  purrr     1.0.2     
+#> ── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
+#>  dplyr::filter() masks stats::filter()
+#>  dplyr::lag()    masks stats::lag()
+#>  Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors
+if (!requireNamespace("OSAT")) {
+  print("This vignette can only be rendered if `OSAT` package is installed.")
+  knitr::knit_exit()
+}
+#> Loading required namespace: OSAT
+

Loading samples. We add two dummy columns to demonstrate how to +choose batch columns of interest.

+
+osat_data_path <- system.file("extdata", package = "OSAT")
+samples <- read_tsv(file.path(osat_data_path, "samples.txt"),
+  col_types = cols(SampleType = col_factor(), Race = col_factor(), AgeGrp = col_factor())
+) %>%
+  mutate(dummy_var1 = rnorm(n()), dummy_var2 = str_c(SampleType, Race, sep = " "))
+
+

Running OSAT optimization +

+

Here we use OSAT to optimize setup.

+
+gs <- OSAT::setup.sample(samples, optimal = c("SampleType", "Race", "AgeGrp"))
+
+gc <- OSAT::setup.container(OSAT::IlluminaBeadChip96Plate, 7, batch = "plates")
+
+set.seed(1234)
+
+bench::system_time(
+  g_setup <- OSAT::create.optimized.setup(sample = gs, container = gc, nSim = params$iterations)
+)
+#> Warning in OSAT::create.optimized.setup(sample = gs, container = gc, nSim =
+#> params$iterations): Using default optimization method: optimal.shuffle
+#> process    real 
+#>   936ms   936ms
+
+OSAT::QC(g_setup)
+#> 
+#> Test independence between "plates" and sample variables
+#> 
+#> Pearson's Chi-squared test
+#>          Var X-squared df   p.value
+#> 1 SampleType 0.4938509  6 0.9979125
+#> 2       Race 0.7424849  6 0.9935279
+#> 3     AgeGrp 1.8472070 24 1.0000000
+#> 
+

+

Saving starting point of optimization

+
+set.seed(1234)
+
+g_setup_start <- OSAT::create.optimized.setup(sample = gs, container = gc, nSim = 1) %>%
+  OSAT::get.experiment.setup()
+#> Warning in OSAT::create.optimized.setup(sample = gs, container = gc, nSim = 1):
+#> Using default optimization method: optimal.shuffle
+

Visualize various batch factors. OSAT score is optimized only for +plates in this case.

+
+OSAT::get.experiment.setup(g_setup) %>%
+  select(AgeGrp, plates, chipRows, chipColumns, chips, rows, columns, wells) %>%
+  pivot_longer(-AgeGrp) %>%
+  count(AgeGrp, value, name) %>%
+  ggplot(aes(AgeGrp, n, fill = factor(value))) +
+  geom_col(position = "dodge") +
+  facet_wrap(~name, scales = "free_y")
+

+
+

Visualize for plates +

+
+plot_batch <- function(df) {
+  df %>%
+    select(plates, SampleType, Race, AgeGrp) %>%
+    pivot_longer(c(SampleType, Race, AgeGrp), names_to = "variable", values_to = "level") %>%
+    count(plates, variable, level) %>%
+    ggplot(aes(level, n, fill = factor(plates))) +
+    geom_col(position = "dodge") +
+    facet_wrap(~variable, scales = "free", ncol = 1)
+}
+

Before the optimization.

+
+g_setup_start %>% plot_batch()
+

+

After the optimization.

+
+OSAT::get.experiment.setup(g_setup) %>%
+  plot_batch()
+

+
+
+
+

Compare scores with various implementations +

+

Compare OSAT score generated using designit.

+
+OSAT::getLayout(gc) %>%
+  left_join(OSAT::get.experiment.setup(g_setup)) %>%
+  data.table::data.table() %>%
+  osat_score("plates", c("SampleType", "Race", "AgeGrp")) %>%
+  .$score
+#> Joining with `by = join_by(plates, chipRows, chipColumns, chips, rows, columns,
+#> wells)`
+#> Warning in osat_score(., "plates", c("SampleType", "Race", "AgeGrp")): NAs in
+#> features / batch columns; they will be excluded from scoring
+#> [1] 34.85714
+
+# score using OSAT
+g_setup@metadata$optValue %>% tail(1)
+#> [1] 34.85714
+
+
+

Run using BatchContainer +

+

First let’s create a BatchContainer with same dimensions.

+
+bc <- BatchContainer$new(
+  dimensions = c(plates = 7, chips = 8, rows = 6, columns = 2)
+)
+bc
+#> Batch container with 672 locations.
+#>   Dimensions: plates, chips, rows, columns
+
+bc$n_locations
+#> [1] 672
+

Assign samples and get initial setup.

+
+bc <- assign_in_order(bc, samples)
+
+starting_assignment <- bc$get_locations() %>%
+  left_join(g_setup_start) %>%
+  pull(ID) %>%
+  as.integer()
+#> Joining with `by = join_by(plates, chips, rows, columns)`
+
+bc$move_samples(location_assignment = starting_assignment)
+
+bc$get_samples(remove_empty_locations = TRUE) %>%
+  plot_batch()
+

+
+

Using designit OSAT score implementation +

+
+scoring_f <- osat_score_generator("plates", c("SampleType", "Race", "AgeGrp"))
+
+bc$score(scoring_f)
+#> Warning in osat_score(bc, batch_vars = batch_vars, feature_vars = feature_vars,
+#> : NAs in features / batch columns; they will be excluded from scoring
+#>  score_1 
+#> 360.8571
+g_setup@metadata$optValue %>% head(1)
+#> [1] 360.8571
+# should be identical
+
+bench::system_time({
+  set.seed(123)
+  bc_reference <- optimize_design(bc, scoring = scoring_f, max_iter = params$iterations)
+})
+#> Checking variances of 1-dim. score vector.
+#> ... (6749.04) - OK
+#> Initial score: 360.857
+#> Achieved score: 348.857 at iteration 7
+#> Achieved score: 344.857 at iteration 8
+#> Achieved score: 338.857 at iteration 10
+#> Achieved score: 326.857 at iteration 19
+#> Achieved score: 322.857 at iteration 22
+#> Achieved score: 320.857 at iteration 24
+#> Achieved score: 318.857 at iteration 26
+#> Achieved score: 314.857 at iteration 27
+#> Achieved score: 308.857 at iteration 28
+#> Achieved score: 302.857 at iteration 32
+#> Achieved score: 300.857 at iteration 33
+#> Achieved score: 292.857 at iteration 36
+#> Achieved score: 290.857 at iteration 38
+#> Achieved score: 284.857 at iteration 40
+#> Achieved score: 276.857 at iteration 45
+#> Achieved score: 272.857 at iteration 50
+#> Achieved score: 266.857 at iteration 54
+#> Achieved score: 258.857 at iteration 55
+#> Achieved score: 248.857 at iteration 60
+#> Achieved score: 242.857 at iteration 62
+#> Achieved score: 224.857 at iteration 71
+#> Achieved score: 218.857 at iteration 73
+#> Achieved score: 214.857 at iteration 76
+#> Achieved score: 204.857 at iteration 78
+#> Achieved score: 200.857 at iteration 79
+#> Achieved score: 192.857 at iteration 80
+#> Achieved score: 184.857 at iteration 84
+#> Achieved score: 176.857 at iteration 85
+#> Achieved score: 172.857 at iteration 86
+#> Achieved score: 170.857 at iteration 95
+#> Achieved score: 166.857 at iteration 96
+#> Achieved score: 156.857 at iteration 98
+#> Achieved score: 150.857 at iteration 99
+#> Achieved score: 148.857 at iteration 102
+#> Achieved score: 144.857 at iteration 103
+#> Achieved score: 138.857 at iteration 113
+#> Achieved score: 132.857 at iteration 133
+#> Achieved score: 124.857 at iteration 138
+#> Achieved score: 120.857 at iteration 140
+#> Achieved score: 112.857 at iteration 149
+#> Achieved score: 108.857 at iteration 169
+#> Achieved score: 106.857 at iteration 175
+#> Achieved score: 104.857 at iteration 176
+#> Achieved score: 100.857 at iteration 178
+#> Achieved score: 98.857 at iteration 179
+#> Achieved score: 92.857 at iteration 188
+#> Achieved score: 90.857 at iteration 189
+#> Achieved score: 86.857 at iteration 190
+#> Achieved score: 82.857 at iteration 202
+#> Achieved score: 76.857 at iteration 210
+#> Achieved score: 72.857 at iteration 223
+#> Achieved score: 68.857 at iteration 231
+#> Achieved score: 66.857 at iteration 239
+#> Achieved score: 64.857 at iteration 262
+#> Achieved score: 62.857 at iteration 324
+#> Achieved score: 60.857 at iteration 336
+#> Achieved score: 58.857 at iteration 358
+#> Achieved score: 56.857 at iteration 360
+#> Achieved score: 52.857 at iteration 406
+#> Achieved score: 50.857 at iteration 419
+#> Achieved score: 48.857 at iteration 425
+#> Achieved score: 46.857 at iteration 455
+#> Achieved score: 42.857 at iteration 505
+#> Achieved score: 40.857 at iteration 507
+#> Achieved score: 38.857 at iteration 532
+#> Achieved score: 36.857 at iteration 618
+#> Achieved score: 34.857 at iteration 727
+#> Achieved score: 32.857 at iteration 786
+#> Achieved score: 30.857 at iteration 960
+#> process    real 
+#>  15.38s   7.94s
+
+# final score
+bc_reference$score(scoring_f)
+#>  score_1 
+#> 30.85714
+bc_reference$plot_trace() +
+  ggtitle(str_glue("Final score={bc$score(scoring_f)}"))
+

+
+bc$get_samples(remove_empty_locations = TRUE) %>%
+  plot_batch()
+

+
+
+

Manually work with data.table +

+

Instead of relying on BatchContainer, here we have a +manual optimization process using data.table.

+
+fast_osat_optimize <- function(bc, batch_vars, feature_vars, iterations) {
+  bc <- bc$copy()
+  ldf <- data.table::data.table(bc$get_locations())[, c("plates")][, ".sample_id" := bc$assignment]
+  fcols <- c(".sample_id", feature_vars)
+  smp <- data.table::data.table(bc$samples)[, ..fcols]
+  df <- smp[ldf, on = ".sample_id"]
+
+  v <- osat_score(df, batch_vars, feature_vars)
+  edf <- v$expected_dt
+  current_score <- v$score
+  scores <- numeric(length = iterations)
+  n_avail <- nrow(df)
+
+  for (i in 1:iterations) {
+    repeat {
+      pos <- sample(n_avail, 2)
+
+      # does not make sense to shuffle NAs
+      if (any(!is.na(df[pos, feature_vars[1]]))) {
+        break
+      }
+    }
+
+    val <- df[c(pos[2], pos[1]), fcols, with = FALSE]
+    df[c(pos[1], pos[2]), (fcols) := val]
+
+    new_score <- osat_score(df, batch_vars, feature_vars, edf)$score
+    if (new_score <= current_score) {
+      current_score <- new_score
+    } else {
+      df[c(pos[2], pos[1]), (fcols) := val]
+    }
+
+    scores[i] <- current_score
+  }
+
+  bc$assignment <- df$.sample_id
+
+  list(bc=bc, scores=scores)
+}
+
+bench::system_time({
+  set.seed(123)
+  opt_res <- fast_osat_optimize(bc, "plates", c("SampleType", "Race", "AgeGrp"), iterations = params$iterations)
+})
+#> Warning in osat_score(df, batch_vars, feature_vars): NAs in features / batch
+#> columns; they will be excluded from scoring
+#> Warning in (function (assignment) : this field might become read-only in the
+#> future, please use $move_samples() instead
+#> process    real 
+#>  10.49s   5.34s
+
+
+
+

Shuffle optimization with burn-in +

+
+scoring_f <- osat_score_generator("plates", c("SampleType", "Race", "AgeGrp"))
+
+burn_in_it <- floor(params$iterations * 0.1)
+burn_in_it
+#> [1] 100
+
+bench::system_time({
+  set.seed(123)
+  bc_burn_in <- optimize_design(
+    bc,
+    scoring = scoring_f,
+    n_shuffle = c(
+      rep(20, burn_in_it),
+      rep(
+        2,
+        params$iterations - burn_in_it
+      )
+    ),
+    max_iter = params$iterations
+  )
+})
+#> Warning in osat_score(bc, batch_vars = batch_vars, feature_vars = feature_vars,
+#> : NAs in features / batch columns; they will be excluded from scoring
+#> Checking variances of 1-dim. score vector.
+#> ... (5018.697) - OK
+#> Initial score: 360.857
+#> Achieved score: 322.857 at iteration 1
+#> Achieved score: 290.857 at iteration 5
+#> Achieved score: 278.857 at iteration 7
+#> Achieved score: 254.857 at iteration 8
+#> Achieved score: 238.857 at iteration 15
+#> Achieved score: 224.857 at iteration 28
+#> Achieved score: 216.857 at iteration 32
+#> Achieved score: 198.857 at iteration 34
+#> Achieved score: 196.857 at iteration 50
+#> Achieved score: 184.857 at iteration 54
+#> Achieved score: 172.857 at iteration 59
+#> Achieved score: 162.857 at iteration 75
+#> Achieved score: 158.857 at iteration 80
+#> Achieved score: 156.857 at iteration 101
+#> Achieved score: 152.857 at iteration 102
+#> Achieved score: 150.857 at iteration 103
+#> Achieved score: 144.857 at iteration 104
+#> Achieved score: 142.857 at iteration 112
+#> Achieved score: 140.857 at iteration 114
+#> Achieved score: 136.857 at iteration 115
+#> Achieved score: 130.857 at iteration 118
+#> Achieved score: 126.857 at iteration 136
+#> Achieved score: 124.857 at iteration 139
+#> Achieved score: 122.857 at iteration 142
+#> Achieved score: 116.857 at iteration 145
+#> Achieved score: 114.857 at iteration 146
+#> Achieved score: 112.857 at iteration 147
+#> Achieved score: 106.857 at iteration 150
+#> Achieved score: 102.857 at iteration 153
+#> Achieved score: 98.857 at iteration 161
+#> Achieved score: 96.857 at iteration 165
+#> Achieved score: 94.857 at iteration 167
+#> Achieved score: 90.857 at iteration 191
+#> Achieved score: 84.857 at iteration 194
+#> Achieved score: 82.857 at iteration 198
+#> Achieved score: 78.857 at iteration 202
+#> Achieved score: 76.857 at iteration 211
+#> Achieved score: 74.857 at iteration 232
+#> Achieved score: 72.857 at iteration 238
+#> Achieved score: 70.857 at iteration 268
+#> Achieved score: 68.857 at iteration 295
+#> Achieved score: 66.857 at iteration 297
+#> Achieved score: 64.857 at iteration 316
+#> Achieved score: 62.857 at iteration 324
+#> Achieved score: 60.857 at iteration 402
+#> Achieved score: 58.857 at iteration 405
+#> Achieved score: 54.857 at iteration 409
+#> Achieved score: 52.857 at iteration 436
+#> Achieved score: 48.857 at iteration 440
+#> Achieved score: 46.857 at iteration 499
+#> Achieved score: 44.857 at iteration 521
+#> Achieved score: 42.857 at iteration 562
+#> Achieved score: 40.857 at iteration 621
+#> Achieved score: 38.857 at iteration 788
+#> Achieved score: 36.857 at iteration 793
+#> Achieved score: 34.857 at iteration 807
+#> Achieved score: 32.857 at iteration 827
+#> process    real 
+#>  15.77s   8.18s
+
+tibble(
+  i = bc_burn_in$trace$scores[[1]]$step,
+  normal = bc_reference$trace$scores[[1]]$score_1,
+  burnin = bc_burn_in$trace$scores[[1]]$score_1
+) %>%
+  pivot_longer(-i, names_to = "method", values_to = "score") %>%
+  ggplot(aes(i, score, col = method)) +
+  geom_line()
+

+
+
+

Score demonstration +

+
+bc$score(scoring_f)
+#>  score_1 
+#> 360.8571
+
+assign_random(bc)
+#> Batch container with 672 locations and 576 samples (assigned).
+#>   Dimensions: plates, chips, rows, columns
+
+bc$get_samples()
+#> # A tibble: 672 × 10
+#>    plates chips  rows columns    ID SampleType Race     AgeGrp   dummy_var1
+#>     <int> <int> <int>   <int> <dbl> <fct>      <fct>    <fct>         <dbl>
+#>  1      1     1     1       1   563 Control    Hispanic (30,40]      -0.960
+#>  2      1     1     1       2   488 Control    European (30,40]       1.17 
+#>  3      1     1     2       1   215 Case       European (50,60]      -0.310
+#>  4      1     1     2       2   268 Case       Hispanic (40,50]       0.541
+#>  5      1     1     3       1   165 Case       European (60,100]      0.346
+#>  6      1     1     3       2    86 Case       Hispanic (60,100]     -0.382
+#>  7      1     1     4       1   264 Case       European (60,100]      1.51 
+#>  8      1     1     4       2   451 Control    European (30,40]       1.41 
+#>  9      1     1     5       1   250 Case       Hispanic (60,100]     -0.956
+#> 10      1     1     5       2    NA NA         NA       NA           NA    
+#> # ℹ 662 more rows
+#> # ℹ 1 more variable: dummy_var2 <chr>
+bc$get_samples(remove_empty_locations = TRUE)
+#> # A tibble: 576 × 10
+#>    plates chips  rows columns    ID SampleType Race     AgeGrp   dummy_var1
+#>     <int> <int> <int>   <int> <dbl> <fct>      <fct>    <fct>         <dbl>
+#>  1      1     1     1       1   563 Control    Hispanic (30,40]      -0.960
+#>  2      1     1     1       2   488 Control    European (30,40]       1.17 
+#>  3      1     1     2       1   215 Case       European (50,60]      -0.310
+#>  4      1     1     2       2   268 Case       Hispanic (40,50]       0.541
+#>  5      1     1     3       1   165 Case       European (60,100]      0.346
+#>  6      1     1     3       2    86 Case       Hispanic (60,100]     -0.382
+#>  7      1     1     4       1   264 Case       European (60,100]      1.51 
+#>  8      1     1     4       2   451 Control    European (30,40]       1.41 
+#>  9      1     1     5       1   250 Case       Hispanic (60,100]     -0.956
+#> 10      1     1     6       1   191 Case       Hispanic (60,100]     -0.529
+#> # ℹ 566 more rows
+#> # ℹ 1 more variable: dummy_var2 <chr>
+
+scoring_f <- list(
+  fc0 = function(samples) rnorm(1) + 2 * rexp(1),
+  fc1 = function(samples) rnorm(1, 100),
+  fc2 = function(samples) -7
+)
+
+bc$score(scoring_f)
+#>       fc0       fc1       fc2 
+#>   3.64428 100.78084  -7.00000
+
+
+ + + +
+ + + + +
+ + + + + + + + diff --git a/articles/osat_files/figure-html/unnamed-chunk-11-1.png b/articles/osat_files/figure-html/unnamed-chunk-11-1.png new file mode 100644 index 00000000..7e681f54 Binary files /dev/null and b/articles/osat_files/figure-html/unnamed-chunk-11-1.png differ diff --git a/articles/osat_files/figure-html/unnamed-chunk-13-1.png b/articles/osat_files/figure-html/unnamed-chunk-13-1.png new file mode 100644 index 00000000..6fe76b5f Binary files /dev/null and b/articles/osat_files/figure-html/unnamed-chunk-13-1.png differ diff --git a/articles/osat_files/figure-html/unnamed-chunk-13-2.png b/articles/osat_files/figure-html/unnamed-chunk-13-2.png new file mode 100644 index 00000000..7e681f54 Binary files /dev/null and b/articles/osat_files/figure-html/unnamed-chunk-13-2.png differ diff --git a/articles/osat_files/figure-html/unnamed-chunk-16-1.png b/articles/osat_files/figure-html/unnamed-chunk-16-1.png new file mode 100644 index 00000000..ad3992cc Binary files /dev/null and b/articles/osat_files/figure-html/unnamed-chunk-16-1.png differ diff --git a/articles/osat_files/figure-html/unnamed-chunk-3-1.png b/articles/osat_files/figure-html/unnamed-chunk-3-1.png new file mode 100644 index 00000000..3f2e7914 Binary files /dev/null and b/articles/osat_files/figure-html/unnamed-chunk-3-1.png differ diff --git a/articles/osat_files/figure-html/unnamed-chunk-5-1.png b/articles/osat_files/figure-html/unnamed-chunk-5-1.png new file mode 100644 index 00000000..e17e1228 Binary files /dev/null and b/articles/osat_files/figure-html/unnamed-chunk-5-1.png differ diff --git a/articles/osat_files/figure-html/unnamed-chunk-7-1.png b/articles/osat_files/figure-html/unnamed-chunk-7-1.png new file mode 100644 index 00000000..7e681f54 Binary files /dev/null and b/articles/osat_files/figure-html/unnamed-chunk-7-1.png differ diff --git a/articles/osat_files/figure-html/unnamed-chunk-8-1.png b/articles/osat_files/figure-html/unnamed-chunk-8-1.png new file mode 100644 index 00000000..f84db75d Binary files /dev/null and b/articles/osat_files/figure-html/unnamed-chunk-8-1.png differ diff --git a/articles/plate_layouts.html b/articles/plate_layouts.html new file mode 100644 index 00000000..3dddb682 --- /dev/null +++ b/articles/plate_layouts.html @@ -0,0 +1,2648 @@ + + + + + + + +Plate layouts • designit + + + + + + + + + + + + + + + + + + + +
+
+ + + + +
+
+ + + + +
#> ── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
+#>  dplyr     1.1.3      readr     2.1.4
+#>  forcats   1.0.0      stringr   1.5.0
+#>  ggplot2   3.4.4      tibble    3.2.1
+#>  lubridate 1.9.3      tidyr     1.3.0
+#>  purrr     1.0.2     
+#> ── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
+#>  dplyr::filter() masks stats::filter()
+#>  dplyr::lag()    masks stats::lag()
+#>  Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors
+
+

Introduction +

+

Distributing samples to wells plates for experimental procedures is a +very common task. In the following we use a data set of longitudinal +subject samples that are to be spread across several n-well plates, +balanced for treatment group and time point +longitudinal_subject_samples.

+
+data("longitudinal_subject_samples")
+head(longitudinal_subject_samples)
+#> # A tibble: 6 × 9
+#>   SampleID SampleType SubjectID Group  Week Sex     Age   BMI SamplesPerSubject
+#>   <chr>    <fct>      <chr>     <chr> <dbl> <chr> <dbl> <dbl>             <dbl>
+#> 1 P01W1    Sample     P01       1         1 F        71  28.1                 7
+#> 2 P01W4    Sample     P01       1         4 F        71  28.1                 7
+#> 3 P01W6    Sample     P01       1         6 F        71  28.1                 7
+#> 4 P01W10   Sample     P01       1        10 F        71  28.1                 7
+#> 5 P01W14   Sample     P01       1        14 F        71  28.1                 7
+#> 6 P01W18   Sample     P01       1        18 F        71  28.1                 7
+

In the fist example we’ll use a subset of samples to demonstrate the +process.

+
    +
  • We have 33 subject with each 2 samples.
  • +
  • Factors we want to balance are treatment group and Sex.
  • +
+
+dat <- longitudinal_subject_samples %>%
+  filter(Group %in% 1:5, Week %in% c(1, 4)) %>%
+  select(SampleID, SubjectID, Group, Sex, Week)
+
+# for simplicity: remove two subjects that don't have both visits
+dat <- dat %>%
+  group_by(SubjectID) %>%
+  filter(n() == 2) %>%
+  ungroup()
+
+
+

Layout optimization in one go +

+

For placing samples on plates and optimizing across plate +distribution of factors as well as the within plate spacial +distribution, the multi_plate_wrapper() function can be +used. It focuses first on assigning samples to plates and then optimizes +the layout within plates.

+

To place all 66 samples on 24-well plates we create a +batch_container with 3 plates

+

We do the initial assignment of sample to plates and plot it

+
+set.seed(42)
+
+bc <- BatchContainer$new(
+  dimensions = list("plate" = 3, "row" = 4, "col" = 6),
+)
+
+bc <- assign_in_order(bc, dat)
+
+head(bc$get_samples()) %>% gt::gt()
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
platerowcolSampleIDSubjectIDGroupSexWeek
111P01W1P011F1
112P01W4P011F4
113P02W1P021M1
114P02W4P021M4
115P03W1P031M1
116P03W4P031M4
+
+

We can view the initial assignment with plot_plate

+
+cowplot::plot_grid(
+  plotlist = list(
+    plot_plate(bc,
+      plate = plate, row = row, column = col, .color = Group,
+      title = "Initial layout by Group"
+    ),
+    plot_plate(bc,
+      plate = plate, row = row, column = col, .color = Sex,
+      title = "Initial layout by Sex"
+    )
+  ),
+  nrow = 2
+)
+

+

For optimization optimize_multi_plate_design() +iteratively calls optimize_design() for different steps of +the experiment. For across plate optimization osat scoring is used. For +within plate optimization spatial scoreing is used. The order of the +factors indicate their relative importance. In this case we prioritize +Group over Sex.

+
+bc <- optimize_multi_plate_design(bc,
+  across_plates_variables = c("Group", "Sex"),
+  within_plate_variables = c("Group"),
+  plate = "plate",
+  row = "row",
+  column = "col",
+  n_shuffle = 2,
+  max_iter = 700,
+  quiet = TRUE
+)
+#> Warning in osat_score(bc, batch_vars = batch_vars, feature_vars = feature_vars,
+#> : NAs in features / batch columns; they will be excluded from scoring
+
+#> Warning in osat_score(bc, batch_vars = batch_vars, feature_vars = feature_vars,
+#> : NAs in features / batch columns; they will be excluded from scoring
+
+cowplot::plot_grid(
+  plotlist = list(
+    plot_plate(bc,
+      plate = plate, row = row, column = col, .color = Group,
+      title = "Initial layout by Group"
+    ),
+    plot_plate(bc,
+      plate = plate, row = row, column = col, .color = Sex,
+      title = "Initial layout by Sex"
+    )
+  ),
+  nrow = 2
+)
+

+

We can look at the trace objects for each internal +optimize_design run, returned from the wrapper +function.

+
+bc$scores_table() |>
+  ggplot(aes(step, value, color = score)) +
+  geom_line() +
+  geom_point() +
+  facet_wrap(~ optimization_index, scales = "free_y")
+#> Warning: Removed 6309 rows containing missing values (`geom_line()`).
+#> Warning: Removed 6309 rows containing missing values (`geom_point()`).
+

+
+

Plate scoring +

+

Note that internally the wrapper function sets up plate specific +scoring functions that could manually be set up in the following +way.

+
+scoring_f <- c(
+  Group = mk_plate_scoring_functions(bc,
+    plate = "plate", row = "row", column = "col",
+    group = "Group", penalize_lines = "hard"
+  ),
+  Sex = mk_plate_scoring_functions(bc,
+    plate = "plate", row = "row", column = "col",
+    group = "Sex", penalize_lines = "hard"
+  )
+)
+

For more information on customized plate scoring see vignette +Plate scoring examples.

+
+
+
+

Two step approach +

+

Sometimes layout requests can be more complicated. Assume we want to +keep the two samples of a subject on the same 24 well plate.

+

Now we need to customize across plate optimization more so we need to +split the process into two steps.

+
+

Step 1: Subjects to plates +

+

There are 31 subjects with each 2 time points, i.e. we need ~ 11 +subjects per plate and want to balance by treatment, sex.

+

First we create a batch container with 3 batches that each fit 11 +subjects i.e. have 11 virtual locations.

+

For layout scoring we use OSAT score on Group and +Sex variables.

+

Then we assign the samples randomly to the batches and look at their +initial distribution.

+
+set.seed(17) # gives `bad` random assignment
+
+bc <- BatchContainer$new(
+  dimensions = list("batch" = 3, "location" = 11)
+)
+
+scoring_f <- list(
+  group = osat_score_generator(batch_vars = "batch", feature_vars = "Group"),
+  sex = osat_score_generator(batch_vars = "batch", feature_vars = "Sex")
+)
+
+bc <- assign_random(
+  bc,
+  dat %>% select(SubjectID, Group, Sex) %>% distinct()
+)
+
+bc$get_samples() %>%
+  head() %>%
+  gt::gt()
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
batchlocationSubjectIDGroupSex
11NANANA
12P325M
13P103F
14P263M
15P175M
16P072F
+
+
+cowplot::plot_grid(
+  plotlist = list(
+    bc$get_samples() %>% ggplot(aes(x = batch, fill = Group)) +
+      geom_bar() +
+      labs(y = "subject count"),
+    bc$get_samples() %>% ggplot(aes(x = batch, fill = Sex)) +
+      geom_bar() +
+      labs(y = "subject count")
+  ),
+  nrow = 1
+)
+

+

Optimizing the layout with optimize_design()

+
+bc <- optimize_design(
+  bc,
+  scoring = scoring_f,
+  n_shuffle = 1,
+  acceptance_func = ~ accept_leftmost_improvement(..., tolerance = 0.01),
+  max_iter = 150,
+  quiet = TRUE
+)
+#> Warning in osat_score(bc, batch_vars = batch_vars, feature_vars = feature_vars,
+#> : NAs in features / batch columns; they will be excluded from scoring
+
+#> Warning in osat_score(bc, batch_vars = batch_vars, feature_vars = feature_vars,
+#> : NAs in features / batch columns; they will be excluded from scoring
+

After optimization the group and sex of samples are equally +distributed across all plates. The lower right panel shows the +optimization trace of the scores.

+
+cowplot::plot_grid(
+  plotlist = list(
+    bc$get_samples() %>% ggplot(aes(x = batch, fill = Group)) +
+      geom_bar() +
+      labs(y = "subject count"),
+    bc$get_samples() %>% ggplot(aes(x = batch, fill = Sex)) +
+      geom_bar() +
+      labs(y = "subject count"),
+    bc$plot_trace(include_aggregated = TRUE)
+  ),
+  ncol = 3
+)
+

+
+
+

Step 2: Within plate sample distribution +

+

Using the result from step 1 we now optimize the layout within +plates. For this we still need to add empty wells to each batch and +assign the pre-allocated sample sheet in the right way to the new batch +container.

+
+dat <- dat %>%
+  left_join(bc$get_samples() %>%
+    select(SubjectID, batch))
+#> Joining with `by = join_by(SubjectID)`
+
+# add empty wells depending on how full the batch plate is
+dat <- dat %>%
+  bind_rows(data.frame(
+    SubjectID = "empty",
+    SampleID = paste("empty", 1:(3 * 24 - nrow(dat))),
+    batch = rep(1:3, 24 - (dat %>% count(batch) %>% .$n))
+  ))
+
+bc <- BatchContainer$new(
+  dimensions = list("plate" = 3, "row" = 4, "col" = 6)
+)
+
+# initial assignment such that the original plate assigned stays the same
+bc <- assign_in_order(
+  bc,
+  dat %>% arrange(batch)
+)
+
+
+cowplot::plot_grid(
+  plotlist = list(
+    plot_plate(bc,
+      plate = plate, row = row, column = col, .color = Group,
+      title = "Initial layout by Group"
+    ),
+    plot_plate(bc,
+      plate = plate, row = row, column = col, .color = Sex,
+      title = "Initial layout by Sex"
+    )
+  ),
+  nrow = 2
+)
+

+

As we have already assigned samples to plates, the across plate +optimization can be skipped in the wrapper. For distributing samples +within each plate, we use variables Group and Sex again. The order of +the factors indicate their relative importance.

+
+bc <- optimize_multi_plate_design(bc,
+  within_plate_variables = c("Group", "Sex"),
+  plate = "plate",
+  row = "row",
+  column = "col",
+  n_shuffle = 2,
+  max_iter = 1000,
+  quiet = TRUE
+)
+
+cowplot::plot_grid(
+  plotlist = list(
+    plot_plate(bc,
+      plate = plate, row = row, column = col, .color = Group,
+      title = "Final layout by Group"
+    ),
+    plot_plate(bc,
+      plate = plate, row = row, column = col, .color = Sex,
+      title = "Final layout by Sex"
+    )
+  ),
+  nrow = 2
+)
+

+
+bc$scores_table() |>
+  ggplot(aes(step, value, color = score)) +
+  geom_line() +
+  geom_point() +
+  facet_wrap(~ optimization_index)
+

+
+
+
+

Full dataset +

+

In the following we use the full data set of longitudinal subject +samples that are to be spread across several n-well plates, balanced for +treatment group and time point +longitudinal_subject_samples.

+

In addition to the normal samples there are also controls to be +placed on each plate. These are added after the sample batching +step.

+

For accommodation of samples to plates there are the following +control samples available

+
+longitudinal_subject_samples %>%
+  filter(SampleType != "Sample") %>%
+  count(SampleType, Group) %>%
+  gt::gt()
+
+ + + + + + + + + + + + + + + + + + + +
SampleTypeGroupn
ControlPool6
StandardSpikeIn15
+
+
+

Step 1: Batching +

+

Again we want to keep all samples of a subject on the same plate. A +first step could be grouping subjects into 3 batches blocking by +treatment, sex and age. There are 34 subjects with each 3 - 8 time +points, i.e. we need ~ 11 subjects per plate.

+

We first create a ‘subjects’ dataset.

+
+# get subject data for batching
+subjects <- longitudinal_subject_samples %>%
+  filter(SampleType == "Sample") %>%
+  count(SubjectID, Group, Sex, Age, name = "nTimePoints") %>%
+  distinct()
+
+subjects %>%
+  select(-nTimePoints) %>%
+  slice(1:5) %>%
+  gt::gt() %>%
+  gt::tab_options()
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
SubjectIDGroupSexAge
P011F71
P021M74
P031M76
P041F83
P052M79
+
+

Then we create a batch container for the samples with 3 batches +called plate that each fit 11 subjects i.e. have 11 virtual +locations.

+

For layout scoring we use OSAT score on Group and +Sex variables. We initially assign the samples randomly to +the batches and check the layout.

+
+set.seed(42)
+
+bc <- BatchContainer$new(
+  dimensions = list("plate" = 3, "locations" = 11)
+)
+
+scoring_f <- list(
+  group = osat_score_generator(batch_vars = "plate", feature_vars = c("Group")),
+  sex = osat_score_generator(batch_vars = "plate", feature_vars = "Sex")
+)
+
+bc <- assign_random(bc, subjects)
+
+cowplot::plot_grid(
+  plotlist = list(
+    bc$get_samples() %>% ggplot(aes(x = plate, fill = Group)) +
+      geom_bar() +
+      labs(y = "subject count"),
+    bc$get_samples() %>% ggplot(aes(x = plate, fill = Sex)) +
+      geom_bar() +
+      labs(y = "subject count"),
+    bc$get_samples() %>% ggplot(aes(x = factor(plate), y = Age)) +
+      geom_boxplot() +
+      geom_point()
+  ),
+  nrow = 1
+)
+

+

Optimizing the layout with optimize_design()

+
+bc <- optimize_design(
+  bc,
+  scoring = scoring_f,
+  n_shuffle = 1,
+  acceptance_func = ~ accept_leftmost_improvement(..., tolerance = 0.1),
+  max_iter = 150,
+  quiet = TRUE
+)
+

After optimization the group and sex of samples are equally +distributed across all plates. The lower right panel shows the +optimization trace of the scores.

+
+cowplot::plot_grid(
+  plotlist = list(
+    bc$get_samples() %>% ggplot(aes(x = plate, fill = Group)) +
+      geom_bar() +
+      labs(y = "subject count"),
+    bc$get_samples() %>% ggplot(aes(x = plate, fill = Sex)) +
+      geom_bar() +
+      labs(y = "subject count"),
+    bc$get_samples() %>% ggplot(aes(x = factor(plate), y = Age)) +
+      geom_boxplot() +
+      geom_point(),
+    bc$plot_trace(include_aggregated = TRUE)
+  ),
+  nrow = 2
+)
+

+
+
+

Step 2: Within plate sample distribution +

+

We start here by creating the batch container for all samples and +making an initial assignment. Note there will be empty positions on the +plates which we have to add before we assign the samples to the batch +container in order.

+
+samples_with_plate <- longitudinal_subject_samples %>%
+  left_join(bc$get_samples() %>%
+    select(-locations)) %>%
+  mutate(plate = ifelse(SampleType == "Sample", plate, str_extract(SampleID, ".$")))
+#> Joining with `by = join_by(SubjectID, Group, Sex, Age)`
+
+# not all plates have same amount of samples
+samples_with_plate %>% count(plate)
+#> # A tibble: 3 × 2
+#>   plate     n
+#>   <chr> <int>
+#> 1 1        77
+#> 2 2        80
+#> 3 3        73
+
+# add empty wells depending on how full the batch plate is
+# column 11 and 12 are left empty: 96 - 16 = 80 samples per plate
+samples_with_plate <- samples_with_plate %>%
+  bind_rows(data.frame(
+    SubjectID = "empty",
+    SampleID = paste("empty", 1:(3 * 80 - nrow(samples_with_plate))),
+    plate = rep(1:3, 80 - (samples_with_plate %>% count(plate) %>% .$n)) %>%
+      as.character()
+  ))
+
+
+# new batch container for step 2
+bc <- BatchContainer$new(
+  dimensions = list(plate = 3, row = 8, col = 12),
+  exclude = crossing(plate = 1:3, row = 1:8, col = 11:12)
+)
+
+# assign samples in order of plate
+bc <- assign_in_order(
+  bc,
+  samples_with_plate %>%
+    arrange(plate) %>%
+    rename(orig_plate = plate)
+)
+
+# check if plate assignment is still correct
+bc$get_samples() %>%
+  summarize(all(plate == orig_plate)) %>%
+  unlist()
+#> all(plate == orig_plate) 
+#>                     TRUE
+
+cowplot::plot_grid(
+  plotlist = list(
+    plot_plate(bc,
+      plate = plate, row = row, column = col, .color = Group,
+      title = "Initial layout by Group"
+    ),
+    plot_plate(bc,
+      plate = plate, row = row, column = col, .color = SubjectID,
+      title = "Initial layout by SubjectID"
+    ) +
+      theme(legend.key.size = unit(.25, "cm")),
+    plot_plate(bc,
+      plate = plate, row = row, column = col, .color = Sex,
+      title = "Initial layout by Sex"
+    )
+  ),
+  nrow = 3
+)
+

+

As we have already assigned samples to plates, the across plate +optimization can be skipped in the wrapper. For distributing samples +within each plate, we use variables Group and Sex again. The order of +the factors indicate their relative importance.

+
+bc <- optimize_multi_plate_design(bc,
+  within_plate_variables = c("Group", "SubjectID", "Sex"),
+  plate = "plate",
+  row = "row",
+  column = "col",
+  n_shuffle = 2,
+  max_iter = 1000,
+  quiet = TRUE
+)
+
+cowplot::plot_grid(
+  plotlist = list(
+    plot_plate(bc,
+      plate = plate, row = row, column = col, .color = Group,
+      title = "Final layout by Group"
+    ),
+    plot_plate(bc,
+      plate = plate, row = row, column = col, .color =
+        SubjectID, title = "Final layout by SubjectID"
+    ) +
+      theme(legend.key.size = unit(.25, "cm")),
+    plot_plate(bc,
+      plate = plate, row = row, column = col, .color = Sex,
+      title = "Final layout by Sex"
+    )
+  ),
+  nrow = 3
+)
+

+
+bc$scores_table() |>
+  ggplot(aes(step, value, color = score)) +
+  geom_line() +
+  geom_point() +
+  facet_wrap(~ optimization_index)
+

+
+
+
+ + + +
+ + + + +
+ + + + + + + + diff --git a/articles/plate_layouts_files/figure-html/unnamed-chunk-11-1.png b/articles/plate_layouts_files/figure-html/unnamed-chunk-11-1.png new file mode 100644 index 00000000..5ba017b2 Binary files /dev/null and b/articles/plate_layouts_files/figure-html/unnamed-chunk-11-1.png differ diff --git a/articles/plate_layouts_files/figure-html/unnamed-chunk-13-1.png b/articles/plate_layouts_files/figure-html/unnamed-chunk-13-1.png new file mode 100644 index 00000000..bbcf6381 Binary files /dev/null and b/articles/plate_layouts_files/figure-html/unnamed-chunk-13-1.png differ diff --git a/articles/plate_layouts_files/figure-html/unnamed-chunk-14-1.png b/articles/plate_layouts_files/figure-html/unnamed-chunk-14-1.png new file mode 100644 index 00000000..26d39e1d Binary files /dev/null and b/articles/plate_layouts_files/figure-html/unnamed-chunk-14-1.png differ diff --git a/articles/plate_layouts_files/figure-html/unnamed-chunk-16-1.png b/articles/plate_layouts_files/figure-html/unnamed-chunk-16-1.png new file mode 100644 index 00000000..16c99a08 Binary files /dev/null and b/articles/plate_layouts_files/figure-html/unnamed-chunk-16-1.png differ diff --git a/articles/plate_layouts_files/figure-html/unnamed-chunk-17-1.png b/articles/plate_layouts_files/figure-html/unnamed-chunk-17-1.png new file mode 100644 index 00000000..57827f42 Binary files /dev/null and b/articles/plate_layouts_files/figure-html/unnamed-chunk-17-1.png differ diff --git a/articles/plate_layouts_files/figure-html/unnamed-chunk-21-1.png b/articles/plate_layouts_files/figure-html/unnamed-chunk-21-1.png new file mode 100644 index 00000000..5489f341 Binary files /dev/null and b/articles/plate_layouts_files/figure-html/unnamed-chunk-21-1.png differ diff --git a/articles/plate_layouts_files/figure-html/unnamed-chunk-23-1.png b/articles/plate_layouts_files/figure-html/unnamed-chunk-23-1.png new file mode 100644 index 00000000..803fba54 Binary files /dev/null and b/articles/plate_layouts_files/figure-html/unnamed-chunk-23-1.png differ diff --git a/articles/plate_layouts_files/figure-html/unnamed-chunk-25-1.png b/articles/plate_layouts_files/figure-html/unnamed-chunk-25-1.png new file mode 100644 index 00000000..f8702140 Binary files /dev/null and b/articles/plate_layouts_files/figure-html/unnamed-chunk-25-1.png differ diff --git a/articles/plate_layouts_files/figure-html/unnamed-chunk-27-1.png b/articles/plate_layouts_files/figure-html/unnamed-chunk-27-1.png new file mode 100644 index 00000000..425292bb Binary files /dev/null and b/articles/plate_layouts_files/figure-html/unnamed-chunk-27-1.png differ diff --git a/articles/plate_layouts_files/figure-html/unnamed-chunk-28-1.png b/articles/plate_layouts_files/figure-html/unnamed-chunk-28-1.png new file mode 100644 index 00000000..4f4017b8 Binary files /dev/null and b/articles/plate_layouts_files/figure-html/unnamed-chunk-28-1.png differ diff --git a/articles/plate_layouts_files/figure-html/unnamed-chunk-5-1.png b/articles/plate_layouts_files/figure-html/unnamed-chunk-5-1.png new file mode 100644 index 00000000..491595bf Binary files /dev/null and b/articles/plate_layouts_files/figure-html/unnamed-chunk-5-1.png differ diff --git a/articles/plate_layouts_files/figure-html/unnamed-chunk-7-1.png b/articles/plate_layouts_files/figure-html/unnamed-chunk-7-1.png new file mode 100644 index 00000000..ef033105 Binary files /dev/null and b/articles/plate_layouts_files/figure-html/unnamed-chunk-7-1.png differ diff --git a/articles/plate_layouts_files/figure-html/unnamed-chunk-8-1.png b/articles/plate_layouts_files/figure-html/unnamed-chunk-8-1.png new file mode 100644 index 00000000..b28f3289 Binary files /dev/null and b/articles/plate_layouts_files/figure-html/unnamed-chunk-8-1.png differ diff --git a/articles/plate_scoring_examples.html b/articles/plate_scoring_examples.html new file mode 100644 index 00000000..86cbd9b5 --- /dev/null +++ b/articles/plate_scoring_examples.html @@ -0,0 +1,963 @@ + + + + + + + +Plate scoring examples • designit + + + + + + + + + + + + + + + + + + + +
+
+ + + + +
+
+ + + + +
library(designit)
+library(ggplot2)
+library(dplyr)
+#> 
+#> Attaching package: 'dplyr'
+#> The following objects are masked from 'package:stats':
+#> 
+#>     filter, lag
+#> The following objects are masked from 'package:base':
+#> 
+#>     intersect, setdiff, setequal, union
+library(tidyr)
+
+

+Example 1: An expensive way to construct a 4x4 latin square (one plate) + +

+

+(latin square should give the best score) +

+

+First using a combination of two OSAT scores (for row and column). +

+

+This usually produces a latin square when using the squared L2 norm +(L2s) for aggregation of the 2 scores. +

+
# Setting up the batch container
+example1 <- BatchContainer$new(
+  dimensions = c(
+    plate = 1,
+    row = 4, col = 4
+  )
+)
+
+# Add samples to container
+# Need unique Sample ID. Can we drop this constraint?
+example1 <- assign_in_order(example1,
+  samples = tibble::tibble(
+    Group = rep(c("Grp 1", "Grp 2", "Grp 3", "Grp 4"), each = 4),
+    ID = 1:16
+  )
+)
+
+# The following does not work (an gives a constant score of 144!)
+# scoring_f <- osat_score_generator(batch_vars = c("row","col"), feature_vars = c("Group"))
+# First analysis of problem indicates that osat_score generates a full row*col vector of 'ideal scores'
+# which are in fact the same value, implying an identical overall result as each position can be either
+# allocated by 1 sample or 0 samples, the sum of 1's being the sample count.
+# --> don't use osat_score if there's a lack of samples as compared to possible positioning
+
+# # Set scoring function
+scoring_f <- list(
+  Row.Score = osat_score_generator(batch_vars = c("row"), feature_vars = c("Group")),
+  Column.Score = osat_score_generator(batch_vars = c("col"), feature_vars = c("Group"))
+)
+
set.seed(41)
+
+bc <- optimize_design(
+  example1,
+  scoring = scoring_f,
+  max_iter = 300, # this is set to shorten vignette run-time based on known random seed, normally we don't know.
+  n_shuffle = 2,
+  acceptance_func = mk_simanneal_acceptance_func(mk_simanneal_temp_func(T0 = 1000, alpha = 0.5)),
+  aggregate_scores_func = L2s_norm
+)
+#> Checking variances of 2-dim. score vector.
+#> ... (11.385, 16.687) - OK
+#> Initial score: c(48, 0)
+#>    Aggregated: 2304
+#> Achieved score: c(36, 4) at iteration 1
+#>    Aggregated: 1312
+#> Achieved score: c(24, 4) at iteration 2
+#>    Aggregated: 592
+#> Achieved score: c(24, 12) at iteration 3
+#>    Aggregated: 720
+#> Achieved score: c(24, 8) at iteration 4
+#>    Aggregated: 640
+#> Achieved score: c(16, 10) at iteration 5
+#>    Aggregated: 356
+#> Achieved score: c(12, 10) at iteration 6
+#>    Aggregated: 244
+#> Achieved score: c(10, 10) at iteration 7
+#>    Aggregated: 200
+#> Achieved score: c(10, 6) at iteration 9
+#>    Aggregated: 136
+#> Achieved score: c(10, 4) at iteration 10
+#>    Aggregated: 116
+#> Achieved score: c(8, 10) at iteration 11
+#>    Aggregated: 164
+#> Achieved score: c(8, 8) at iteration 12
+#>    Aggregated: 128
+#> Achieved score: c(8, 8) at iteration 14
+#>    Aggregated: 128
+#> Achieved score: c(4, 10) at iteration 19
+#>    Aggregated: 116
+#> Achieved score: c(4, 6) at iteration 20
+#>    Aggregated: 52
+#> Achieved score: c(4, 4) at iteration 22
+#>    Aggregated: 32
+#> Achieved score: c(4, 4) at iteration 27
+#>    Aggregated: 32
+#> Achieved score: c(4, 4) at iteration 36
+#>    Aggregated: 32
+#> Achieved score: c(4, 4) at iteration 38
+#>    Aggregated: 32
+#> Achieved score: c(0, 4) at iteration 39
+#>    Aggregated: 16
+#> Achieved score: c(0, 4) at iteration 50
+#>    Aggregated: 16
+#> Achieved score: c(0, 4) at iteration 54
+#>    Aggregated: 16
+#> Achieved score: c(0, 4) at iteration 82
+#>    Aggregated: 16
+#> Achieved score: c(0, 4) at iteration 87
+#>    Aggregated: 16
+#> Achieved score: c(0, 4) at iteration 119
+#>    Aggregated: 16
+#> Achieved score: c(0, 4) at iteration 125
+#>    Aggregated: 16
+#> Achieved score: c(0, 4) at iteration 200
+#>    Aggregated: 16
+#> Achieved score: c(4, 0) at iteration 215
+#>    Aggregated: 16
+#> Achieved score: c(0, 0) at iteration 284
+#>    Aggregated: 0
+
bc$trace$elapsed
+#> Time difference of 5.483629 secs
+
+plot_plate(bc,
+  plate = plate, row = row, column = col, .color = Group,
+  title = "Ex1: Using OSAT scores for plate design\n(not the recommended way!)"
+)
+

+

+

+Now using a dedicated scoring for the group distances on a plate. +

+

+This should reliably lead to a nice symmetry-bearing latin square design +with only a one-dimensional score to look at. +

+
scoring_f <- mk_plate_scoring_functions(bc, row = "row", column = "col", group = "Group")
+
set.seed(42)
+bc <- optimize_design(
+  example1,
+  scoring = scoring_f,
+  max_iter = 1000, # this is set to shorten vignette run-time based on random seed, normally we don't know.
+  n_shuffle = 2,
+  acceptance_func = mk_simanneal_acceptance_func(mk_simanneal_temp_func(T0 = 1000, alpha = 0.5)),
+  quiet = TRUE
+)
+
bc$trace$elapsed
+#> Time difference of 6.182886 secs
+
+plot_plate(bc,
+  plate = plate, row = row, column = col, .color = Group,
+  title = "Ex1: Using a dedicated plate scoring function:\nThis should show a latin square!"
+)
+

+

+
+
library(designit)
+library(ggplot2)
+library(dplyr)
+#> 
+#> Attaching package: 'dplyr'
+#> The following objects are masked from 'package:stats':
+#> 
+#>     filter, lag
+#> The following objects are masked from 'package:base':
+#> 
+#>     intersect, setdiff, setequal, union
+library(tidyr)
+
+

+Example 2: Scoring two plates at once + +

+

+(latin square for each plate should give the best score) +

+

+We set up in one go 2 plate scoring functions, each one acting locally +on a specific plate, plus one osat score to guarantee uniform +distribution of groups across plates. +

+

+The initial sample allocation (by assign_in_order) leads to a poor +starting point since each plate has only 2 of the 4 groups represented. +

+

+This is not a problem as long as we make sure that initial permutations +are likely to remedy the situation. That’s why we ensure 10 pairwise +sample swaps for the first iterations. +

+
# Setting up the batch container
+example2 <- BatchContainer$new(
+  dimensions = c(
+    plate = 2,
+    row = 4, col = 4
+  )
+)
+
+# Add samples to container
+example2 <- assign_in_order(example2, samples = tibble::tibble(
+  Group = c(rep(c("Grp 1", "Grp 2", "Grp 3", "Grp 4"), each = 8)),
+  ID = 1:32
+))
+
+scoring_f <- c(mk_plate_scoring_functions(example2, plate = "plate", row = "row", column = "col", group = "Group"),
+  osat_plate = osat_score_generator(batch_vars = c("plate"), feature_vars = c("Group"))
+)
+
+plot_plate(example2,
+  plate = plate, row = row, column = col, .color = Group,
+  title = "Ex2: Initial sample arrangement"
+)
+

+

+

+example2$score(scoring_f)
+#>    Plate 1    Plate 2 osat_plate 
+#>   23.89265   23.89265  128.00000
+
set.seed(41)
+bc <- optimize_design(
+  example2,
+  scoring = scoring_f,
+  n_shuffle = c(rep(10, 10), rep(3, 90), rep(2, 100), rep(1, 1400)),
+  acceptance_func = mk_simanneal_acceptance_func(mk_simanneal_temp_func(T0 = 10000, alpha = 0.5)),
+  aggregate_scores_func = worst_score,
+  quiet = TRUE
+)
+
bc$trace$elapsed
+#> Time difference of 16.73602 secs
+
+bc$score(scoring_f)
+#>    Plate 1    Plate 2 osat_plate 
+#>   6.127258   6.094080   0.000000
+
+plot_plate(bc,
+  plate = plate, row = row, column = col, .color = Group,
+  title = "Ex2: Design created by swapping samples 'globally' across the plates"
+)
+

+

+

+While this ‘global’ optimization is possible, it does probably not +converge to an (almost) ideal solution in an acceptable time if there +are more samples involved. This is due to a lot of unproductive sample +swapping happening across the plates. +

+

+One way to address this: we may split the optimization into two cycles, +first assigning samples to plates (balancing groups), then improving the +positions of the samples within each plate. This motivates the use of a +dedicated sample permutation function which takes the plate structure +into account and only shuffles samples around within one plate. +

+
scoring_f <- osat_score_generator(batch_vars = c("plate"), feature_vars = c("Group"))
+
+set.seed(42)
+bc <- optimize_design(
+  example2,
+  scoring = scoring_f,
+  quiet = TRUE,
+  max_iter = 200, # this is set to shorten vignette run-time, normally we don't know.
+  n_shuffle = 2,
+  acceptance_func = mk_simanneal_acceptance_func(mk_simanneal_temp_func(T0 = 10000, alpha = 0.5)),
+)
+bc$trace$elapsed
+#> Time difference of 2.140794 secs
+
+plot_plate(bc,
+  plate = plate, row = row, column = col, .color = Group,
+  title = "Ex2: 'Plate wise' design\nStep 1: after allocating samples to plates"
+)
+

+

+

+scoring_f <- mk_plate_scoring_functions(bc, plate = "plate", row = "row", column = "col", group = "Group")
+
+bc$score(scoring_f)
+#>  Plate 1  Plate 2 
+#> 12.77527 13.63704
+
set.seed(42)
+bc <- optimize_design(
+  bc,
+  scoring = scoring_f,
+  max_iter = 400,
+  shuffle_proposal_func = mk_subgroup_shuffling_function(subgroup_vars = c("plate")),
+  acceptance_func = mk_simanneal_acceptance_func(mk_simanneal_temp_func(T0 = 1000, alpha = 0.5)),
+  aggregate_scores_func = L2s_norm,
+  quiet = TRUE
+)
+
bc$trace$elapsed
+#> Time differences in secs
+#> [1] 2.140794 3.270934
+
+bc$score(scoring_f)
+#>  Plate 1  Plate 2 
+#> 6.854748 6.309297
+
+plot_plate(bc,
+  plate = plate, row = row, column = col, .color = Group,
+  title = "Ex2: 'Plate wise' design\nStep 2: after arranging samples within plates"
+)
+

+

+

+In this case, the shuffling function exchanges 1 pair of sample +assignments every time (the default). However, any number of constant +swaps or a swapping protocol (formally a vector of integers) can be +supplied as well. +

+

+Now for the most efficient solution: we start again by first assigning +samples to plates (balancing groups), then making use of the +independence of the two within-plate optimizations and improving them +one after the other. +

+

+This is possible by passing the argument to the function that generates +the permutations. It enforces permutation only to happen first within +plate 1, then within plate 2, so that the two scores can be optimized in +succeeding runs. +

+
scoring_f <- osat_score_generator(batch_vars = c("plate"), feature_vars = c("Group"))
+
set.seed(42)
+bc <- optimize_design(
+  example2,
+  scoring = scoring_f,
+  quiet = TRUE,
+  max_iter = 150, # this is set to shorten vignette run-time, normally we don't know.
+  n_shuffle = 2,
+  acceptance_func = mk_simanneal_acceptance_func(mk_simanneal_temp_func(T0 = 10000, alpha = 0.5)),
+)
+
bc$trace$elapsed
+#> Time difference of 1.791624 secs
+
+plot_plate(bc,
+  plate = plate, row = row, column = col, .color = Group,
+  title = "Ex2: 'Serial plate' design\nStep 1: after allocating samples to plates"
+)
+

+

+

+scoring_f <- mk_plate_scoring_functions(bc, plate = "plate", row = "row", column = "col", group = "Group")
+
+bc$score(scoring_f)
+#>  Plate 1  Plate 2 
+#> 10.57482 26.16613
+
set.seed(42)
+bc <- optimize_design(
+  bc,
+  scoring = scoring_f,
+  max_iter = 150,
+  quiet = TRUE,
+  shuffle_proposal_func = mk_subgroup_shuffling_function(subgroup_vars = c("plate"), restrain_on_subgroup_levels = c(1)),
+  acceptance_func = mk_simanneal_acceptance_func(mk_simanneal_temp_func(T0 = 1000, alpha = 0.5)),
+  aggregate_scores_func = L2s_norm
+)
+
bc$trace$elapsed
+#> Time differences in secs
+#> [1] 1.791624 1.591002
+
+bc$score(scoring_f)
+#>   Plate 1   Plate 2 
+#>  6.416193 26.166134
+
set.seed(42)
+bc <- optimize_design(
+  bc,
+  scoring = scoring_f,
+  max_iter = 550,
+  quiet = TRUE,
+  shuffle_proposal_func = mk_subgroup_shuffling_function(subgroup_vars = c("plate"), restrain_on_subgroup_levels = c(2)),
+  acceptance_func = mk_simanneal_acceptance_func(mk_simanneal_temp_func(T0 = 1000, alpha = 0.5)),
+  aggregate_scores_func = L2s_norm
+)
+
bc$trace$elapsed
+#> Time differences in secs
+#> [1] 1.791624 1.591002 4.226352
+
+bc$score(scoring_f)
+#>  Plate 1  Plate 2 
+#> 6.416193 6.581966
+
+plot_plate(bc,
+  plate = plate, row = row, column = col, .color = Group,
+  title = "Ex2: 'Serial plate' design\nStep 2: after optimizing each plate in turn"
+)
+

+

+
+
library(designit)
+library(ggplot2)
+library(dplyr)
+#> 
+#> Attaching package: 'dplyr'
+#> The following objects are masked from 'package:stats':
+#> 
+#>     filter, lag
+#> The following objects are masked from 'package:base':
+#> 
+#>     intersect, setdiff, setequal, union
+library(tidyr)
+
+

+Example 3: 3 plates with different dimension and different sample group +sizes + +

+

+We simulate one ordinary 96 well plate and two smaller ones with sizes +6x8 and 4x6, respectively. There are 3 experimental groups as well with +sample sizes of 69, 30 and 69, respectively. This example should +demonstrate that an empirically determined normalization of the scores +yield 3 comparable numerical values, independent of the different plate +and group sizes. +

+

+Again, a first optimization aims to achieve same group allocation on +each plate, while the second run takes care of the sample distribution +on each plate. +

+

+We use assign_random in this example to start from a more balanced +initial position as compared to example 2. +

+

+Aggregation of scores is done by the L2s method (square of L2 norm). +Because of the comparable numerical range of scores, also the +worst_score method could be used for aggregation. However, the L2s +method always takes into account all individual scores, providing more +stability in case the 3 plate scores are not exactly normalized. +

+
# Setting up the batch container
+
+example3 <- BatchContainer$new(
+  dimensions = c(
+    plate = 3,
+    row = 8, col = 12
+  ),
+  exclude = dplyr::bind_rows(
+    tidyr::crossing(plate = 2, row = 1:8, col = 1:12) %>% dplyr::filter(row > 6 | col > 8),
+    tidyr::crossing(plate = 3, row = 1:8, col = 1:12) %>% dplyr::filter(row > 4 | col > 6)
+  )
+)
+
+
+# Assign samples randomly to start from a better initial state
+example3 <- assign_random(example3,
+  samples = tibble::tibble(
+    Group = rep.int(c("Grp 1", "Grp 2", "Grp3"),
+      times = c(69, 30, 69)
+    ),
+    ID = 1:168
+  )
+)
+
+scoring_f <- osat_score_generator(batch_vars = c("plate"), feature_vars = c("Group"))
+
set.seed(42)
+bc <- optimize_design(
+  example3,
+  scoring = scoring_f,
+  quiet = TRUE,
+  max_iter = 150,
+  n_shuffle = 2,
+  acceptance_func = mk_simanneal_acceptance_func(mk_simanneal_temp_func(T0 = 1000, alpha = 0.5)),
+)
+
bc$trace$elapsed
+#> Time difference of 2.03003 secs
+
plot_plate(bc,
+  plate = plate, row = row, column = col, .color = Group,
+  title = "Ex3: Dealing with plates of different size\nStep 1: after distributing groups across plates"
+)
+

+

+
scoring_f <- mk_plate_scoring_functions(bc,
+  plate = "plate", row = "row",
+  column = "col", group = "Group"
+)
+
+bc$score(scoring_f)
+#>   Plate 1   Plate 2   Plate 3 
+#>  9.387071 10.302690  9.826243
+
set.seed(42)
+bc <- optimize_design(
+  bc,
+  scoring = scoring_f,
+  max_iter = 300,
+  shuffle_proposal_func = mk_subgroup_shuffling_function(
+    subgroup_vars = c("plate"),
+    n_swaps = c(rep(5, 500), rep(3, 1500), rep(2, 3000), rep(1, 5000))
+  ),
+  # acceptance_func = mk_simanneal_acceptance_func(mk_simanneal_temp_func(T0 = 10000, alpha = 1)),
+  aggregate_scores_func = L2s_norm,
+  quiet = TRUE
+)
+
bc$trace$elapsed
+#> Time differences in secs
+#> [1] 2.030030 4.778121
+
+bc$score(scoring_f)
+#>  Plate 1  Plate 2  Plate 3 
+#> 8.809205 8.553802 8.185525
+
plot_plate(bc,
+  plate = plate, row = row, column = col, .color = Group,
+  title = "Ex3: Dealing with plates of different size\nStep 2: after swapping samples within plates"
+)
+

+

+
+
library(designit)
+library(ggplot2)
+library(dplyr)
+#> 
+#> Attaching package: 'dplyr'
+#> The following objects are masked from 'package:stats':
+#> 
+#>     filter, lag
+#> The following objects are masked from 'package:base':
+#> 
+#>     intersect, setdiff, setequal, union
+library(tidyr)
+
+

+Example 4: More than one group factor to balance and empty plate +positions + +

+

+In this example, we have 2 factors to distribute across one plate: +Treatment and (animal) sex. +

+

+To indicate that the balancing of treatment is considered more important +than the animal sex we assign a custom aggregation function giving more +weight to the treatment variable. (A better aggregation mechanism has to +be implemented!!!) +

+

+There can be less samples than possible positions on the plate(s). In +this case, we simulate 20 animal derived samples distributed on a plate +with 24 locations. +

+
# Setting up the batch container
+example4 <- BatchContainer$new(
+  dimensions = c(
+    plate = 1, row = 6, col = 4
+  )
+)
+
+
+# Assign samples randomly to start from lower score (avoid Inf values even since plate 3 will miss 2 groups initially :)
+example4 <- assign_in_order(example4, samples = tibble::tibble(
+  Group = rep.int(c("Treatment 1", "Treatment 2"), times = c(10, 10)),
+  Sex = c(rep(c("M", "F", "F", "M"), times = 4), "M", NA, NA, "F"), ID = 1:20
+))
+
+cowplot::plot_grid(
+  plot_plate(example4, plate = plate, row = row, column = col, .color = Group, title = "Initial layout by Group"),
+  plot_plate(example4, plate = plate, row = row, column = col, .color = Sex, title = "Initial layout by Sex"),
+  ncol = 2
+)
+

+

+

+
+scoring_f <- c(
+  Group = mk_plate_scoring_functions(example4, row = "row", column = "col", group = "Group"),
+  Sex = mk_plate_scoring_functions(example4, row = "row", column = "col", group = "Sex")
+)
+
+example4$score(scoring_f)
+#> Group.Plate   Sex.Plate 
+#>    83.63858   239.20748
+
set.seed(42)
+bc <- optimize_design(
+  example4,
+  scoring = scoring_f,
+  max_iter = 750,
+  n_shuffle = 1,
+  acceptance_func = mk_simanneal_acceptance_func(mk_simanneal_temp_func(T0 = 10000, alpha = 1)),
+  aggregate_scores_func = function(scores, ...) {
+    2 * scores["Group.Plate"] + scores["Sex.Plate"]
+  },
+  quiet = TRUE
+)
+
bc$trace$elapsed
+#> Time difference of 6.251454 secs
+
+bc$score(scoring_f)
+#> Group.Plate   Sex.Plate 
+#>    8.019656    7.608810
+
+cowplot::plot_grid(
+  plot_plate(bc, plate = plate, row = row, column = col, .color = Group, title = "Final layout by Group"),
+  plot_plate(bc, plate = plate, row = row, column = col, .color = Sex, title = "Final layout by Sex"),
+  ncol = 2
+)
+

+

+

+We do the same example with auto-scaling, weighted scoring and SA to +have a reference! +

+
set.seed(42)
+bc <- optimize_design(
+  bc,
+  scoring = scoring_f,
+  max_iter = 500,
+  n_shuffle = 1,
+  acceptance_func = mk_simanneal_acceptance_func(mk_simanneal_temp_func(T0 = 10000, alpha = 1)),
+  aggregate_scores_func = function(scores, ...) {
+    purrr::set_names(2 * scores["Group.Plate"] + scores["Sex.Plate"], nm = "Weighted.Score")
+  },
+  autoscale_scores = T,
+  quiet = TRUE
+)
+#> ... Performing simple mean/stddev adjustment.
+
bc$score(scoring_f)
+#> Group.Plate   Sex.Plate 
+#>    8.080860    7.458345
+
+cowplot::plot_grid(
+  plot_plate(bc, plate = plate, row = row, column = col, .color = Group, title = "Final layout by Group"),
+  plot_plate(bc, plate = plate, row = row, column = col, .color = Sex, title = "Final layout by Sex"),
+  ncol = 2
+)
+

+

+

+We do the same example with auto-scaling and position-dependent scoring +now, not aggregating the score vector! This is more effective even when +using the default acceptance function. We are strictly prioritizing the +leftmost score in addition to reflect relevance for the design. +

+
scoring_f <- c(
+  Group = mk_plate_scoring_functions(example4, row = "row", column = "col", group = "Group"),
+  Sex = mk_plate_scoring_functions(example4, row = "row", column = "col", group = "Sex")
+)
+
+example4$score(scoring_f)
+#> Group.Plate   Sex.Plate 
+#>    83.63858   239.20748
+
+set.seed(42)
+bc <- optimize_design(
+  example4,
+  scoring = scoring_f,
+  max_iter = 5000,
+  n_shuffle = 1,
+  acceptance_func = accept_leftmost_improvement,
+  autoscale_scores = TRUE,
+  quiet = TRUE
+)
+#> ... Performing simple mean/stddev adjustment.
+
bc$score(scoring_f)
+#> Group.Plate   Sex.Plate 
+#>    7.619846    7.473524
+
+cowplot::plot_grid(
+  plot_plate(bc, plate = plate, row = row, column = col, .color = Group, title = "Final layout by Group"),
+  plot_plate(bc, plate = plate, row = row, column = col, .color = Sex, title = "Final layout by Sex"),
+  ncol = 2
+)
+

+

+

+Using a tolerance value to accept slightly worse solutions in the +leftmost relevant score if overcompensated by other scores: +

+
scoring_f <- c(
+  Group = mk_plate_scoring_functions(example4, row = "row", column = "col", group = "Group"),
+  Sex = mk_plate_scoring_functions(example4, row = "row", column = "col", group = "Sex")
+)
+
+
+set.seed(42)
+bc <- optimize_design(
+  example4,
+  scoring = scoring_f,
+  max_iter = 5000,
+  n_shuffle = 1,
+  acceptance_func = ~ accept_leftmost_improvement(..., tolerance = 0.1),
+  autoscale_scores = TRUE,
+  quiet = TRUE
+)
+#> ... Performing simple mean/stddev adjustment.
+
+bc$score(scoring_f)
+#> Group.Plate   Sex.Plate 
+#>    7.366667    7.323324
+
cowplot::plot_grid(
+  plot_plate(bc, plate = plate, row = row, column = col, .color = Group, title = "Final layout by Group"),
+  plot_plate(bc, plate = plate, row = row, column = col, .color = Sex, title = "Final layout by Sex"),
+  ncol = 2
+)
+

+

+

+Testing an alternative left-to-right weighing of scores, based on +exponential down-weighing of the respective score differences at +position \(p\) with factor \(\kappa^p\), \(0 &lt; \kappa +&lt; 1\) We choose a \(\kappa\) of 0.5, i.e. the second +score’s improvement counts half of that of the first one. +

+
scoring_f <- c(
+  Group = mk_plate_scoring_functions(example4, row = "row", column = "col", group = "Group"),
+  Sex = mk_plate_scoring_functions(example4, row = "row", column = "col", group = "Sex")
+)
+
+bc$score(scoring_f)
+#> Group.Plate   Sex.Plate 
+#>    7.366667    7.323324
+
+set.seed(42)
+bc <- optimize_design(
+  example4,
+  scoring = scoring_f,
+  max_iter = 1000,
+  n_shuffle = 1,
+  acceptance_func = mk_exponentially_weighted_acceptance_func(kappa = 0.5, simulated_annealing = T),
+  autoscale_scores = TRUE,
+  quiet = TRUE
+)
+#> ... Performing simple mean/stddev adjustment.
+
bc$score(scoring_f)
+#> Group.Plate   Sex.Plate 
+#>    7.630367    7.616179
+
+cowplot::plot_grid(
+  plot_plate(bc, plate = plate, row = row, column = col, .color = Group, title = "Final layout by Group"),
+  plot_plate(bc, plate = plate, row = row, column = col, .color = Sex, title = "Final layout by Sex"),
+  ncol = 2
+)
+

+

+
+
library(designit)
+library(ggplot2)
+library(dplyr)
+#> 
+#> Attaching package: 'dplyr'
+#> The following objects are masked from 'package:stats':
+#> 
+#>     filter, lag
+#> The following objects are masked from 'package:base':
+#> 
+#>     intersect, setdiff, setequal, union
+library(tidyr)
+
+

+Example 5: Avoiding ‘regular patterns’ in plate layout + +

+

+In some cases it may be essential to avoid samples of the same group +being put into the same row or column on a plate, i.e. these variables +are regarded as factor levels of their own, in addition to the spatial +relation of the samples. +

+

+Plate scoring functions can use an specific penalty for these ‘linearly +arranged’ samples on top of the distance metrics chosen. +

+
# Setting up the batch container
+example5 <- BatchContainer$new(
+  dimensions = c(
+    plate = 1, row = 8, col = 12
+  )
+)
+
+# Assign samples randomly to start from lower score (avoid `Inf` values when doing the 'hard' penalization)
+example5 <- assign_random(example5, samples = tibble::tibble(
+  Group = rep.int(paste("Group", 1:5), times = c(8, 8, 8, 8, 64)),
+  ID = 1:96
+))
+
+penalize_lines <- "hard"
+
+scoring_f <- c(
+  Group = mk_plate_scoring_functions(example5, row = "row", column = "col", group = "Group", p = 2, penalize_lines = penalize_lines)
+)
+
+example5$score(scoring_f)
+#> Group.Plate 
+#>    11.08608
+
set.seed(42)
+bc <- optimize_design(
+  example5,
+  scoring = scoring_f,
+  max_iter = 5000,
+  n_shuffle = 1,
+  acceptance_func = mk_simanneal_acceptance_func(mk_simanneal_temp_func(T0 = 500, alpha = 0.1)),
+  quiet = T
+)
+
bc$trace$elapsed
+#> Time difference of 29.47413 secs
+
+bc$score(scoring_f)
+#> Group.Plate 
+#>    8.785693
+
+plot_plate(bc, plate = plate, row = row, column = col, .color = Group, title = stringr::str_c("Line penalization: ", penalize_lines))
+

+

+
+
+ + + +
+ + + + +
+ + + + + + + + diff --git a/articles/shuffling_with_constraints.html b/articles/shuffling_with_constraints.html new file mode 100644 index 00000000..1abdbc0b --- /dev/null +++ b/articles/shuffling_with_constraints.html @@ -0,0 +1,2606 @@ + + + + + + + +Shuffling with constraints • designit + + + + + + + + + + + + + + + + + + + +
+
+ + + + +
+
+ + + + +
+

Purpose of the vignette +

+

This example demonstrates that by using customized shuffling +functions, it is possible to restrain the design optimization to only +score sample arrangements that fit the given constraints.

+

Key idea is that every reshuffling produces a ‘valid’ sample +permutation that is not violating those constraints, even if the +suggested solution may be quite bad. During optimization, we pick the +best design solution from the possible ones by appropriate scoring.

+

The user is free to implement custom shuffling functions and pass +those to the optimizer. However, some knowledge is required regarding +the internal workings of the optimization and batch container setup. +Therefore the package provides a little generic constructor for +customized shufflings shuffle_grouped_data in which +certain types of constraints that relate to grouped samples may be +specified by the passed parameters.

+
+
+

The design problem +

+
+

Samples and treatments +

+

We refer to a simplified version of the in vivo example +which is examined deeper in a dedicated vignette.

+
+data("invivo_study_samples")
+
+invivo_study_samples <- dplyr::mutate(invivo_study_samples,
+  Litter_combine_females = ifelse(Sex == "F", "female_all", Litter)
+)
+str(invivo_study_samples)
+#> 'data.frame':    59 obs. of  9 variables:
+#>  $ AnimalID              : chr  "F1" "F2" "F3" "F4" ...
+#>  $ Strain                : chr  "Strain B" "Strain B" "Strain B" "Strain B" ...
+#>  $ Sex                   : chr  "F" "F" "F" "F" ...
+#>  $ BirthDate             : Date, format: "2021-05-24" "2021-03-01" ...
+#>  $ Earmark               : chr  "R" "2L" "2L1R" "L" ...
+#>  $ ArrivalWeight         : num  19.4 26.5 20.8 22.1 22.9 ...
+#>  $ Arrival.weight.Unit   : chr  "g" "g" "g" "g" ...
+#>  $ Litter                : chr  "Litter 1" "Litter 2" "Litter 2" "Litter 2" ...
+#>  $ Litter_combine_females: chr  "female_all" "female_all" "female_all" "female_all" ...
+
+invivo_study_samples %>%
+  dplyr::count(Strain, Sex, Litter_combine_females) %>%
+  gt::gt()
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
StrainSexLitter_combine_femalesn
Strain AFfemale_all7
Strain AMLitter 103
Strain AMLitter 114
Strain AMLitter 125
Strain AMLitter 134
Strain AMLitter 146
Strain BFfemale_all7
Strain BMLitter 13
Strain BMLitter 35
Strain BMLitter 44
Strain BMLitter 54
Strain BMLitter 64
Strain BMLitter 73
+
+

We will use the litter as a factor to form cages in our design. +However, in order to indicate the compatibility of female animals (see +in vivo study vignette), a pseudo-litter +female_all is created here to group all the females +together, marking them as interchangeable for the subgroup (i.e. cage) +allocation.

+

In the simplified setup we want to assign two treatments to those +animals, balancing for strain and sex as the primary suspected +confounders. The batch container is prepared as follows:

+
+treatments <- factor(rep(c("Treatment A", "Treatment B"), c(30, 29)))
+table(treatments)
+#> treatments
+#> Treatment A Treatment B 
+#>          30          29
+
+bc <- BatchContainer$new(locations_table = data.frame(Treatment = treatments, Position = seq_along(treatments)))
+
+bc <- assign_in_order(bc, invivo_study_samples)
+
+scoring_f <- osat_score_generator(batch_vars = "Treatment", feature_vars = c("Strain", "Sex"))
+
+bc
+#> Batch container with 59 locations and 59 samples (assigned).
+#>   Dimensions: Treatment, Position
+
+
+ +

As noted, we have to assign animals to cages in this example. The +cage is thus acting as the grouping factor for the samples (animals) on +which we may want to put further constraints. Concretely:

+
    +
  • We want to form cages with ideally 3 animals each +(tolerated/preferred range is from 2-5)
  • +
  • Variables Strain, Sex and Treatment must be homogeneous within +cage
  • +
  • Animals of different litters must not be put into the same cage
  • +
  • If at all possible, avoid putting animals with the same ear markings +into one cage
  • +
+

We will tackle the usual factor balancing (using the osat score) and +the additional constraints at the same time, combined in one +conceptional framework.

+

As stated, the main idea is to provide a customized shuffling +function that ensures that only ‘suitable’ design proposals are +generated and passed to the scoring function which will then identify a +good one.

+

Also keep in mind that what is the cage here could be any subgroup +into which samples have to be partitioned.

+
+
+
+

Doing it all in one go +

+

The wrapper shuffle_grouped_data allows to construct a +shuffling function that satisfies all constraints defined above at the +same time. It can be passed to the optimizer together with other user +defined options such as the scoring or acceptance functions.

+
+bc2 <- optimize_design(
+  bc,
+  scoring = scoring_f,
+  shuffle_proposal_func = shuffle_grouped_data(bc,
+    allocate_var = "Treatment",
+    keep_together_vars = c("Strain", "Sex"),
+    keep_separate_vars = c("Earmark"),
+    subgroup_var_name = "Cage",
+    n_min = 2, n_ideal = 3, n_max = 5,
+    strict = TRUE,
+    report_grouping_as_attribute = TRUE
+  ),
+  max_iter = 600
+)
+#> 
+#> Formed 4 homogeneous groups using 59 samples.
+#> 22 subgroups needed to satisfy size constraints.
+#> 
+#> Finding possible ways to allocate variable of interest with 2 levels ...
+#> 
+#> Aborted after 1000010 recursive calls (maxCalls limit).
+#> 176364 allocations found.
+#> Usage of sample attributes --> executing first shuffling call.
+#> Checking variances of 1-dim. score vector.
+#> ... (295.565) - OK
+#> Initial score: 453.202
+#> Adding 4 attributes to samples.
+#> Achieved score: 355.575 at iteration 2
+#> Achieved score: 305.134 at iteration 19
+#> Achieved score: 272.592 at iteration 20
+#> No permutations fulfilling the 'keep_separate' constraints in 1000 iters!
+#> Increasing number of tolerated violations to 1
+#> Achieved score: 231.507 at iteration 34
+#> Achieved score: 181.473 at iteration 52
+#> Achieved score: 143.032 at iteration 116
+#> Achieved score: 122.49 at iteration 123
+#> Achieved score: 105.405 at iteration 165
+#> Achieved score: 104.999 at iteration 356
+#> Achieved score: 79.371 at iteration 384
+#> Achieved score: 52.931 at iteration 525
+#> Achieved score: 44.388 at iteration 546
+
+design <- bc2$get_samples()
+

allocate_var is the batch container variable that should +be primarily assigned to individual samples.

+

keep_together_vars is a list of variables that must be +homogeneous within a subgroup (here: cage).

+

keep_separate_vars lists variables which should have +different values within a subgroup (here: cage), if at all possible. +This is a soft constraint and will be relaxed in a stepwise way until +solutions can be found.

+

subgroup_var_name allows to give the generated subgroup +variable a useful name.

+

n_min, n_max and n_ideal +specify the minimal, maximal and ideal group sizes, respectively. It is +often necessary to release the strict criterion to find any +solution at all that satisfies those size criteria.

+

report_grouping_as_attribute allows, if TRUE, to add the +updated group variable into the batch container at each iteration, so +that scoring functions could make use of this variable (here: cage)!

+

Following the output of the optimizer, we see that a solution was +identified that satisfies all constraints, with the exception of +tolerating one violation of earmark-uniqueness within a cage.

+

The following cages (homogeneous in strain, sex and treatment) have +been generated in the process:

+
+design %>%
+  dplyr::count(Cage, Strain, Sex, Treatment) %>%
+  gt::gt()
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
CageStrainSexTreatmentn
1_1Strain AFTreatment A3
1_2Strain AFTreatment A2
1_3Strain AFTreatment A2
2_1Strain AMTreatment A3
2_2Strain AMTreatment A3
2_3Strain AMTreatment A3
2_4Strain AMTreatment A3
2_5Strain AMTreatment B3
2_6Strain AMTreatment B3
2_7Strain AMTreatment B2
2_8Strain AMTreatment B2
3_1Strain BFTreatment B3
3_2Strain BFTreatment A2
3_3Strain BFTreatment B2
4_1Strain BMTreatment A3
4_2Strain BMTreatment A3
4_3Strain BMTreatment A3
4_4Strain BMTreatment B3
4_5Strain BMTreatment B3
4_6Strain BMTreatment B3
4_7Strain BMTreatment B3
4_8Strain BMTreatment B2
+
+
+
+

Multiple step approach +

+

shuffle_grouped_data is a wrapper that consecutively +calls other helper function. As an addendum, let us break the whole +procedure down into parts that show what is happening internally at each +step.

+
+

Form homogeneous subgroups - pools of animals that could go into one +cage +

+

We have to divide our animal cohort into subgroups with same strain +and sex, meeting size constraints as stated above. Since 2-5 animals +should go into one cage, we specify n_minand +n_maxaccordingly. n_ideal would be selected by +default as the mean of those two, but we specify it explicitly here, +too.

+

The homogeneity of subgroups regarding strain and sex is achieved by +listing those two parameters as keep_together_vars.

+

Assignment of treatments should be performed as well at some point. +We thus specify Treatment as the allocation variable.

+

Note that the Treatment variable is technically a batch +container location and not a part of the sample list. This distinction +does not matter at this point. However, all required variables must +exist in the batch container object.

+

The following call to form_homogeneous_subgroups() +produces an object that holds all relevant information about the +samples, the allocation variable and the sizes of the subgroups that +have to be formed. It is NOT decided, however, which animal will end up +in which subgroup. This will be a matter of optimization later on.

+
+subg <- form_homogeneous_subgroups(
+  batch_container = bc, allocate_var = "Treatment",
+  keep_together_vars = c("Strain", "Sex", "Litter_combine_females"),
+  subgroup_var_name = "Cage",
+  n_min = 2, n_ideal = 3, n_max = 5
+)
+#> 
+#> Formed 13 homogeneous groups using 59 samples.
+#> 18 subgroups needed to satisfy size constraints.
+

In this example, 18 subgroups have to be formed to meet all +constraints.

+

It is possible to obtain more information from the returned list +object. Inspection of element Subgroup_Sizes tells us that +13 ‘animal pools’ have to be formed which are homogeneous in the +relevant parameters (here: strain and sex). Each of those groups happens +to be split in subgroups with a size between 2 and 4 animals , which +will later constitute the individual cages.

+
+subg$Subgroup_Sizes
+#> $`Strain A/F/female_all`
+#> [1] 3 4
+#> 
+#> $`Strain A/M/Litter 10`
+#> [1] 3
+#> 
+#> $`Strain A/M/Litter 11`
+#> [1] 4
+#> 
+#> $`Strain A/M/Litter 12`
+#> [1] 3 2
+#> 
+#> $`Strain A/M/Litter 13`
+#> [1] 4
+#> 
+#> $`Strain A/M/Litter 14`
+#> [1] 3 3
+#> 
+#> $`Strain B/F/female_all`
+#> [1] 3 4
+#> 
+#> $`Strain B/M/Litter 1`
+#> [1] 3
+#> 
+#> $`Strain B/M/Litter 3`
+#> [1] 3 2
+#> 
+#> $`Strain B/M/Litter 4`
+#> [1] 4
+#> 
+#> $`Strain B/M/Litter 5`
+#> [1] 4
+#> 
+#> $`Strain B/M/Litter 6`
+#> [1] 4
+#> 
+#> $`Strain B/M/Litter 7`
+#> [1] 3
+
+
+

Find all valid ways to allocate treatments to the subgroups +

+

Each subgroup of animals receives one specific treatment. Or more +generally: subgroups have to be homogeneous regarding the allocation +variable.

+

This introduces another type of constraint, since numbers have to add +up to 10 ‘Control’ and 10 ‘Compound’ cases, as given by the +treatments variable. As a next step, we have to find all +possible combinations of subgroups which produce valid options for the +treatment allocation. That’s done with the next call.

+

This will find a large number of different ways to assign treatments +to subgroups that lead to the correct overall number of treated +animals.

+
+possible <- compile_possible_subgroup_allocation(subg)
+#> 
+#> Finding possible ways to allocate variable of interest with 2 levels ...
+#> 
+#> Finished with 108296 recursive calls.
+#> 14660 allocations found.
+
+
+

Generate shuffling function for potential study designs +

+

So far we only know the sizes of subgroups (i.e. cages). Thus, in a +last step we have to assign specific animals to the various subgroups. +Ideally each group of ‘equivalent animals’ (in terms of strain and sex) +is split up into more than one subgroup, so there’s many potential ways +to assign animals to those.

+

To allow optimization as usual, we want to generate a shuffling +function that produces only valid solutions in terms of our constraints, +so that optimization can iterate efficiently over this solution space. +The function can be generated by calling +shuffle_with_subgroup_formation() with the previously created +subgrouping object and the list of possible treatment allocations.

+

Every call to this shuffling function will return a permutation index +(of the original samples) that constitutes a valid solution to be +scored.

+

The permutation function actually also constructs a ‘Cage’ variable +(see parameter subgroup_var_name in the call to +form_homogeneous_subgroups()). To make this parameter available +and join it to the samples in the batch container, use flag +report_grouping_as_attribute in the construction of the +permutation function.

+
+shuffle_proposal <- shuffle_with_subgroup_formation(subg, possible, report_grouping_as_attribute = TRUE)
+
+shuffle_proposal()
+#> $location_assignment
+#>  [1]  8 10 12  9 11 13 14 38 39 40 41 42 43 44 46 48 49 45 47 50 51 52 53 55 56
+#> [26] 58  1  3  4  5 54 57 59  2  6  7 35 36 37 19 20 21 26 27 15 16 17 18 22 23
+#> [51] 24 25 28 29 30 31 32 33 34
+#> 
+#> $samples_attr
+#> # A tibble: 59 × 4
+#>    alloc_var_level group subgroup Cage 
+#>    <chr>           <int>    <int> <chr>
+#>  1 Treatment A         7        2 7_2  
+#>  2 Treatment B         7        1 7_1  
+#>  3 Treatment A         7        2 7_2  
+#>  4 Treatment A         7        2 7_2  
+#>  5 Treatment A         7        2 7_2  
+#>  6 Treatment B         7        1 7_1  
+#>  7 Treatment B         7        1 7_1  
+#>  8 Treatment A         1        1 1_1  
+#>  9 Treatment A         1        2 1_2  
+#> 10 Treatment A         1        1 1_1  
+#> # ℹ 49 more rows
+

Calling the shuffle proposal function repeatedly produces a valid +(constraint-aware) sample arrangement each time, with the grouping +variable (here: Cage) reported alongside. (The optimizer will merge the +‘Cage’ variable into the batch container after each iteration, so that +it can be used for scoring as if it would have been in the container +from the beginning!)

+
+
+

Use shuffling function for optimizing design +

+

We can finally use the customized shuffling function in the +optimization.

+
+bc3 <- optimize_design(
+  bc,
+  scoring = scoring_f,
+  shuffle_proposal_func = shuffle_proposal,
+  max_iter = 300
+)
+#> Usage of sample attributes --> executing first shuffling call.
+#> Checking variances of 1-dim. score vector.
+#> ... (337.114) - OK
+#> Initial score: 289.541
+#> Adding 4 attributes to samples.
+#> Achieved score: 189.066 at iteration 9
+#> Achieved score: 139.439 at iteration 15
+#> Achieved score: 105.405 at iteration 34
+#> Achieved score: 52.931 at iteration 55
+#> Achieved score: 51.304 at iteration 70
+#> Achieved score: 32.863 at iteration 206
+
+design <- bc3$get_samples()
+
+# Obeying all constraints does not lead to a very balanced sample allocation:
+dplyr::count(design, Treatment, Strain) %>% gt::gt()
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TreatmentStrainn
Treatment AStrain A17
Treatment AStrain B13
Treatment BStrain A12
Treatment BStrain B17
+
+
+
+dplyr::count(design, Treatment, Sex) %>% gt::gt()
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TreatmentSexn
Treatment AF10
Treatment AM20
Treatment BF4
Treatment BM25
+
+
+
+
+ + + +
+ + + + +
+ + + + + + + + diff --git a/authors.html b/authors.html new file mode 100644 index 00000000..f64dfb3e --- /dev/null +++ b/authors.html @@ -0,0 +1,151 @@ + +Authors and Citation • designit + + +
+
+ + + +
+
+
+ + + +
  • +

    Iakov I. Davydov. Author, maintainer, copyright holder. +

    +
  • +
  • +

    Juliane Siebourg-Polster. Author, copyright holder. +

    +
  • +
  • +

    Guido Steiner. Author, copyright holder. +

    +
  • +
  • +

    Balazs Banfai. Author, copyright holder. +

    +
  • +
  • +

    F. Hoffman-La Roche. Copyright holder, funder. +

    +
  • +
+
+
+

Citation

+ Source: DESCRIPTION +
+
+ + +

Davydov II, Siebourg-Polster J, Steiner G, Banfai B (2023). +designit: Blocking and Randomization for Experimental Design. +R package version 0.4.1, https://github.com/BEDApub/designit/, https://bedapub.github.io/designit/. +

+
@Manual{,
+  title = {designit: Blocking and Randomization for Experimental Design},
+  author = {Iakov I. Davydov and Juliane Siebourg-Polster and Guido Steiner and Balazs Banfai},
+  year = {2023},
+  note = {R package version 0.4.1, https://github.com/BEDApub/designit/},
+  url = {https://bedapub.github.io/designit/},
+}
+ +
+ +
+ + + +
+ + + + + + + + diff --git a/bootstrap-toc.css b/bootstrap-toc.css new file mode 100644 index 00000000..5a859415 --- /dev/null +++ b/bootstrap-toc.css @@ -0,0 +1,60 @@ +/*! + * Bootstrap Table of Contents v0.4.1 (http://afeld.github.io/bootstrap-toc/) + * Copyright 2015 Aidan Feldman + * Licensed under MIT (https://github.com/afeld/bootstrap-toc/blob/gh-pages/LICENSE.md) */ + +/* modified from https://github.com/twbs/bootstrap/blob/94b4076dd2efba9af71f0b18d4ee4b163aa9e0dd/docs/assets/css/src/docs.css#L548-L601 */ + +/* All levels of nav */ +nav[data-toggle='toc'] .nav > li > a { + display: block; + padding: 4px 20px; + font-size: 13px; + font-weight: 500; + color: #767676; +} +nav[data-toggle='toc'] .nav > li > a:hover, +nav[data-toggle='toc'] .nav > li > a:focus { + padding-left: 19px; + color: #563d7c; + text-decoration: none; + background-color: transparent; + border-left: 1px solid #563d7c; +} +nav[data-toggle='toc'] .nav > .active > a, +nav[data-toggle='toc'] .nav > .active:hover > a, +nav[data-toggle='toc'] .nav > .active:focus > a { + padding-left: 18px; + font-weight: bold; + color: #563d7c; + background-color: transparent; + border-left: 2px solid #563d7c; +} + +/* Nav: second level (shown on .active) */ +nav[data-toggle='toc'] .nav .nav { + display: none; /* Hide by default, but at >768px, show it */ + padding-bottom: 10px; +} +nav[data-toggle='toc'] .nav .nav > li > a { + padding-top: 1px; + padding-bottom: 1px; + padding-left: 30px; + font-size: 12px; + font-weight: normal; +} +nav[data-toggle='toc'] .nav .nav > li > a:hover, +nav[data-toggle='toc'] .nav .nav > li > a:focus { + padding-left: 29px; +} +nav[data-toggle='toc'] .nav .nav > .active > a, +nav[data-toggle='toc'] .nav .nav > .active:hover > a, +nav[data-toggle='toc'] .nav .nav > .active:focus > a { + padding-left: 28px; + font-weight: 500; +} + +/* from https://github.com/twbs/bootstrap/blob/e38f066d8c203c3e032da0ff23cd2d6098ee2dd6/docs/assets/css/src/docs.css#L631-L634 */ +nav[data-toggle='toc'] .nav > .active > ul { + display: block; +} diff --git a/bootstrap-toc.js b/bootstrap-toc.js new file mode 100644 index 00000000..1cdd573b --- /dev/null +++ b/bootstrap-toc.js @@ -0,0 +1,159 @@ +/*! + * Bootstrap Table of Contents v0.4.1 (http://afeld.github.io/bootstrap-toc/) + * Copyright 2015 Aidan Feldman + * Licensed under MIT (https://github.com/afeld/bootstrap-toc/blob/gh-pages/LICENSE.md) */ +(function() { + 'use strict'; + + window.Toc = { + helpers: { + // return all matching elements in the set, or their descendants + findOrFilter: function($el, selector) { + // http://danielnouri.org/notes/2011/03/14/a-jquery-find-that-also-finds-the-root-element/ + // http://stackoverflow.com/a/12731439/358804 + var $descendants = $el.find(selector); + return $el.filter(selector).add($descendants).filter(':not([data-toc-skip])'); + }, + + generateUniqueIdBase: function(el) { + var text = $(el).text(); + var anchor = text.trim().toLowerCase().replace(/[^A-Za-z0-9]+/g, '-'); + return anchor || el.tagName.toLowerCase(); + }, + + generateUniqueId: function(el) { + var anchorBase = this.generateUniqueIdBase(el); + for (var i = 0; ; i++) { + var anchor = anchorBase; + if (i > 0) { + // add suffix + anchor += '-' + i; + } + // check if ID already exists + if (!document.getElementById(anchor)) { + return anchor; + } + } + }, + + generateAnchor: function(el) { + if (el.id) { + return el.id; + } else { + var anchor = this.generateUniqueId(el); + el.id = anchor; + return anchor; + } + }, + + createNavList: function() { + return $(''); + }, + + createChildNavList: function($parent) { + var $childList = this.createNavList(); + $parent.append($childList); + return $childList; + }, + + generateNavEl: function(anchor, text) { + var $a = $(''); + $a.attr('href', '#' + anchor); + $a.text(text); + var $li = $('
  • '); + $li.append($a); + return $li; + }, + + generateNavItem: function(headingEl) { + var anchor = this.generateAnchor(headingEl); + var $heading = $(headingEl); + var text = $heading.data('toc-text') || $heading.text(); + return this.generateNavEl(anchor, text); + }, + + // Find the first heading level (`

    `, then `

    `, etc.) that has more than one element. Defaults to 1 (for `

    `). + getTopLevel: function($scope) { + for (var i = 1; i <= 6; i++) { + var $headings = this.findOrFilter($scope, 'h' + i); + if ($headings.length > 1) { + return i; + } + } + + return 1; + }, + + // returns the elements for the top level, and the next below it + getHeadings: function($scope, topLevel) { + var topSelector = 'h' + topLevel; + + var secondaryLevel = topLevel + 1; + var secondarySelector = 'h' + secondaryLevel; + + return this.findOrFilter($scope, topSelector + ',' + secondarySelector); + }, + + getNavLevel: function(el) { + return parseInt(el.tagName.charAt(1), 10); + }, + + populateNav: function($topContext, topLevel, $headings) { + var $context = $topContext; + var $prevNav; + + var helpers = this; + $headings.each(function(i, el) { + var $newNav = helpers.generateNavItem(el); + var navLevel = helpers.getNavLevel(el); + + // determine the proper $context + if (navLevel === topLevel) { + // use top level + $context = $topContext; + } else if ($prevNav && $context === $topContext) { + // create a new level of the tree and switch to it + $context = helpers.createChildNavList($prevNav); + } // else use the current $context + + $context.append($newNav); + + $prevNav = $newNav; + }); + }, + + parseOps: function(arg) { + var opts; + if (arg.jquery) { + opts = { + $nav: arg + }; + } else { + opts = arg; + } + opts.$scope = opts.$scope || $(document.body); + return opts; + } + }, + + // accepts a jQuery object, or an options object + init: function(opts) { + opts = this.helpers.parseOps(opts); + + // ensure that the data attribute is in place for styling + opts.$nav.attr('data-toggle', 'toc'); + + var $topContext = this.helpers.createChildNavList(opts.$nav); + var topLevel = this.helpers.getTopLevel(opts.$scope); + var $headings = this.helpers.getHeadings(opts.$scope, topLevel); + this.helpers.populateNav($topContext, topLevel, $headings); + } + }; + + $(function() { + $('nav[data-toggle="toc"]').each(function(i, el) { + var $nav = $(el); + Toc.init($nav); + }); + }); +})(); diff --git a/dev/CODE_OF_CONDUCT.html b/dev/CODE_OF_CONDUCT.html new file mode 100644 index 00000000..ad29a99d --- /dev/null +++ b/dev/CODE_OF_CONDUCT.html @@ -0,0 +1,122 @@ + +Contributor Code of Conduct • designit + + +
    +
    + + + +
    +
    + + +
    + +

    As contributors and maintainers of this project, we pledge to respect all people who contribute through reporting issues, posting feature requests, updating documentation, submitting pull requests or patches, and other activities.

    +

    We are committed to making participation in this project a harassment-free experience for everyone, regardless of level of experience, gender, gender identity and expression, sexual orientation, disability, personal appearance, body size, race, ethnicity, age, or religion.

    +

    Examples of unacceptable behavior by participants include the use of sexual language or imagery, derogatory comments or personal attacks, trolling, public or private harassment, insults, or other unprofessional conduct.

    +

    Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct. Project maintainers who do not follow the Code of Conduct may be removed from the project team.

    +

    Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by opening an issue or contacting one or more of the project maintainers.

    +

    This Code of Conduct is adapted from the Contributor Covenant (https://www.contributor-covenant.org), version 1.0.0, available at https://contributor-covenant.org/version/1/0/0/.

    +
    + +
    + + + +
    + + + +
    + +
    +

    Site built with pkgdown 2.0.7.

    +
    + +
    + + + + + + + + diff --git a/dev/ISSUE_TEMPLATE.html b/dev/ISSUE_TEMPLATE.html new file mode 100644 index 00000000..6cbdb5e4 --- /dev/null +++ b/dev/ISSUE_TEMPLATE.html @@ -0,0 +1,121 @@ + +NA • designit + + +
    +
    + + + +
    +
    + + + +

    Please DO NOT use any confidential data when submitting an issue. For Roche internal data use code.roche.com.

    +

    Please briefly describe your problem and what output you expect. If you have a question, please don’t use this form. Instead, ask in the Discussions.

    +

    When possible, please include a minimal reproducible example (AKA a reprex). If you’ve never heard of a reprex before, start by reading https://www.tidyverse.org/help/#reprex.

    +

    Brief description of the problem

    +
    +# insert reprex here
    + + +
    + + + +
    + + + +
    + +
    +

    Site built with pkgdown 2.0.7.

    +
    + +
    + + + + + + + + diff --git a/dev/LICENSE-text.html b/dev/LICENSE-text.html new file mode 100644 index 00000000..875fda29 --- /dev/null +++ b/dev/LICENSE-text.html @@ -0,0 +1,116 @@ + +License • designit + + +
    +
    + + + +
    +
    + + +
    YEAR: 2022
    +COPYRIGHT HOLDER: Iakov I. Davydov, Juliane Siebourg-Polster, Guido Steiner, Balazs Banfai, F. Hoffman-La Roche
    +
    + +
    + + + +
    + + + +
    + +
    +

    Site built with pkgdown 2.0.7.

    +
    + +
    + + + + + + + + diff --git a/dev/LICENSE.html b/dev/LICENSE.html new file mode 100644 index 00000000..22dfe906 --- /dev/null +++ b/dev/LICENSE.html @@ -0,0 +1,120 @@ + +MIT License • designit + + +
    +
    + + + +
    +
    + + +
    + +

    Copyright (c) 2022 Iakov I. Davydov, Juliane Siebourg-Polster, Guido Steiner, Balazs Banfai, F. Hoffman-La Roche

    +

    Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

    +

    The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

    +

    THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

    +
    + +
    + + + +
    + + + +
    + +
    +

    Site built with pkgdown 2.0.7.

    +
    + +
    + + + + + + + + diff --git a/dev/apple-touch-icon-120x120.png b/dev/apple-touch-icon-120x120.png new file mode 100644 index 00000000..2eb0292f Binary files /dev/null and b/dev/apple-touch-icon-120x120.png differ diff --git a/dev/apple-touch-icon-152x152.png b/dev/apple-touch-icon-152x152.png new file mode 100644 index 00000000..1ef8fa06 Binary files /dev/null and b/dev/apple-touch-icon-152x152.png differ diff --git a/dev/apple-touch-icon-180x180.png b/dev/apple-touch-icon-180x180.png new file mode 100644 index 00000000..4a93ae13 Binary files /dev/null and b/dev/apple-touch-icon-180x180.png differ diff --git a/dev/apple-touch-icon-60x60.png b/dev/apple-touch-icon-60x60.png new file mode 100644 index 00000000..1cae2d51 Binary files /dev/null and b/dev/apple-touch-icon-60x60.png differ diff --git a/dev/apple-touch-icon-76x76.png b/dev/apple-touch-icon-76x76.png new file mode 100644 index 00000000..b480c4d5 Binary files /dev/null and b/dev/apple-touch-icon-76x76.png differ diff --git a/dev/apple-touch-icon.png b/dev/apple-touch-icon.png new file mode 100644 index 00000000..ee61604a Binary files /dev/null and b/dev/apple-touch-icon.png differ diff --git a/dev/articles/NCS22_talk.html b/dev/articles/NCS22_talk.html new file mode 100644 index 00000000..06e98c37 --- /dev/null +++ b/dev/articles/NCS22_talk.html @@ -0,0 +1,1364 @@ + + + + + + + +designit: a flexible engine to generate experiment layouts • designit + + + + + + + + + + + + + + + + + + + + +
    +
    + + + + +
    +
    + + + + +
    +

    Introduction +

    +

    Examples in this vignette are used in a talk at NCS22.

    +

    It uses a subset of the longitudinal_subject_samples +dataset.

    +
    +data("longitudinal_subject_samples")
    +
    +dat <- longitudinal_subject_samples %>% 
    +  filter(Group %in% 1:5, Week %in% c(1,4)) %>% 
    +  select(SampleID, SubjectID, Group, Sex, Week)
    +
    +# for simplicity: remove two subjects that don't have both visits  
    +dat <- dat %>% 
    +  filter(SubjectID %in% (dat %>% count(SubjectID) %>% filter(n == 2) %>% .$SubjectID)) 
    +
    +
    +subject_data <- dat %>% select(SubjectID, Group, Sex) %>% unique()
    +
    +

    Go fully random? +

    +
      +
    • Could it be sufficient to randomly distribute samples across +batches?
    • +
    • Not necessarily! +
        +
      • Often sample sizes are too small to avoid grouping by change
      • +
      • Experimental constraints might not allow for a fully random +layout
      • +
      +
    • +
    +

    Gone wrong: Random distribution of 31 grouped subjects into 3 batches +turns out unbalanced:

    +

    +

    Block what you can and randomize +what you cannot.” (G. Box, 1978)

    +
    +
    +

    designit +

    +
    +

    To avoid batch or gradient effects in complex +experiments, designit is an R package that offers flexible +ways to allocate a given set of samples to experiment +layouts. It’s strength is that it implements a very general +framework that can easily be customized and extended to fit specific +constrained layouts.

    +
    +
      +
    • Data structure: BatchContainer class +
        +
      • R6 object storing: +
          +
        • Experiment dimensions (cages, plates…)
        • +
        • Sample annotation
        • +
        • Scoring functions for sample distribution
        • +
        +
      • +
      +
    • +
    • Main function: optimize_design() +
        +
      • Optimizes the layout with user defined +
          +
        • Scores for sample distribution
        • +
        • Optimization protocols
        • +
        • Sample shuffling functions
        • +
        +
      • +
      • Returns improved design and optimization trace
      • +
      +
    • +
    +
    +
    +
    +

    Sample Batching +

    +
    +

    Setup +

    +
      +
    • Assign 31 samples to 3 equally sized batches
    • +
    • Balance by: +
        +
      • treatment group (higher priority)
      • +
      • sex (lower priority)
      • +
      +
    • +
    +
    +bc <- BatchContainer$new(
    +  dimensions = list("batch" = 3, "location" = 11),
    +)
    +bc$scoring_f <- list(
    +  group = osat_score_generator(batch_vars = "batch", 
    +                               feature_vars = "Group"),
    +  sex = osat_score_generator(batch_vars = "batch", 
    +                             feature_vars = "Sex")
    +)
    +assign_random(bc, subject_data)
    +

    Batch composition before optimization

    +

    +
    +bc$get_samples()
    +
    #> Warning: There was 1 warning in `mutate()`.
    +#>  In argument: `across(, as.character)`.
    +#> Caused by warning:
    +#> ! Using `across()` without supplying `.cols` was deprecated in dplyr 1.1.0.
    +#>  Please supply `.cols` instead.
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    batchlocationSubjectIDGroupSex
    11NANANA
    12P325M
    13P103F
    ... ............
    39P313F
    310P335M
    311P245F
    +
    +
    +
    +

    Optimization +

    +
      +
    • Assign 31 samples to 3 equally sized batches
    • +
    • Balance by: +
        +
      • treatment group (higher priority)
      • +
      • sex (lower priority)
      • +
      +
    • +
    +
    +trace <- optimize_design(
    +  bc,
    +  n_shuffle = 1,
    +  acceptance_func = 
    +    ~ accept_leftmost_improvement(..., tolerance = 0.01),
    +  max_iter = 150,
    +  quiet = TRUE
    +)
    +

    Batch composition after optimization

    +

    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    batchlocationSubjectIDGroupSex
    11NANANA
    12P011F
    13P103F
    ... ............
    39P295F
    310P335M
    311P123F
    +
    +
    +
    +
    +

    Plate layouts +

    +
    +

    Continuous confounding +

    +

    Assays are often performed in well plates (24, 96, 384)

    +

    Observed effects

    +
      +
    • Edge effects (bad plate sealing)
    • +
    • Gradients (non-equal temperature distribution)
    • +
    • Row / column effects (pipetting issues)
    • +
    +

    Since plate effects often cannot be avoided, we aim to distribute +sample groups of interest evenly across the plate and adjust for the +effect computationally.

    +
    +
    +

    Setup +

    +
      +
    • Assume previous batches are 24-well plates
    • +
    • Within plate optimization & across plate blocking
    • +
    • Balanced by: +
        +
      • treatment group (higher priority)
      • +
      • sex (lower priority)
      • +
      +
    • +
    +
    +set.seed(1) #1 #2
    +
    +bc <- BatchContainer$new(
    +  dimensions = list("plate" = 3, "row" = 4, "col" = 6),
    +)
    +assign_random(bc, dat)
    +#assign_in_order(bc, dat)
    +
    +plot_plate(bc, plate = plate, row = row, column = col,
    +           .color = Group, title = "Initial layout by Group")
    +plot_plate(bc, plate = plate, row = row, column = col, 
    +           .color = Sex, title = "Initial layout by Sex")
    +

    +

    2-step optimization +multi_plate_layout()

    +
      +
    • Across plate optimization using osat score as before
    • +
    • Within plate optimization using distance based sample scoring +function
    • +
    +
    +
    +

    Spatial arrangement +

    +
    +traces <- optimize_multi_plate_design(
    +  bc,
    +  across_plates_variables = c("Group", "Sex"),
    +  within_plate_variables = c("Group"),
    +  plate = "plate", row = "row", column = "col",
    +  n_shuffle = 2,
    +  max_iter = 500 #2000
    +)
    +#> 1 ... 2 ... 3 ...
    +

    +
    #> $osat_across_plates
    +

    +
    #> 
    +#> $within_plate_1
    +

    +
    +
    +
    +

    Glimpse on more complex application +

    +

    Goal:

    +
      +
    • Assign 3 treatment conditions to 59 animals, representing 2 relevant +strains
    • +
    • Avoid confounding by sex, weight and age
    • +
    +

    Constraints:

    +
      +
    • Cages host ideally 3 animals (preferably 2-5)
    • +
    • Strain, Sex and Treatment must be homogeneous within a cage
    • +
    • Don’t put males from different litters same cage; litter mixing is +possible for females!
    • +
    • Average weight and age composition comparable between treatment +groups and cages
    • +
    • Avoid animals with identical ear markings in same cage (if +possible)
    • +
    • Treatment distribution across animal subgroups (if specified) has to +be respected
    • +
    +

    see vignette invivo_study_design for the full story.

    +
    +
    +

    Conclusion +

    +
      +
    • designit aims to be general and adaptable +
        +
      • One framework to address simple batching as well as complex +multi-step procedures
      • +
      • Easy add-ons: custom scoring-functions, acceptance-criteria and +shuffling-procedures can be passed to optimize_design by the user
      • +
      +
    • +
    • Includes functions and vignettes for frequently used layouts such as +plates.
    • +
    +

    Acknowledgements

    +
      +
    • Martha Serrano
    • +
    • Sabine Wilson
    • +
    • David Jitao Zhang
    • +
    • Fabian Birzele
    • +
    • PMDA group for feedback?
    • +
    +

    +
    +
    + + + +
    + + + +
    + +
    +

    +

    Site built with pkgdown 2.0.7.

    +
    + +
    +
    + + + + + + + + diff --git a/dev/articles/NCS22_talk_files/figure-html/unnamed-chunk-10-1.png b/dev/articles/NCS22_talk_files/figure-html/unnamed-chunk-10-1.png new file mode 100644 index 00000000..4681e2f6 Binary files /dev/null and b/dev/articles/NCS22_talk_files/figure-html/unnamed-chunk-10-1.png differ diff --git a/dev/articles/NCS22_talk_files/figure-html/unnamed-chunk-14-1.png b/dev/articles/NCS22_talk_files/figure-html/unnamed-chunk-14-1.png new file mode 100644 index 00000000..dac3c5c2 Binary files /dev/null and b/dev/articles/NCS22_talk_files/figure-html/unnamed-chunk-14-1.png differ diff --git a/dev/articles/NCS22_talk_files/figure-html/unnamed-chunk-16-1.png b/dev/articles/NCS22_talk_files/figure-html/unnamed-chunk-16-1.png new file mode 100644 index 00000000..84a5a501 Binary files /dev/null and b/dev/articles/NCS22_talk_files/figure-html/unnamed-chunk-16-1.png differ diff --git a/dev/articles/NCS22_talk_files/figure-html/unnamed-chunk-17-1.png b/dev/articles/NCS22_talk_files/figure-html/unnamed-chunk-17-1.png new file mode 100644 index 00000000..58048baa Binary files /dev/null and b/dev/articles/NCS22_talk_files/figure-html/unnamed-chunk-17-1.png differ diff --git a/dev/articles/NCS22_talk_files/figure-html/unnamed-chunk-17-2.png b/dev/articles/NCS22_talk_files/figure-html/unnamed-chunk-17-2.png new file mode 100644 index 00000000..2663aeea Binary files /dev/null and b/dev/articles/NCS22_talk_files/figure-html/unnamed-chunk-17-2.png differ diff --git a/dev/articles/NCS22_talk_files/figure-html/unnamed-chunk-18-1.png b/dev/articles/NCS22_talk_files/figure-html/unnamed-chunk-18-1.png new file mode 100644 index 00000000..ae63e34c Binary files /dev/null and b/dev/articles/NCS22_talk_files/figure-html/unnamed-chunk-18-1.png differ diff --git a/dev/articles/NCS22_talk_files/figure-html/unnamed-chunk-3-1.png b/dev/articles/NCS22_talk_files/figure-html/unnamed-chunk-3-1.png new file mode 100644 index 00000000..84a03703 Binary files /dev/null and b/dev/articles/NCS22_talk_files/figure-html/unnamed-chunk-3-1.png differ diff --git a/dev/articles/NCS22_talk_files/figure-html/unnamed-chunk-6-1.png b/dev/articles/NCS22_talk_files/figure-html/unnamed-chunk-6-1.png new file mode 100644 index 00000000..5ba017b2 Binary files /dev/null and b/dev/articles/NCS22_talk_files/figure-html/unnamed-chunk-6-1.png differ diff --git a/dev/articles/basic_examples.html b/dev/articles/basic_examples.html new file mode 100644 index 00000000..1fc89ee1 --- /dev/null +++ b/dev/articles/basic_examples.html @@ -0,0 +1,1410 @@ + + + + + + + +Basic example • designit + + + + + + + + + + + + + + + + + + + + +
    +
    + + + + +
    +
    + + + + +
    +library(designit)
    +library(ggplot2)
    +library(dplyr)
    +#> 
    +#> Attaching package: 'dplyr'
    +#> The following objects are masked from 'package:stats':
    +#> 
    +#>     filter, lag
    +#> The following objects are masked from 'package:base':
    +#> 
    +#>     intersect, setdiff, setequal, union
    +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

    +
    +# 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)
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    grouptreatmentdose
    1vehicle0
    2TRT125
    3TRT225
    4TRT150
    5TRT250
    +
    +

    We will have 3 animals per groups with 4 replicates each

    +
    +# 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()
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    replicateanimalgrouptreatmentdoseSampleIDAnimalID
    111vehicle0vehicle_1_1vehicle_1
    112TRT125TRT1_1_1TRT1_1
    113TRT225TRT2_1_1TRT2_1
    114TRT150TRT1_1_1TRT1_1
    115TRT250TRT2_1_1TRT2_1
    121vehicle0vehicle_2_1vehicle_2
    122TRT125TRT1_2_1TRT1_2
    123TRT225TRT2_2_1TRT2_2
    124TRT150TRT1_2_1TRT1_2
    125TRT250TRT2_2_1TRT2_2
    +
    +
    +
    +

    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 60 samples, they will +fit on 2 plates

    +
    +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

    +
    +bc <- BatchContainer$new(
    +  dimensions = c("plate" = n_plates, "column" = 8, "row" = 6),
    +  exclude = exclude_wells
    +)
    +bc
    +#> Batch container with 88 locations.
    +#>   Dimensions: plate, column, row
    +
    +bc$n_locations
    +#> [1] 88
    +bc$exclude
    +#> NULL
    +bc$get_locations() %>% head()
    +#> # A tibble: 6 × 3
    +#>   plate column   row
    +#>   <int>  <int> <int>
    +#> 1     1      1     2
    +#> 2     1      1     3
    +#> 3     1      1     4
    +#> 4     1      1     5
    +#> 5     1      2     1
    +#> 6     1      2     2
    +
    +
    +

    Moving samples +

    +

    Use random assignment function to place samples to plate +locations

    +
    +assign_random(bc, samples)
    +
    +bc$get_samples()
    +#> # A tibble: 88 × 10
    +#>    plate column   row replicate animal group treatment dose  SampleID    Anima…¹
    +#>    <int>  <int> <int> <chr>     <chr>  <dbl> <chr>     <fct> <chr>       <chr>  
    +#>  1     1      1     2 NA        NA        NA NA        NA    NA          NA     
    +#>  2     1      1     3 1         1          2 TRT1      25    TRT1_1_1    TRT1_1 
    +#>  3     1      1     4 1         1          1 vehicle   0     vehicle_1_1 vehicl…
    +#>  4     1      1     5 1         2          5 TRT2      50    TRT2_2_1    TRT2_2 
    +#>  5     1      2     1 1         3          4 TRT1      50    TRT1_3_1    TRT1_3 
    +#>  6     1      2     2 1         1          5 TRT2      50    TRT2_1_1    TRT2_1 
    +#>  7     1      2     3 2         1          1 vehicle   0     vehicle_1_2 vehicl…
    +#>  8     1      2     4 3         2          1 vehicle   0     vehicle_2_3 vehicl…
    +#>  9     1      2     5 NA        NA        NA NA        NA    NA          NA     
    +#> 10     1      2     6 NA        NA        NA NA        NA    NA          NA     
    +#> # … with 78 more rows, and abbreviated variable name ¹​AnimalID
    +bc$get_samples(remove_empty_locations = TRUE)
    +#> # A tibble: 60 × 10
    +#>    plate column   row replicate animal group treatment dose  SampleID    Anima…¹
    +#>    <int>  <int> <int> <chr>     <chr>  <dbl> <chr>     <fct> <chr>       <chr>  
    +#>  1     1      1     3 1         1          2 TRT1      25    TRT1_1_1    TRT1_1 
    +#>  2     1      1     4 1         1          1 vehicle   0     vehicle_1_1 vehicl…
    +#>  3     1      1     5 1         2          5 TRT2      50    TRT2_2_1    TRT2_2 
    +#>  4     1      2     1 1         3          4 TRT1      50    TRT1_3_1    TRT1_3 
    +#>  5     1      2     2 1         1          5 TRT2      50    TRT2_1_1    TRT2_1 
    +#>  6     1      2     3 2         1          1 vehicle   0     vehicle_1_2 vehicl…
    +#>  7     1      2     4 3         2          1 vehicle   0     vehicle_2_3 vehicl…
    +#>  8     1      3     2 4         1          5 TRT2      50    TRT2_1_4    TRT2_1 
    +#>  9     1      3     3 2         2          2 TRT1      25    TRT1_2_2    TRT1_2 
    +#> 10     1      3     4 3         3          1 vehicle   0     vehicle_3_3 vehicl…
    +#> # … with 50 more rows, and abbreviated variable name ¹​AnimalID
    +

    Plot of the result using the plot_plate function

    +
    +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

    +
    +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

    +
    +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. The example below orders samples by ID +and adds the empty locations afterwards

    +
    +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
    +)
    +

    +
    +
    +

    Scoring a layout +

    +

    To evaluate how good a layout is, we need a scoring function. This we +also assign to the batch container.

    +

    This function will assess how well treatment and dose are balanced +across the two plates.

    +
    +bc$scoring_f <- osat_score_generator(
    +  batch_vars = "plate",
    +  feature_vars = c("treatment", "dose")
    +)
    +
    +
    +

    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.

    +
    +trace <- optimize_design(bc,
    +  # shuffling schedule
    +  n_shuffle = c(rep(10, 200), rep(2, 400))
    +)
    +#> Warning in osat_score(bc, batch_vars = batch_vars, feature_vars = feature_vars,
    +#> : NAs in features / batch columns; they will be excluded from scoring
    +#> Checking variances of 1-dim. score vector.
    +#> ... (250.697) - OK
    +#> Initial score: 80
    +#> Achieved score: 66 at iteration 1
    +#> Achieved score: 46 at iteration 2
    +#> Achieved score: 44 at iteration 3
    +#> Achieved score: 30 at iteration 6
    +#> Achieved score: 28 at iteration 8
    +#> Achieved score: 24 at iteration 9
    +#> Achieved score: 22 at iteration 10
    +#> Achieved score: 12 at iteration 11
    +#> Achieved score: 8 at iteration 16
    +#> Achieved score: 4 at iteration 18
    +#> Achieved score: 2 at iteration 27
    +#> Achieved score: 0 at iteration 234
    +

    Development of the score can be viewed with

    +
    +trace$plot()
    +

    +

    The layout after plate batching looks the following

    +
    +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

    +
    +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 +
    • +
    +
    +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.

    +
    +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!

    +
    +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()
    +

    +
    +
    +
    + + + +
    + + + +
    + +
    +

    +

    Site built with pkgdown 2.0.7.

    +
    + +
    +
    + + + + + + + + diff --git a/dev/articles/basic_examples_files/figure-html/unnamed-chunk-10-1.png b/dev/articles/basic_examples_files/figure-html/unnamed-chunk-10-1.png new file mode 100644 index 00000000..2556a32f Binary files /dev/null and b/dev/articles/basic_examples_files/figure-html/unnamed-chunk-10-1.png differ diff --git a/dev/articles/basic_examples_files/figure-html/unnamed-chunk-13-1.png b/dev/articles/basic_examples_files/figure-html/unnamed-chunk-13-1.png new file mode 100644 index 00000000..c8a0b732 Binary files /dev/null and b/dev/articles/basic_examples_files/figure-html/unnamed-chunk-13-1.png differ diff --git a/dev/articles/basic_examples_files/figure-html/unnamed-chunk-14-1.png b/dev/articles/basic_examples_files/figure-html/unnamed-chunk-14-1.png new file mode 100644 index 00000000..1b8119a3 Binary files /dev/null and b/dev/articles/basic_examples_files/figure-html/unnamed-chunk-14-1.png differ diff --git a/dev/articles/basic_examples_files/figure-html/unnamed-chunk-15-1.png b/dev/articles/basic_examples_files/figure-html/unnamed-chunk-15-1.png new file mode 100644 index 00000000..fb5ad783 Binary files /dev/null and b/dev/articles/basic_examples_files/figure-html/unnamed-chunk-15-1.png differ diff --git a/dev/articles/basic_examples_files/figure-html/unnamed-chunk-16-1.png b/dev/articles/basic_examples_files/figure-html/unnamed-chunk-16-1.png new file mode 100644 index 00000000..2d9f342b Binary files /dev/null and b/dev/articles/basic_examples_files/figure-html/unnamed-chunk-16-1.png differ diff --git a/dev/articles/basic_examples_files/figure-html/unnamed-chunk-17-1.png b/dev/articles/basic_examples_files/figure-html/unnamed-chunk-17-1.png new file mode 100644 index 00000000..3dc9307a Binary files /dev/null and b/dev/articles/basic_examples_files/figure-html/unnamed-chunk-17-1.png differ diff --git a/dev/articles/basic_examples_files/figure-html/unnamed-chunk-18-1.png b/dev/articles/basic_examples_files/figure-html/unnamed-chunk-18-1.png new file mode 100644 index 00000000..3cb0c914 Binary files /dev/null and b/dev/articles/basic_examples_files/figure-html/unnamed-chunk-18-1.png differ diff --git a/dev/articles/basic_examples_files/figure-html/unnamed-chunk-7-1.png b/dev/articles/basic_examples_files/figure-html/unnamed-chunk-7-1.png new file mode 100644 index 00000000..3765581d Binary files /dev/null and b/dev/articles/basic_examples_files/figure-html/unnamed-chunk-7-1.png differ diff --git a/dev/articles/basic_examples_files/figure-html/unnamed-chunk-8-1.png b/dev/articles/basic_examples_files/figure-html/unnamed-chunk-8-1.png new file mode 100644 index 00000000..74680962 Binary files /dev/null and b/dev/articles/basic_examples_files/figure-html/unnamed-chunk-8-1.png differ diff --git a/dev/articles/basic_examples_files/figure-html/unnamed-chunk-9-1.png b/dev/articles/basic_examples_files/figure-html/unnamed-chunk-9-1.png new file mode 100644 index 00000000..9da68d02 Binary files /dev/null and b/dev/articles/basic_examples_files/figure-html/unnamed-chunk-9-1.png differ diff --git a/dev/articles/custom_shuffle.html b/dev/articles/custom_shuffle.html new file mode 100644 index 00000000..3cbf9132 --- /dev/null +++ b/dev/articles/custom_shuffle.html @@ -0,0 +1,375 @@ + + + + + + + +Using custom shuffle schedule • designit + + + + + + + + + + + + + + + + + + + + +
    +
    + + + + +
    +
    + + + + +
    +library(designit)
    +library(tidyverse)
    +#> ── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
    +#>  dplyr     1.1.0      readr     2.1.4
    +#>  forcats   1.0.0      stringr   1.5.0
    +#>  ggplot2   3.4.1      tibble    3.2.0
    +#>  lubridate 1.9.2      tidyr     1.3.0
    +#>  purrr     1.0.1     
    +#> ── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
    +#>  dplyr::filter() masks stats::filter()
    +#>  dplyr::lag()    masks stats::lag()
    +#>  Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors
    +

    In this example we would like to distribute animals among cages with +constraints:

    +
      +
    • There should be not more than one male per cage.
    • +
    • Number of treatment/control animals should be comparable per +cage
    • +
    • Average weight per cage should be comparable between cages
    • +
    +
    +set.seed(43)
    +samples <- tibble(
    +  id = 1:params$n_samples,
    +  sex = sample(c("F", "M"), params$n_samples, replace = TRUE, prob = c(0.8, 0.2)),
    +  group = sample(c("treatment", "control"), params$n_samples, replace = TRUE),
    +  weight = runif(params$n_samples, 20, 30)
    +)
    +samples %>%
    +  head()
    +#> # A tibble: 6 × 4
    +#>      id sex   group     weight
    +#>   <int> <chr> <chr>      <dbl>
    +#> 1     1 F     treatment   26.2
    +#> 2     2 M     treatment   26.1
    +#> 3     3 F     control     26.6
    +#> 4     4 F     control     25.4
    +#> 5     5 F     treatment   24.3
    +#> 6     6 F     treatment   21.5
    +
    +samples %>%
    +  count(sex)
    +#> # A tibble: 2 × 2
    +#>   sex       n
    +#>   <chr> <int>
    +#> 1 F        42
    +#> 2 M         8
    +

    We create a BatchContainer with 11 cages and 5 positions +per cage. Note that positions do not actually matter; this is just to +limit the number of animals per cage.

    +

    We start by assigning samples randomly.

    +
    +set.seed(42)
    +bc <- BatchContainer$new(
    +  dimensions = c("cage" = 11, "position" = 5)
    +)
    +assign_random(bc, samples)
    +bc
    +#> Batch container with 55 locations and 50 samples (assigned).
    +#>   Dimensions: cage, position
    +

    Functions to plot number of males per cage, weights per cage and +treatment/control ratios.

    +
    +males_per_cage <- function(bc) {
    +  bc$get_samples() %>%
    +    filter(sex == "M") %>%
    +    count(cage) %>%
    +    ggplot(aes(cage, n)) +
    +    geom_col()
    +}
    +
    +weight_d <- function(bc) {
    +  bc$get_samples() %>%
    +    ggplot(aes(factor(cage), weight)) +
    +    geom_violin() +
    +    geom_point() +
    +    stat_summary(fun = mean, geom = "point", size = 2, shape = 23, color = "red")
    +}
    +
    +group_d <- function(bc) {
    +  bc$get_samples(remove_empty_locations = TRUE) %>%
    +    ggplot(aes(factor(cage), fill = group)) +
    +    geom_bar(position = "fill")
    +}
    +
    +males_per_cage(bc)
    +

    +
    +weight_d(bc)
    +#> Warning: Removed 5 rows containing non-finite values
    +#> (`stat_ydensity()`).
    +#> Warning: Removed 5 rows containing non-finite values (`stat_summary()`).
    +#> Warning: Removed 5 rows containing missing values (`geom_point()`).
    +

    +
    +group_d(bc)
    +

    +

    First, we use OSAT scoring function to ensure even distribution of +males among cages. Only cage and sex +interactions are considered in the scoring function. We only use 10 +iterations, since shuffling is limited to locations with males and +enforces change of cage on every iteration.

    +
    +bc$scoring_f <- osat_score_generator(
    +  "cage",
    +  "sex"
    +)
    +
    +set.seed(10)
    +
    +res <- optimize_design(
    +  bc,
    +  shuffle_proposal_func = shuffle_with_constraints(
    +    sex == "M",
    +    cage != .src$cage
    +  ),
    +  max_iter = 10
    +)
    +#> Warning in osat_score(bc, batch_vars = batch_vars, feature_vars = feature_vars,
    +#> : NAs in features / batch columns; they will be excluded from scoring
    +#> Checking variances of 1-dim. score vector.
    +#> ... (21.451) - OK
    +#> Initial score: 15.818
    +#> Achieved score: 11.818 at iteration 1
    +#> Achieved score: 9.818 at iteration 10
    +
    +plot(res)
    +

    +We expect the distribution of males become even, while other variables +are not significantly affected.

    +
    +males_per_cage(bc)
    +

    +
    +weight_d(bc)
    +#> Warning: Removed 5 rows containing non-finite values
    +#> (`stat_ydensity()`).
    +#> Warning: Removed 5 rows containing non-finite values (`stat_summary()`).
    +#> Warning: Removed 5 rows containing missing values (`geom_point()`).
    +

    +
    +group_d(bc)
    +

    +

    Here we only define our custom scoring function which ensures even +distribution of weights and treatment/control groups. Only female +samples are shuffled and male samples are kept in their locations. We +also ensure that on every iteration the cage number is changed; we do +this because position dimension does affect actual animal +allocation.

    +
    +bc$scoring_f <- function(bc) {
    +  samples <- bc$get_samples(include_id = TRUE, as_tibble = FALSE)
    +  avg_w <- samples[, mean(weight, na.rm = TRUE)]
    +  avg_w_per_cage <- samples[!is.na(weight), mean(weight), by = cage]$V1
    +  trt_per_cage <- samples[!is.na(group), sum(group == "treatment") / .N, by = cage]$V1
    +
    +  w_score <- mean((avg_w - avg_w_per_cage)**2)
    +  trt_score <- mean((trt_per_cage - 0.5)**2)
    +  w_score + 10 * trt_score
    +}
    +
    +set.seed(12)
    +res <- optimize_design(bc,
    +  shuffle_proposal = shuffle_with_constraints(
    +    sex == "F",
    +    cage != .src$cage & (is.na(sex) | sex != "M")
    +  ),
    +  n_shuffle = c(rep(10, 20), rep(5, 20), rep(3, 20), rep(1, 140)),
    +  max_iter = 200
    +)
    +#> Checking variances of 1-dim. score vector.
    +#> ... (0.457) - OK
    +#> Initial score: 2.657
    +#> Achieved score: 1.916 at iteration 2
    +#> Achieved score: 1.835 at iteration 5
    +#> Achieved score: 1.289 at iteration 9
    +#> Achieved score: 1.225 at iteration 10
    +#> Achieved score: 1.089 at iteration 11
    +#> Achieved score: 1.074 at iteration 16
    +#> Achieved score: 1.033 at iteration 18
    +#> Achieved score: 0.875 at iteration 19
    +#> Achieved score: 0.574 at iteration 22
    +#> Achieved score: 0.523 at iteration 23
    +#> Achieved score: 0.522 at iteration 32
    +#> Achieved score: 0.483 at iteration 41
    +#> Achieved score: 0.394 at iteration 49
    +#> Achieved score: 0.379 at iteration 67
    +#> Achieved score: 0.372 at iteration 73
    +#> Achieved score: 0.365 at iteration 84
    +#> Achieved score: 0.361 at iteration 90
    +#> Achieved score: 0.348 at iteration 96
    +#> Achieved score: 0.322 at iteration 102
    +#> Achieved score: 0.302 at iteration 131
    +#> Achieved score: 0.302 at iteration 141
    +#> Achieved score: 0.246 at iteration 165
    +#> Achieved score: 0.245 at iteration 166
    +#> Achieved score: 0.241 at iteration 184
    +#> Achieved score: 0.241 at iteration 191
    +#> Achieved score: 0.237 at iteration 196
    +plot(res)
    +

    +
    +bc$score()
    +#> [1] 0.2370109
    +

    Now we have a much more even distribution of weights and +treatment/control balance.

    +
    +males_per_cage(bc)
    +

    +
    +weight_d(bc)
    +#> Warning: Removed 5 rows containing non-finite values
    +#> (`stat_ydensity()`).
    +#> Warning: Removed 5 rows containing non-finite values (`stat_summary()`).
    +#> Warning: Removed 5 rows containing missing values (`geom_point()`).
    +

    +
    +group_d(bc)
    +

    +
    + + + +
    + + + +
    + +
    +

    +

    Site built with pkgdown 2.0.7.

    +
    + +
    +
    + + + + + + + + diff --git a/dev/articles/custom_shuffle_files/figure-html/unnamed-chunk-10-1.png b/dev/articles/custom_shuffle_files/figure-html/unnamed-chunk-10-1.png new file mode 100644 index 00000000..feb120c3 Binary files /dev/null and b/dev/articles/custom_shuffle_files/figure-html/unnamed-chunk-10-1.png differ diff --git a/dev/articles/custom_shuffle_files/figure-html/unnamed-chunk-10-2.png b/dev/articles/custom_shuffle_files/figure-html/unnamed-chunk-10-2.png new file mode 100644 index 00000000..4fadb7ef Binary files /dev/null and b/dev/articles/custom_shuffle_files/figure-html/unnamed-chunk-10-2.png differ diff --git a/dev/articles/custom_shuffle_files/figure-html/unnamed-chunk-10-3.png b/dev/articles/custom_shuffle_files/figure-html/unnamed-chunk-10-3.png new file mode 100644 index 00000000..b10179b4 Binary files /dev/null and b/dev/articles/custom_shuffle_files/figure-html/unnamed-chunk-10-3.png differ diff --git a/dev/articles/custom_shuffle_files/figure-html/unnamed-chunk-6-1.png b/dev/articles/custom_shuffle_files/figure-html/unnamed-chunk-6-1.png new file mode 100644 index 00000000..8a3b1217 Binary files /dev/null and b/dev/articles/custom_shuffle_files/figure-html/unnamed-chunk-6-1.png differ diff --git a/dev/articles/custom_shuffle_files/figure-html/unnamed-chunk-6-2.png b/dev/articles/custom_shuffle_files/figure-html/unnamed-chunk-6-2.png new file mode 100644 index 00000000..53258003 Binary files /dev/null and b/dev/articles/custom_shuffle_files/figure-html/unnamed-chunk-6-2.png differ diff --git a/dev/articles/custom_shuffle_files/figure-html/unnamed-chunk-6-3.png b/dev/articles/custom_shuffle_files/figure-html/unnamed-chunk-6-3.png new file mode 100644 index 00000000..687d33dc Binary files /dev/null and b/dev/articles/custom_shuffle_files/figure-html/unnamed-chunk-6-3.png differ diff --git a/dev/articles/custom_shuffle_files/figure-html/unnamed-chunk-7-1.png b/dev/articles/custom_shuffle_files/figure-html/unnamed-chunk-7-1.png new file mode 100644 index 00000000..b10b1a69 Binary files /dev/null and b/dev/articles/custom_shuffle_files/figure-html/unnamed-chunk-7-1.png differ diff --git a/dev/articles/custom_shuffle_files/figure-html/unnamed-chunk-8-1.png b/dev/articles/custom_shuffle_files/figure-html/unnamed-chunk-8-1.png new file mode 100644 index 00000000..feb120c3 Binary files /dev/null and b/dev/articles/custom_shuffle_files/figure-html/unnamed-chunk-8-1.png differ diff --git a/dev/articles/custom_shuffle_files/figure-html/unnamed-chunk-8-2.png b/dev/articles/custom_shuffle_files/figure-html/unnamed-chunk-8-2.png new file mode 100644 index 00000000..4dc3364d Binary files /dev/null and b/dev/articles/custom_shuffle_files/figure-html/unnamed-chunk-8-2.png differ diff --git a/dev/articles/custom_shuffle_files/figure-html/unnamed-chunk-8-3.png b/dev/articles/custom_shuffle_files/figure-html/unnamed-chunk-8-3.png new file mode 100644 index 00000000..94beea9b Binary files /dev/null and b/dev/articles/custom_shuffle_files/figure-html/unnamed-chunk-8-3.png differ diff --git a/dev/articles/custom_shuffle_files/figure-html/unnamed-chunk-9-1.png b/dev/articles/custom_shuffle_files/figure-html/unnamed-chunk-9-1.png new file mode 100644 index 00000000..c2acc604 Binary files /dev/null and b/dev/articles/custom_shuffle_files/figure-html/unnamed-chunk-9-1.png differ diff --git a/dev/articles/index.html b/dev/articles/index.html new file mode 100644 index 00000000..bff2ce42 --- /dev/null +++ b/dev/articles/index.html @@ -0,0 +1,131 @@ + +Articles • designit + + +
    +
    + + + +
    + + +
    + +
    +

    Site built with pkgdown 2.0.7.

    +
    + +
    + + + + + + + + diff --git a/dev/articles/invivo_study_design.html b/dev/articles/invivo_study_design.html new file mode 100644 index 00000000..8c19ded4 --- /dev/null +++ b/dev/articles/invivo_study_design.html @@ -0,0 +1,2539 @@ + + + + + + + +In-vivo study design • designit + + + + + + + + + + + + + + + + + + + + +
    +
    + + + + +
    +
    + + + + +
    +

    Purpose of vignette +

    +

    This example demonstrates how recurring complex design problems of +similar structure may be handled by writing dedicated wrappers that use +designIt functionality in the background while presenting a simplified +interface to the user. These wrapper functions may completely hide the +construction of batch containers, scoring functions and other +fundamental package concepts from the user, allowing to focus on the +correct specification of the concrete design task at hand.

    +

    We are using the very specific design constraints of certain in +vivo studies as an example. The implementation of the respective +wrapper functions won’t be discussed here, but code may be inspected in +the .Rmd file of the vignette if desired.

    +
    +
    +

    Dataset and design task +

    +

    We would like to assign 3 treatment conditions to a cohort of 59 +animals, representing 2 relevant strains. There are a few concrete user +specified constraints for the study, on top we have to avoid confounding +by common variables such as animal sex, body weight and age.

    +

    The animal information is provided in a sample sheet, the treatment +list has to be stored separately. The example data we are looking at is +included in the package.

    +
    +data("invivo_study_samples")
    +data("invivo_study_treatments")
    +
    +

    The animal (sample) sheet +

    +
    +str(invivo_study_samples)
    +#> 'data.frame':    59 obs. of  8 variables:
    +#>  $ AnimalID           : chr  "F1" "F2" "F3" "F4" ...
    +#>  $ Strain             : chr  "Strain B" "Strain B" "Strain B" "Strain B" ...
    +#>  $ Sex                : chr  "F" "F" "F" "F" ...
    +#>  $ BirthDate          : Date, format: "2021-05-24" "2021-03-01" ...
    +#>  $ Earmark            : chr  "R" "2L" "2L1R" "L" ...
    +#>  $ ArrivalWeight      : num  19.4 26.5 20.8 22.1 22.9 ...
    +#>  $ Arrival.weight.Unit: chr  "g" "g" "g" "g" ...
    +#>  $ Litter             : chr  "Litter 1" "Litter 2" "Litter 2" "Litter 2" ...
    +
    +invivo_study_samples %>%
    +  dplyr::count(Strain, Sex, BirthDate) %>%
    +  gt::gt()
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    StrainSexBirthDaten
    Strain AFNA7
    Strain AMNA22
    Strain BF2021-03-014
    Strain BF2021-04-122
    Strain BF2021-05-241
    Strain BM2021-02-224
    Strain BM2021-03-158
    Strain BM2021-04-125
    Strain BM2021-05-173
    Strain BM2021-05-243
    +
    +

    A simple data summary reveals that the cohort is almost equally +composed of Strains A and B. There are male and female animals in quite +different proportions, with a noticeable excess of the males. Birth +dates are available for Strain A, but missing completely for Strain +B.

    +

    Initial body weights (arrival weights), identifying ear marks and +litter information are available for all animals. The litter is nested +within the strain and all individuals within one litter naturally share +one birth date.

    +
    +invivo_study_samples %>%
    +  dplyr::count(Strain, Litter, BirthDate) %>%
    +  gt::gt()
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    StrainLitterBirthDaten
    Strain ALitter 10NA5
    Strain ALitter 11NA7
    Strain ALitter 12NA7
    Strain ALitter 13NA4
    Strain ALitter 14NA6
    Strain BLitter 12021-05-244
    Strain BLitter 22021-03-014
    Strain BLitter 32021-04-127
    Strain BLitter 42021-03-154
    Strain BLitter 52021-02-224
    Strain BLitter 62021-03-154
    Strain BLitter 72021-05-173
    +
    +
    +
    +

    Treatment list +

    +
    +str(invivo_study_treatments)
    +#> 'data.frame':    59 obs. of  3 variables:
    +#>  $ Treatment: chr  "Treatment 1" "Treatment 1" "Treatment 1" "Treatment 1" ...
    +#>  $ Strain   : chr  "Strain A" "Strain A" "Strain A" "Strain A" ...
    +#>  $ Sex      : chr  "M" "M" "M" "M" ...
    +
    +invivo_study_treatments %>%
    +  dplyr::count(Treatment, Strain, Sex) %>%
    +  gt::gt()
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    TreatmentStrainSexn
    Treatment 1Strain AM10
    Treatment 1Strain BM10
    Treatment 2Strain AF5
    Treatment 2Strain AM5
    Treatment 2Strain BF5
    Treatment 2Strain BM5
    Treatment 3Strain AM6
    Treatment 3Strain BM6
    untreatedStrain AF2
    untreatedStrain AM1
    untreatedStrain BF2
    untreatedStrain BM2
    +
    +

    We have 3 treatments that should each be administered to a defined +number of animals. In addition, some satellite animals of either strain +will not receive any treatment at all, which is specified by a fourth +(‘untreated’) condition.

    +

    In most cases the treatment list could be reduced to the first +column, i.e. repeating each label for the right number of times so that +the total length matches the sample sheet.

    +

    However, additional study specific constraints may be specified by +adding columns that also appear in the animal list and indicate how the +treatments should be assigned to subgroups of the cohort. In this +example, a different number of animals is used for each of the +treatments, balanced across strains. However, female animals are only to +be used for treatment 2.

    +
    +
    +

    Design constraints and data preparation +

    +

    The specific constraints for our type of in vivo study may +be summarized as follows:

    +
      +
    • We want to form cages, each hosting ideally 3 animals (preferred +range from 2-5)
    • +
    • Strain, Sex and Treatment must be homogeneous within a cage
    • +
    • Males from different litters must not be put into the same cage; +litter mixing is possible however for female animals!
    • +
    • Average body weight and age composition should be comparable between +treatment groups and cages
    • +
    • If at all possible, we avoid putting animals with identical ear +markings into the same cage
    • +
    • The distribution of treatments across animal subgroups (if specified +by the treatment list!) has to be respected
    • +
    +

    The very special and intricate nature of these requirements motivate +th creation of dedicated functionality on top of this package, as +demonstrated by this vignette.

    +

    Before using these functions, we add two auxiliary columns to the +sample sheet:

    +
      +
    • +AgeGroup represents the different birth dates as an +integer variable, where unknown (NA) values get their own code.
    • +
    • +Litter_combine_females groups all female animals in +a pseudo litter, facilitating the assignment of animals to cages at +which point only the females can be freely combined (co-housed).
    • +
    +
    +invivo_study_samples <- dplyr::mutate(invivo_study_samples,
    +  AgeGroup = as.integer(factor(BirthDate, exclude = NULL)),
    +  Litter_combine_females = ifelse(Sex == "F", "female_all", Litter)
    +)
    +
    +invivo_study_samples %>%
    +  dplyr::count(Strain, Litter_combine_females, BirthDate, AgeGroup) %>%
    +  gt::gt()
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    StrainLitter_combine_femalesBirthDateAgeGroupn
    Strain ALitter 10NA73
    Strain ALitter 11NA74
    Strain ALitter 12NA75
    Strain ALitter 13NA74
    Strain ALitter 14NA76
    Strain Afemale_allNA77
    Strain BLitter 12021-05-2463
    Strain BLitter 32021-04-1245
    Strain BLitter 42021-03-1534
    Strain BLitter 52021-02-2214
    Strain BLitter 62021-03-1534
    Strain BLitter 72021-05-1753
    Strain Bfemale_all2021-03-0124
    Strain Bfemale_all2021-04-1242
    Strain Bfemale_all2021-05-2461
    +
    +
    +
    +
    +

    Design steps +

    +

    The process of solving the design problem can be divided into 3 +successive steps, each of which is addressed by a specific in +vivo-specific wrapper function.

    +
      +
    1. Assign treatments to individuals animals (function +InVivo_assignTreatments())

    2. +
    3. Allocate animals to cages (function +Invivo_assignCages())

    4. +
    5. Arrange cages in one or more racks of given dimension (function +Invivo_arrangeCages())

    6. +
    +

    Dedicated constraints have to be handled at each step, as is +reflected in the interface of those wrappers.

    +

    As stated above, implementation details are beyond the scope of this +example. We will instead just show the interfaces of the three wrappers, +run the example case and visualize the resulting design.

    +
    +

    Assign treatments to animal list +

    +
    +InVivo_assignTreatments <- function(animal_list, treatments,
    +                                    balance_treatment_vars = c(),
    +                                    form_cages_by = c(),
    +                                    n_shuffle = c(rep(5, 100), rep(3, 200), rep(2, 500), rep(1, 20000)),
    +                                    quiet_process = FALSE, quiet_optimize = TRUE) {
    +  (...)
    +}
    +

    The function works with the initial animal and treatment lists.

    +

    Most importantly, balance_treatment_vars lists the +variables that should be balanced across treatments (e.g. strain, sex, +body weight, age, litter). Different scoring functions will be created +for categorical and numerical covariates.

    +

    form_cages_by is not mandatory, but gives important +clues regarding the variables that will later be homogeneous within each +cage (e.g. strain, sex, litter). Providing this may be crucial for +finding good solutions with a low number of single-housed animals that +don’t fit into any other cage.

    +

    It is also possible to modify the shuffling protocol and toggle +messaging on the level of processing steps as well as optimization +iterations.

    +
    +
    +

    Populate cages +

    +
    +Invivo_assignCages <- function(design_trt,
    +                               cagegroup_vars,
    +                               unique_vars = c(),
    +                               balance_cage_vars = c(),
    +                               n_min = 2, n_max = 5, n_ideal = 2, prefer_big_groups = TRUE, strict = TRUE,
    +                               maxiter = 5e3,
    +                               quiet_process = FALSE, quiet_optimize = TRUE) {
    +  (...)
    +}
    +

    This wrapper takes the output of the previous step (‘design_trt’) as +input.

    +
      +
    • +cagegroup_vars is a list of variables that must be +uniform within each cage (e.g. treatment”, strain, sex, litter).
    • +
    • +unique_vars is a list of variables whose values +should be unique per cage (e.g. ear marking). This constraint will be +relaxed in a stepwise way if no solution can be found under strict +adherence.
    • +
    • +balance_cage_vars lists variables which should be +evenly distributed across cages, as far as possible (e.g. age, body +weight).
    • +
    • +n_min, n_max and +n_ideal specify the minimal, maximal and ideal cage +sizes, respectively. It is often necessary to release the +strict criterion to find any solution at all or reduce +the number of remaining single-housed animals.
    • +
    +
    +
    +

    Arrange cages in rack(s) +

    +
    +Invivo_arrangeCages <- function(design_cage,
    +                                distribute_cagerack_vars = "Treatment",
    +                                rack_size_x = 4,
    +                                rack_size_y = 4,
    +                                n_shuffle = c(rep(5, 100), rep(3, 400), rep(2, 500), rep(1, 4000)),
    +                                quiet_process = FALSE, quiet_optimize = TRUE) {
    +  (...)
    +}
    +

    This wrapper takes the output of the previous step (‘design_cage’) as +input.

    +

    distribute_cagerack_vars is a list of variables that +should be evenly spaced out across the rows and columns of a rack (or +several racks, if needed). Typical cases may include treatment, strain +and sex of the animals.

    +

    rack_size_x and rack_size_y specify +the number of cages that fit into the rows and columns of a grid like +rack, respectively. Depending on the actual number of cages, one or more +racks are automatically assigned. Only rectangular sub-grids may be used +of any rack to accommodate the cages.

    +
    +

    +Calculating the design + +

    +

    +A full run of the three wrapper functions is executed below, printing +messages on the level of processing steps, but not the iterations within +every optimization. +

    +
    set.seed(44)
    +
    +# Assign treatments to animals, respecting user provided as well as passed constraints
    +design_trt <- InVivo_assignTreatments(invivo_study_samples, invivo_study_treatments,
    +  form_cages_by = c("Strain", "Sex", "Litter_combine_females"),
    +  balance_treatment_vars = c("Strain", "Sex", "ArrivalWeight", "AgeGroup"),
    +  n_shuffle = c(rep(5, 200), rep(3, 300), rep(2, 500), rep(1, 3000)),
    +  quiet_process = FALSE,
    +  quiet_optimize = TRUE
    +)
    +#> Performing treatment assignment with constrained animal selection.
    +#> Using constraints in variables: Strain, Sex
    +#> Checking if solution is possible:
    +#>    ... Yes!
    +#> Setting up batch container.
    +#> Constructing scoring functions:
    +#>      ... user specified treatment allocation constraint (Treatment-Strain-Sex)
    +#>      ... facilitating homogeneity of treatment in cages (CageGroup)
    +#>      ... ANOVA -logP for numerical variables balanced across treatment (ArrivalWeight, AgeGroup)
    +#> CAUTION: User defined constraints could not be fully met (remaining score 4)
    +
    +# Form cages with reasonable animal numbers and compliant with all constraints
    +design_cage <- Invivo_assignCages(design_trt,
    +  cagegroup_vars = c("Treatment", "Strain", "Sex", "Litter_combine_females"),
    +  unique_vars = c("Earmark"),
    +  balance_cage_vars = c("ArrivalWeight", "AgeGroup"),
    +  n_min = 2, n_max = 5, n_ideal = 2, prefer_big_groups = T, strict = F,
    +  maxiter = 1000,
    +  quiet_process = FALSE,
    +  quiet_optimize = TRUE
    +)
    +#> Setting up batch container.
    +#> 
    +#> Formed 19 homogeneous groups using 59 samples.
    +#> 27 subgroups needed to satisfy size constraints.
    +#> 
    +#> Finding possible ways to allocate variable of interest with 1 levels ...
    +#> 
    +#> Finished with 27 recursive calls.
    +#> 1 allocations found.
    +#> No permutations fulfilling the 'keep_separate' constraints in 1000 iters!
    +#> Increasing number of tolerated violations to 1
    +#> 
    +#> Expecting 27 cages to be created and 3 single-housed animals.
    +#> Constructing scoring functions:
    +#>      ... ANOVA -logP for numerical variables balanced across cages (ArrivalWeight, AgeGroup)
    +#> Adding 4 attributes to samples.
    +
    +# Arrange cages in sub-grid of one rack (or several racks), avoiding spatial clusters
    +design_rack <- Invivo_arrangeCages(design_cage,
    +  distribute_cagerack_vars = c("Treatment", "Strain", "Sex"),
    +  rack_size_x = 7,
    +  rack_size_y = 10,
    +  n_shuffle = c(rep(5, 100), rep(3, 200), rep(2, 300), rep(1, 500)),
    +  quiet_process = FALSE,
    +  quiet_optimize = TRUE
    +)
    +#> Needing 1 rack with a grid of 4 x 7 cages.
    +#> There will be 1 empty position overall.
    +#> Setting up batch container.
    +#> 
    +#> Distributing target variables (Treatment, Strain, Sex) within rack
    +#>    ... Rack 1
    +#> ... Performing simple mean/stddev adjustment.
    +#>    ... final scores: Plate_Treatment: 5.2, Plate_Strain: 5.46, Plate_Sex: 5.67
    +
    +
    +

    +Visualization of the study design + +

    +
    +

    +Cage composition + +

    +

    +There are 27 cages in total. +

    +

    +Strains and age groups should be evenly split (balanced) across the +treatments. Also,in each cage there should be only animals with the same +treatment, strain and sex. +

    +

    +Females are exclusively used for treatment 2, as was specified in the +treatment list. +

    +

    +

    +
    +
    +

    +Body weights + +

    +

    +Body weights should be balanced across treatments as well as possible. +

    +

    +The plot illustrates that this is true for the overall weight +distribution (box plots). Interestingly, as there are females +(associated with considerable less body weight) involved in treatment 2, +the optimization favored the selection of heavier males in this group to +compensate, achieving better cross-treatment balance of this factor. +

    +

    +Red diamonds mark the mean values for a specific sex within each +treatment group. +

    +

    +

    +
    +
    +

    +Cage arrangement in rack + +

    +

    +The following plots show the organization of the cage rack, individual +cages colored by different variables each time. +

    +

    +

    +
    +
    +

    +Individual animals in cages + +

    +

    +Finally, an overview plot illustrates the placement of animals in the +cages. Notice the distinct earmarks within each cage, a ‘soft’ design +constraint that could be achieved with the given solution. +

    +

    +

    +
    +
    +
    +
    +
    + + + +
    + + + +
    + +
    +

    +

    Site built with pkgdown 2.0.7.

    +
    + +
    +
    + + + + + + + + diff --git a/dev/articles/nested_dimensions_examples.html b/dev/articles/nested_dimensions_examples.html new file mode 100644 index 00000000..ede4140f --- /dev/null +++ b/dev/articles/nested_dimensions_examples.html @@ -0,0 +1,856 @@ + + + + + + + +Nested dimension example • designit + + + + + + + + + + + + + + + + + + + + +
    +
    + + + + +
    +
    + + + + +
    +library(designit)
    +library(tidyverse)
    +#> ── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
    +#>  dplyr     1.1.0      readr     2.1.4
    +#>  forcats   1.0.0      stringr   1.5.0
    +#>  ggplot2   3.4.1      tibble    3.2.0
    +#>  lubridate 1.9.2      tidyr     1.3.0
    +#>  purrr     1.0.1     
    +#> ── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
    +#>  dplyr::filter() masks stats::filter()
    +#>  dplyr::lag()    masks stats::lag()
    +#>  Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors
    +
    +

    Sample annotation overview +

    +
    +data("multi_trt_day_samples")
    +

    Samples are grouped by Treatment and Collection time with the +following group sizes:

    +
    +multi_trt_day_samples %>%
    +  count(Time, Treatment) %>%
    +  gt::gt()
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    TimeTreatmentn
    4CTRL3
    4SOC_TRT14
    4SOC_TRT1_TRT23
    4SOC_TRT1_TRT34
    4SOC_TRT1_TRT3_TRT24
    8SOC_TRT13
    8SOC_TRT1_TRT23
    8SOC_TRT1_TRT34
    8SOC_TRT1_TRT3_TRT24
    +
    +

    Total number of samples is: 32

    +
    +
    +

    Task +

    +

    Samples are to be blocked in batches for scRNA-seq.

    +
      +
    • 8 samples can be processed per day (batch)
    • +
    • Within day they need to be split into 2 parallel runs (4 + 4).
    • +
    +
    +
    +

    Optimize batch +

    +
    +# Setting up the batch container
    +bc <- BatchContainer$new(
    +  dimensions = c(
    +    batch = ceiling(nrow(multi_trt_day_samples) / 8),
    +    run = 2, position = 4
    +  )
    +)
    +
    +# Add samples to container
    +bc$samples <- multi_trt_day_samples
    +# Initial random assignment
    +assign_in_order(bc)
    +# Set scoring function
    +bc$scoring_f <- osat_score_generator(c("batch"), c("Treatment", "Time"))
    +
    +bc
    +#> Batch container with 32 locations and 32 samples (assigned).
    +#>   Dimensions: batch, run, position
    +

    The samples are distributed to 4 batches (processing days). This is +done using osat scoring on sample Treatment and +Time, optimizing by shuffling.

    +
    +n_shuffle <- rep(c(32, 10, 2), c(100, 80, 20))
    +n_iterations <- length(n_shuffle)
    +
    +set.seed(42) # should we have conventions for this?
    +
    +# initial score
    +# bc$score()
    +trace <- optimize_design(
    +  bc,
    +  n_shuffle = n_shuffle,
    +  max_iter = n_iterations
    +) # default is 10000
    +#> Re-defined number of swaps to 16 in swapping function.
    +#> Checking variances of 1-dim. score vector.
    +#> ... (29.235) - OK
    +#> Initial score: 75
    +#> Achieved score: 25 at iteration 1
    +#> Achieved score: 21 at iteration 2
    +#> Achieved score: 15 at iteration 4
    +#> Achieved score: 13 at iteration 5
    +#> Achieved score: 11 at iteration 95
    +#> Achieved score: 9 at iteration 112
    +#> Achieved score: 5 at iteration 188
    +

    NOTE: Here the shuffling procedure is short, as it was optimized for +this vignette. I practice you will have to run for a much higher number +of iterations.

    +
    +

    Optimization trace +

    +
    +qplot(
    +  x = 1:trace$n_steps, y = trace$scores, color = factor(c(32, n_shuffle)),
    +  main = str_glue("Final score={bc$score()}"), geom = "point"
    +)
    +#> Warning: `qplot()` was deprecated in ggplot2 3.4.0.
    +#> This warning is displayed once every 8 hours.
    +#> Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
    +#> generated.
    +

    +
    +
    +

    Final batch layout +

    +
    +bc$get_samples(assignment = TRUE) %>%
    +  mutate(batch = factor(batch)) %>%
    +  ggplot(aes(x = batch, fill = Treatment, alpha = factor(Time))) +
    +  geom_bar()
    +#> Warning: Using alpha for a discrete variable is not advised.
    +

    +
    +
    +
    +

    Repeat but use shuffle with contraints +

    +
    +
    +# copy batch container for second optimization
    +bc2 <- bc$copy()
    +# Initial random assignment
    +assign_in_order(bc2)
    +
    +n_iterations <- 200
    +
    +set.seed(42) # should we have conventions for this?
    +
    +trace2 <- optimize_design(
    +  bc2,
    +  shuffle_proposal = shuffle_with_constraints(
    +    src = TRUE,
    +    # batch needs to change for shuffle to be accepted
    +    dst = .src$batch != batch
    +  ),
    +  max_iter = n_iterations
    +)
    +#> Checking variances of 1-dim. score vector.
    +#> ... (26.382) - OK
    +#> Initial score: 75
    +#> Achieved score: 67 at iteration 1
    +#> Achieved score: 63 at iteration 2
    +#> Achieved score: 53 at iteration 3
    +#> Achieved score: 49 at iteration 4
    +#> Achieved score: 47 at iteration 5
    +#> Achieved score: 37 at iteration 6
    +#> Achieved score: 35 at iteration 9
    +#> Achieved score: 33 at iteration 11
    +#> Achieved score: 29 at iteration 13
    +#> Achieved score: 27 at iteration 14
    +#> Achieved score: 25 at iteration 19
    +#> Achieved score: 19 at iteration 20
    +#> Achieved score: 17 at iteration 25
    +#> Achieved score: 15 at iteration 36
    +#> Achieved score: 13 at iteration 40
    +#> Achieved score: 11 at iteration 49
    +#> Achieved score: 9 at iteration 57
    +#> Achieved score: 7 at iteration 79
    +#> Achieved score: 5 at iteration 126
    +#> Achieved score: 3 at iteration 180
    +
    +qplot(
    +  x = 1:trace$n_steps, y = trace2$scores, # color = factor(n_shuffle),
    +  main = str_glue("Final score={bc2$score()}"), geom = "point"
    +)
    +

    +
    +
    +bc2$get_samples(assignment = TRUE) %>%
    +  mutate(batch = factor(batch)) %>%
    +  ggplot(aes(x = batch, fill = Treatment, alpha = factor(Time))) +
    +  geom_bar()
    +#> Warning: Using alpha for a discrete variable is not advised.
    +

    +NOTE: It is not possible to calculate the theoretically minimal osat +score, right?

    +
    +
    +

    Optimize runs within batch +

    +

    Using shuffle with constraints

    +

    Within each day there will be 2 runs (samples processed together) +with 4 samples each. For this we keep the optimized batch +and now only optimize run with constraint.

    +
    +n_iterations <- 100
    +
    +# assign new optimization function
    +bc$scoring_f <- osat_score_generator(c("run"), c("Treatment", "Time"))
    +# like this the optimization score is wrong because it tries to optimize across Batches.
    +# Possible ways to go:
    +# - we'd need something like c("batch", batch/run") for optimize by batch and run within batch.
    +# - or we add "batch/run" to the constraints somehow.
    +bc$score()
    +#> [1] 16
    +
    +trace_run <- optimize_design(
    +  bc,
    +  shuffle_proposal = shuffle_with_constraints(
    +    src = TRUE,
    +    # batch remains the same and run needs to change
    +    dst = batch == .src$batch & run != .src$run
    +  ),
    +  max_iter = n_iterations
    +)
    +#> Checking variances of 1-dim. score vector.
    +#> ... (36.071) - OK
    +#> Initial score: 16
    +#> Achieved score: 14 at iteration 2
    +#> Achieved score: 8 at iteration 4
    +#> Achieved score: 6 at iteration 10
    +#> Achieved score: 4 at iteration 11
    +#> Achieved score: 2 at iteration 16
    +
    +qplot(
    +  x = 1:trace_run$n_steps, y = trace_run$scores, color = factor(n_iterations),
    +  main = str_glue("Final score={bc$score()}"), geom = "point"
    +)
    +

    +
    +

    Final run layout +

    +

    This is not giving the expected mix of treatments across runs.

    +
    +
    +bc$get_samples() %>%
    +  mutate(run = factor(run)) %>%
    +  ggplot(aes(x = run, fill = Treatment, alpha = factor(Time))) +
    +  geom_bar() +
    +  facet_wrap(~batch)
    +#> Warning: Using alpha for a discrete variable is not advised.
    +

    +
    +
    +
    + + + +
    + + + +
    + +
    +

    +

    Site built with pkgdown 2.0.7.

    +
    + +
    +
    + + + + + + + + diff --git a/dev/articles/nested_dimensions_examples_files/figure-html/unnamed-chunk-10-1.png b/dev/articles/nested_dimensions_examples_files/figure-html/unnamed-chunk-10-1.png new file mode 100644 index 00000000..987d0b3a Binary files /dev/null and b/dev/articles/nested_dimensions_examples_files/figure-html/unnamed-chunk-10-1.png differ diff --git a/dev/articles/nested_dimensions_examples_files/figure-html/unnamed-chunk-11-1.png b/dev/articles/nested_dimensions_examples_files/figure-html/unnamed-chunk-11-1.png new file mode 100644 index 00000000..78b5bbb0 Binary files /dev/null and b/dev/articles/nested_dimensions_examples_files/figure-html/unnamed-chunk-11-1.png differ diff --git a/dev/articles/nested_dimensions_examples_files/figure-html/unnamed-chunk-6-1.png b/dev/articles/nested_dimensions_examples_files/figure-html/unnamed-chunk-6-1.png new file mode 100644 index 00000000..90879330 Binary files /dev/null and b/dev/articles/nested_dimensions_examples_files/figure-html/unnamed-chunk-6-1.png differ diff --git a/dev/articles/nested_dimensions_examples_files/figure-html/unnamed-chunk-7-1.png b/dev/articles/nested_dimensions_examples_files/figure-html/unnamed-chunk-7-1.png new file mode 100644 index 00000000..057a2815 Binary files /dev/null and b/dev/articles/nested_dimensions_examples_files/figure-html/unnamed-chunk-7-1.png differ diff --git a/dev/articles/nested_dimensions_examples_files/figure-html/unnamed-chunk-8-1.png b/dev/articles/nested_dimensions_examples_files/figure-html/unnamed-chunk-8-1.png new file mode 100644 index 00000000..c8f37d8b Binary files /dev/null and b/dev/articles/nested_dimensions_examples_files/figure-html/unnamed-chunk-8-1.png differ diff --git a/dev/articles/nested_dimensions_examples_files/figure-html/unnamed-chunk-8-2.png b/dev/articles/nested_dimensions_examples_files/figure-html/unnamed-chunk-8-2.png new file mode 100644 index 00000000..4fdfd101 Binary files /dev/null and b/dev/articles/nested_dimensions_examples_files/figure-html/unnamed-chunk-8-2.png differ diff --git a/dev/articles/optimizer_examples.html b/dev/articles/optimizer_examples.html new file mode 100644 index 00000000..1c355a4b --- /dev/null +++ b/dev/articles/optimizer_examples.html @@ -0,0 +1,1260 @@ + + + + + + + +Optimizer examples • designit + + + + + + + + + + + + + + + + + + + + +
    +
    + + + + +
    +
    + + + + + +
    +

    Sample annotation overview +

    +
    +data("multi_trt_day_samples")
    +

    Samples are grouped by Treatment and Collection time with the +following group sizes:

    +
    +multi_trt_day_samples %>%
    +  dplyr::count(Time, Treatment) %>%
    +  gt::gt()
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    TimeTreatmentn
    4CTRL3
    4SOC_TRT14
    4SOC_TRT1_TRT23
    4SOC_TRT1_TRT34
    4SOC_TRT1_TRT3_TRT24
    8SOC_TRT13
    8SOC_TRT1_TRT23
    8SOC_TRT1_TRT34
    8SOC_TRT1_TRT3_TRT24
    +
    +

    Total number of samples is: 32

    +
    +
    +

    Task +

    +

    Samples are to be blocked in batches for scRNA-seq.

    +
      +
    • 8 samples can be processed per day (batch)
    • +
    • Within day they need to be split into 2 parallel runs (4 + 4).
    • +
    +

    This data set is also used in the nested dimensions example. Here, we +focus on using different methods for the optimization.

    +
    +
    +

    Setting up batch container +

    +

    We allocate surplus positions in the batch container and some +excluded positions to check that all optimization methods support empty +container positions.

    +
    +# Setting up the batch container
    +bc <- BatchContainer$new(
    +  dimensions = c(
    +    batch = ceiling(nrow(multi_trt_day_samples) / 8),
    +    run = 2, position = 5
    +  ),
    +  exclude = tibble::tibble(batch = 4, run = c(1, 2), position = c(5, 5))
    +)
    +
    +# Add samples to container
    +assign_in_order(bc, samples = multi_trt_day_samples)
    +# Set scoring function
    +bc$scoring_f <- osat_score_generator(c("batch"), c("Treatment", "Time"))
    +
    +bc
    +#> Batch container with 38 locations and 32 samples (assigned).
    +#>   Dimensions: batch, run, position
    +
    +
    +

    First optimization with fixed shuffling protocol +

    +

    The samples are distributed to 4 batches (processing days). We use +the osat scoring on sample Treatment and Time, +using first a shuffling protocol with a fixed number of sample swaps on +each iteration.

    +

    Note that doing 32 swaps on 38 free container positions does not make +sense, since each swapping operation affects two different positions +anyway. The upper limit is reduced to the max number of meaningful swaps +(19) on the fly.

    +

    Optimization finishes after the list of permutations is +exhausted.

    +
    +n_shuffle <- rep(c(32, 10, 5, 2, 1), c(20, 40, 40, 50, 50))
    +
    +
    +bc1 <- bc$copy()
    +
    +trace1 <- optimize_design(
    +  bc1,
    +  n_shuffle = n_shuffle # will implicitly generate a shuffling function according to the provided schedule
    +)
    +#> Re-defined number of swaps to 19 in swapping function.
    +#> Warning in osat_score(bc, batch_vars = batch_vars, feature_vars = feature_vars,
    +#> : NAs in features / batch columns; they will be excluded from scoring
    +#> Checking variances of 1-dim. score vector.
    +#> ... (25.046) - OK
    +#> Initial score: 73.03
    +#> Achieved score: 20.925 at iteration 1
    +#> Achieved score: 20.399 at iteration 5
    +#> Achieved score: 18.82 at iteration 7
    +#> Achieved score: 18.294 at iteration 9
    +#> Achieved score: 17.346 at iteration 13
    +#> Achieved score: 12.82 at iteration 21
    +#> Achieved score: 10.925 at iteration 22
    +#> Achieved score: 6.82 at iteration 49
    +#> Achieved score: 4.82 at iteration 85
    +#> Achieved score: 4.504 at iteration 174
    +
    +trace1$elapsed
    +#> Time difference of 2.559221 secs
    +
    +

    Optimization trace +

    +

    Custom plot with some colours:

    +
    +ggplot2::qplot(x = seq_along(trace1$scores), y = trace1$scores, color = factor(n_shuffle)[1:length(trace1$scores)], geom = "point") +
    +  ggplot2::labs(title = "Score 1 tracing", subtitle = stringr::str_glue("Final score = {bc1$score()}"), x = "Iteration", y = "Score", color = "n_shuffle")
    +#> Warning: `qplot()` was deprecated in ggplot2 3.4.0.
    +#> This warning is displayed once every 8 hours.
    +#> Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
    +#> generated.
    +

    +

    Using the internal method…

    +
    +trace1$plot()
    +

    +

    We may safely apply the batch container methods get_samples() and +score() also after using the new optimization code.

    +
    +
    +

    Final batch layout +

    +
    +bc1$score()
    +#> [1] 4.504155
    +
    +bc1$get_samples(assignment = TRUE) %>%
    +  dplyr::filter(!is.na(Treatment)) %>%
    +  dplyr::mutate(anno = stringr::str_c(Time, " hr")) %>%
    +  ggplot2::ggplot(ggplot2::aes(x = batch, y = interaction(position, run), fill = Treatment)) +
    +  ggplot2::geom_tile(color = "white") +
    +  ggplot2::geom_hline(yintercept = 5.5, size = 1) +
    +  ggplot2::geom_text(ggplot2::aes(label = anno)) +
    +  ggplot2::labs(x = "Batch", y = "Position . Run")
    +#> Warning: Using `size` aesthetic for lines was deprecated in ggplot2 3.4.0.
    +#>  Please use `linewidth` instead.
    +#> This warning is displayed once every 8 hours.
    +#> Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
    +#> generated.
    +

    +
    +
    +

    Perform new iterations on optimized batch container +

    +

    Further optimization (using a different shuffling protocol maybe) can +be done immediately on the same batch container.

    +
    +n_shuffle <- rep(c(5, 2, 1), c(30, 30, 30))
    +
    +optimize_design(
    +  bc1,
    +  n_shuffle = n_shuffle
    +)
    +#> Checking variances of 1-dim. score vector.
    +#> ... (24.63) - OK
    +#> Initial score: 4.504
    +#> Achieved score: 2.609 at iteration 88
    +#> Optimization trace (91 score values, elapsed 1.469071 secs).
    +#>   Starting score: 4.504
    +#>   Final score   : 2.609
    +
    +
    +
    +

    Optimization with specified stopping criteria +

    +

    Starting optimization from scratch, we are passing now some stopping +criteria that may terminate optimization before a shuffling protocol has +been exhausted.

    +

    For demonstration, we use a shuffling function now that will do 3 +sample (position) swaps per iteration and can be called an arbitrary +number of times. Thus, iteration has to be stopped by either the +max_iter criterion or by reaching a specific minimum delta threshold +(score improvement from one selected solution to the next).

    +
    +bc2 <- bc$copy()
    +
    +optimize_design(
    +  bc2,
    +  n_shuffle = 3, # will implicitly generate a shuffling function that will do 3 swaps at each iteration
    +  max_iter = 2000,
    +  min_delta = 0.1
    +)
    +#> Checking variances of 1-dim. score vector.
    +#> ... (29.544) - OK
    +#> Initial score: 73.03
    +#> Achieved score: 67.662 at iteration 1
    +#> Achieved score: 54.083 at iteration 2
    +#> Achieved score: 38.083 at iteration 3
    +#> Achieved score: 36.504 at iteration 4
    +#> Achieved score: 34.715 at iteration 5
    +#> Achieved score: 30.715 at iteration 6
    +#> Achieved score: 28.715 at iteration 7
    +#> Achieved score: 26.715 at iteration 8
    +#> Achieved score: 22.715 at iteration 9
    +#> Achieved score: 14.294 at iteration 11
    +#> Achieved score: 12.294 at iteration 27
    +#> Achieved score: 12.083 at iteration 29
    +#> Achieved score: 8.188 at iteration 66
    +#> Achieved score: 6.188 at iteration 109
    +#> Achieved score: 4.188 at iteration 146
    +#> Achieved score: 2.609 at iteration 334
    +#> Achieved score: 2.294 at iteration 621
    +#> Optimization trace (2001 score values, elapsed 16.78205 secs).
    +#>   Starting score: 73.03
    +#>   Final score   : 2.294
    +
    +
    +

    Optimization with multi-variate scoring function +

    +

    Instead of passing a single scoring function, a list of multiple +scoring functions can be assigned to a batch container, each of which to +return a scalar value on evaluation.

    +

    By default, a strict improvement rule is applied for classifying a +potential solution as “better”: each of the individual scores has to be +smaller than or equal to its previous value, and one of the scores has +to be changed.

    +

    However, the user could specify other methods for aggregating the +scores or defining the acceptance criterion. See later examples.

    +

    The second scoring function used here is by the way rather redundant +and just serves for illustration.

    +
    +bc3 <- bc$copy()
    +
    +bc3$scoring_f <- list(
    +  osat_score_generator(c("batch"), c("Treatment", "Time")),
    +  osat_score_generator(c("batch"), c("Treatment"))
    +)
    +
    +
    +trace <- optimize_design(
    +  bc3,
    +  n_shuffle = 3,
    +  max_iter = 200,
    +  min_delta = 0.1
    +)
    +#> Warning in osat_score(bc, batch_vars = batch_vars, feature_vars = feature_vars,
    +#> : NAs in features / batch columns; they will be excluded from scoring
    +
    +#> Warning in osat_score(bc, batch_vars = batch_vars, feature_vars = feature_vars,
    +#> : NAs in features / batch columns; they will be excluded from scoring
    +#> Checking variances of 2-dim. score vector.
    +#> ... (27.086, 53.151) - OK
    +#> Initial score: c(73.03, 44.803)
    +#> Achieved score: c(51.452, 39.645) at iteration 2
    +#> Achieved score: c(35.452, 29.645) at iteration 3
    +#> Achieved score: c(29.662, 25.751) at iteration 5
    +#> Achieved score: c(25.662, 21.751) at iteration 6
    +#> Achieved score: c(23.978, 14.382) at iteration 16
    +#> Achieved score: c(14.399, 9.119) at iteration 20
    +#> Achieved score: c(12.504, 7.33) at iteration 22
    +#> Achieved score: c(10.504, 7.33) at iteration 31
    +#> Achieved score: c(10.504, 5.751) at iteration 45
    +#> Achieved score: c(6.504, 5.751) at iteration 66
    +#> Achieved score: c(4.925, 4.593) at iteration 136
    +#> Achieved score: c(4.925, 4.593) at iteration 179
    +#> Reached min delta in 179 iterations.
    +

    Note that the first score tends to yield higher values than the +second one. This could be a problem when trying to select a solution +based on an aggregated, overall score. We repeat the same optimization +now by using the autoscaling functionality of the optimizer.

    +
    +
    +

    Auto-scaling scores +

    +

    We’re just adding the autoscale_scores option here to +estimate the distribution of individual scores on a number of completely +random sample assignments (200 in this case) and then apply a +transformation to rescale each score to a standard normal.

    +

    Note that by ‘normalizing’ the distribution of the scores we obtain +values centered around zero, thus that the optimized scores are likely +to be negative. We may also want to decrease the delta_min parameter to +match the new numerical range.

    +
    +bc3_as <- bc$copy()
    +
    +bc3_as$scoring_f <- list(
    +  osat_score_generator(c("batch"), c("Treatment", "Time")),
    +  osat_score_generator(c("batch"), c("Treatment"))
    +)
    +
    +
    +trace <- optimize_design(
    +  bc3_as,
    +  n_shuffle = 3,
    +  max_iter = 200,
    +  min_delta = 0.01,
    +  autoscale_scores = T,
    +  autoscaling_permutations = 200
    +)
    +#> Warning in osat_score(bc, batch_vars = batch_vars, feature_vars = feature_vars,
    +#> : NAs in features / batch columns; they will be excluded from scoring
    +
    +#> Warning in osat_score(bc, batch_vars = batch_vars, feature_vars = feature_vars,
    +#> : NAs in features / batch columns; they will be excluded from scoring
    +#> Checking variances of 2-dim. score vector.
    +#> ... (33.045, 64.702) - OK
    +#> Creating autoscaling function for 2-dim. score vector. (200 random permutations)
    +#> ... Performing boxcox lambda estimation.
    +#> Initial score: c(5.727, 2.888)
    +#> Achieved score: c(3.589, 1.885) at iteration 1
    +#> Achieved score: c(2.74, 1.253) at iteration 2
    +#> Achieved score: c(1.948, 0.953) at iteration 3
    +#> Achieved score: c(-0.026, 0.296) at iteration 4
    +#> Achieved score: c(-1.029, -0.621) at iteration 6
    +#> Achieved score: c(-2.022, -1.418) at iteration 14
    +#> Achieved score: c(-3.505, -2.281) at iteration 28
    +#> Achieved score: c(-3.505, -2.307) at iteration 40
    +#> Achieved score: c(-4.252, -2.598) at iteration 56
    +#> Achieved score: c(-5.705, -2.8) at iteration 76
    +#> Achieved score: c(-7.415, -2.8) at iteration 92
    +

    Having directly comparable scores, it may be reasonable now to use a +function that somehow aggregates the scores to decide on the best +iteration (instead of looking at the scores individually).

    +

    An easy way to do this is to use the built-in worst_score function. +This will simply set the aggregated score to whichever of the individual +scores is larger (i.e. ‘worse’ in terms of the optimization).

    +
    +bc4 <- bc$copy()
    +
    +bc4$scoring_f <- list(
    +  osat_score_generator(c("batch"), c("Treatment", "Time")),
    +  osat_score_generator(c("batch"), c("Treatment"))
    +)
    +
    +
    +optimize_design(
    +  bc4,
    +  n_shuffle = 3,
    +  aggregate_scores_func = worst_score,
    +  max_iter = 200,
    +  autoscale_scores = TRUE,
    +  autoscaling_permutations = 200
    +)
    +#> Warning in osat_score(bc, batch_vars = batch_vars, feature_vars = feature_vars,
    +#> : NAs in features / batch columns; they will be excluded from scoring
    +
    +#> Warning in osat_score(bc, batch_vars = batch_vars, feature_vars = feature_vars,
    +#> : NAs in features / batch columns; they will be excluded from scoring
    +#> Checking variances of 2-dim. score vector.
    +#> ... (23.096, 45.492) - OK
    +#> Creating autoscaling function for 2-dim. score vector. (200 random permutations)
    +#> ... Performing boxcox lambda estimation.
    +#> Initial score: c(7.044, 2.491)
    +#>    Aggregated: 7.044
    +#> Achieved score: c(3.972, 0.497) at iteration 1
    +#>    Aggregated: 3.972
    +#> Achieved score: c(3.958, 0.952) at iteration 2
    +#>    Aggregated: 3.958
    +#> Achieved score: c(1.999, -0.642) at iteration 3
    +#>    Aggregated: 1.999
    +#> Achieved score: c(1.752, -1.588) at iteration 4
    +#>    Aggregated: 1.752
    +#> Achieved score: c(1.17, -1.421) at iteration 6
    +#>    Aggregated: 1.17
    +#> Achieved score: c(-0.265, -3.156) at iteration 7
    +#>    Aggregated: -0.265
    +#> Achieved score: c(-0.64, -1.87) at iteration 8
    +#>    Aggregated: -0.64
    +#> Achieved score: c(-1.516, -1.029) at iteration 11
    +#>    Aggregated: -1.029
    +#> Achieved score: c(-1.492, -1.398) at iteration 14
    +#>    Aggregated: -1.398
    +#> Achieved score: c(-1.882, -1.79) at iteration 48
    +#>    Aggregated: -1.79
    +#> Achieved score: c(-2.349, -2.18) at iteration 50
    +#>    Aggregated: -2.18
    +#> Achieved score: c(-2.376, -2.995) at iteration 58
    +#>    Aggregated: -2.376
    +#> Achieved score: c(-2.403, -3.917) at iteration 67
    +#>    Aggregated: -2.403
    +#> Achieved score: c(-2.403, -3.917) at iteration 83
    +#>    Aggregated: -2.403
    +#> Achieved score: c(-2.431, -4.029) at iteration 132
    +#>    Aggregated: -2.431
    +#> Achieved score: c(-3.093, -2.697) at iteration 143
    +#>    Aggregated: -2.697
    +#> Achieved score: c(-3.676, -3.417) at iteration 151
    +#>    Aggregated: -3.417
    +#> Optimization trace (201 score values, elapsed 6.154244 secs).
    +#>   Starting score: 7.044,2.491
    +#>   Final score   : -3.676,-3.417
    +

    Another - more interesting - option would be to aggregate the two +scores by taking their sum. This way both scores will influence the +optimization at every step.

    +

    For illustration, we omit the n_shuffle parameter here, +which will lead by default to pairwise sample swaps being done on each +iteration.

    +
    +bc5 <- bc$copy()
    +
    +bc5$scoring_f <- list(
    +  osat_score_generator(c("batch"), c("Treatment", "Time")),
    +  osat_score_generator(c("batch"), c("Treatment"))
    +)
    +
    +optimize_design(
    +  bc5,
    +  aggregate_scores_func = sum_scores,
    +  max_iter = 200,
    +  autoscale_scores = TRUE,
    +  autoscaling_permutations = 200
    +)
    +

    As a final example, we calculate the (squared) L2 norm to actually +aggregate the two scores. Not that this choice is not really motivated +in this case, but it could be used if optimization was carried on +meaningful distance vectors or normalized n-tuples.

    +

    Note that we don’t use the auto-scaling in this case as the L2-norm +based optimization would force both normalized scores towards zero, not +the minimal (negative) value that would be desired in that case.

    +
    +bc5_2 <- bc$copy()
    +
    +bc5_2$scoring_f <- list(
    +  osat_score_generator(c("batch"), c("Treatment", "Time")),
    +  osat_score_generator(c("batch"), c("Treatment"))
    +)
    +
    +optimize_design(
    +  bc5_2,
    +  aggregate_scores_func = L2s_norm,
    +  max_iter = 200,
    +)
    +
    +
    +

    Passing a customized shuffling function +

    +

    It is recommended to use the n_shuffle parameter to +steer the optimization protocol. However, you may also provide a +dedicated shuffling function that on each call has to return a shuffling +order (as integer vector) or a list with the source and destination +positions (src and dst) of the sample positions to be swapped.

    +

    The following example uses a template for creating complete random +shuffles across all available positions in the batch container. Note +that this is usually not a good strategy for converging to a +solution.

    +
    +bc6 <- bc$copy()
    +
    +optimize_design(
    +  bc6,
    +  shuffle_proposal_func = complete_random_shuffling,
    +  max_iter = 200
    +)
    +#> Checking variances of 1-dim. score vector.
    +#> ... (31.558) - OK
    +#> Initial score: 73.03
    +#> Achieved score: 32.925 at iteration 1
    +#> Achieved score: 19.241 at iteration 2
    +#> Achieved score: 15.978 at iteration 4
    +#> Achieved score: 12.925 at iteration 24
    +#> Achieved score: 12.82 at iteration 25
    +#> Achieved score: 10.399 at iteration 34
    +#> Achieved score: 8.82 at iteration 87
    +#> Optimization trace (201 score values, elapsed 1.999838 secs).
    +#>   Starting score: 73.03
    +#>   Final score   : 8.82
    +
    +
    +

    Using simulated annealing (SA) for optimization +

    +

    Esp. for very large search spaces, better solutions can be quite +successfully obtained by a SA protocol which allows the optimizer to +jump over ‘energy barriers’ to more likely converge at lower local +minima.

    +

    The optimizer usually remembers the permutation with the best overall +score to start with, but this behavior can be changed by supplying a +simulated annealing protocol, most simply by generating a ready-made +function template.

    +

    It is generally recommended for SA to make small changes at each +step, like allowing just 1 sample swap per iteration.

    +

    Currently the simulated annealing protocol requires a single double +value score to be optimized. Choose an appropriate aggregation function +if you happen to have multiple scores initially.

    +
    +bc7 <- bc$copy()
    +
    +trace7 <- optimize_design(
    +  bc7,
    +  n_shuffle = 1,
    +  acceptance_func = mk_simanneal_acceptance_func(),
    +  max_iter = 200
    +)
    +#> Checking variances of 1-dim. score vector.
    +#> ... (26.224) - OK
    +#> Initial score: 73.03
    +#> Achieved score: 67.452 at iteration 1
    +#> Achieved score: 67.452 at iteration 2
    +#> Achieved score: 67.452 at iteration 3
    +#> Achieved score: 67.452 at iteration 4
    +#> Achieved score: 67.452 at iteration 5
    +#> Achieved score: 65.452 at iteration 6
    +#> Achieved score: 55.452 at iteration 7
    +#> Achieved score: 49.873 at iteration 8
    +#> Achieved score: 43.873 at iteration 9
    +#> Achieved score: 43.873 at iteration 10
    +#> Achieved score: 43.873 at iteration 11
    +#> Achieved score: 41.873 at iteration 14
    +#> Achieved score: 37.767 at iteration 15
    +#> Achieved score: 35.767 at iteration 16
    +#> Achieved score: 35.767 at iteration 17
    +#> Achieved score: 35.767 at iteration 18
    +#> Achieved score: 31.767 at iteration 19
    +#> Achieved score: 28.083 at iteration 20
    +#> Achieved score: 26.188 at iteration 21
    +#> Achieved score: 26.188 at iteration 23
    +#> Achieved score: 24.188 at iteration 24
    +#> Achieved score: 22.188 at iteration 25
    +#> Achieved score: 24.188 at iteration 26
    +#> Achieved score: 24.083 at iteration 27
    +#> Achieved score: 24.083 at iteration 28
    +#> Achieved score: 20.083 at iteration 29
    +#> Achieved score: 18.083 at iteration 30
    +#> Achieved score: 18.083 at iteration 31
    +#> Achieved score: 18.083 at iteration 33
    +#> Achieved score: 16.083 at iteration 38
    +#> Achieved score: 16.083 at iteration 40
    +#> Achieved score: 16.083 at iteration 49
    +#> Achieved score: 14.083 at iteration 51
    +#> Achieved score: 14.083 at iteration 52
    +#> Achieved score: 14.399 at iteration 54
    +#> Achieved score: 14.399 at iteration 61
    +#> Achieved score: 14.399 at iteration 62
    +#> Achieved score: 12.399 at iteration 63
    +#> Achieved score: 12.399 at iteration 64
    +#> Achieved score: 12.399 at iteration 68
    +#> Achieved score: 12.399 at iteration 69
    +#> Achieved score: 12.399 at iteration 74
    +#> Achieved score: 10.82 at iteration 80
    +#> Achieved score: 10.82 at iteration 82
    +#> Achieved score: 8.82 at iteration 86
    +#> Achieved score: 8.82 at iteration 109
    +#> Achieved score: 6.82 at iteration 122
    +#> Achieved score: 4.82 at iteration 124
    +

    The trace may show a non strictly monotonic behavior now, reflecting +the SA protocol at work.

    +
    +trace7$plot()
    +

    +

    Better results and quicker convergence may be achieved by playing +with the starting temperature (T0) and cooling speed (alpha) in a +specific case.

    +
    +bc8 <- bc$copy()
    +
    +trace8 <- optimize_design(
    +  bc8,
    +  n_shuffle = 1,
    +  acceptance_func = mk_simanneal_acceptance_func(mk_simanneal_temp_func(T0 = 100, alpha = 2)),
    +  max_iter = 150
    +)
    +#> Checking variances of 1-dim. score vector.
    +#> ... (34.519) - OK
    +#> Initial score: 73.03
    +#> Achieved score: 73.03 at iteration 1
    +#> Achieved score: 69.03 at iteration 2
    +#> Achieved score: 61.03 at iteration 3
    +#> Achieved score: 61.03 at iteration 4
    +#> Achieved score: 55.03 at iteration 5
    +#> Achieved score: 49.03 at iteration 6
    +#> Achieved score: 49.03 at iteration 7
    +#> Achieved score: 43.03 at iteration 9
    +#> Achieved score: 33.03 at iteration 10
    +#> Achieved score: 23.03 at iteration 11
    +#> Achieved score: 23.03 at iteration 12
    +#> Achieved score: 23.03 at iteration 14
    +#> Achieved score: 21.03 at iteration 15
    +#> Achieved score: 21.03 at iteration 17
    +#> Achieved score: 19.03 at iteration 18
    +#> Achieved score: 17.03 at iteration 21
    +#> Achieved score: 17.03 at iteration 28
    +#> Achieved score: 17.03 at iteration 35
    +#> Achieved score: 13.03 at iteration 37
    +#> Achieved score: 11.03 at iteration 42
    +#> Achieved score: 10.925 at iteration 45
    +#> Achieved score: 9.346 at iteration 60
    +#> Achieved score: 7.346 at iteration 62
    +#> Achieved score: 5.452 at iteration 86
    +#> Achieved score: 3.873 at iteration 140
    +
    +trace8$plot()
    +

    +
    +
    +

    Full blown example +

    +

    The following example puts together all possible options to +illustrate the flexibility of the optimization.

    +
    +bc$scoring_f <- list(
    +  osat_score_generator(c("batch"), c("Treatment", "Time")),
    +  osat_score_generator(c("batch"), c("Treatment")),
    +  osat_score_generator(c("batch"), c("Time"))
    +)
    +
    +n_shuffle <- rep(c(3, 2, 1), c(20, 20, 200))
    +
    +trace <- optimize_design(
    +  bc,
    +  n_shuffle = n_shuffle,
    +  aggregate_scores_func = sum_scores,
    +  acceptance_func = mk_simanneal_acceptance_func(mk_simanneal_temp_func(T0 = 500, alpha = 1)),
    +  max_iter = 200,
    +  min_delta = 1e-8,
    +  autoscale_scores = T
    +)
    +#> Warning in osat_score(bc, batch_vars = batch_vars, feature_vars = feature_vars,
    +#> : NAs in features / batch columns; they will be excluded from scoring
    +
    +#> Warning in osat_score(bc, batch_vars = batch_vars, feature_vars = feature_vars,
    +#> : NAs in features / batch columns; they will be excluded from scoring
    +
    +#> Warning in osat_score(bc, batch_vars = batch_vars, feature_vars = feature_vars,
    +#> : NAs in features / batch columns; they will be excluded from scoring
    +#> Checking variances of 3-dim. score vector.
    +#> ... (24.506, 52.938, 67.784) - OK
    +#> Creating autoscaling function for 3-dim. score vector. (100 random permutations)
    +#> ... Performing boxcox lambda estimation.
    +#> Initial score: c(5.079, 2.547, 3.612)
    +#>    Aggregated: 11.238
    +#> Achieved score: c(4.084, 2.547, 2.882) at iteration 1
    +#>    Aggregated: 9.513
    +#> Achieved score: c(3.143, 1.774, 2.721) at iteration 2
    +#>    Aggregated: 7.638
    +#> Achieved score: c(2.081, 0.995, 2.004) at iteration 3
    +#>    Aggregated: 5.08
    +#> Achieved score: c(2.17, 1.726, 1.54) at iteration 4
    +#>    Aggregated: 5.437
    +#> Achieved score: c(1.376, 1.541, -0.098) at iteration 5
    +#>    Aggregated: 2.818
    +#> Achieved score: c(1.376, 1.541, -0.098) at iteration 6
    +#>    Aggregated: 2.818
    +#> Reached min delta in 6 iterations.
    +
    +trace$plot()
    +

    +
    +
    +bc$get_samples(assignment = TRUE) %>%
    +  dplyr::mutate(batch = factor(batch)) %>%
    +  ggplot2::ggplot(ggplot2::aes(x = batch, fill = Treatment, alpha = factor(Time))) +
    +  ggplot2::geom_bar()
    +#> Warning: Using alpha for a discrete variable is not advised.
    +

    +
    +
    + + + +
    + + + +
    + +
    +

    +

    Site built with pkgdown 2.0.7.

    +
    + +
    +
    + + + + + + + + diff --git a/dev/articles/optimizer_examples_files/figure-html/unnamed-chunk-18-1.png b/dev/articles/optimizer_examples_files/figure-html/unnamed-chunk-18-1.png new file mode 100644 index 00000000..24a05f43 Binary files /dev/null and b/dev/articles/optimizer_examples_files/figure-html/unnamed-chunk-18-1.png differ diff --git a/dev/articles/optimizer_examples_files/figure-html/unnamed-chunk-19-1.png b/dev/articles/optimizer_examples_files/figure-html/unnamed-chunk-19-1.png new file mode 100644 index 00000000..a4cfeb33 Binary files /dev/null and b/dev/articles/optimizer_examples_files/figure-html/unnamed-chunk-19-1.png differ diff --git a/dev/articles/optimizer_examples_files/figure-html/unnamed-chunk-20-1.png b/dev/articles/optimizer_examples_files/figure-html/unnamed-chunk-20-1.png new file mode 100644 index 00000000..ec25f8a9 Binary files /dev/null and b/dev/articles/optimizer_examples_files/figure-html/unnamed-chunk-20-1.png differ diff --git a/dev/articles/optimizer_examples_files/figure-html/unnamed-chunk-20-2.png b/dev/articles/optimizer_examples_files/figure-html/unnamed-chunk-20-2.png new file mode 100644 index 00000000..9b76cf8f Binary files /dev/null and b/dev/articles/optimizer_examples_files/figure-html/unnamed-chunk-20-2.png differ diff --git a/dev/articles/optimizer_examples_files/figure-html/unnamed-chunk-6-1.png b/dev/articles/optimizer_examples_files/figure-html/unnamed-chunk-6-1.png new file mode 100644 index 00000000..a09fb1df Binary files /dev/null and b/dev/articles/optimizer_examples_files/figure-html/unnamed-chunk-6-1.png differ diff --git a/dev/articles/optimizer_examples_files/figure-html/unnamed-chunk-7-1.png b/dev/articles/optimizer_examples_files/figure-html/unnamed-chunk-7-1.png new file mode 100644 index 00000000..d3a590b0 Binary files /dev/null and b/dev/articles/optimizer_examples_files/figure-html/unnamed-chunk-7-1.png differ diff --git a/dev/articles/optimizer_examples_files/figure-html/unnamed-chunk-8-1.png b/dev/articles/optimizer_examples_files/figure-html/unnamed-chunk-8-1.png new file mode 100644 index 00000000..5a20ab7e Binary files /dev/null and b/dev/articles/optimizer_examples_files/figure-html/unnamed-chunk-8-1.png differ diff --git a/dev/articles/osat.html b/dev/articles/osat.html new file mode 100644 index 00000000..5bf3e95f --- /dev/null +++ b/dev/articles/osat.html @@ -0,0 +1,624 @@ + + + + + + + +OSAT and scoring functions • designit + + + + + + + + + + + + + + + + + + + + +
    +
    + + + + +
    +
    + + + + +
    +library(designit)
    +library(tidyverse)
    +#> ── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
    +#>  dplyr     1.1.0      readr     2.1.4
    +#>  forcats   1.0.0      stringr   1.5.0
    +#>  ggplot2   3.4.1      tibble    3.2.0
    +#>  lubridate 1.9.2      tidyr     1.3.0
    +#>  purrr     1.0.1     
    +#> ── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
    +#>  dplyr::filter() masks stats::filter()
    +#>  dplyr::lag()    masks stats::lag()
    +#>  Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors
    +if (!requireNamespace("OSAT")) {
    +  print("This vignette can only be rendered if `OSAT` package is installed.")
    +  knitr::knit_exit()
    +}
    +#> Loading required namespace: OSAT
    +

    Loading samples. We add two dummy columns to demonstrate how to +choose batch columns of interest.

    +
    +osat_data_path <- system.file("extdata", package = "OSAT")
    +samples <- read_tsv(file.path(osat_data_path, "samples.txt"),
    +  col_types = cols(SampleType = col_factor(), Race = col_factor(), AgeGrp = col_factor())
    +) %>%
    +  mutate(dummy_var1 = rnorm(n()), dummy_var2 = str_c(SampleType, Race, sep = " "))
    +
    +

    Running OSAT optimization +

    +

    Here we use OSAT to optimize setup.

    +
    +gs <- OSAT::setup.sample(samples, optimal = c("SampleType", "Race", "AgeGrp"))
    +
    +gc <- OSAT::setup.container(OSAT::IlluminaBeadChip96Plate, 7, batch = "plates")
    +
    +set.seed(1234)
    +
    +bench::system_time(
    +  g_setup <- OSAT::create.optimized.setup(sample = gs, container = gc, nSim = params$iterations)
    +)
    +#> Warning in OSAT::create.optimized.setup(sample = gs, container = gc, nSim =
    +#> params$iterations): Using default optimization method: optimal.shuffle
    +#> process    real 
    +#>   1.21s   1.21s
    +
    +OSAT::QC(g_setup)
    +#> 
    +#> Test independence between "plates" and sample variables
    +#> 
    +#> Pearson's Chi-squared test
    +#>          Var X-squared df   p.value
    +#> 1 SampleType 0.4938509  6 0.9979125
    +#> 2       Race 0.7424849  6 0.9935279
    +#> 3     AgeGrp 1.8472070 24 1.0000000
    +#> 
    +

    +

    Saving starting point of optimization

    +
    +set.seed(1234)
    +
    +g_setup_start <- OSAT::create.optimized.setup(sample = gs, container = gc, nSim = 1) %>%
    +  OSAT::get.experiment.setup()
    +#> Warning in OSAT::create.optimized.setup(sample = gs, container = gc, nSim = 1):
    +#> Using default optimization method: optimal.shuffle
    +

    Visualize various batch factors. OSAT score is optimized only for +plates in this case.

    +
    +OSAT::get.experiment.setup(g_setup) %>%
    +  select(AgeGrp, plates, chipRows, chipColumns, chips, rows, columns, wells) %>%
    +  pivot_longer(-AgeGrp) %>%
    +  count(AgeGrp, value, name) %>%
    +  ggplot(aes(AgeGrp, n, fill = factor(value))) +
    +  geom_col(position = "dodge") +
    +  facet_wrap(~name, scales = "free_y")
    +

    +
    +

    Visualize for plates +

    +
    +plot_batch <- function(df) {
    +  df %>%
    +    select(plates, SampleType, Race, AgeGrp) %>%
    +    pivot_longer(c(SampleType, Race, AgeGrp), names_to = "variable", values_to = "level") %>%
    +    count(plates, variable, level) %>%
    +    ggplot(aes(level, n, fill = factor(plates))) +
    +    geom_col(position = "dodge") +
    +    facet_wrap(~variable, scales = "free", ncol = 1)
    +}
    +

    Before the optimization.

    +
    +g_setup_start %>% plot_batch()
    +

    +

    After the optimization.

    +
    +OSAT::get.experiment.setup(g_setup) %>%
    +  plot_batch()
    +

    +
    +
    +
    +

    Compare scores with various implementations +

    +

    Compare OSAT score generated using designit.

    +
    +OSAT::getLayout(gc) %>%
    +  left_join(OSAT::get.experiment.setup(g_setup)) %>%
    +  data.table::data.table() %>%
    +  osat_score("plates", c("SampleType", "Race", "AgeGrp")) %>%
    +  .$score
    +#> Joining with `by = join_by(plates, chipRows, chipColumns, chips, rows, columns,
    +#> wells)`
    +#> Warning in osat_score(., "plates", c("SampleType", "Race", "AgeGrp")): NAs in
    +#> features / batch columns; they will be excluded from scoring
    +#> [1] 34.85714
    +
    +# score using OSAT
    +g_setup@metadata$optValue %>% tail(1)
    +#> [1] 34.85714
    +
    +
    +

    Run using BatchContainer +

    +

    First let’s create a BatchContainer with same dimensions.

    +
    +bc <- BatchContainer$new(
    +  dimensions = c(plates = 7, chips = 8, rows = 6, columns = 2)
    +)
    +bc
    +#> Batch container with 672 locations.
    +#>   Dimensions: plates, chips, rows, columns
    +
    +bc$n_locations
    +#> [1] 672
    +

    Assign samples and get initial setup.

    +
    +bc$samples <- samples
    +
    +starting_assignment <- bc$get_locations() %>%
    +  left_join(g_setup_start) %>%
    +  pull(ID) %>%
    +  as.integer()
    +#> Joining with `by = join_by(plates, chips, rows, columns)`
    +
    +bc$move_samples(location_assignment = starting_assignment)
    +
    +bc$get_samples(remove_empty_locations = TRUE) %>%
    +  plot_batch()
    +

    +
    +

    Using designit OSAT score implementation +

    +
    +bc$scoring_f <- osat_score_generator("plates", c("SampleType", "Race", "AgeGrp"))
    +
    +bc$score()
    +#> Warning in osat_score(bc, batch_vars = batch_vars, feature_vars = feature_vars,
    +#> : NAs in features / batch columns; they will be excluded from scoring
    +#> [1] 360.8571
    +g_setup@metadata$optValue %>% head(1)
    +#> [1] 360.8571
    +# should be identical
    +
    +bench::system_time({
    +  set.seed(123)
    +  trace_reference <- optimize_design(bc, max_iter = params$iterations)
    +})
    +#> Checking variances of 1-dim. score vector.
    +#> ... (6749.04) - OK
    +#> Initial score: 360.857
    +#> Achieved score: 348.857 at iteration 7
    +#> Achieved score: 344.857 at iteration 8
    +#> Achieved score: 338.857 at iteration 10
    +#> Achieved score: 326.857 at iteration 19
    +#> Achieved score: 322.857 at iteration 22
    +#> Achieved score: 320.857 at iteration 24
    +#> Achieved score: 318.857 at iteration 26
    +#> Achieved score: 314.857 at iteration 27
    +#> Achieved score: 308.857 at iteration 28
    +#> Achieved score: 302.857 at iteration 32
    +#> Achieved score: 300.857 at iteration 33
    +#> Achieved score: 292.857 at iteration 36
    +#> Achieved score: 290.857 at iteration 38
    +#> Achieved score: 284.857 at iteration 40
    +#> Achieved score: 276.857 at iteration 45
    +#> Achieved score: 272.857 at iteration 50
    +#> Achieved score: 266.857 at iteration 54
    +#> Achieved score: 258.857 at iteration 55
    +#> Achieved score: 248.857 at iteration 60
    +#> Achieved score: 242.857 at iteration 62
    +#> Achieved score: 224.857 at iteration 71
    +#> Achieved score: 218.857 at iteration 73
    +#> Achieved score: 214.857 at iteration 76
    +#> Achieved score: 204.857 at iteration 78
    +#> Achieved score: 200.857 at iteration 79
    +#> Achieved score: 192.857 at iteration 80
    +#> Achieved score: 184.857 at iteration 84
    +#> Achieved score: 176.857 at iteration 85
    +#> Achieved score: 172.857 at iteration 86
    +#> Achieved score: 170.857 at iteration 95
    +#> Achieved score: 166.857 at iteration 96
    +#> Achieved score: 156.857 at iteration 98
    +#> Achieved score: 150.857 at iteration 99
    +#> Achieved score: 148.857 at iteration 102
    +#> Achieved score: 144.857 at iteration 103
    +#> Achieved score: 138.857 at iteration 113
    +#> Achieved score: 132.857 at iteration 133
    +#> Achieved score: 124.857 at iteration 138
    +#> Achieved score: 120.857 at iteration 140
    +#> Achieved score: 112.857 at iteration 149
    +#> Achieved score: 108.857 at iteration 169
    +#> Achieved score: 106.857 at iteration 175
    +#> Achieved score: 104.857 at iteration 176
    +#> Achieved score: 100.857 at iteration 178
    +#> Achieved score: 98.857 at iteration 179
    +#> Achieved score: 92.857 at iteration 188
    +#> Achieved score: 90.857 at iteration 189
    +#> Achieved score: 86.857 at iteration 190
    +#> Achieved score: 82.857 at iteration 202
    +#> Achieved score: 76.857 at iteration 210
    +#> Achieved score: 72.857 at iteration 223
    +#> Achieved score: 68.857 at iteration 231
    +#> Achieved score: 66.857 at iteration 239
    +#> Achieved score: 64.857 at iteration 262
    +#> Achieved score: 62.857 at iteration 324
    +#> Achieved score: 60.857 at iteration 336
    +#> Achieved score: 58.857 at iteration 358
    +#> Achieved score: 56.857 at iteration 360
    +#> Achieved score: 52.857 at iteration 406
    +#> Achieved score: 50.857 at iteration 419
    +#> Achieved score: 48.857 at iteration 425
    +#> Achieved score: 46.857 at iteration 455
    +#> Achieved score: 42.857 at iteration 505
    +#> Achieved score: 40.857 at iteration 507
    +#> Achieved score: 38.857 at iteration 532
    +#> Achieved score: 36.857 at iteration 618
    +#> Achieved score: 34.857 at iteration 727
    +#> Achieved score: 32.857 at iteration 786
    +#> Achieved score: 30.857 at iteration 960
    +#> process    real 
    +#>   10.2s   10.2s
    +
    +# final score
    +bc$score()
    +#> [1] 30.85714
    +plot(trace_reference, main = str_glue("Final score={bc$score()}"))
    +

    +
    +bc$get_samples(remove_empty_locations = TRUE) %>%
    +  plot_batch()
    +

    +
    +
    +

    Manually work with data.table +

    +

    Instead of relying on BatchContainer, here we have a +manual optimization process using data.table.

    +
    +bc$move_samples(location_assignment = starting_assignment)
    +
    +fast_osat_optimize <- function(bc, batch_vars, feature_vars, iterations) {
    +  ldf <- data.table::data.table(bc$get_locations())[, c("plates")][, ".sample_id" := bc$assignment]
    +  fcols <- c(".sample_id", feature_vars)
    +  smp <- data.table::data.table(bc$samples)[, ..fcols]
    +  df <- smp[ldf, on = ".sample_id"]
    +
    +  v <- osat_score(df, batch_vars, feature_vars)
    +  edf <- v$expected_dt
    +  current_score <- v$score
    +  scores <- numeric(length = iterations)
    +  n_avail <- nrow(df)
    +
    +  for (i in 1:iterations) {
    +    repeat {
    +      pos <- sample(n_avail, 2)
    +
    +      # does not make sense to shuffle NAs
    +      if (any(!is.na(df[pos, feature_vars[1]]))) {
    +        break
    +      }
    +    }
    +
    +    val <- df[c(pos[2], pos[1]), fcols, with = FALSE]
    +    df[c(pos[1], pos[2]), (fcols) := val]
    +
    +    new_score <- osat_score(df, batch_vars, feature_vars, edf)$score
    +    if (new_score <= current_score) {
    +      current_score <- new_score
    +    } else {
    +      df[c(pos[2], pos[1]), (fcols) := val]
    +    }
    +
    +    scores[i] <- current_score
    +  }
    +
    +  bc$assignment <- df$.sample_id
    +
    +  scores
    +}
    +
    +bench::system_time({
    +  set.seed(123)
    +  trace <- fast_osat_optimize(bc, "plates", c("SampleType", "Race", "AgeGrp"), iterations = params$iterations)
    +})
    +#> Warning in osat_score(df, batch_vars, feature_vars): NAs in features / batch
    +#> columns; they will be excluded from scoring
    +#> Warning in (function (assignment) : this field might become read-only in the
    +#> future, please use $move_samples() instead
    +#> process    real 
    +#>   7.41s   7.41s
    +
    +
    +
    +

    Shuffle optimization with burn-in +

    +
    +bc$move_samples(location_assignment = starting_assignment)
    +
    +bc$scoring_f <- osat_score_generator("plates", c("SampleType", "Race", "AgeGrp"))
    +
    +burn_in_it <- floor(params$iterations * 0.1)
    +burn_in_it
    +#> [1] 100
    +
    +bench::system_time({
    +  set.seed(123)
    +  trace_burn_in <- optimize_design(bc,
    +    n_shuffle = c(
    +      rep(20, burn_in_it),
    +      rep(
    +        2,
    +        params$iterations - burn_in_it
    +      )
    +    ),
    +    max_iter = params$iterations
    +  )
    +})
    +#> Warning in osat_score(bc, batch_vars = batch_vars, feature_vars = feature_vars,
    +#> : NAs in features / batch columns; they will be excluded from scoring
    +#> Checking variances of 1-dim. score vector.
    +#> ... (5018.697) - OK
    +#> Initial score: 360.857
    +#> Achieved score: 322.857 at iteration 1
    +#> Achieved score: 290.857 at iteration 5
    +#> Achieved score: 278.857 at iteration 7
    +#> Achieved score: 254.857 at iteration 8
    +#> Achieved score: 238.857 at iteration 15
    +#> Achieved score: 224.857 at iteration 28
    +#> Achieved score: 216.857 at iteration 32
    +#> Achieved score: 198.857 at iteration 34
    +#> Achieved score: 196.857 at iteration 50
    +#> Achieved score: 184.857 at iteration 54
    +#> Achieved score: 172.857 at iteration 59
    +#> Achieved score: 162.857 at iteration 75
    +#> Achieved score: 158.857 at iteration 80
    +#> Achieved score: 156.857 at iteration 101
    +#> Achieved score: 152.857 at iteration 102
    +#> Achieved score: 150.857 at iteration 103
    +#> Achieved score: 144.857 at iteration 104
    +#> Achieved score: 142.857 at iteration 112
    +#> Achieved score: 140.857 at iteration 114
    +#> Achieved score: 136.857 at iteration 115
    +#> Achieved score: 130.857 at iteration 118
    +#> Achieved score: 126.857 at iteration 136
    +#> Achieved score: 124.857 at iteration 139
    +#> Achieved score: 122.857 at iteration 142
    +#> Achieved score: 116.857 at iteration 145
    +#> Achieved score: 114.857 at iteration 146
    +#> Achieved score: 112.857 at iteration 147
    +#> Achieved score: 106.857 at iteration 150
    +#> Achieved score: 102.857 at iteration 153
    +#> Achieved score: 98.857 at iteration 161
    +#> Achieved score: 96.857 at iteration 165
    +#> Achieved score: 94.857 at iteration 167
    +#> Achieved score: 90.857 at iteration 191
    +#> Achieved score: 84.857 at iteration 194
    +#> Achieved score: 82.857 at iteration 198
    +#> Achieved score: 78.857 at iteration 202
    +#> Achieved score: 76.857 at iteration 211
    +#> Achieved score: 74.857 at iteration 232
    +#> Achieved score: 72.857 at iteration 238
    +#> Achieved score: 70.857 at iteration 268
    +#> Achieved score: 68.857 at iteration 295
    +#> Achieved score: 66.857 at iteration 297
    +#> Achieved score: 64.857 at iteration 316
    +#> Achieved score: 62.857 at iteration 324
    +#> Achieved score: 60.857 at iteration 402
    +#> Achieved score: 58.857 at iteration 405
    +#> Achieved score: 54.857 at iteration 409
    +#> Achieved score: 52.857 at iteration 436
    +#> Achieved score: 48.857 at iteration 440
    +#> Achieved score: 46.857 at iteration 499
    +#> Achieved score: 44.857 at iteration 521
    +#> Achieved score: 42.857 at iteration 562
    +#> Achieved score: 40.857 at iteration 621
    +#> Achieved score: 38.857 at iteration 788
    +#> Achieved score: 36.857 at iteration 793
    +#> Achieved score: 34.857 at iteration 807
    +#> Achieved score: 32.857 at iteration 827
    +#> process    real 
    +#>   10.2s   10.2s
    +
    +tibble(
    +  i = seq_len(trace_burn_in$n_steps),
    +  normal = trace_reference$scores,
    +  burnin = trace_burn_in$scores
    +) %>%
    +  pivot_longer(-i, names_to = "method", values_to = "score") %>%
    +  ggplot(aes(i, score, col = method)) +
    +  geom_line()
    +

    +
    +
    +

    Score demonstration +

    +
    +bc$score()
    +#> [1] 32.85714
    +bc$scoring_f <- function(...) rnorm(1)
    +bc$score()
    +#> [1] -1.349697
    +
    +assign_random(bc)
    +
    +bc$get_samples()
    +#> # A tibble: 672 × 10
    +#>    plates chips  rows columns    ID SampleType Race     AgeGrp   dummy…¹ dummy…²
    +#>     <int> <int> <int>   <int> <dbl> <fct>      <fct>    <fct>      <dbl> <chr>  
    +#>  1      1     1     1       1   444 Control    European (50,60]  -1.49   Contro…
    +#>  2      1     1     1       2   486 Control    European (40,50]  -0.344  Contro…
    +#>  3      1     1     2       1   318 Control    European (0,30]   -0.337  Contro…
    +#>  4      1     1     2       2   107 Case       Hispanic (40,50]   0.520  Case H…
    +#>  5      1     1     3       1   432 Control    European (30,40]   0.0443 Contro…
    +#>  6      1     1     3       2   366 Control    European (0,30]   -1.18   Contro…
    +#>  7      1     1     4       1   172 Case       European (30,40]   0.329  Case E…
    +#>  8      1     1     4       2   248 Case       European (60,100] -0.861  Case E…
    +#>  9      1     1     5       1   443 Control    European (60,100] -0.0980 Contro…
    +#> 10      1     1     5       2    NA NA         NA       NA       NA      NA     
    +#> # … with 662 more rows, and abbreviated variable names ¹​dummy_var1, ²​dummy_var2
    +bc$get_samples(remove_empty_locations = TRUE)
    +#> # A tibble: 576 × 10
    +#>    plates chips  rows columns    ID SampleType Race     AgeGrp   dummy…¹ dummy…²
    +#>     <int> <int> <int>   <int> <dbl> <fct>      <fct>    <fct>      <dbl> <chr>  
    +#>  1      1     1     1       1   444 Control    European (50,60]  -1.49   Contro…
    +#>  2      1     1     1       2   486 Control    European (40,50]  -0.344  Contro…
    +#>  3      1     1     2       1   318 Control    European (0,30]   -0.337  Contro…
    +#>  4      1     1     2       2   107 Case       Hispanic (40,50]   0.520  Case H…
    +#>  5      1     1     3       1   432 Control    European (30,40]   0.0443 Contro…
    +#>  6      1     1     3       2   366 Control    European (0,30]   -1.18   Contro…
    +#>  7      1     1     4       1   172 Case       European (30,40]   0.329  Case E…
    +#>  8      1     1     4       2   248 Case       European (60,100] -0.861  Case E…
    +#>  9      1     1     5       1   443 Control    European (60,100] -0.0980 Contro…
    +#> 10      1     1     6       1   272 Case       European (30,40]   1.28   Case E…
    +#> # … with 566 more rows, and abbreviated variable names ¹​dummy_var1, ²​dummy_var2
    +
    +bc$score()
    +#> [1] -1.645012
    +
    +bc$scoring_f <- list(
    +  fc0 = function(samples) rnorm(1) + 2 * rexp(1),
    +  fc1 = function(samples) rnorm(1, 100),
    +  fc2 = function(samples) -7
    +)
    +
    +bc$score()
    +#>       fc0       fc1       fc2 
    +#>  1.843001 99.649906 -7.000000
    +
    +
    + + + +
    + + + +
    + +
    +

    +

    Site built with pkgdown 2.0.7.

    +
    + +
    +
    + + + + + + + + diff --git a/dev/articles/osat_files/figure-html/unnamed-chunk-11-1.png b/dev/articles/osat_files/figure-html/unnamed-chunk-11-1.png new file mode 100644 index 00000000..7e681f54 Binary files /dev/null and b/dev/articles/osat_files/figure-html/unnamed-chunk-11-1.png differ diff --git a/dev/articles/osat_files/figure-html/unnamed-chunk-13-1.png b/dev/articles/osat_files/figure-html/unnamed-chunk-13-1.png new file mode 100644 index 00000000..265dfcb9 Binary files /dev/null and b/dev/articles/osat_files/figure-html/unnamed-chunk-13-1.png differ diff --git a/dev/articles/osat_files/figure-html/unnamed-chunk-13-2.png b/dev/articles/osat_files/figure-html/unnamed-chunk-13-2.png new file mode 100644 index 00000000..387fc243 Binary files /dev/null and b/dev/articles/osat_files/figure-html/unnamed-chunk-13-2.png differ diff --git a/dev/articles/osat_files/figure-html/unnamed-chunk-16-1.png b/dev/articles/osat_files/figure-html/unnamed-chunk-16-1.png new file mode 100644 index 00000000..ad3992cc Binary files /dev/null and b/dev/articles/osat_files/figure-html/unnamed-chunk-16-1.png differ diff --git a/dev/articles/osat_files/figure-html/unnamed-chunk-3-1.png b/dev/articles/osat_files/figure-html/unnamed-chunk-3-1.png new file mode 100644 index 00000000..3f2e7914 Binary files /dev/null and b/dev/articles/osat_files/figure-html/unnamed-chunk-3-1.png differ diff --git a/dev/articles/osat_files/figure-html/unnamed-chunk-5-1.png b/dev/articles/osat_files/figure-html/unnamed-chunk-5-1.png new file mode 100644 index 00000000..e17e1228 Binary files /dev/null and b/dev/articles/osat_files/figure-html/unnamed-chunk-5-1.png differ diff --git a/dev/articles/osat_files/figure-html/unnamed-chunk-7-1.png b/dev/articles/osat_files/figure-html/unnamed-chunk-7-1.png new file mode 100644 index 00000000..7e681f54 Binary files /dev/null and b/dev/articles/osat_files/figure-html/unnamed-chunk-7-1.png differ diff --git a/dev/articles/osat_files/figure-html/unnamed-chunk-8-1.png b/dev/articles/osat_files/figure-html/unnamed-chunk-8-1.png new file mode 100644 index 00000000..f84db75d Binary files /dev/null and b/dev/articles/osat_files/figure-html/unnamed-chunk-8-1.png differ diff --git a/dev/articles/plate_layouts.html b/dev/articles/plate_layouts.html new file mode 100644 index 00000000..0a502c5d --- /dev/null +++ b/dev/articles/plate_layouts.html @@ -0,0 +1,2541 @@ + + + + + + + +Plate layouts • designit + + + + + + + + + + + + + + + + + + + + +
    +
    + + + + +
    +
    + + + + +
    #> ── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
    +#>  dplyr     1.1.0      readr     2.1.4
    +#>  forcats   1.0.0      stringr   1.5.0
    +#>  ggplot2   3.4.1      tibble    3.2.0
    +#>  lubridate 1.9.2      tidyr     1.3.0
    +#>  purrr     1.0.1     
    +#> ── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
    +#>  dplyr::filter() masks stats::filter()
    +#>  dplyr::lag()    masks stats::lag()
    +#>  Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors
    +
    +

    Introduction +

    +

    Distributing samples to wells plates for experimental procedures is a +very common task. In the following we use a data set of longitudinal +subject samples that are to be spread across several n-well plates, +balanced for treatment group and time point +longitudinal_subject_samples.

    +
    +data("longitudinal_subject_samples")
    +head(longitudinal_subject_samples)
    +#> # A tibble: 6 × 9
    +#>   SampleID SampleType SubjectID Group  Week Sex     Age   BMI SamplesPerSubject
    +#>   <chr>    <fct>      <chr>     <chr> <dbl> <chr> <dbl> <dbl>             <dbl>
    +#> 1 P01W1    Sample     P01       1         1 F        71  28.1                 7
    +#> 2 P01W4    Sample     P01       1         4 F        71  28.1                 7
    +#> 3 P01W6    Sample     P01       1         6 F        71  28.1                 7
    +#> 4 P01W10   Sample     P01       1        10 F        71  28.1                 7
    +#> 5 P01W14   Sample     P01       1        14 F        71  28.1                 7
    +#> 6 P01W18   Sample     P01       1        18 F        71  28.1                 7
    +

    In the fist example we’ll use a subset of samples to demonstrate the +process.

    +
      +
    • We have 33 subject with each 2 samples.
    • +
    • Factors we want to balance are treatment group and Sex.
    • +
    +
    +dat <- longitudinal_subject_samples %>%
    +  filter(Group %in% 1:5, Week %in% c(1, 4)) %>%
    +  select(SampleID, SubjectID, Group, Sex, Week)
    +
    +# for simplicity: remove two subjects that don't have both visits
    +dat <- dat %>%
    +  group_by(SubjectID) %>%
    +  filter(n() == 2) %>%
    +  ungroup()
    +
    +
    +

    Layout optimization in one go +

    +

    For placing samples on plates and optimizing across plate +distribution of factors as well as the within plate spacial +distribution, the multi_plate_wrapper() function can be +used. It focuses first on assigning samples to plates and then optimizes +the layout within plates.

    +

    To place all 66 samples on 24-well plates we create a +batch_container with 3 plates

    +

    We do the initial assignment of sample to plates and plot it

    +
    +set.seed(42)
    +
    +bc <- BatchContainer$new(
    +  dimensions = list("plate" = 3, "row" = 4, "col" = 6),
    +)
    +
    +assign_in_order(bc, dat)
    +
    +head(bc$get_samples()) %>% gt::gt()
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    platerowcolSampleIDSubjectIDGroupSexWeek
    111P01W1P011F1
    112P01W4P011F4
    113P02W1P021M1
    114P02W4P021M4
    115P03W1P031M1
    116P03W4P031M4
    +
    +

    We can view the initial assignment with plot_plate

    +
    +cowplot::plot_grid(
    +  plotlist = list(
    +    plot_plate(bc,
    +      plate = plate, row = row, column = col, .color = Group,
    +      title = "Initial layout by Group"
    +    ),
    +    plot_plate(bc,
    +      plate = plate, row = row, column = col, .color = Sex,
    +      title = "Initial layout by Sex"
    +    )
    +  ),
    +  nrow = 2
    +)
    +

    +

    For optimization optimize_multi_plate_design() +iteratively calls optimize_design() for different steps of +the experiment. For across plate optimization osat scoring is used. For +within plate optimization spatial scoreing is used. The order of the +factors indicate their relative importance. In this case we prioritize +Group over Sex.

    +
    +traces <- optimize_multi_plate_design(bc,
    +  across_plates_variables = c("Group", "Sex"),
    +  within_plate_variables = c("Group"),
    +  plate = "plate",
    +  row = "row",
    +  column = "col",
    +  n_shuffle = 2,
    +  max_iter = 700,
    +  quiet = TRUE
    +)
    +#> Warning in osat_score(bc, batch_vars = batch_vars, feature_vars = feature_vars,
    +#> : NAs in features / batch columns; they will be excluded from scoring
    +
    +#> Warning in osat_score(bc, batch_vars = batch_vars, feature_vars = feature_vars,
    +#> : NAs in features / batch columns; they will be excluded from scoring
    +
    +cowplot::plot_grid(
    +  plotlist = list(
    +    plot_plate(bc,
    +      plate = plate, row = row, column = col, .color = Group,
    +      title = "Initial layout by Group"
    +    ),
    +    plot_plate(bc,
    +      plate = plate, row = row, column = col, .color = Sex,
    +      title = "Initial layout by Sex"
    +    )
    +  ),
    +  nrow = 2
    +)
    +

    +

    We can look at the trace objects for each internal +optimize_design run, returned from the wrapper +function.

    +
    +purrr::imap(traces, ~ .x$plot(include_aggregated = TRUE) + labs(title = .y))
    +#> $osat_across_plates
    +

    +
    #> 
    +#> $within_plate_1
    +

    +
    #> 
    +#> $within_plate_2
    +

    +
    #> 
    +#> $within_plate_3
    +

    +
    +

    Plate scoring +

    +

    Note that internally the wrapper function sets up plate specific +scoring functions that could manually be set up in the following +way.

    +
    +bc$scoring_f <- c(
    +  Group = mk_plate_scoring_functions(bc,
    +    plate = "plate", row = "row", column = "col",
    +    group = "Group", penalize_lines = "hard"
    +  ),
    +  Sex = mk_plate_scoring_functions(bc,
    +    plate = "plate", row = "row", column = "col",
    +    group = "Sex", penalize_lines = "hard"
    +  )
    +)
    +

    For more information on customized plate scoring see vignette +Plate scoring examples.

    +
    +
    +
    +

    Two step approach +

    +

    Sometimes layout requests can be more complicated. Assume we want to +keep the two samples of a subject on the same 24 well plate.

    +

    Now we need to customize across plate optimization more so we need to +split the process into two steps.

    +
    +

    Step 1: Subjects to plates +

    +

    There are 31 subjects with each 2 time points, i.e. we need ~ 11 +subjects per plate and want to balance by treatment, sex.

    +

    First we create a batch container with 3 batches that each fit 11 +subjects i.e. have 11 virtual locations.

    +

    For layout scoring we use OSAT score on Group and +Sex variables.

    +

    Then we assign the samples randomly to the batches and look at their +initial distribution.

    +
    +set.seed(17) # gives `bad` random assignment
    +
    +bc <- BatchContainer$new(
    +  dimensions = list("batch" = 3, "location" = 11)
    +)
    +
    +bc$scoring_f <- list(
    +  group = osat_score_generator(batch_vars = "batch", feature_vars = "Group"),
    +  sex = osat_score_generator(batch_vars = "batch", feature_vars = "Sex")
    +)
    +
    +assign_random(
    +  bc,
    +  dat %>% select(SubjectID, Group, Sex) %>% distinct()
    +)
    +
    +bc$get_samples() %>%
    +  head() %>%
    +  gt::gt()
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    batchlocationSubjectIDGroupSex
    11NANANA
    12P325M
    13P103F
    14P263M
    15P175M
    16P072F
    +
    +
    +cowplot::plot_grid(
    +  plotlist = list(
    +    bc$get_samples() %>% ggplot(aes(x = batch, fill = Group)) +
    +      geom_bar() +
    +      labs(y = "subject count"),
    +    bc$get_samples() %>% ggplot(aes(x = batch, fill = Sex)) +
    +      geom_bar() +
    +      labs(y = "subject count")
    +  ),
    +  nrow = 1
    +)
    +

    +

    Optimizing the layout with optimize_design()

    +
    +trace <- optimize_design(
    +  bc,
    +  n_shuffle = 1,
    +  acceptance_func = ~ accept_leftmost_improvement(..., tolerance = 0.01),
    +  max_iter = 150,
    +  quiet = TRUE
    +)
    +#> Warning in osat_score(bc, batch_vars = batch_vars, feature_vars = feature_vars,
    +#> : NAs in features / batch columns; they will be excluded from scoring
    +
    +#> Warning in osat_score(bc, batch_vars = batch_vars, feature_vars = feature_vars,
    +#> : NAs in features / batch columns; they will be excluded from scoring
    +

    After optimization the group and sex of samples are equally +distributed across all plates. The lower right panel shows the +optimization trace of the scores.

    +
    +cowplot::plot_grid(
    +  plotlist = list(
    +    bc$get_samples() %>% ggplot(aes(x = batch, fill = Group)) +
    +      geom_bar() +
    +      labs(y = "subject count"),
    +    bc$get_samples() %>% ggplot(aes(x = batch, fill = Sex)) +
    +      geom_bar() +
    +      labs(y = "subject count"),
    +    trace$plot(include_aggregated = TRUE)
    +  ),
    +  ncol = 3
    +)
    +

    +
    +
    +

    Step 2: Within plate sample distribution +

    +

    Using the result from step 1 we now optimize the layout within +plates. For this we still need to add empty wells to each batch and +assign the pre-allocated sample sheet in the right way to the new batch +container.

    +
    +dat <- dat %>%
    +  left_join(bc$get_samples() %>%
    +    select(SubjectID, batch))
    +#> Joining with `by = join_by(SubjectID)`
    +
    +# add empty wells depending on how full the batch plate is
    +dat <- dat %>%
    +  bind_rows(data.frame(
    +    SubjectID = "empty",
    +    SampleID = paste("empty", 1:(3 * 24 - nrow(dat))),
    +    batch = rep(1:3, 24 - (dat %>% count(batch) %>% .$n))
    +  ))
    +
    +bc <- BatchContainer$new(
    +  dimensions = list("plate" = 3, "row" = 4, "col" = 6)
    +)
    +
    +# initial assignment such that the original plate assigned stays the same
    +assign_in_order(
    +  bc,
    +  dat %>% arrange(batch)
    +)
    +
    +
    +cowplot::plot_grid(
    +  plotlist = list(
    +    plot_plate(bc,
    +      plate = plate, row = row, column = col, .color = Group,
    +      title = "Initial layout by Group"
    +    ),
    +    plot_plate(bc,
    +      plate = plate, row = row, column = col, .color = Sex,
    +      title = "Initial layout by Sex"
    +    )
    +  ),
    +  nrow = 2
    +)
    +

    +

    As we have already assigned samples to plates, the across plate +optimization can be skipped in the wrapper. For distributing samples +within each plate, we use variables Group and Sex again. The order of +the factors indicate their relative importance.

    +
    +traces <- optimize_multi_plate_design(bc,
    +  within_plate_variables = c("Group", "Sex"),
    +  plate = "plate",
    +  row = "row",
    +  column = "col",
    +  n_shuffle = 2,
    +  max_iter = 1000,
    +  quiet = TRUE
    +)
    +
    +cowplot::plot_grid(
    +  plotlist = list(
    +    plot_plate(bc,
    +      plate = plate, row = row, column = col, .color = Group,
    +      title = "Final layout by Group"
    +    ),
    +    plot_plate(bc,
    +      plate = plate, row = row, column = col, .color = Sex,
    +      title = "Final layout by Sex"
    +    )
    +  ),
    +  nrow = 2
    +)
    +

    +
    +purrr::imap(traces, ~ .x$plot(include_aggregated = TRUE) + labs(title = .y))
    +#> $within_plate_1
    +

    +
    #> 
    +#> $within_plate_2
    +

    +
    #> 
    +#> $within_plate_3
    +

    +
    +
    +
    +

    Full dataset +

    +

    In the following we use the full data set of longitudinal subject +samples that are to be spread across several n-well plates, balanced for +treatment group and time point +longitudinal_subject_samples.

    +

    In addition to the normal samples there are also controls to be +placed on each plate. These are added after the sample batching +step.

    +

    For accommodation of samples to plates there are the following +control samples available

    +
    +longitudinal_subject_samples %>%
    +  filter(SampleType != "Sample") %>%
    +  count(SampleType, Group) %>%
    +  gt::gt()
    +
    + + + + + + + + + + + + + + + + + + + +
    SampleTypeGroupn
    ControlPool6
    StandardSpikeIn15
    +
    +
    +

    Step 1: Batching +

    +

    Again we want to keep all samples of a subject on the same plate. A +first step could be grouping subjects into 3 batches blocking by +treatment, sex and age. There are 34 subjects with each 3 - 8 time +points, i.e. we need ~ 11 subjects per plate.

    +

    We first create a ‘subjects’ dataset.

    +
    +# get subject data for batching
    +subjects <- longitudinal_subject_samples %>%
    +  filter(SampleType == "Sample") %>%
    +  count(SubjectID, Group, Sex, Age, name = "nTimePoints") %>%
    +  distinct()
    +
    +subjects %>%
    +  select(-nTimePoints) %>%
    +  slice(1:5) %>%
    +  gt::gt() %>%
    +  gt::tab_options()
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    SubjectIDGroupSexAge
    P011F71
    P021M74
    P031M76
    P041F83
    P052M79
    +
    +

    Then we create a batch container for the samples with 3 batches +called plate that each fit 11 subjects i.e. have 11 virtual +locations.

    +

    For layout scoring we use OSAT score on Group and +Sex variables. We initially assign the samples randomly to +the batches and check the layout.

    +
    +set.seed(42)
    +
    +bc <- BatchContainer$new(
    +  dimensions = list("plate" = 3, "locations" = 11)
    +)
    +
    +bc$scoring_f <- list(
    +  group = osat_score_generator(batch_vars = "plate", feature_vars = c("Group")),
    +  sex = osat_score_generator(batch_vars = "plate", feature_vars = "Sex")
    +)
    +
    +assign_random(bc, subjects)
    +
    +cowplot::plot_grid(
    +  plotlist = list(
    +    bc$get_samples() %>% ggplot(aes(x = plate, fill = Group)) +
    +      geom_bar() +
    +      labs(y = "subject count"),
    +    bc$get_samples() %>% ggplot(aes(x = plate, fill = Sex)) +
    +      geom_bar() +
    +      labs(y = "subject count"),
    +    bc$get_samples() %>% ggplot(aes(x = factor(plate), y = Age)) +
    +      geom_boxplot() +
    +      geom_point()
    +  ),
    +  nrow = 1
    +)
    +

    +

    Optimizing the layout with optimize_design()

    +
    +trace <- optimize_design(
    +  bc,
    +  n_shuffle = 1,
    +  acceptance_func = ~ accept_leftmost_improvement(..., tolerance = 0.1),
    +  max_iter = 150,
    +  quiet = TRUE
    +)
    +

    After optimization the group and sex of samples are equally +distributed across all plates. The lower right panel shows the +optimization trace of the scores.

    +
    +cowplot::plot_grid(
    +  plotlist = list(
    +    bc$get_samples() %>% ggplot(aes(x = plate, fill = Group)) +
    +      geom_bar() +
    +      labs(y = "subject count"),
    +    bc$get_samples() %>% ggplot(aes(x = plate, fill = Sex)) +
    +      geom_bar() +
    +      labs(y = "subject count"),
    +    bc$get_samples() %>% ggplot(aes(x = factor(plate), y = Age)) +
    +      geom_boxplot() +
    +      geom_point(),
    +    trace$plot(include_aggregated = TRUE)
    +  ),
    +  nrow = 2
    +)
    +

    +
    +
    +

    Step 2: Within plate sample distribution +

    +

    We start here by creating the batch container for all samples and +making an initial assignment. Note there will be empty positions on the +plates which we have to add before we assign the samples to the batch +container in order.

    +
    +samples_with_plate <- longitudinal_subject_samples %>%
    +  left_join(bc$get_samples() %>%
    +    select(-locations)) %>%
    +  mutate(plate = ifelse(SampleType == "Sample", plate, str_extract(SampleID, ".$")))
    +#> Joining with `by = join_by(SubjectID, Group, Sex, Age)`
    +
    +# not all plates have same amount of samples
    +samples_with_plate %>% count(plate)
    +#> # A tibble: 3 × 2
    +#>   plate     n
    +#>   <chr> <int>
    +#> 1 1        77
    +#> 2 2        80
    +#> 3 3        73
    +
    +# add empty wells depending on how full the batch plate is
    +# column 11 and 12 are left empty: 96 - 16 = 80 samples per plate
    +samples_with_plate <- samples_with_plate %>%
    +  bind_rows(data.frame(
    +    SubjectID = "empty",
    +    SampleID = paste("empty", 1:(3 * 80 - nrow(samples_with_plate))),
    +    plate = rep(1:3, 80 - (samples_with_plate %>% count(plate) %>% .$n)) %>%
    +      as.character()
    +  ))
    +
    +
    +# new batch container for step 2
    +bc <- BatchContainer$new(
    +  dimensions = list(plate = 3, row = 8, col = 12),
    +  exclude = crossing(plate = 1:3, row = 1:8, col = 11:12)
    +)
    +
    +# assign samples in order of plate
    +assign_in_order(
    +  bc,
    +  samples_with_plate %>%
    +    arrange(plate) %>%
    +    rename(orig_plate = plate)
    +)
    +
    +# check if plate assignment is still correct
    +bc$get_samples() %>%
    +  summarize(all(plate == orig_plate)) %>%
    +  unlist()
    +#> all(plate == orig_plate) 
    +#>                     TRUE
    +
    +cowplot::plot_grid(
    +  plotlist = list(
    +    plot_plate(bc,
    +      plate = plate, row = row, column = col, .color = Group,
    +      title = "Initial layout by Group"
    +    ),
    +    plot_plate(bc,
    +      plate = plate, row = row, column = col, .color = SubjectID,
    +      title = "Initial layout by SubjectID"
    +    ) +
    +      theme(legend.key.size = unit(.25, "cm")),
    +    plot_plate(bc,
    +      plate = plate, row = row, column = col, .color = Sex,
    +      title = "Initial layout by Sex"
    +    )
    +  ),
    +  nrow = 3
    +)
    +

    +

    As we have already assigned samples to plates, the across plate +optimization can be skipped in the wrapper. For distributing samples +within each plate, we use variables Group and Sex again. The order of +the factors indicate their relative importance.

    +
    +traces <- optimize_multi_plate_design(bc,
    +  within_plate_variables = c("Group", "SubjectID", "Sex"),
    +  plate = "plate",
    +  row = "row",
    +  column = "col",
    +  n_shuffle = 2,
    +  max_iter = 1000,
    +  quiet = TRUE
    +)
    +
    +cowplot::plot_grid(
    +  plotlist = list(
    +    plot_plate(bc,
    +      plate = plate, row = row, column = col, .color = Group,
    +      title = "Final layout by Group"
    +    ),
    +    plot_plate(bc,
    +      plate = plate, row = row, column = col, .color =
    +        SubjectID, title = "Final layout by SubjectID"
    +    ) +
    +      theme(legend.key.size = unit(.25, "cm")),
    +    plot_plate(bc,
    +      plate = plate, row = row, column = col, .color = Sex,
    +      title = "Final layout by Sex"
    +    )
    +  ),
    +  nrow = 3
    +)
    +

    +
    +purrr::imap(traces, ~ .x$plot(include_aggregated = TRUE) + labs(title = .y))
    +#> $within_plate_1
    +

    +
    #> 
    +#> $within_plate_2
    +

    +
    #> 
    +#> $within_plate_3
    +

    +
    +
    +
    + + + +
    + + + +
    + +
    +

    +

    Site built with pkgdown 2.0.7.

    +
    + +
    +
    + + + + + + + + diff --git a/dev/articles/plate_layouts_files/figure-html/unnamed-chunk-11-1.png b/dev/articles/plate_layouts_files/figure-html/unnamed-chunk-11-1.png new file mode 100644 index 00000000..5ba017b2 Binary files /dev/null and b/dev/articles/plate_layouts_files/figure-html/unnamed-chunk-11-1.png differ diff --git a/dev/articles/plate_layouts_files/figure-html/unnamed-chunk-13-1.png b/dev/articles/plate_layouts_files/figure-html/unnamed-chunk-13-1.png new file mode 100644 index 00000000..4681e2f6 Binary files /dev/null and b/dev/articles/plate_layouts_files/figure-html/unnamed-chunk-13-1.png differ diff --git a/dev/articles/plate_layouts_files/figure-html/unnamed-chunk-14-1.png b/dev/articles/plate_layouts_files/figure-html/unnamed-chunk-14-1.png new file mode 100644 index 00000000..26d39e1d Binary files /dev/null and b/dev/articles/plate_layouts_files/figure-html/unnamed-chunk-14-1.png differ diff --git a/dev/articles/plate_layouts_files/figure-html/unnamed-chunk-16-1.png b/dev/articles/plate_layouts_files/figure-html/unnamed-chunk-16-1.png new file mode 100644 index 00000000..16c99a08 Binary files /dev/null and b/dev/articles/plate_layouts_files/figure-html/unnamed-chunk-16-1.png differ diff --git a/dev/articles/plate_layouts_files/figure-html/unnamed-chunk-17-1.png b/dev/articles/plate_layouts_files/figure-html/unnamed-chunk-17-1.png new file mode 100644 index 00000000..5f8095bb Binary files /dev/null and b/dev/articles/plate_layouts_files/figure-html/unnamed-chunk-17-1.png differ diff --git a/dev/articles/plate_layouts_files/figure-html/unnamed-chunk-17-2.png b/dev/articles/plate_layouts_files/figure-html/unnamed-chunk-17-2.png new file mode 100644 index 00000000..e5227869 Binary files /dev/null and b/dev/articles/plate_layouts_files/figure-html/unnamed-chunk-17-2.png differ diff --git a/dev/articles/plate_layouts_files/figure-html/unnamed-chunk-17-3.png b/dev/articles/plate_layouts_files/figure-html/unnamed-chunk-17-3.png new file mode 100644 index 00000000..f8646423 Binary files /dev/null and b/dev/articles/plate_layouts_files/figure-html/unnamed-chunk-17-3.png differ diff --git a/dev/articles/plate_layouts_files/figure-html/unnamed-chunk-21-1.png b/dev/articles/plate_layouts_files/figure-html/unnamed-chunk-21-1.png new file mode 100644 index 00000000..5489f341 Binary files /dev/null and b/dev/articles/plate_layouts_files/figure-html/unnamed-chunk-21-1.png differ diff --git a/dev/articles/plate_layouts_files/figure-html/unnamed-chunk-23-1.png b/dev/articles/plate_layouts_files/figure-html/unnamed-chunk-23-1.png new file mode 100644 index 00000000..4327fca8 Binary files /dev/null and b/dev/articles/plate_layouts_files/figure-html/unnamed-chunk-23-1.png differ diff --git a/dev/articles/plate_layouts_files/figure-html/unnamed-chunk-25-1.png b/dev/articles/plate_layouts_files/figure-html/unnamed-chunk-25-1.png new file mode 100644 index 00000000..f8702140 Binary files /dev/null and b/dev/articles/plate_layouts_files/figure-html/unnamed-chunk-25-1.png differ diff --git a/dev/articles/plate_layouts_files/figure-html/unnamed-chunk-27-1.png b/dev/articles/plate_layouts_files/figure-html/unnamed-chunk-27-1.png new file mode 100644 index 00000000..425292bb Binary files /dev/null and b/dev/articles/plate_layouts_files/figure-html/unnamed-chunk-27-1.png differ diff --git a/dev/articles/plate_layouts_files/figure-html/unnamed-chunk-28-1.png b/dev/articles/plate_layouts_files/figure-html/unnamed-chunk-28-1.png new file mode 100644 index 00000000..b8447ca6 Binary files /dev/null and b/dev/articles/plate_layouts_files/figure-html/unnamed-chunk-28-1.png differ diff --git a/dev/articles/plate_layouts_files/figure-html/unnamed-chunk-28-2.png b/dev/articles/plate_layouts_files/figure-html/unnamed-chunk-28-2.png new file mode 100644 index 00000000..f123d33b Binary files /dev/null and b/dev/articles/plate_layouts_files/figure-html/unnamed-chunk-28-2.png differ diff --git a/dev/articles/plate_layouts_files/figure-html/unnamed-chunk-28-3.png b/dev/articles/plate_layouts_files/figure-html/unnamed-chunk-28-3.png new file mode 100644 index 00000000..2b2a18c8 Binary files /dev/null and b/dev/articles/plate_layouts_files/figure-html/unnamed-chunk-28-3.png differ diff --git a/dev/articles/plate_layouts_files/figure-html/unnamed-chunk-5-1.png b/dev/articles/plate_layouts_files/figure-html/unnamed-chunk-5-1.png new file mode 100644 index 00000000..491595bf Binary files /dev/null and b/dev/articles/plate_layouts_files/figure-html/unnamed-chunk-5-1.png differ diff --git a/dev/articles/plate_layouts_files/figure-html/unnamed-chunk-7-1.png b/dev/articles/plate_layouts_files/figure-html/unnamed-chunk-7-1.png new file mode 100644 index 00000000..ef033105 Binary files /dev/null and b/dev/articles/plate_layouts_files/figure-html/unnamed-chunk-7-1.png differ diff --git a/dev/articles/plate_layouts_files/figure-html/unnamed-chunk-8-1.png b/dev/articles/plate_layouts_files/figure-html/unnamed-chunk-8-1.png new file mode 100644 index 00000000..f3b5d514 Binary files /dev/null and b/dev/articles/plate_layouts_files/figure-html/unnamed-chunk-8-1.png differ diff --git a/dev/articles/plate_layouts_files/figure-html/unnamed-chunk-8-2.png b/dev/articles/plate_layouts_files/figure-html/unnamed-chunk-8-2.png new file mode 100644 index 00000000..3d1e25e1 Binary files /dev/null and b/dev/articles/plate_layouts_files/figure-html/unnamed-chunk-8-2.png differ diff --git a/dev/articles/plate_layouts_files/figure-html/unnamed-chunk-8-3.png b/dev/articles/plate_layouts_files/figure-html/unnamed-chunk-8-3.png new file mode 100644 index 00000000..b8cc284d Binary files /dev/null and b/dev/articles/plate_layouts_files/figure-html/unnamed-chunk-8-3.png differ diff --git a/dev/articles/plate_layouts_files/figure-html/unnamed-chunk-8-4.png b/dev/articles/plate_layouts_files/figure-html/unnamed-chunk-8-4.png new file mode 100644 index 00000000..f40bbb7d Binary files /dev/null and b/dev/articles/plate_layouts_files/figure-html/unnamed-chunk-8-4.png differ diff --git a/dev/articles/plate_scoring_examples.html b/dev/articles/plate_scoring_examples.html new file mode 100644 index 00000000..a82fd790 --- /dev/null +++ b/dev/articles/plate_scoring_examples.html @@ -0,0 +1,941 @@ + + + + + + + +Plate scoring examples • designit + + + + + + + + + + + + + + + + + + + + +
    +
    + + + + +
    +
    + + + + +
    library(designit)
    +library(ggplot2)
    +library(dplyr)
    +#> 
    +#> Attaching package: 'dplyr'
    +#> The following objects are masked from 'package:stats':
    +#> 
    +#>     filter, lag
    +#> The following objects are masked from 'package:base':
    +#> 
    +#>     intersect, setdiff, setequal, union
    +library(tidyr)
    +
    +

    +Example 1: An expensive way to construct a 4x4 latin square (one plate) + +

    +

    +(latin square should give the best score) +

    +

    +First using a combination of two OSAT scores (for row and column). +

    +

    +This usually produces a latin square when using the squared L2 norm +(L2s) for aggregation of the 2 scores. +

    +
    # Setting up the batch container
    +example1 <- BatchContainer$new(
    +  dimensions = c(
    +    plate = 1,
    +    row = 4, col = 4
    +  )
    +)
    +
    +# Add samples to container
    +# Need unique Sample ID. Can we drop this constraint?
    +assign_in_order(example1,
    +  samples = tibble::tibble(
    +    Group = rep(c("Grp 1", "Grp 2", "Grp 3", "Grp 4"), each = 4),
    +    ID = 1:16
    +  )
    +)
    +
    +# The following does not work (an gives a constant score of 144!)
    +# example1$scoring_f <- osat_score_generator(batch_vars = c("row","col"), feature_vars = c("Group"))
    +# First analysis of problem indicates that osat_score generates a full row*col vector of 'ideal scores'
    +# which are in fact the same value, implying an identical overall result as each position can be either
    +# allocated by 1 sample or 0 samples, the sum of 1's being the sample count.
    +# --> don't use osat_score if there's a lack of samples as compared to possible positioning
    +
    +bc <- example1$copy()
    +
    +# # Set scoring function
    +bc$scoring_f <- list(
    +  Row.Score = osat_score_generator(batch_vars = c("row"), feature_vars = c("Group")),
    +  Column.Score = osat_score_generator(batch_vars = c("col"), feature_vars = c("Group"))
    +)
    +
    
    +set.seed(41)
    +
    +trace <- optimize_design(bc,
    +  max_iter = 300, # this is set to shorten vignette run-time based on known random seed, normally we don't know.
    +  n_shuffle = 2,
    +  acceptance_func = mk_simanneal_acceptance_func(mk_simanneal_temp_func(T0 = 1000, alpha = 0.5)),
    +  aggregate_scores_func = L2s_norm
    +)
    +#> Checking variances of 2-dim. score vector.
    +#> ... (11.385, 16.687) - OK
    +#> Initial score: c(48, 0)
    +#>    Aggregated: 2304
    +#> Achieved score: c(36, 4) at iteration 1
    +#>    Aggregated: 1312
    +#> Achieved score: c(24, 4) at iteration 2
    +#>    Aggregated: 592
    +#> Achieved score: c(24, 12) at iteration 3
    +#>    Aggregated: 720
    +#> Achieved score: c(24, 8) at iteration 4
    +#>    Aggregated: 640
    +#> Achieved score: c(16, 10) at iteration 5
    +#>    Aggregated: 356
    +#> Achieved score: c(12, 10) at iteration 6
    +#>    Aggregated: 244
    +#> Achieved score: c(10, 10) at iteration 7
    +#>    Aggregated: 200
    +#> Achieved score: c(10, 6) at iteration 9
    +#>    Aggregated: 136
    +#> Achieved score: c(10, 4) at iteration 10
    +#>    Aggregated: 116
    +#> Achieved score: c(8, 10) at iteration 11
    +#>    Aggregated: 164
    +#> Achieved score: c(8, 8) at iteration 12
    +#>    Aggregated: 128
    +#> Achieved score: c(8, 8) at iteration 14
    +#>    Aggregated: 128
    +#> Achieved score: c(4, 10) at iteration 19
    +#>    Aggregated: 116
    +#> Achieved score: c(4, 6) at iteration 20
    +#>    Aggregated: 52
    +#> Achieved score: c(4, 4) at iteration 22
    +#>    Aggregated: 32
    +#> Achieved score: c(4, 4) at iteration 27
    +#>    Aggregated: 32
    +#> Achieved score: c(4, 4) at iteration 36
    +#>    Aggregated: 32
    +#> Achieved score: c(4, 4) at iteration 38
    +#>    Aggregated: 32
    +#> Achieved score: c(0, 4) at iteration 39
    +#>    Aggregated: 16
    +#> Achieved score: c(0, 4) at iteration 50
    +#>    Aggregated: 16
    +#> Achieved score: c(0, 4) at iteration 54
    +#>    Aggregated: 16
    +#> Achieved score: c(0, 4) at iteration 82
    +#>    Aggregated: 16
    +#> Achieved score: c(0, 4) at iteration 87
    +#>    Aggregated: 16
    +#> Achieved score: c(0, 4) at iteration 119
    +#>    Aggregated: 16
    +#> Achieved score: c(0, 4) at iteration 125
    +#>    Aggregated: 16
    +#> Achieved score: c(0, 4) at iteration 200
    +#>    Aggregated: 16
    +#> Achieved score: c(4, 0) at iteration 215
    +#>    Aggregated: 16
    +#> Achieved score: c(0, 0) at iteration 284
    +#>    Aggregated: 0
    +
    trace
    +#> Optimization trace (301 score values, elapsed 21.10947 secs).
    +#>   Starting score: 48,0
    +#>   Final score   : 0,0
    +
    +plot_plate(bc,
    +  plate = plate, row = row, column = col, .color = Group,
    +  title = "Ex1: Using OSAT scores for plate design\n(not the recommended way!)"
    +)
    +

    +

    +

    +Now using a dedicated scoring for the group distances on a plate. +

    +

    +This should reliably lead to a nice symmetry-bearing latin square design +with only a one-dimensional score to look at. +

    +
    bc <- example1$copy()
    +
    +bc$scoring_f <- mk_plate_scoring_functions(bc, row = "row", column = "col", group = "Group")
    +
    set.seed(42)
    +trace <- optimize_design(bc,
    +  max_iter = 1000, # this is set to shorten vignette run-time based on random seed, normally we don't know.
    +  n_shuffle = 2,
    +  acceptance_func = mk_simanneal_acceptance_func(mk_simanneal_temp_func(T0 = 1000, alpha = 0.5)),
    +  quiet = TRUE
    +)
    +
    trace$elapsed
    +#> Time difference of 11.43023 secs
    +
    +plot_plate(bc,
    +  plate = plate, row = row, column = col, .color = Group,
    +  title = "Ex1: Using a dedicated plate scoring function:\nThis should show a latin square!"
    +)
    +

    +

    +
    +
    library(designit)
    +library(ggplot2)
    +library(dplyr)
    +library(tidyr)
    +
    +

    +Example 2: Scoring two plates at once + +

    +

    +(latin square for each plate should give the best score) +

    +

    +We set up in one go 2 plate scoring functions, each one acting locally +on a specific plate, plus one osat score to guarantee uniform +distribution of groups across plates. +

    +

    +The initial sample allocation (by assign_in_order) leads to a poor +starting point since each plate has only 2 of the 4 groups represented. +

    +

    +This is not a problem as long as we make sure that initial permutations +are likely to remedy the situation. That’s why we ensure 10 pairwise +sample swaps for the first iterations. +

    +
    # Setting up the batch container
    +example2 <- BatchContainer$new(
    +  dimensions = c(
    +    plate = 2,
    +    row = 4, col = 4
    +  )
    +)
    +
    +# Add samples to container
    +assign_in_order(example2, samples = tibble::tibble(
    +  Group = c(rep(c("Grp 1", "Grp 2", "Grp 3", "Grp 4"), each = 8)),
    +  ID = 1:32
    +))
    +
    +bc <- example2$copy()
    +
    +bc$scoring_f <- c(mk_plate_scoring_functions(bc, plate = "plate", row = "row", column = "col", group = "Group"),
    +  osat_plate = osat_score_generator(batch_vars = c("plate"), feature_vars = c("Group"))
    +)
    +
    +plot_plate(bc,
    +  plate = plate, row = row, column = col, .color = Group,
    +  title = "Ex2: Initial sample arrangement"
    +)
    +

    +

    +
    
    +bc$score()
    +#>    Plate 1    Plate 2 osat_plate 
    +#>   23.89265   23.89265  128.00000
    +
    set.seed(41)
    +trace <- optimize_design(bc,
    +  n_shuffle = c(rep(10, 10), rep(3, 90), rep(2, 100), rep(1, 1400)),
    +  acceptance_func = mk_simanneal_acceptance_func(mk_simanneal_temp_func(T0 = 10000, alpha = 0.5)),
    +  aggregate_scores_func = worst_score,
    +  quiet = TRUE
    +)
    +
    trace$elapsed
    +#> Time difference of 25.73155 secs
    +
    +bc$score()
    +#>    Plate 1    Plate 2 osat_plate 
    +#>   6.127258   6.094080   0.000000
    +
    +plot_plate(bc,
    +  plate = plate, row = row, column = col, .color = Group,
    +  title = "Ex2: Design created by swapping samples 'globally' across the plates"
    +)
    +

    +

    +

    +While this ‘global’ optimization is possible, it does probably not +converge to an (almost) ideal solution in an acceptable time if there +are more samples involved. This is due to a lot of unproductive sample +swapping happening across the plates. +

    +

    +One way to address this: we may split the optimization into two cycles, +first assigning samples to plates (balancing groups), then improving the +positions of the samples within each plate. This motivates the use of a +dedicated sample permutation function which takes the plate structure +into account and only shuffles samples around within one plate. +

    +
    # Setting up the batch container
    +
    +bc <- example2$copy()
    +
    +bc$scoring_f <- osat_score_generator(batch_vars = c("plate"), feature_vars = c("Group"))
    +
    +set.seed(42)
    +optimize_design(bc,
    +  quiet = TRUE,
    +  max_iter = 200, # this is set to shorten vignette run-time, normally we don't know.
    +  n_shuffle = 2,
    +  acceptance_func = mk_simanneal_acceptance_func(mk_simanneal_temp_func(T0 = 10000, alpha = 0.5)),
    +)
    +#> Optimization trace (201 score values, elapsed 4.254329 secs).
    +#>   Starting score: 128
    +#>   Final score   : 0
    +
    +plot_plate(bc,
    +  plate = plate, row = row, column = col, .color = Group,
    +  title = "Ex2: 'Plate wise' design\nStep 1: after allocating samples to plates"
    +)
    +

    +

    +
    
    +bc$scoring_f <- mk_plate_scoring_functions(bc, plate = "plate", row = "row", column = "col", group = "Group")
    +
    +bc$score()
    +#>  Plate 1  Plate 2 
    +#> 12.77527 13.63704
    +
    set.seed(42)
    +trace <- optimize_design(bc,
    +  max_iter = 400,
    +  shuffle_proposal_func = mk_subgroup_shuffling_function(subgroup_vars = c("plate")),
    +  acceptance_func = mk_simanneal_acceptance_func(mk_simanneal_temp_func(T0 = 1000, alpha = 0.5)),
    +  aggregate_scores_func = L2s_norm,
    +  quiet = TRUE
    +)
    +
    trace
    +#> Optimization trace (401 score values, elapsed 3.579697 secs).
    +#>   Starting score: 12.775,13.637
    +#>   Final score   : 6.855,6.309
    +
    +bc$score()
    +#>  Plate 1  Plate 2 
    +#> 6.854748 6.309297
    +
    +plot_plate(bc,
    +  plate = plate, row = row, column = col, .color = Group,
    +  title = "Ex2: 'Plate wise' design\nStep 2: after arranging samples within plates"
    +)
    +

    +

    +

    +In this case, the shuffling function exchanges 1 pair of sample +assignments every time (the default). However, any number of constant +swaps or a swapping protocol (formally a vector of integers) can be +supplied as well. +

    +

    +Now for the most efficient solution: we start again by first assigning +samples to plates (balancing groups), then making use of the +independence of the two within-plate optimizations and improving them +one after the other. +

    +

    +This is possible by passing the argument to the function that generates +the permutations. It enforces permutation only to happen first within +plate 1, then within plate 2, so that the two scores can be optimized in +succeeding runs. +

    +
    # Setting up the batch container
    +
    +bc <- example2$copy()
    +
    +bc$scoring_f <- osat_score_generator(batch_vars = c("plate"), feature_vars = c("Group"))
    +
    set.seed(42)
    +trace <- optimize_design(bc,
    +  quiet = TRUE,
    +  max_iter = 150, # this is set to shorten vignette run-time, normally we don't know.
    +  n_shuffle = 2,
    +  acceptance_func = mk_simanneal_acceptance_func(mk_simanneal_temp_func(T0 = 10000, alpha = 0.5)),
    +)
    +
    trace
    +#> Optimization trace (151 score values, elapsed 4.056035 secs).
    +#>   Starting score: 128
    +#>   Final score   : 0
    +
    +plot_plate(bc,
    +  plate = plate, row = row, column = col, .color = Group,
    +  title = "Ex2: 'Serial plate' design\nStep 1: after allocating samples to plates"
    +)
    +

    +

    +
    
    +bc$scoring_f <- mk_plate_scoring_functions(bc, plate = "plate", row = "row", column = "col", group = "Group")
    +
    +bc$score()
    +#>  Plate 1  Plate 2 
    +#> 10.57482 26.16613
    +
    set.seed(42)
    +trace <- optimize_design(bc,
    +  max_iter = 150,
    +  quiet = TRUE,
    +  shuffle_proposal_func = mk_subgroup_shuffling_function(subgroup_vars = c("plate"), restrain_on_subgroup_levels = c(1)),
    +  acceptance_func = mk_simanneal_acceptance_func(mk_simanneal_temp_func(T0 = 1000, alpha = 0.5)),
    +  aggregate_scores_func = L2s_norm
    +)
    +
    trace
    +#> Optimization trace (151 score values, elapsed 2.528134 secs).
    +#>   Starting score: 10.575,26.166
    +#>   Final score   : 6.416,26.166
    +
    +bc$score()
    +#>   Plate 1   Plate 2 
    +#>  6.416193 26.166134
    +
    set.seed(42)
    +trace <- optimize_design(bc,
    +  max_iter = 550,
    +  quiet = TRUE,
    +  shuffle_proposal_func = mk_subgroup_shuffling_function(subgroup_vars = c("plate"), restrain_on_subgroup_levels = c(2)),
    +  acceptance_func = mk_simanneal_acceptance_func(mk_simanneal_temp_func(T0 = 1000, alpha = 0.5)),
    +  aggregate_scores_func = L2s_norm
    +)
    +
    trace
    +#> Optimization trace (551 score values, elapsed 2.93787 secs).
    +#>   Starting score: 6.416,26.166
    +#>   Final score   : 6.416,6.582
    +
    +bc$score()
    +#>  Plate 1  Plate 2 
    +#> 6.416193 6.581966
    +
    +plot_plate(bc,
    +  plate = plate, row = row, column = col, .color = Group,
    +  title = "Ex2: 'Serial plate' design\nStep 2: after optimizing each plate in turn"
    +)
    +

    +

    +
    +
    library(designit)
    +library(ggplot2)
    +library(dplyr)
    +library(tidyr)
    +
    +

    +Example 3: 3 plates with different dimension and different sample group +sizes + +

    +

    +We simulate one ordinary 96 well plate and two smaller ones with sizes +6x8 and 4x6, respectively. There are 3 experimental groups as well with +sample sizes of 69, 30 and 69, respectively. This example should +demonstrate that an empirically determined normalization of the scores +yield 3 comparable numerical values, independent of the different plate +and group sizes. +

    +

    +Again, a first optimization aims to achieve same group allocation on +each plate, while the second run takes care of the sample distribution +on each plate. +

    +

    +We use assign_random in this example to start from a more balanced +initial position as compared to example 2. +

    +

    +Aggregation of scores is done by the L2s method (square of L2 norm). +Because of the comparable numerical range of scores, also the +worst_score method could be used for aggregation. However, the L2s +method always takes into account all individual scores, providing more +stability in case the 3 plate scores are not exactly normalized. +

    +
    # Setting up the batch container
    +
    +example3 <- BatchContainer$new(
    +  dimensions = c(
    +    plate = 3,
    +    row = 8, col = 12
    +  ),
    +  exclude = dplyr::bind_rows(
    +    tidyr::crossing(plate = 2, row = 1:8, col = 1:12) %>% dplyr::filter(row > 6 | col > 8),
    +    tidyr::crossing(plate = 3, row = 1:8, col = 1:12) %>% dplyr::filter(row > 4 | col > 6)
    +  )
    +)
    +
    +
    +# Assign samples randomly to start from a better initial state
    +assign_random(example3,
    +  samples = tibble::tibble(
    +    Group = rep.int(c("Grp 1", "Grp 2", "Grp3"),
    +      times = c(69, 30, 69)
    +    ),
    +    ID = 1:168
    +  )
    +)
    +
    +bc <- example3$copy()
    +
    +bc$scoring_f <- osat_score_generator(batch_vars = c("plate"), feature_vars = c("Group"))
    +
    set.seed(42)
    +trace <- optimize_design(bc,
    +  quiet = TRUE,
    +  max_iter = 150,
    +  n_shuffle = 2,
    +  acceptance_func = mk_simanneal_acceptance_func(mk_simanneal_temp_func(T0 = 1000, alpha = 0.5)),
    +)
    +
    trace
    +#> Optimization trace (151 score values, elapsed 3.348524 secs).
    +#>   Starting score: 17.714
    +#>   Final score   : 1.429
    +
    plot_plate(bc,
    +  plate = plate, row = row, column = col, .color = Group,
    +  title = "Ex3: Dealing with plates of different size\nStep 1: after distributing groups across plates"
    +)
    +

    +

    +
    bc$scoring_f <- mk_plate_scoring_functions(bc,
    +  plate = "plate", row = "row",
    +  column = "col", group = "Group"
    +)
    +
    +bc$score()
    +#>   Plate 1   Plate 2   Plate 3 
    +#>  9.706637  9.585770 10.419567
    +
    set.seed(42)
    +trace <- optimize_design(bc,
    +  max_iter = 300,
    +  shuffle_proposal_func = mk_subgroup_shuffling_function(
    +    subgroup_vars = c("plate"),
    +    n_swaps = c(rep(5, 500), rep(3, 1500), rep(2, 3000), rep(1, 5000))
    +  ),
    +  # acceptance_func = mk_simanneal_acceptance_func(mk_simanneal_temp_func(T0 = 10000, alpha = 1)),
    +  aggregate_scores_func = L2s_norm,
    +  quiet = TRUE
    +)
    +
    trace$elapsed
    +#> Time difference of 40.35472 secs
    +
    +bc$score()
    +#>  Plate 1  Plate 2  Plate 3 
    +#> 8.974408 8.253074 7.980756
    +
    plot_plate(bc,
    +  plate = plate, row = row, column = col, .color = Group,
    +  title = "Ex3: Dealing with plates of different size\nStep 2: after swapping samples within plates"
    +)
    +

    +

    +
    +
    library(designit)
    +library(ggplot2)
    +library(dplyr)
    +library(tidyr)
    +
    +

    +Example 4: More than one group factor to balance and empty plate +positions + +

    +

    +In this example, we have 2 factors to distribute across one plate: +Treatment and (animal) sex. +

    +

    +To indicate that the balancing of treatment is considered more important +than the animal sex we assign a custom aggregation function giving more +weight to the treatment variable. (A better aggregation mechanism has to +be implemented!!!) +

    +

    +There can be less samples than possible positions on the plate(s). In +this case, we simulate 20 animal derived samples distributed on a plate +with 24 locations. +

    +
    # Setting up the batch container
    +example4 <- BatchContainer$new(
    +  dimensions = c(
    +    plate = 1, row = 6, col = 4
    +  )
    +)
    +
    +
    +# Assign samples randomly to start from lower score (avoid Inf values even since plate 3 will miss 2 groups initially :)
    +assign_in_order(example4, samples = tibble::tibble(
    +  Group = rep.int(c("Treatment 1", "Treatment 2"), times = c(10, 10)),
    +  Sex = c(rep(c("M", "F", "F", "M"), times = 4), "M", NA, NA, "F"), ID = 1:20
    +))
    +
    +bc <- example4$copy()
    +
    +cowplot::plot_grid(
    +  plot_plate(bc, plate = plate, row = row, column = col, .color = Group, title = "Initial layout by Group"),
    +  plot_plate(bc, plate = plate, row = row, column = col, .color = Sex, title = "Initial layout by Sex"),
    +  ncol = 2
    +)
    +

    +

    +
    
    +
    +bc$scoring_f <- c(
    +  Group = mk_plate_scoring_functions(bc, row = "row", column = "col", group = "Group"),
    +  Sex = mk_plate_scoring_functions(bc, row = "row", column = "col", group = "Sex")
    +)
    +
    +bc$score()
    +#> Group.Plate   Sex.Plate 
    +#>    83.63858   239.20748
    +
    set.seed(42)
    +trace <- optimize_design(bc,
    +  max_iter = 750,
    +  n_shuffle = 1,
    +  acceptance_func = mk_simanneal_acceptance_func(mk_simanneal_temp_func(T0 = 10000, alpha = 1)),
    +  aggregate_scores_func = function(scores, ...) {
    +    2 * scores["Group.Plate"] + scores["Sex.Plate"]
    +  },
    +  quiet = TRUE
    +)
    +
    trace$elapsed
    +#> Time difference of 7.062086 secs
    +
    +bc$score()
    +#> Group.Plate   Sex.Plate 
    +#>    8.019656    7.608810
    +
    +cowplot::plot_grid(
    +  plot_plate(bc, plate = plate, row = row, column = col, .color = Group, title = "Final layout by Group"),
    +  plot_plate(bc, plate = plate, row = row, column = col, .color = Sex, title = "Final layout by Sex"),
    +  ncol = 2
    +)
    +

    +

    +

    +We do the same example with auto-scaling, weighted scoring and SA to +have a reference! +

    +
    set.seed(42)
    +trace <- optimize_design(bc,
    +  max_iter = 500,
    +  n_shuffle = 1,
    +  acceptance_func = mk_simanneal_acceptance_func(mk_simanneal_temp_func(T0 = 10000, alpha = 1)),
    +  aggregate_scores_func = function(scores, ...) {
    +    purrr::set_names(2 * scores["Group.Plate"] + scores["Sex.Plate"], nm = "Weighted.Score")
    +  },
    +  autoscale_scores = T,
    +  quiet = TRUE
    +)
    +#> ... Performing simple mean/stddev adjustment.
    +
    bc$score()
    +#> Group.Plate   Sex.Plate 
    +#>    8.080860    7.458345
    +
    +cowplot::plot_grid(
    +  plot_plate(bc, plate = plate, row = row, column = col, .color = Group, title = "Final layout by Group"),
    +  plot_plate(bc, plate = plate, row = row, column = col, .color = Sex, title = "Final layout by Sex"),
    +  ncol = 2
    +)
    +

    +

    +

    +We do the same example with auto-scaling and position-dependent scoring +now, not aggregating the score vector! This is more effective even when +using the default acceptance function. We are strictly prioritizing the +leftmost score in addition to reflect relevance for the design. +

    +
    bc <- example4$copy()
    +
    +bc$scoring_f <- c(
    +  Group = mk_plate_scoring_functions(bc, row = "row", column = "col", group = "Group"),
    +  Sex = mk_plate_scoring_functions(bc, row = "row", column = "col", group = "Sex")
    +)
    +
    +bc$score()
    +#> Group.Plate   Sex.Plate 
    +#>    83.63858   239.20748
    +
    +set.seed(42)
    +trace <- optimize_design(bc,
    +  max_iter = 5000,
    +  n_shuffle = 1,
    +  acceptance_func = accept_leftmost_improvement,
    +  autoscale_scores = TRUE,
    +  quiet = TRUE
    +)
    +#> ... Performing simple mean/stddev adjustment.
    +
    bc$score()
    +#> Group.Plate   Sex.Plate 
    +#>    7.619846    7.473524
    +
    +cowplot::plot_grid(
    +  plot_plate(bc, plate = plate, row = row, column = col, .color = Group, title = "Final layout by Group"),
    +  plot_plate(bc, plate = plate, row = row, column = col, .color = Sex, title = "Final layout by Sex"),
    +  ncol = 2
    +)
    +

    +

    +

    +Using a tolerance value to accept slightly worse solutions in the +leftmost relevant score if overcompensated by other scores: +

    +
    bc <- example4$copy()
    +
    +
    +bc$scoring_f <- c(
    +  Group = mk_plate_scoring_functions(bc, row = "row", column = "col", group = "Group"),
    +  Sex = mk_plate_scoring_functions(bc, row = "row", column = "col", group = "Sex")
    +)
    +
    +
    +set.seed(42)
    +trace <- optimize_design(bc,
    +  max_iter = 5000,
    +  n_shuffle = 1,
    +  acceptance_func = ~ accept_leftmost_improvement(..., tolerance = 0.1),
    +  autoscale_scores = TRUE,
    +  quiet = TRUE
    +)
    +#> ... Performing simple mean/stddev adjustment.
    +
    +bc$score()
    +#> Group.Plate   Sex.Plate 
    +#>    7.366667    7.323324
    +
    bc$score()
    +#> Group.Plate   Sex.Plate 
    +#>    7.366667    7.323324
    +
    +cowplot::plot_grid(
    +  plot_plate(bc, plate = plate, row = row, column = col, .color = Group, title = "Final layout by Group"),
    +  plot_plate(bc, plate = plate, row = row, column = col, .color = Sex, title = "Final layout by Sex"),
    +  ncol = 2
    +)
    +

    +

    +

    +Testing an alternative left-to-right weighing of scores, based on +exponential down-weighing of the respective score differences at +position \(p\) with factor \(\kappa^p\), \(0 &lt; \kappa +&lt; 1\) We choose a \(\kappa\) of 0.5, i.e. the second +score’s improvement counts half of that of the first one. +

    +
    bc <- example4$copy()
    +
    +bc$scoring_f <- c(
    +  Group = mk_plate_scoring_functions(bc, row = "row", column = "col", group = "Group"),
    +  Sex = mk_plate_scoring_functions(bc, row = "row", column = "col", group = "Sex")
    +)
    +
    +bc$score()
    +#> Group.Plate   Sex.Plate 
    +#>    83.63858   239.20748
    +
    +set.seed(42)
    +trace <- optimize_design(bc,
    +  max_iter = 1000,
    +  n_shuffle = 1,
    +  acceptance_func = mk_exponentially_weighted_acceptance_func(kappa = 0.5, simulated_annealing = T),
    +  autoscale_scores = TRUE,
    +  quiet = TRUE
    +)
    +#> ... Performing simple mean/stddev adjustment.
    +
    bc$score()
    +#> Group.Plate   Sex.Plate 
    +#>    7.630367    7.616179
    +
    +cowplot::plot_grid(
    +  plot_plate(bc, plate = plate, row = row, column = col, .color = Group, title = "Final layout by Group"),
    +  plot_plate(bc, plate = plate, row = row, column = col, .color = Sex, title = "Final layout by Sex"),
    +  ncol = 2
    +)
    +

    +

    +
    +
    library(designit)
    +library(ggplot2)
    +library(dplyr)
    +library(tidyr)
    +
    +

    +Example 5: Avoiding ‘regular patterns’ in plate layout + +

    +

    +In some cases it may be essential to avoid samples of the same group +being put into the same row or column on a plate, i.e. these variables +are regarded as factor levels of their own, in addition to the spatial +relation of the samples. +

    +

    +Plate scoring functions can use an specific penalty for these ‘linearly +arranged’ samples on top of the distance metrics chosen. +

    +
    # Setting up the batch container
    +example5 <- BatchContainer$new(
    +  dimensions = c(
    +    plate = 1, row = 8, col = 12
    +  )
    +)
    +
    +# Assign samples randomly to start from lower score (avoid `Inf` values when doing the 'hard' penalization)
    +assign_random(example5, samples = tibble::tibble(
    +  Group = rep.int(paste("Group", 1:5), times = c(8, 8, 8, 8, 64)),
    +  ID = 1:96
    +))
    +
    +penalize_lines <- "hard"
    +
    +bc <- example5$copy()
    +
    +bc$scoring_f <- c(
    +  Group = mk_plate_scoring_functions(bc, row = "row", column = "col", group = "Group", p = 2, penalize_lines = penalize_lines)
    +)
    +
    +bc$score()
    +#> Group.Plate 
    +#>    9.960584
    +
    set.seed(42)
    +trace <- optimize_design(bc,
    +  max_iter = 5000,
    +  n_shuffle = 1,
    +  acceptance_func = mk_simanneal_acceptance_func(mk_simanneal_temp_func(T0 = 500, alpha = 0.1)),
    +  quiet = T
    +)
    +
    trace$elapsed
    +#> Time difference of 28.7293 secs
    +
    +bc$score()
    +#> Group.Plate 
    +#>    8.819968
    +
    +plot_plate(bc, plate = plate, row = row, column = col, .color = Group, title = stringr::str_c("Line penalization: ", penalize_lines))
    +

    +

    +
    +
    + + + +
    + + + +
    + +
    +

    +

    Site built with pkgdown 2.0.7.

    +
    + +
    +
    + + + + + + + + diff --git a/dev/articles/shuffling_with_constraints.html b/dev/articles/shuffling_with_constraints.html new file mode 100644 index 00000000..aa354c32 --- /dev/null +++ b/dev/articles/shuffling_with_constraints.html @@ -0,0 +1,2495 @@ + + + + + + + +Shuffling with constraints • designit + + + + + + + + + + + + + + + + + + + + +
    +
    + + + + +
    +
    + + + + +
    +

    Purpose of the vignette +

    +

    This example demonstrates that by using customized shuffling +functions, it is possible to restrain the design optimization to only +score sample arrangements that fit the given constraints.

    +

    Key idea is that every reshuffling produces a ‘valid’ sample +permutation that is not violating those constraints, even if the +suggested solution may be quite bad. During optimization, we pick the +best design solution from the possible ones by appropriate scoring.

    +

    The user is free to implement custom shuffling functions and pass +those to the optimizer. However, some knowledge is required regarding +the internal workings of the optimization and batch container setup. +Therefore the package provides a little generic constructor for +customized shufflings shuffle_grouped_data in which +certain types of constraints that relate to grouped samples may be +specified by the passed parameters.

    +
    +
    +

    The design problem +

    +
    +

    Samples and treatments +

    +

    We refer to a simplified version of the in vivo example +which is examined deeper in a dedicated vignette.

    +
    +data("invivo_study_samples")
    +
    +invivo_study_samples <- dplyr::mutate(invivo_study_samples,
    +  Litter_combine_females = ifelse(Sex == "F", "female_all", Litter)
    +)
    +str(invivo_study_samples)
    +#> 'data.frame':    59 obs. of  9 variables:
    +#>  $ AnimalID              : chr  "F1" "F2" "F3" "F4" ...
    +#>  $ Strain                : chr  "Strain B" "Strain B" "Strain B" "Strain B" ...
    +#>  $ Sex                   : chr  "F" "F" "F" "F" ...
    +#>  $ BirthDate             : Date, format: "2021-05-24" "2021-03-01" ...
    +#>  $ Earmark               : chr  "R" "2L" "2L1R" "L" ...
    +#>  $ ArrivalWeight         : num  19.4 26.5 20.8 22.1 22.9 ...
    +#>  $ Arrival.weight.Unit   : chr  "g" "g" "g" "g" ...
    +#>  $ Litter                : chr  "Litter 1" "Litter 2" "Litter 2" "Litter 2" ...
    +#>  $ Litter_combine_females: chr  "female_all" "female_all" "female_all" "female_all" ...
    +
    +invivo_study_samples %>%
    +  dplyr::count(Strain, Sex, Litter_combine_females) %>%
    +  gt::gt()
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    StrainSexLitter_combine_femalesn
    Strain AFfemale_all7
    Strain AMLitter 103
    Strain AMLitter 114
    Strain AMLitter 125
    Strain AMLitter 134
    Strain AMLitter 146
    Strain BFfemale_all7
    Strain BMLitter 13
    Strain BMLitter 35
    Strain BMLitter 44
    Strain BMLitter 54
    Strain BMLitter 64
    Strain BMLitter 73
    +
    +

    We will use the litter as a factor to form cages in our design. +However, in order to indicate the compatibility of female animals (see +in vivo study vignette), a pseudo-litter +female_all is created here to group all the females +together, marking them as interchangeable for the subgroup (i.e. cage) +allocation.

    +

    In the simplified setup we want to assign two treatments to those +animals, balancing for strain and sex as the primary suspected +confounders. The batch container is prepared as follows:

    +
    +treatments <- factor(rep(c("Treatment A", "Treatment B"), c(30, 29)))
    +table(treatments)
    +#> treatments
    +#> Treatment A Treatment B 
    +#>          30          29
    +
    +bc <- BatchContainer$new(locations_table = data.frame(Treatment = treatments, Position = seq_along(treatments)))
    +
    +assign_in_order(bc, invivo_study_samples)
    +
    +bc$scoring_f <- osat_score_generator(batch_vars = "Treatment", feature_vars = c("Strain", "Sex"))
    +
    +bc
    +#> Batch container with 59 locations and 59 samples (assigned).
    +#>   Dimensions: Treatment, Position
    +
    +
    + +

    As noted, we have to assign animals to cages in this example. The +cage is thus acting as the grouping factor for the samples (animals) on +which we may want to put further constraints. Concretely:

    +
      +
    • We want to form cages with ideally 3 animals each +(tolerated/preferred range is from 2-5)
    • +
    • Variables Strain, Sex and Treatment must be homogeneous within +cage
    • +
    • Animals of different litters must not be put into the same cage
    • +
    • If at all possible, avoid putting animals with the same ear markings +into one cage
    • +
    +

    We will tackle the usual factor balancing (using the osat score) and +the additional constraints at the same time, combined in one +conceptional framework.

    +

    As stated, the main idea is to provide a customized shuffling +function that ensures that only ‘suitable’ design proposals are +generated and passed to the scoring function which will then identify a +good one.

    +

    Also keep in mind that what is the cage here could be any subgroup +into which samples have to be partitioned.

    +
    +
    +
    +

    Doing it all in one go +

    +

    The wrapper shuffle_grouped_data allows to construct a +shuffling function that satisfies all constraints defined above at the +same time. It can be passed to the optimizer together with other user +defined options such as the scoring or acceptance functions.

    +
    +bc2 <- bc$copy()
    +
    +optimize_design(
    +  bc2,
    +  shuffle_proposal_func = shuffle_grouped_data(bc2,
    +    allocate_var = "Treatment",
    +    keep_together_vars = c("Strain", "Sex"),
    +    keep_separate_vars = c("Earmark"),
    +    subgroup_var_name = "Cage",
    +    n_min = 2, n_ideal = 3, n_max = 5,
    +    strict = TRUE,
    +    report_grouping_as_attribute = TRUE
    +  ),
    +  max_iter = 600
    +)
    +#> 
    +#> Formed 4 homogeneous groups using 59 samples.
    +#> 22 subgroups needed to satisfy size constraints.
    +#> 
    +#> Finding possible ways to allocate variable of interest with 2 levels ...
    +#> 
    +#> Aborted after 1000010 recursive calls (maxCalls limit).
    +#> 176364 allocations found.
    +#> Usage of sample attributes --> executing first shuffling call.
    +#> Checking variances of 1-dim. score vector.
    +#> ... (204.701) - OK
    +#> Initial score: 453.202
    +#> Adding 4 attributes to samples.
    +#> Achieved score: 355.575 at iteration 2
    +#> No permutations fulfilling the 'keep_separate' constraints in 1000 iters!
    +#> Increasing number of tolerated violations to 1
    +#> Achieved score: 305.134 at iteration 19
    +#> Achieved score: 272.592 at iteration 20
    +#> Achieved score: 231.507 at iteration 34
    +#> Achieved score: 181.473 at iteration 52
    +#> Achieved score: 143.032 at iteration 116
    +#> Achieved score: 122.49 at iteration 123
    +#> Achieved score: 105.405 at iteration 165
    +#> Achieved score: 104.999 at iteration 356
    +#> Achieved score: 79.371 at iteration 384
    +#> Achieved score: 52.931 at iteration 525
    +#> Achieved score: 44.388 at iteration 546
    +#> Optimization trace (601 score values, elapsed 47.57102 secs).
    +#>   Starting score: 453.202
    +#>   Final score   : 44.388
    +
    +design <- bc2$get_samples()
    +

    allocate_var is the batch container variable that should +be primarily assigned to individual samples.

    +

    keep_together_vars is a list of variables that must be +homogeneous within a subgroup (here: cage).

    +

    keep_separate_vars lists variables which should have +different values within a subgroup (here: cage), if at all possible. +This is a soft constraint and will be relaxed in a stepwise way until +solutions can be found.

    +

    subgroup_var_name allows to give the generated subgroup +variable a useful name.

    +

    n_min, n_max and n_ideal +specify the minimal, maximal and ideal group sizes, respectively. It is +often necessary to release the strict criterion to find any +solution at all that satisfies those size criteria.

    +

    report_grouping_as_attribute allows, if TRUE, to add the +updated group variable into the batch container at each iteration, so +that scoring functions could make use of this variable (here: cage)!

    +

    Following the output of the optimizer, we see that a solution was +identified that satisfies all constraints, with the exception of +tolerating one violation of earmark-uniqueness within a cage.

    +

    The following cages (homogeneous in strain, sex and treatment) have +been generated in the process:

    +
    +design %>%
    +  dplyr::count(Cage, Strain, Sex, Treatment) %>%
    +  gt::gt()
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    CageStrainSexTreatmentn
    1_1Strain AFTreatment A3
    1_2Strain AFTreatment A2
    1_3Strain AFTreatment A2
    2_1Strain AMTreatment A3
    2_2Strain AMTreatment A3
    2_3Strain AMTreatment A3
    2_4Strain AMTreatment A3
    2_5Strain AMTreatment B3
    2_6Strain AMTreatment B3
    2_7Strain AMTreatment B2
    2_8Strain AMTreatment B2
    3_1Strain BFTreatment B3
    3_2Strain BFTreatment A2
    3_3Strain BFTreatment B2
    4_1Strain BMTreatment A3
    4_2Strain BMTreatment A3
    4_3Strain BMTreatment A3
    4_4Strain BMTreatment B3
    4_5Strain BMTreatment B3
    4_6Strain BMTreatment B3
    4_7Strain BMTreatment B3
    4_8Strain BMTreatment B2
    +
    +
    +
    +

    Multiple step approach +

    +

    shuffle_grouped_data is a wrapper that consecutively +calls other helper function. As an addendum, let us break the whole +procedure down into parts that show what is happening internally at each +step.

    +
    +

    Form homogeneous subgroups - pools of animals that could go into one +cage +

    +

    We have to divide our animal cohort into subgroups with same strain +and sex, meeting size constraints as stated above. Since 2-5 animals +should go into one cage, we specify n_minand +n_maxaccordingly. n_ideal would be selected by +default as the mean of those two, but we specify it explicitly here, +too.

    +

    The homogeneity of subgroups regarding strain and sex is achieved by +listing those two parameters as keep_together_vars.

    +

    Assignment of treatments should be performed as well at some point. +We thus specify Treatment as the allocation variable.

    +

    Note that the Treatment variable is technically a batch +container location and not a part of the sample list. This distinction +does not matter at this point. However, all required variables must +exist in the batch container object.

    +

    The following call to form_homogeneous_subgroups() +produces an object that holds all relevant information about the +samples, the allocation variable and the sizes of the subgroups that +have to be formed. It is NOT decided, however, which animal will end up +in which subgroup. This will be a matter of optimization later on.

    +
    +subg <- form_homogeneous_subgroups(
    +  batch_container = bc, allocate_var = "Treatment",
    +  keep_together_vars = c("Strain", "Sex", "Litter_combine_females"),
    +  subgroup_var_name = "Cage",
    +  n_min = 2, n_ideal = 3, n_max = 5
    +)
    +#> 
    +#> Formed 13 homogeneous groups using 59 samples.
    +#> 18 subgroups needed to satisfy size constraints.
    +

    In this example, 18 subgroups have to be formed to meet all +constraints.

    +

    It is possible to obtain more information from the returned list +object. Inspection of element Subgroup_Sizes tells us that +13 ‘animal pools’ have to be formed which are homogeneous in the +relevant parameters (here: strain and sex). Each of those groups happens +to be split in subgroups with a size between 2 and 4 animals , which +will later constitute the individual cages.

    +
    +subg$Subgroup_Sizes
    +#> $`Strain A/F/female_all`
    +#> [1] 3 4
    +#> 
    +#> $`Strain A/M/Litter 10`
    +#> [1] 3
    +#> 
    +#> $`Strain A/M/Litter 11`
    +#> [1] 4
    +#> 
    +#> $`Strain A/M/Litter 12`
    +#> [1] 3 2
    +#> 
    +#> $`Strain A/M/Litter 13`
    +#> [1] 4
    +#> 
    +#> $`Strain A/M/Litter 14`
    +#> [1] 3 3
    +#> 
    +#> $`Strain B/F/female_all`
    +#> [1] 3 4
    +#> 
    +#> $`Strain B/M/Litter 1`
    +#> [1] 3
    +#> 
    +#> $`Strain B/M/Litter 3`
    +#> [1] 3 2
    +#> 
    +#> $`Strain B/M/Litter 4`
    +#> [1] 4
    +#> 
    +#> $`Strain B/M/Litter 5`
    +#> [1] 4
    +#> 
    +#> $`Strain B/M/Litter 6`
    +#> [1] 4
    +#> 
    +#> $`Strain B/M/Litter 7`
    +#> [1] 3
    +
    +
    +

    Find all valid ways to allocate treatments to the subgroups +

    +

    Each subgroup of animals receives one specific treatment. Or more +generally: subgroups have to be homogeneous regarding the allocation +variable.

    +

    This introduces another type of constraint, since numbers have to add +up to 10 ‘Control’ and 10 ‘Compound’ cases, as given by the +treatments variable. As a next step, we have to find all +possible combinations of subgroups which produce valid options for the +treatment allocation. That’s done with the next call.

    +

    This will find a large number of different ways to assign treatments +to subgroups that lead to the correct overall number of treated +animals.

    +
    +possible <- compile_possible_subgroup_allocation(subg)
    +#> 
    +#> Finding possible ways to allocate variable of interest with 2 levels ...
    +#> 
    +#> Finished with 108296 recursive calls.
    +#> 14660 allocations found.
    +
    +
    +

    Generate shuffling function for potential study designs +

    +

    So far we only know the sizes of subgroups (i.e. cages). Thus, in a +last step we have to assign specific animals to the various subgroups. +Ideally each group of ‘equivalent animals’ (in terms of strain and sex) +is split up into more than one subgroup, so there’s many potential ways +to assign animals to those.

    +

    To allow optimization as usual, we want to generate a shuffling +function that produces only valid solutions in terms of our constraints, +so that optimization can iterate efficiently over this solution space. +The function can be generated by calling +shuffle_with_subgroup_formation() with the previously created +subgrouping object and the list of possible treatment allocations.

    +

    Every call to this shuffling function will return a permutation index +(of the original samples) that constitutes a valid solution to be +scored.

    +

    The permutation function actually also constructs a ‘Cage’ variable +(see parameter subgroup_var_name in the call to +form_homogeneous_subgroups()). To make this parameter available +and join it to the samples in the batch container, use flag +report_grouping_as_attribute in the construction of the +permutation function.

    +
    +shuffle_proposal <- shuffle_with_subgroup_formation(subg, possible, report_grouping_as_attribute = TRUE)
    +
    +shuffle_proposal()
    +#> $location_assignment
    +#>  [1]  8 13 14  9 10 11 12 38 39 40 41 42 43 44 47 48 49 45 46 50 51 52 53 55 58
    +#> [26] 59  1  2  4  5 54 56 57  3  6  7 35 36 37 19 20 26 21 27 15 16 17 18 22 23
    +#> [51] 24 25 28 29 30 31 32 33 34
    +#> 
    +#> $samples_attr
    +#> # A tibble: 59 × 4
    +#>    alloc_var_level group subgroup Cage 
    +#>    <chr>           <int>    <int> <chr>
    +#>  1 Treatment A         7        2 7_2  
    +#>  2 Treatment A         7        2 7_2  
    +#>  3 Treatment B         7        1 7_1  
    +#>  4 Treatment A         7        2 7_2  
    +#>  5 Treatment A         7        2 7_2  
    +#>  6 Treatment B         7        1 7_1  
    +#>  7 Treatment B         7        1 7_1  
    +#>  8 Treatment A         1        1 1_1  
    +#>  9 Treatment A         1        2 1_2  
    +#> 10 Treatment A         1        2 1_2  
    +#> # … with 49 more rows
    +

    Calling the shuffle proposal function repeatedly produces a valid +(constraint-aware) sample arrangement each time, with the grouping +variable (here: Cage) reported alongside. (The optimizer will merge the +‘Cage’ variable into the batch container after each iteration, so that +it can be used for scoring as if it would have been in the container +from the beginning!)

    +
    +
    +

    Use shuffling function for optimizing design +

    +

    We can finally use the customized shuffling function in the +optimization.

    +
    +bc3 <- bc$copy()
    +
    +trace <- optimize_design(
    +  bc3,
    +  shuffle_proposal_func = shuffle_proposal,
    +  max_iter = 300
    +)
    +#> Usage of sample attributes --> executing first shuffling call.
    +#> Checking variances of 1-dim. score vector.
    +#> ... (190.436) - OK
    +#> Initial score: 289.541
    +#> Adding 4 attributes to samples.
    +#> Achieved score: 189.066 at iteration 9
    +#> Achieved score: 139.439 at iteration 15
    +#> Achieved score: 105.405 at iteration 34
    +#> Achieved score: 52.931 at iteration 55
    +#> Achieved score: 51.304 at iteration 70
    +#> Achieved score: 32.863 at iteration 206
    +
    +design <- bc3$get_samples()
    +
    +# Obeying all constraints does not lead to a very balanced sample allocation:
    +dplyr::count(design, Treatment, Strain) %>% gt::gt()
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    TreatmentStrainn
    Treatment AStrain A17
    Treatment AStrain B13
    Treatment BStrain A12
    Treatment BStrain B17
    +
    + +dplyr::count(design, Treatment, Sex) %>% gt::gt() +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    TreatmentSexn
    Treatment AF10
    Treatment AM20
    Treatment BF4
    Treatment BM25
    +
    +
    +
    +
    + + + +
    + + + +
    + +
    +

    +

    Site built with pkgdown 2.0.7.

    +
    + +
    +
    + + + + + + + + diff --git a/dev/authors.html b/dev/authors.html new file mode 100644 index 00000000..0e68a790 --- /dev/null +++ b/dev/authors.html @@ -0,0 +1,150 @@ + +Authors and Citation • designit + + +
    +
    + + + +
    +
    +
    + + + +
    • +

      Iakov I. Davydov. Author, maintainer, copyright holder. +

      +
    • +
    • +

      Juliane Siebourg-Polster. Author, copyright holder. +

      +
    • +
    • +

      Guido Steiner. Author, copyright holder. +

      +
    • +
    • +

      Balazs Banfai. Author, copyright holder. +

      +
    • +
    • +

      F. Hoffman-La Roche. Copyright holder, funder. +

      +
    • +
    +
    +
    +

    Citation

    + Source: DESCRIPTION +
    +
    + + +

    Davydov II, Siebourg-Polster J, Steiner G, Banfai B (2023). +designit: Blocking and Randomization for Experimental Design. +https://bedapub.github.io/designit/, https://github.com/BEDApub/designit/. +

    +
    @Manual{,
    +  title = {designit: Blocking and Randomization for Experimental Design},
    +  author = {Iakov I. Davydov and Juliane Siebourg-Polster and Guido Steiner and Balazs Banfai},
    +  year = {2023},
    +  note = {https://bedapub.github.io/designit/, https://github.com/BEDApub/designit/},
    +}
    + +
    + +
    + + + +
    + +
    +

    Site built with pkgdown 2.0.7.

    +
    + +
    + + + + + + + + diff --git a/dev/bootstrap-toc.css b/dev/bootstrap-toc.css new file mode 100644 index 00000000..5a859415 --- /dev/null +++ b/dev/bootstrap-toc.css @@ -0,0 +1,60 @@ +/*! + * Bootstrap Table of Contents v0.4.1 (http://afeld.github.io/bootstrap-toc/) + * Copyright 2015 Aidan Feldman + * Licensed under MIT (https://github.com/afeld/bootstrap-toc/blob/gh-pages/LICENSE.md) */ + +/* modified from https://github.com/twbs/bootstrap/blob/94b4076dd2efba9af71f0b18d4ee4b163aa9e0dd/docs/assets/css/src/docs.css#L548-L601 */ + +/* All levels of nav */ +nav[data-toggle='toc'] .nav > li > a { + display: block; + padding: 4px 20px; + font-size: 13px; + font-weight: 500; + color: #767676; +} +nav[data-toggle='toc'] .nav > li > a:hover, +nav[data-toggle='toc'] .nav > li > a:focus { + padding-left: 19px; + color: #563d7c; + text-decoration: none; + background-color: transparent; + border-left: 1px solid #563d7c; +} +nav[data-toggle='toc'] .nav > .active > a, +nav[data-toggle='toc'] .nav > .active:hover > a, +nav[data-toggle='toc'] .nav > .active:focus > a { + padding-left: 18px; + font-weight: bold; + color: #563d7c; + background-color: transparent; + border-left: 2px solid #563d7c; +} + +/* Nav: second level (shown on .active) */ +nav[data-toggle='toc'] .nav .nav { + display: none; /* Hide by default, but at >768px, show it */ + padding-bottom: 10px; +} +nav[data-toggle='toc'] .nav .nav > li > a { + padding-top: 1px; + padding-bottom: 1px; + padding-left: 30px; + font-size: 12px; + font-weight: normal; +} +nav[data-toggle='toc'] .nav .nav > li > a:hover, +nav[data-toggle='toc'] .nav .nav > li > a:focus { + padding-left: 29px; +} +nav[data-toggle='toc'] .nav .nav > .active > a, +nav[data-toggle='toc'] .nav .nav > .active:hover > a, +nav[data-toggle='toc'] .nav .nav > .active:focus > a { + padding-left: 28px; + font-weight: 500; +} + +/* from https://github.com/twbs/bootstrap/blob/e38f066d8c203c3e032da0ff23cd2d6098ee2dd6/docs/assets/css/src/docs.css#L631-L634 */ +nav[data-toggle='toc'] .nav > .active > ul { + display: block; +} diff --git a/dev/bootstrap-toc.js b/dev/bootstrap-toc.js new file mode 100644 index 00000000..1cdd573b --- /dev/null +++ b/dev/bootstrap-toc.js @@ -0,0 +1,159 @@ +/*! + * Bootstrap Table of Contents v0.4.1 (http://afeld.github.io/bootstrap-toc/) + * Copyright 2015 Aidan Feldman + * Licensed under MIT (https://github.com/afeld/bootstrap-toc/blob/gh-pages/LICENSE.md) */ +(function() { + 'use strict'; + + window.Toc = { + helpers: { + // return all matching elements in the set, or their descendants + findOrFilter: function($el, selector) { + // http://danielnouri.org/notes/2011/03/14/a-jquery-find-that-also-finds-the-root-element/ + // http://stackoverflow.com/a/12731439/358804 + var $descendants = $el.find(selector); + return $el.filter(selector).add($descendants).filter(':not([data-toc-skip])'); + }, + + generateUniqueIdBase: function(el) { + var text = $(el).text(); + var anchor = text.trim().toLowerCase().replace(/[^A-Za-z0-9]+/g, '-'); + return anchor || el.tagName.toLowerCase(); + }, + + generateUniqueId: function(el) { + var anchorBase = this.generateUniqueIdBase(el); + for (var i = 0; ; i++) { + var anchor = anchorBase; + if (i > 0) { + // add suffix + anchor += '-' + i; + } + // check if ID already exists + if (!document.getElementById(anchor)) { + return anchor; + } + } + }, + + generateAnchor: function(el) { + if (el.id) { + return el.id; + } else { + var anchor = this.generateUniqueId(el); + el.id = anchor; + return anchor; + } + }, + + createNavList: function() { + return $(''); + }, + + createChildNavList: function($parent) { + var $childList = this.createNavList(); + $parent.append($childList); + return $childList; + }, + + generateNavEl: function(anchor, text) { + var $a = $(''); + $a.attr('href', '#' + anchor); + $a.text(text); + var $li = $('
  • '); + $li.append($a); + return $li; + }, + + generateNavItem: function(headingEl) { + var anchor = this.generateAnchor(headingEl); + var $heading = $(headingEl); + var text = $heading.data('toc-text') || $heading.text(); + return this.generateNavEl(anchor, text); + }, + + // Find the first heading level (`

    `, then `

    `, etc.) that has more than one element. Defaults to 1 (for `

    `). + getTopLevel: function($scope) { + for (var i = 1; i <= 6; i++) { + var $headings = this.findOrFilter($scope, 'h' + i); + if ($headings.length > 1) { + return i; + } + } + + return 1; + }, + + // returns the elements for the top level, and the next below it + getHeadings: function($scope, topLevel) { + var topSelector = 'h' + topLevel; + + var secondaryLevel = topLevel + 1; + var secondarySelector = 'h' + secondaryLevel; + + return this.findOrFilter($scope, topSelector + ',' + secondarySelector); + }, + + getNavLevel: function(el) { + return parseInt(el.tagName.charAt(1), 10); + }, + + populateNav: function($topContext, topLevel, $headings) { + var $context = $topContext; + var $prevNav; + + var helpers = this; + $headings.each(function(i, el) { + var $newNav = helpers.generateNavItem(el); + var navLevel = helpers.getNavLevel(el); + + // determine the proper $context + if (navLevel === topLevel) { + // use top level + $context = $topContext; + } else if ($prevNav && $context === $topContext) { + // create a new level of the tree and switch to it + $context = helpers.createChildNavList($prevNav); + } // else use the current $context + + $context.append($newNav); + + $prevNav = $newNav; + }); + }, + + parseOps: function(arg) { + var opts; + if (arg.jquery) { + opts = { + $nav: arg + }; + } else { + opts = arg; + } + opts.$scope = opts.$scope || $(document.body); + return opts; + } + }, + + // accepts a jQuery object, or an options object + init: function(opts) { + opts = this.helpers.parseOps(opts); + + // ensure that the data attribute is in place for styling + opts.$nav.attr('data-toggle', 'toc'); + + var $topContext = this.helpers.createChildNavList(opts.$nav); + var topLevel = this.helpers.getTopLevel(opts.$scope); + var $headings = this.helpers.getHeadings(opts.$scope, topLevel); + this.helpers.populateNav($topContext, topLevel, $headings); + } + }; + + $(function() { + $('nav[data-toggle="toc"]').each(function(i, el) { + var $nav = $(el); + Toc.init($nav); + }); + }); +})(); diff --git a/dev/docsearch.css b/dev/docsearch.css new file mode 100644 index 00000000..e5f1fe1d --- /dev/null +++ b/dev/docsearch.css @@ -0,0 +1,148 @@ +/* Docsearch -------------------------------------------------------------- */ +/* + Source: https://github.com/algolia/docsearch/ + License: MIT +*/ + +.algolia-autocomplete { + display: block; + -webkit-box-flex: 1; + -ms-flex: 1; + flex: 1 +} + +.algolia-autocomplete .ds-dropdown-menu { + width: 100%; + min-width: none; + max-width: none; + padding: .75rem 0; + background-color: #fff; + background-clip: padding-box; + border: 1px solid rgba(0, 0, 0, .1); + box-shadow: 0 .5rem 1rem rgba(0, 0, 0, .175); +} + +@media (min-width:768px) { + .algolia-autocomplete .ds-dropdown-menu { + width: 175% + } +} + +.algolia-autocomplete .ds-dropdown-menu::before { + display: none +} + +.algolia-autocomplete .ds-dropdown-menu [class^=ds-dataset-] { + padding: 0; + background-color: rgb(255,255,255); + border: 0; + max-height: 80vh; +} + +.algolia-autocomplete .ds-dropdown-menu .ds-suggestions { + margin-top: 0 +} + +.algolia-autocomplete .algolia-docsearch-suggestion { + padding: 0; + overflow: visible +} + +.algolia-autocomplete .algolia-docsearch-suggestion--category-header { + padding: .125rem 1rem; + margin-top: 0; + font-size: 1.3em; + font-weight: 500; + color: #00008B; + border-bottom: 0 +} + +.algolia-autocomplete .algolia-docsearch-suggestion--wrapper { + float: none; + padding-top: 0 +} + +.algolia-autocomplete .algolia-docsearch-suggestion--subcategory-column { + float: none; + width: auto; + padding: 0; + text-align: left +} + +.algolia-autocomplete .algolia-docsearch-suggestion--content { + float: none; + width: auto; + padding: 0 +} + +.algolia-autocomplete .algolia-docsearch-suggestion--content::before { + display: none +} + +.algolia-autocomplete .ds-suggestion:not(:first-child) .algolia-docsearch-suggestion--category-header { + padding-top: .75rem; + margin-top: .75rem; + border-top: 1px solid rgba(0, 0, 0, .1) +} + +.algolia-autocomplete .ds-suggestion .algolia-docsearch-suggestion--subcategory-column { + display: block; + padding: .1rem 1rem; + margin-bottom: 0.1; + font-size: 1.0em; + font-weight: 400 + /* display: none */ +} + +.algolia-autocomplete .algolia-docsearch-suggestion--title { + display: block; + padding: .25rem 1rem; + margin-bottom: 0; + font-size: 0.9em; + font-weight: 400 +} + +.algolia-autocomplete .algolia-docsearch-suggestion--text { + padding: 0 1rem .5rem; + margin-top: -.25rem; + font-size: 0.8em; + font-weight: 400; + line-height: 1.25 +} + +.algolia-autocomplete .algolia-docsearch-footer { + width: 110px; + height: 20px; + z-index: 3; + margin-top: 10.66667px; + float: right; + font-size: 0; + line-height: 0; +} + +.algolia-autocomplete .algolia-docsearch-footer--logo { + background-image: url("data:image/svg+xml;utf8,"); + background-repeat: no-repeat; + background-position: 50%; + background-size: 100%; + overflow: hidden; + text-indent: -9000px; + width: 100%; + height: 100%; + display: block; + transform: translate(-8px); +} + +.algolia-autocomplete .algolia-docsearch-suggestion--highlight { + color: #FF8C00; + background: rgba(232, 189, 54, 0.1) +} + + +.algolia-autocomplete .algolia-docsearch-suggestion--text .algolia-docsearch-suggestion--highlight { + box-shadow: inset 0 -2px 0 0 rgba(105, 105, 105, .5) +} + +.algolia-autocomplete .ds-suggestion.ds-cursor .algolia-docsearch-suggestion--content { + background-color: rgba(192, 192, 192, .15) +} diff --git a/dev/docsearch.js b/dev/docsearch.js new file mode 100644 index 00000000..b35504cd --- /dev/null +++ b/dev/docsearch.js @@ -0,0 +1,85 @@ +$(function() { + + // register a handler to move the focus to the search bar + // upon pressing shift + "/" (i.e. "?") + $(document).on('keydown', function(e) { + if (e.shiftKey && e.keyCode == 191) { + e.preventDefault(); + $("#search-input").focus(); + } + }); + + $(document).ready(function() { + // do keyword highlighting + /* modified from https://jsfiddle.net/julmot/bL6bb5oo/ */ + var mark = function() { + + var referrer = document.URL ; + var paramKey = "q" ; + + if (referrer.indexOf("?") !== -1) { + var qs = referrer.substr(referrer.indexOf('?') + 1); + var qs_noanchor = qs.split('#')[0]; + var qsa = qs_noanchor.split('&'); + var keyword = ""; + + for (var i = 0; i < qsa.length; i++) { + var currentParam = qsa[i].split('='); + + if (currentParam.length !== 2) { + continue; + } + + if (currentParam[0] == paramKey) { + keyword = decodeURIComponent(currentParam[1].replace(/\+/g, "%20")); + } + } + + if (keyword !== "") { + $(".contents").unmark({ + done: function() { + $(".contents").mark(keyword); + } + }); + } + } + }; + + mark(); + }); +}); + +/* Search term highlighting ------------------------------*/ + +function matchedWords(hit) { + var words = []; + + var hierarchy = hit._highlightResult.hierarchy; + // loop to fetch from lvl0, lvl1, etc. + for (var idx in hierarchy) { + words = words.concat(hierarchy[idx].matchedWords); + } + + var content = hit._highlightResult.content; + if (content) { + words = words.concat(content.matchedWords); + } + + // return unique words + var words_uniq = [...new Set(words)]; + return words_uniq; +} + +function updateHitURL(hit) { + + var words = matchedWords(hit); + var url = ""; + + if (hit.anchor) { + url = hit.url_without_anchor + '?q=' + escape(words.join(" ")) + '#' + hit.anchor; + } else { + url = hit.url + '?q=' + escape(words.join(" ")); + } + + return url; +} diff --git a/dev/favicon-16x16.png b/dev/favicon-16x16.png new file mode 100644 index 00000000..d599928a Binary files /dev/null and b/dev/favicon-16x16.png differ diff --git a/dev/favicon-32x32.png b/dev/favicon-32x32.png new file mode 100644 index 00000000..5de52d8c Binary files /dev/null and b/dev/favicon-32x32.png differ diff --git a/dev/favicon.ico b/dev/favicon.ico new file mode 100644 index 00000000..52522cdd Binary files /dev/null and b/dev/favicon.ico differ diff --git a/dev/index.html b/dev/index.html new file mode 100644 index 00000000..a0d2474c --- /dev/null +++ b/dev/index.html @@ -0,0 +1,306 @@ + + + + + + + +Blocking and Randomization for Experimental Design • designit + + + + + + + + + + + + + + + + + + + + +
    +
    + + + + +
    +
    +
    + + + +

    The goal of designit is to generate optimal sample allocations for experimental designs.

    +
    +

    Installation +

    +

    You can install the development version from GitHub with:

    +
    +# install.packages("devtools")
    +devtools::install_github("BEDApub/designit")
    +
    +
    +

    Usage +

    +

    The main class used is BatchContainer, which holds the dimensions for sample allocation. After creating such a container, a list of samples can be allocated in it using a given assignment function.

    +
    +

    Creating a table with sample information +

    +
    +library(tidyverse)
    +library(designit)
    +
    +data("longitudinal_subject_samples")
    +
    +# we use a subset of longitudinal_subject_samples data
    +subject_data <- longitudinal_subject_samples %>% 
    +  filter(Group %in% 1:5, Week %in% c(1,4)) %>% 
    +  select(SampleID, SubjectID, Group, Sex, Week) %>%
    +  # with two observations per patient
    +  group_by(SubjectID) %>%
    +  filter(n() == 2) %>%
    +  ungroup() %>%
    +  select(SubjectID, Group, Sex) %>%
    +  distinct()
    +
    +head(subject_data)
    +#> # A tibble: 6 × 3
    +#>   SubjectID Group Sex  
    +#>   <chr>     <chr> <chr>
    +#> 1 P01       1     F    
    +#> 2 P02       1     M    
    +#> 3 P03       1     M    
    +#> 4 P04       1     F    
    +#> 5 P19       1     M    
    +#> 6 P20       1     F
    +
    +
    +

    Creating a BatchContainer and assigning samples +

    +
    +# a batch container with 3 batches and 11 locations per batch
    +bc <- BatchContainer$new(
    +  dimensions = list("batch" = 3, "location" = 11),
    +)
    +
    +# assign samples randomly
    +set.seed(17)
    +assign_random(bc, subject_data)
    +
    +bc$get_samples() %>%
    +  ggplot() +
    +  aes(x = batch, fill = Group) +
    +  geom_bar()
    +

    +

    Random assignmet of samples to batches produced an uneven distribution.

    +
    +
    +

    Optimizing the assignemnt +

    +
    +# set scoring functions
    +bc$scoring_f <- list(
    +  # first priority, groups are evenly distributed
    +  group = osat_score_generator(batch_vars = "batch", 
    +                               feature_vars = "Group"),
    +  # second priority, sexes are evenly distributed
    +  sex = osat_score_generator(batch_vars = "batch", 
    +                             feature_vars = "Sex")
    +)
    +
    +trace <- optimize_design(bc, max_iter = 150, quiet = TRUE)
    +
    +bc$get_samples() %>%
    +  ggplot() +
    +  aes(x = batch, fill = Group) +
    +  geom_bar()
    +

    +
    +
    +# show optimization trace
    +plot(trace)
    +

    +
    +
    +
    +

    Examples +

    +

    See vignettes vignette("basic_examples").

    +
    +
    +

    Acknowledgement +

    +

    The logo is inspired by DALL-E 2 and pipette icon by gsagri04.

    +
    +
    +
    + + +
    + + +
    + +
    +

    +

    Site built with pkgdown 2.0.7.

    +
    + +
    +
    + + + + + + + + diff --git a/dev/link.svg b/dev/link.svg new file mode 100644 index 00000000..88ad8276 --- /dev/null +++ b/dev/link.svg @@ -0,0 +1,12 @@ + + + + + + diff --git a/dev/logo.svg b/dev/logo.svg new file mode 100644 index 00000000..8be4741a --- /dev/null +++ b/dev/logo.svg @@ -0,0 +1,2 @@ + + diff --git a/dev/news/index.html b/dev/news/index.html new file mode 100644 index 00000000..ba808b03 --- /dev/null +++ b/dev/news/index.html @@ -0,0 +1,166 @@ + +Changelog • designit + + +
    +
    + + + +
    +
    + + +
    + +
    • multiplate wrapper
    • +
    • fixes in the OptimizationTrace
    • +
    • cleanup
    • +
    +
    + +
    • +BatchContainer stores locations table (dimensions & excluded)
    • +
    • +BatchContainer$new() accepts locations table
    • +
    • +BatchContainer with samples can be created using batch_container_from_table +
    • +
    • +bc$n_available was removed (use bc$n_locations instead)
    • +
    • minor improvements to print(bc) +
    • +
    +
    + +
    • fix dplyr filter issue (once again)
    • +
    • migrate from BEDA to PMDA
    • +
    +
    + +
    • fix dplyr filter issue
    • +
    +
    + +
    • fix plate scoring example vignette caching
    • +
    +
    + +
    • plate scoring
    • +
    +
    + +
    +
    + +
    • +BatchContainer major API update
    • +
    • rename fields for consistency
    • +
    • hide cachind ($samples_dt) behind $get_samples() +
    • +
    • +$sample_attr for sample attributes
    • +
    • unified $move_samples() for moving samples
    • +
    +
    + + + +
    + + +
    + +
    +

    Site built with pkgdown 2.0.7.

    +
    + +
    + + + + + + + + diff --git a/dev/pkgdown.css b/dev/pkgdown.css new file mode 100644 index 00000000..80ea5b83 --- /dev/null +++ b/dev/pkgdown.css @@ -0,0 +1,384 @@ +/* Sticky footer */ + +/** + * Basic idea: https://philipwalton.github.io/solved-by-flexbox/demos/sticky-footer/ + * Details: https://github.com/philipwalton/solved-by-flexbox/blob/master/assets/css/components/site.css + * + * .Site -> body > .container + * .Site-content -> body > .container .row + * .footer -> footer + * + * Key idea seems to be to ensure that .container and __all its parents__ + * have height set to 100% + * + */ + +html, body { + height: 100%; +} + +body { + position: relative; +} + +body > .container { + display: flex; + height: 100%; + flex-direction: column; +} + +body > .container .row { + flex: 1 0 auto; +} + +footer { + margin-top: 45px; + padding: 35px 0 36px; + border-top: 1px solid #e5e5e5; + color: #666; + display: flex; + flex-shrink: 0; +} +footer p { + margin-bottom: 0; +} +footer div { + flex: 1; +} +footer .pkgdown { + text-align: right; +} +footer p { + margin-bottom: 0; +} + +img.icon { + float: right; +} + +/* Ensure in-page images don't run outside their container */ +.contents img { + max-width: 100%; + height: auto; +} + +/* Fix bug in bootstrap (only seen in firefox) */ +summary { + display: list-item; +} + +/* Typographic tweaking ---------------------------------*/ + +.contents .page-header { + margin-top: calc(-60px + 1em); +} + +dd { + margin-left: 3em; +} + +/* Section anchors ---------------------------------*/ + +a.anchor { + display: none; + margin-left: 5px; + width: 20px; + height: 20px; + + background-image: url(./link.svg); + background-repeat: no-repeat; + background-size: 20px 20px; + background-position: center center; +} + +h1:hover .anchor, +h2:hover .anchor, +h3:hover .anchor, +h4:hover .anchor, +h5:hover .anchor, +h6:hover .anchor { + display: inline-block; +} + +/* Fixes for fixed navbar --------------------------*/ + +.contents h1, .contents h2, .contents h3, .contents h4 { + padding-top: 60px; + margin-top: -40px; +} + +/* Navbar submenu --------------------------*/ + +.dropdown-submenu { + position: relative; +} + +.dropdown-submenu>.dropdown-menu { + top: 0; + left: 100%; + margin-top: -6px; + margin-left: -1px; + border-radius: 0 6px 6px 6px; +} + +.dropdown-submenu:hover>.dropdown-menu { + display: block; +} + +.dropdown-submenu>a:after { + display: block; + content: " "; + float: right; + width: 0; + height: 0; + border-color: transparent; + border-style: solid; + border-width: 5px 0 5px 5px; + border-left-color: #cccccc; + margin-top: 5px; + margin-right: -10px; +} + +.dropdown-submenu:hover>a:after { + border-left-color: #ffffff; +} + +.dropdown-submenu.pull-left { + float: none; +} + +.dropdown-submenu.pull-left>.dropdown-menu { + left: -100%; + margin-left: 10px; + border-radius: 6px 0 6px 6px; +} + +/* Sidebar --------------------------*/ + +#pkgdown-sidebar { + margin-top: 30px; + position: -webkit-sticky; + position: sticky; + top: 70px; +} + +#pkgdown-sidebar h2 { + font-size: 1.5em; + margin-top: 1em; +} + +#pkgdown-sidebar h2:first-child { + margin-top: 0; +} + +#pkgdown-sidebar .list-unstyled li { + margin-bottom: 0.5em; +} + +/* bootstrap-toc tweaks ------------------------------------------------------*/ + +/* All levels of nav */ + +nav[data-toggle='toc'] .nav > li > a { + padding: 4px 20px 4px 6px; + font-size: 1.5rem; + font-weight: 400; + color: inherit; +} + +nav[data-toggle='toc'] .nav > li > a:hover, +nav[data-toggle='toc'] .nav > li > a:focus { + padding-left: 5px; + color: inherit; + border-left: 1px solid #878787; +} + +nav[data-toggle='toc'] .nav > .active > a, +nav[data-toggle='toc'] .nav > .active:hover > a, +nav[data-toggle='toc'] .nav > .active:focus > a { + padding-left: 5px; + font-size: 1.5rem; + font-weight: 400; + color: inherit; + border-left: 2px solid #878787; +} + +/* Nav: second level (shown on .active) */ + +nav[data-toggle='toc'] .nav .nav { + display: none; /* Hide by default, but at >768px, show it */ + padding-bottom: 10px; +} + +nav[data-toggle='toc'] .nav .nav > li > a { + padding-left: 16px; + font-size: 1.35rem; +} + +nav[data-toggle='toc'] .nav .nav > li > a:hover, +nav[data-toggle='toc'] .nav .nav > li > a:focus { + padding-left: 15px; +} + +nav[data-toggle='toc'] .nav .nav > .active > a, +nav[data-toggle='toc'] .nav .nav > .active:hover > a, +nav[data-toggle='toc'] .nav .nav > .active:focus > a { + padding-left: 15px; + font-weight: 500; + font-size: 1.35rem; +} + +/* orcid ------------------------------------------------------------------- */ + +.orcid { + font-size: 16px; + color: #A6CE39; + /* margins are required by official ORCID trademark and display guidelines */ + margin-left:4px; + margin-right:4px; + vertical-align: middle; +} + +/* Reference index & topics ----------------------------------------------- */ + +.ref-index th {font-weight: normal;} + +.ref-index td {vertical-align: top; min-width: 100px} +.ref-index .icon {width: 40px;} +.ref-index .alias {width: 40%;} +.ref-index-icons .alias {width: calc(40% - 40px);} +.ref-index .title {width: 60%;} + +.ref-arguments th {text-align: right; padding-right: 10px;} +.ref-arguments th, .ref-arguments td {vertical-align: top; min-width: 100px} +.ref-arguments .name {width: 20%;} +.ref-arguments .desc {width: 80%;} + +/* Nice scrolling for wide elements --------------------------------------- */ + +table { + display: block; + overflow: auto; +} + +/* Syntax highlighting ---------------------------------------------------- */ + +pre, code, pre code { + background-color: #f8f8f8; + color: #333; +} +pre, pre code { + white-space: pre-wrap; + word-break: break-all; + overflow-wrap: break-word; +} + +pre { + border: 1px solid #eee; +} + +pre .img, pre .r-plt { + margin: 5px 0; +} + +pre .img img, pre .r-plt img { + background-color: #fff; +} + +code a, pre a { + color: #375f84; +} + +a.sourceLine:hover { + text-decoration: none; +} + +.fl {color: #1514b5;} +.fu {color: #000000;} /* function */ +.ch,.st {color: #036a07;} /* string */ +.kw {color: #264D66;} /* keyword */ +.co {color: #888888;} /* comment */ + +.error {font-weight: bolder;} +.warning {font-weight: bolder;} + +/* Clipboard --------------------------*/ + +.hasCopyButton { + position: relative; +} + +.btn-copy-ex { + position: absolute; + right: 0; + top: 0; + visibility: hidden; +} + +.hasCopyButton:hover button.btn-copy-ex { + visibility: visible; +} + +/* headroom.js ------------------------ */ + +.headroom { + will-change: transform; + transition: transform 200ms linear; +} +.headroom--pinned { + transform: translateY(0%); +} +.headroom--unpinned { + transform: translateY(-100%); +} + +/* mark.js ----------------------------*/ + +mark { + background-color: rgba(255, 255, 51, 0.5); + border-bottom: 2px solid rgba(255, 153, 51, 0.3); + padding: 1px; +} + +/* vertical spacing after htmlwidgets */ +.html-widget { + margin-bottom: 10px; +} + +/* fontawesome ------------------------ */ + +.fab { + font-family: "Font Awesome 5 Brands" !important; +} + +/* don't display links in code chunks when printing */ +/* source: https://stackoverflow.com/a/10781533 */ +@media print { + code a:link:after, code a:visited:after { + content: ""; + } +} + +/* Section anchors --------------------------------- + Added in pandoc 2.11: https://github.com/jgm/pandoc-templates/commit/9904bf71 +*/ + +div.csl-bib-body { } +div.csl-entry { + clear: both; +} +.hanging-indent div.csl-entry { + margin-left:2em; + text-indent:-2em; +} +div.csl-left-margin { + min-width:2em; + float:left; +} +div.csl-right-inline { + margin-left:2em; + padding-left:1em; +} +div.csl-indent { + margin-left: 2em; +} diff --git a/dev/pkgdown.js b/dev/pkgdown.js new file mode 100644 index 00000000..6f0eee40 --- /dev/null +++ b/dev/pkgdown.js @@ -0,0 +1,108 @@ +/* http://gregfranko.com/blog/jquery-best-practices/ */ +(function($) { + $(function() { + + $('.navbar-fixed-top').headroom(); + + $('body').css('padding-top', $('.navbar').height() + 10); + $(window).resize(function(){ + $('body').css('padding-top', $('.navbar').height() + 10); + }); + + $('[data-toggle="tooltip"]').tooltip(); + + var cur_path = paths(location.pathname); + var links = $("#navbar ul li a"); + var max_length = -1; + var pos = -1; + for (var i = 0; i < links.length; i++) { + if (links[i].getAttribute("href") === "#") + continue; + // Ignore external links + if (links[i].host !== location.host) + continue; + + var nav_path = paths(links[i].pathname); + + var length = prefix_length(nav_path, cur_path); + if (length > max_length) { + max_length = length; + pos = i; + } + } + + // Add class to parent
  • , and enclosing
  • if in dropdown + if (pos >= 0) { + var menu_anchor = $(links[pos]); + menu_anchor.parent().addClass("active"); + menu_anchor.closest("li.dropdown").addClass("active"); + } + }); + + function paths(pathname) { + var pieces = pathname.split("/"); + pieces.shift(); // always starts with / + + var end = pieces[pieces.length - 1]; + if (end === "index.html" || end === "") + pieces.pop(); + return(pieces); + } + + // Returns -1 if not found + function prefix_length(needle, haystack) { + if (needle.length > haystack.length) + return(-1); + + // Special case for length-0 haystack, since for loop won't run + if (haystack.length === 0) { + return(needle.length === 0 ? 0 : -1); + } + + for (var i = 0; i < haystack.length; i++) { + if (needle[i] != haystack[i]) + return(i); + } + + return(haystack.length); + } + + /* Clipboard --------------------------*/ + + function changeTooltipMessage(element, msg) { + var tooltipOriginalTitle=element.getAttribute('data-original-title'); + element.setAttribute('data-original-title', msg); + $(element).tooltip('show'); + element.setAttribute('data-original-title', tooltipOriginalTitle); + } + + if(ClipboardJS.isSupported()) { + $(document).ready(function() { + var copyButton = ""; + + $("div.sourceCode").addClass("hasCopyButton"); + + // Insert copy buttons: + $(copyButton).prependTo(".hasCopyButton"); + + // Initialize tooltips: + $('.btn-copy-ex').tooltip({container: 'body'}); + + // Initialize clipboard: + var clipboardBtnCopies = new ClipboardJS('[data-clipboard-copy]', { + text: function(trigger) { + return trigger.parentNode.textContent.replace(/\n#>[^\n]*/g, ""); + } + }); + + clipboardBtnCopies.on('success', function(e) { + changeTooltipMessage(e.trigger, 'Copied!'); + e.clearSelection(); + }); + + clipboardBtnCopies.on('error', function() { + changeTooltipMessage(e.trigger,'Press Ctrl+C or Command+C to copy'); + }); + }); + } +})(window.jQuery || window.$) diff --git a/dev/pkgdown.yml b/dev/pkgdown.yml new file mode 100644 index 00000000..44e7f572 --- /dev/null +++ b/dev/pkgdown.yml @@ -0,0 +1,19 @@ +pandoc: 2.19.2 +pkgdown: 2.0.7 +pkgdown_sha: ~ +articles: + NCS22_talk: NCS22_talk.html + basic_examples: basic_examples.html + custom_shuffle: custom_shuffle.html + invivo_study_design: invivo_study_design.html + nested_dimensions_examples: nested_dimensions_examples.html + optimizer_examples: optimizer_examples.html + osat: osat.html + plate_layouts: plate_layouts.html + plate_scoring_examples: plate_scoring_examples.html + shuffling_with_constraints: shuffling_with_constraints.html +last_built: 2023-03-16T14:04Z +urls: + reference: https://bedapub.github.io/designit/reference + article: https://bedapub.github.io/designit/articles + diff --git a/dev/reference/BatchContainer.html b/dev/reference/BatchContainer.html new file mode 100644 index 00000000..30808da0 --- /dev/null +++ b/dev/reference/BatchContainer.html @@ -0,0 +1,385 @@ + +R6 Class representing a batch container. — BatchContainer • designit + + +
    +
    + + + +
    +
    + + +
    +

    Describes container dimensions and samples to container location assignment.

    +
    + + +
    +

    Details

    +

    A typical workflow starts with creating a BatchContainer. Then +samples can be assigned to locations in that container.

    +
    +
    +

    Active bindings

    +

    scoring_f
    +

    Scoring functions used for optimization. +Each scoring function should receive a BatchContainer. +This function should return a floating +point score value for the assignment. This a list of functions. +Upon assignment a single function will be automatically converted to a list +In the later case each function is called.

    + + +
    has_samples
    +

    Returns TRUE if BatchContainer has samples.

    + + +
    has_samples_attr
    +

    Returns TRUE if BatchContainer has sample atrributes assigned.

    + + +
    n_locations
    +

    Returns number of locations in a BatchContainer.

    + + +
    n_dimensions
    +

    Returns number of dimensions in a BatchContainer. +This field cannot be assigned.

    + + +
    dimension_names
    +

    character vector with dimension names. +This field cannot be assigned.

    + + +
    samples
    +

    Samples in the batch container. +When assigning data.frame should not have column named .sample_id column.

    + + +
    samples_attr
    +

    Extra attributes of samples. If set, this is included into +BatchContainer$get_samples() output.

    + + +
    assignment
    +

    Sample assignment vector. Should contain NAs for empty locations.

    +

    Assigning this field is deprecated, please use $move_samples() instead.

    + + +

    +
    +
    +

    Methods

    + +


    +

    Method new()

    +

    Create a new BatchContainer object.

    +

    Usage

    +

    BatchContainer$new(locations_table, dimensions, exclude = NULL)

    +
    + +
    +

    Arguments

    +

    locations_table
    +

    A table with available locations.

    + + +
    dimensions
    +

    A vector or list of dimensions. Every dimension +should have a name. Could be an integer vector of dimensions or +a named list. Every value of a list could be either dimension size +or parameters for +BatchContainerDimension$new(). +Can be used as an alternative to passing locations_table.

    + + +
    exclude
    +

    data.frame with excluded locations of a container. +Only used together with dimensions.

    + + +

    +
    +
    +

    Examples

    +

    bc <- BatchContainer$new(
    +  dimensions = list(
    +    "plate" = 3,
    +    "row" = list(values = letters[1:3]),
    +    "column" = list(values = c(1, 3))
    +  ),
    +  exclude = data.frame(plate = 1, row = "a", column = c(1, 3), stringsAsFactors = FALSE)
    +)
    +
    +bc

    +
    + + +


    +

    Method get_samples()

    +

    Return table with samples and sample assignment.

    +

    Usage

    +

    BatchContainer$get_samples(
    +  assignment = TRUE,
    +  include_id = FALSE,
    +  remove_empty_locations = FALSE,
    +  as_tibble = TRUE
    +)

    +
    + +
    +

    Arguments

    +

    assignment
    +

    Return sample assignment. If FALSE, only +samples table is returned, with out batch assignment.

    + + +
    include_id
    +

    Keep .sample_id in the table. Use TRUE for +lower overhead.

    + + +
    remove_empty_locations
    +

    Removes empty locations +from the result tibble.

    + + +
    as_tibble
    +

    Return tibble. +If FALSE returns data.table. This should have +lower overhead, as internally there is a cached data.table.

    + + +

    +
    +
    +

    Returns

    +

    table with samples and sample assignment.

    +
    + +


    +

    Method get_locations()

    +

    Get a table with all the locations in a BatchContainer.

    +

    Usage

    +

    BatchContainer$get_locations()

    +
    + +
    +

    Returns

    +

    A tibble with all the available locations.

    +
    + +


    +

    Method move_samples()

    +

    Move samples between locations

    +

    This method can receive either src and dst or locations_assignment.

    +

    Usage

    +

    BatchContainer$move_samples(src, dst, location_assignment)

    +
    + +
    +

    Arguments

    +

    src
    +

    integer vector of source locations

    + + +
    dst
    +

    integer vector of destination locations (the same length as src).

    + + +
    location_assignment
    +

    integer vector with location assignment. +The length of the vector should match the number of locations, +NA should be used for empty locations.

    + + +

    +
    +
    +

    Returns

    +

    BatchContainer, invisibly

    +
    + +


    +

    Method score()

    +

    Score current sample assignment,

    +

    Usage

    +

    BatchContainer$score()

    +
    + +
    +

    Returns

    +

    Returns a vector of all scoring functions values.

    +
    + +


    +

    Method copy()

    +

    Create an independent copy (clone) of a BatchContainer

    +

    Usage

    +

    BatchContainer$copy()

    +
    + +
    +

    Returns

    +

    Returns a new BatchContainer

    +
    + +


    +

    Method print()

    +

    Prints information about BatchContainer.

    +

    Usage

    +

    BatchContainer$print(...)

    +
    + +
    +

    Arguments

    +

    ...
    +

    not used. +List of scoring functions. +Tibble with batch container locations. +Tibble with sample information and sample ids. +Sample attributes, a data.table. +Vector with assignment of sample ids to locations. +Cached data.table with samples assignment. +Validate sample assignment.

    + + +

    +
    + +
    + +
    + +
    +

    Examples

    +
    
    +## ------------------------------------------------
    +## Method `BatchContainer$new`
    +## ------------------------------------------------
    +
    +bc <- BatchContainer$new(
    +  dimensions = list(
    +    "plate" = 3,
    +    "row" = list(values = letters[1:3]),
    +    "column" = list(values = c(1, 3))
    +  ),
    +  exclude = data.frame(plate = 1, row = "a", column = c(1, 3), stringsAsFactors = FALSE)
    +)
    +
    +bc
    +#> Batch container with 16 locations.
    +#>   Dimensions: plate, row, column
    +
    +
    +
    + +
    + + +
    + +
    +

    Site built with pkgdown 2.0.7.

    +
    + +
    + + + + + + + + diff --git a/dev/reference/BatchContainerDimension.html b/dev/reference/BatchContainerDimension.html new file mode 100644 index 00000000..1ea23040 --- /dev/null +++ b/dev/reference/BatchContainerDimension.html @@ -0,0 +1,232 @@ + +R6 Class representing a batch container dimension. — BatchContainerDimension • designit + + +
    +
    + + + +
    +
    + + +
    +

    R6 Class representing a batch container dimension.

    +

    R6 Class representing a batch container dimension.

    +
    + + +
    +

    Public fields

    +

    name
    +

    dimension name.

    + + +
    values
    +

    vector of dimension values.

    + + +

    +
    +
    +

    Active bindings

    +

    size
    +

    Returns size of a dimension.

    + + +
    short_info
    +

    Returns a string summarizing the dimension. +E.g., "mydim<size=10>".

    + + +

    +
    +
    +

    Methods

    + +


    +

    Method new()

    +

    Create a new BatchContainerDimension object.

    +

    This is usually used implicitly via BatchContainer$new().

    +

    Usage

    +

    BatchContainerDimension$new(name, size = NULL, values = NULL)

    +
    + +
    +

    Arguments

    +

    name
    +

    Dimension name, a character string. Requiered.

    + + +
    size
    +

    Dimension size. Setting this implies that dimension values are 1:size.

    + + +
    values
    +

    Explicit list of dimension values. Could be numeric, character or factor.

    +

    It is required to provide dimension namd and either size of values.

    + + +

    +
    +
    +

    Examples

    +

    plate_dimension <- BatchContainerDimension$new("plate", size=3)
    +row_dimension <- BatchContainerDimension$new("row", values = letters[1:3])
    +column_dimension <- BatchContainerDimension$new("column", values = 1:3)
    +
    +bc <- BatchContainer$new(
    +  dimensions = list(plate_dimension, row_dimension, column_dimension),
    +  exclude = data.frame(plate = 1, row = "a", column = c(1, 3), stringsAsFactors = FALSE)
    +)
    +
    +bc

    +
    + + +


    +

    Method clone()

    +

    The objects of this class are cloneable with this method.

    +

    Usage

    +

    BatchContainerDimension$clone(deep = FALSE)

    +
    + +
    +

    Arguments

    +

    deep
    +

    Whether to make a deep clone.

    + + +

    +
    + +
    + +
    + +
    +

    Examples

    +
    
    +## ------------------------------------------------
    +## Method `BatchContainerDimension$new`
    +## ------------------------------------------------
    +
    +plate_dimension <- BatchContainerDimension$new("plate", size=3)
    +row_dimension <- BatchContainerDimension$new("row", values = letters[1:3])
    +column_dimension <- BatchContainerDimension$new("column", values = 1:3)
    +
    +bc <- BatchContainer$new(
    +  dimensions = list(plate_dimension, row_dimension, column_dimension),
    +  exclude = data.frame(plate = 1, row = "a", column = c(1, 3), stringsAsFactors = FALSE)
    +)
    +
    +bc
    +#> Batch container with 25 locations.
    +#>   Dimensions: plate, row, column
    +
    +
    +
    + +
    + + +
    + +
    +

    Site built with pkgdown 2.0.7.

    +
    + +
    + + + + + + + + diff --git a/dev/reference/L1_norm.html b/dev/reference/L1_norm.html new file mode 100644 index 00000000..89bbb8fd --- /dev/null +++ b/dev/reference/L1_norm.html @@ -0,0 +1,144 @@ + +Aggregation of scores: L1 norm — L1_norm • designit + + +
    +
    + + + +
    +
    + + +
    +

    This function enables comparison of the results of two scoring functions by calculating +an L1 norm (Manhattan distance from origin).

    +
    + +
    +
    L1_norm(scores, ...)
    +
    + +
    +

    Arguments

    +
    scores
    +

    A score or multiple component score vector

    + + +
    ...
    +

    Parameters to be ignored by this aggregation function

    + +
    +
    +

    Value

    + + +

    The L1 norm as an aggregated score.

    +
    + +
    +

    Examples

    +
    L1_norm(c(2, 2))
    +#> [1] 4
    +
    +
    +
    + +
    + + +
    + +
    +

    Site built with pkgdown 2.0.7.

    +
    + +
    + + + + + + + + diff --git a/dev/reference/L2s_norm.html b/dev/reference/L2s_norm.html new file mode 100644 index 00000000..555b9419 --- /dev/null +++ b/dev/reference/L2s_norm.html @@ -0,0 +1,146 @@ + +Aggregation of scores: L2 norm squared — L2s_norm • designit + + +
    +
    + + + +
    +
    + + +
    +

    This function enables comparison of the results of two scoring functions by calculating +an L2 norm (euclidean distance from origin). Since this is only used for ranking solutions, +the squared L2 norm is returned.

    +
    + +
    +
    L2s_norm(scores, ...)
    +
    + +
    +

    Arguments

    +
    scores
    +

    A score or multiple component score vector

    + + +
    ...
    +

    Parameters to be ignored by this aggregation function

    + +
    +
    +

    Value

    + + +

    The squared L2 norm as an aggregated score.

    +
    + +
    +

    Examples

    +
    L2s_norm(c(2, 2))
    +#> [1] 8
    +
    +
    +
    + +
    + + +
    + +
    +

    Site built with pkgdown 2.0.7.

    +
    + +
    + + + + + + + + diff --git a/dev/reference/OptimizationTrace-1.png b/dev/reference/OptimizationTrace-1.png new file mode 100644 index 00000000..b53dc191 Binary files /dev/null and b/dev/reference/OptimizationTrace-1.png differ diff --git a/dev/reference/OptimizationTrace-2.png b/dev/reference/OptimizationTrace-2.png new file mode 100644 index 00000000..5eeb8260 Binary files /dev/null and b/dev/reference/OptimizationTrace-2.png differ diff --git a/dev/reference/OptimizationTrace.html b/dev/reference/OptimizationTrace.html new file mode 100644 index 00000000..49f0d526 --- /dev/null +++ b/dev/reference/OptimizationTrace.html @@ -0,0 +1,454 @@ + +OptimizationTrace represents optimization trace. — OptimizationTrace • designit + + +
    +
    + + + +
    +
    + + +
    +

    Usually it is created by optimize_design().

    +
    + + +
    +

    Public fields

    +

    scores
    +

    Contains a matrix of scores. The matrix size is usually +c(iterations + 1, length(bc$scoring_f))

    + + +
    aggregated_scores
    +

    Contains a matrix of scores after aggregation. +The matrix size is usually c(iterations + 1, length(aggregated)), +where length(aggregated) is the length of aggregated scores vector. +Can be NULL if aggregated scores are not used.

    + + +
    seed
    +

    Saved value of .Random.seed.

    + + +
    elapsed
    +

    Running time of the optimization.

    + + +
    last_step
    +

    Last iteration step for which the score was set.

    + + +

    +
    +
    +

    Active bindings

    +

    n_steps
    +

    Returns number of steps in the OptimizationTrace.

    + + +

    +
    +
    +

    Methods

    + +


    +

    Method new()

    +

    Create a new OptimizationTrace object.

    +

    Usage

    +

    OptimizationTrace$new(n_steps, n_scores, score_names)

    +
    + +
    +

    Arguments

    +

    n_steps
    +

    Number of values to save. Usually n_steps == iterations + 1.

    + + +
    n_scores
    +

    Number of scoring functions.

    + + +
    score_names
    +

    Names of scoring functions.

    + + +

    +
    +
    +

    Examples

    +

    tr <- OptimizationTrace$new(10, 2, c("score1", "score2"))

    +
    + + +


    +

    Method set_scores()

    +

    Set scores for i-th step.

    +

    Usage

    +

    OptimizationTrace$set_scores(i, scores, aggregated_scores)

    +
    + +
    +

    Arguments

    +

    i
    +

    Step number.

    + + +
    scores
    +

    Scores, a vector or a value if no auxiliary functions are used.

    + + +
    aggregated_scores
    +

    Vector of aggregated scores. Can be NULL.

    + + +

    +
    +
    +

    Returns

    +

    OptimizationTrace invisibly.

    +
    +
    +

    Examples

    +

    tr$set_scores(1, c(0.5, 0.5), NULL)
    +tr$set_scores(2, c(0.5, 0.5), NULL)

    +
    + + +


    +

    Method shrink()

    +

    Shrink scores by keeping only first last_step scores.

    +

    Usage

    +

    OptimizationTrace$shrink(last_step = self$last_step)

    +
    + +
    +

    Arguments

    +

    last_step
    +

    Last step to keep.

    + + +

    +
    +
    +

    Returns

    +

    OptimizationTrace invisibly.

    +
    +
    +

    Examples

    +

    tr$shrink(2)

    +
    + + +


    +

    Method get_scores()

    +

    Return individual (not aggregated!) scores by keeping only first last_step scores.

    +

    Usage

    +

    OptimizationTrace$get_scores(last_step = self$last_step)

    +
    + +
    +

    Arguments

    +

    last_step
    +

    Last step to keep.

    + + +

    +
    +
    +

    Returns

    +

    OptimizationTrace invisibly.

    +
    +
    +

    Examples

    +

    tr$get_scores()

    +
    + + +


    +

    Method print()

    +

    Print OptimizationTrace.

    +

    Usage

    +

    OptimizationTrace$print(...)

    +
    + +
    +

    Arguments

    +

    ...
    +

    Unused.

    + + +

    +
    +
    +

    Returns

    +

    OptimizationTrace invisibly.

    +
    +
    +

    Examples

    +

    print(tr)

    +
    + + +


    +

    Method as_tibble()

    +

    Convert to a data.frame.

    +

    Usage

    +

    OptimizationTrace$as_tibble(include_aggregated = TRUE)

    +
    + +
    +

    Arguments

    +

    include_aggregated
    +

    Include aggregated scores. Otherwise only +raw scores are exported.

    + + +

    +
    +
    +

    Returns

    +

    data.frame

    +
    +
    +

    Examples

    +

    tr$as_tibble()

    +
    + + +


    +

    Method plot()

    +

    Plot OptimizationTrace. Only the main score at the moment.

    +

    Usage

    +

    OptimizationTrace$plot(include_aggregated = FALSE, ...)

    +
    + +
    +

    Arguments

    +

    include_aggregated
    +

    Include aggregated scores. Otherwise only +raw scores are plotted.

    + + +
    ...
    +

    Not used.

    + + +

    +
    +
    +

    Examples

    +

    tr <- OptimizationTrace$new(10, 3, letters[1:3])
    +for (i in seq_len(10)) {
    +  tr$set_scores(i, rnorm(3)*(1:3), rnorm(3)*(1:3))
    +}
    +
    +# plot only the main scores
    +plot(tr)
    +# plot main and aggregated scores
    +plot(tr, include_aggregated=TRUE)

    +
    + + +


    +

    Method clone()

    +

    The objects of this class are cloneable with this method.

    +

    Usage

    +

    OptimizationTrace$clone(deep = FALSE)

    +
    + +
    +

    Arguments

    +

    deep
    +

    Whether to make a deep clone.

    + + +

    +
    + +
    + +
    + +
    +

    Examples

    +
    
    +## ------------------------------------------------
    +## Method `OptimizationTrace$new`
    +## ------------------------------------------------
    +
    +tr <- OptimizationTrace$new(10, 2, c("score1", "score2"))
    +
    +## ------------------------------------------------
    +## Method `OptimizationTrace$set_scores`
    +## ------------------------------------------------
    +
    +tr$set_scores(1, c(0.5, 0.5), NULL)
    +tr$set_scores(2, c(0.5, 0.5), NULL)
    +
    +## ------------------------------------------------
    +## Method `OptimizationTrace$shrink`
    +## ------------------------------------------------
    +
    +tr$shrink(2)
    +
    +## ------------------------------------------------
    +## Method `OptimizationTrace$get_scores`
    +## ------------------------------------------------
    +
    +tr$get_scores()
    +#>      score1 score2
    +#> [1,]    0.5    0.5
    +#> [2,]    0.5    0.5
    +
    +## ------------------------------------------------
    +## Method `OptimizationTrace$print`
    +## ------------------------------------------------
    +
    +print(tr)
    +#> Optimization trace (2 score values, elapsed NULL).
    +#>   Starting score: 0.5,0.5
    +#>   Final score   : 0.5,0.5
    +
    +## ------------------------------------------------
    +## Method `OptimizationTrace$as_tibble`
    +## ------------------------------------------------
    +
    +tr$as_tibble()
    +#> # A tibble: 4 × 4
    +#>   type   step score  value
    +#>   <fct> <int> <fct>  <dbl>
    +#> 1 score     1 score1   0.5
    +#> 2 score     1 score2   0.5
    +#> 3 score     2 score1   0.5
    +#> 4 score     2 score2   0.5
    +
    +## ------------------------------------------------
    +## Method `OptimizationTrace$plot`
    +## ------------------------------------------------
    +
    +tr <- OptimizationTrace$new(10, 3, letters[1:3])
    +for (i in seq_len(10)) {
    +  tr$set_scores(i, rnorm(3)*(1:3), rnorm(3)*(1:3))
    +}
    +
    +# plot only the main scores
    +plot(tr)
    +
    +# plot main and aggregated scores
    +plot(tr, include_aggregated=TRUE)
    +
    +
    +
    +
    + +
    + + +
    + +
    +

    Site built with pkgdown 2.0.7.

    +
    + +
    + + + + + + + + diff --git a/dev/reference/Rplot001.png b/dev/reference/Rplot001.png new file mode 100644 index 00000000..17a35806 Binary files /dev/null and b/dev/reference/Rplot001.png differ diff --git a/dev/reference/Rplot002.png b/dev/reference/Rplot002.png new file mode 100644 index 00000000..0bbcdf4e Binary files /dev/null and b/dev/reference/Rplot002.png differ diff --git a/dev/reference/Rplot003.png b/dev/reference/Rplot003.png new file mode 100644 index 00000000..9a94946e Binary files /dev/null and b/dev/reference/Rplot003.png differ diff --git a/dev/reference/accept_leftmost_improvement.html b/dev/reference/accept_leftmost_improvement.html new file mode 100644 index 00000000..cf45d510 --- /dev/null +++ b/dev/reference/accept_leftmost_improvement.html @@ -0,0 +1,145 @@ + +Alternative acceptance function for multi-dimensional scores in which order (left to right, e.g. first to last) denotes relevance. — accept_leftmost_improvement • designit + + +
    +
    + + + +
    +
    + + +
    +

    Alternative acceptance function for multi-dimensional scores in which order (left to right, e.g. first to last) denotes relevance.

    +
    + +
    +
    accept_leftmost_improvement(current_score, best_score, ..., tolerance = 0)
    +
    + +
    +

    Arguments

    +
    current_score
    +

    One- or multi-dimensional score from the current optimizing iteration (double or vector of doubles)

    + + +
    best_score
    +

    Best one- or multi-dimensional score found so far (double or vector of doubles)

    + + +
    ...
    +

    Ignored arguments that may be used by alternative acceptance functions

    + + +
    tolerance
    +

    Tolerance value: When comparing score vectors from left to right, differences within +/- tol won't immediately +shortcut the comparison at this point, allowing improvement in a less important score to exhibit some influence

    + +
    +
    +

    Value

    + + +

    Boolean, TRUE if current score should be taken as the new optimal score, FALSE otherwise

    +
    + +
    + +
    + + +
    + +
    +

    Site built with pkgdown 2.0.7.

    +
    + +
    + + + + + + + + diff --git a/dev/reference/accept_strict_improvement.html b/dev/reference/accept_strict_improvement.html new file mode 100644 index 00000000..53e2acc8 --- /dev/null +++ b/dev/reference/accept_strict_improvement.html @@ -0,0 +1,145 @@ + +Default acceptance function. Accept current score if and only if all elements are less than or equal than in best score +and there's at least one improvement. — accept_strict_improvement • designit + + +
    +
    + + + +
    +
    + + +
    +

    Default acceptance function. Accept current score if and only if all elements are less than or equal than in best score +and there's at least one improvement.

    +
    + +
    +
    accept_strict_improvement(current_score, best_score, ...)
    +
    + +
    +

    Arguments

    +
    current_score
    +

    One- or multi-dimensional score from the current optimizing iteration (double or vector of doubles)

    + + +
    best_score
    +

    Best one- or multi-dimensional score found so far (double or vector of doubles)

    + + +
    ...
    +

    Ignored arguments that may be used by alternative acceptance functions

    + +
    +
    +

    Value

    + + +

    Boolean, TRUE if current score should be taken as the new optimal score, FALSE otherwise

    +
    + +
    + +
    + + +
    + +
    +

    Site built with pkgdown 2.0.7.

    +
    + +
    + + + + + + + + diff --git a/dev/reference/assign_from_table.html b/dev/reference/assign_from_table.html new file mode 100644 index 00000000..10d212d2 --- /dev/null +++ b/dev/reference/assign_from_table.html @@ -0,0 +1,173 @@ + +Distributes samples based on a sample sheet. — assign_from_table • designit + + +
    +
    + + + +
    +
    + + +
    +

    Distributes samples based on a sample sheet.

    +
    + +
    +
    assign_from_table(batch_container, samples)
    +
    + +
    +

    Arguments

    +
    batch_container
    +

    Instance of BatchContainer class

    + + +
    samples
    +

    data.frame with samples (a sample sheet). This data.frame +(or tibble::tibble()) should contain samples together with their locations. No .sample_id +column can be present in the sample sheet. In batch_container already has samples assigned, +the function will check if samples in batch_container are identical to the ones in the +samples argument.

    + +
    +
    +

    Value

    + + +

    Returns BatchContainer, invisibly.

    +
    + +
    +

    Examples

    +
    bc <- BatchContainer$new(
    +  dimensions = list(
    +    plate = 2,
    +    column = list(values = letters[1:3]),
    +    row = 3
    +  )
    +)
    +
    +sample_sheet <- tibble::tribble(
    +  ~plate, ~column, ~row, ~sampleID, ~group,
    +  1, "a", 1, 1, "TRT",
    +  1, "b", 2, 2, "CNTRL",
    +  2, "a", 1, 3, "TRT",
    +  2, "b", 2, 4, "CNTRL",
    +  2, "a", 3, 5, "TRT",
    +)
    +# assign samples from the sample sheet
    +assign_from_table(bc, sample_sheet)
    +
    +bc$get_samples(remove_empty_locations = TRUE)
    +#> # A tibble: 5 × 5
    +#>   plate column   row sampleID group
    +#>   <int> <fct>  <int>    <dbl> <chr>
    +#> 1     1 a          1        1 TRT  
    +#> 2     1 b          2        2 CNTRL
    +#> 3     2 a          1        3 TRT  
    +#> 4     2 a          3        5 TRT  
    +#> 5     2 b          2        4 CNTRL
    +
    +
    +
    +
    + +
    + + +
    + +
    +

    Site built with pkgdown 2.0.7.

    +
    + +
    + + + + + + + + diff --git a/dev/reference/assign_in_order.html b/dev/reference/assign_in_order.html new file mode 100644 index 00000000..73304627 --- /dev/null +++ b/dev/reference/assign_in_order.html @@ -0,0 +1,180 @@ + +Distributes samples in order. — assign_in_order • designit + + +
    +
    + + + +
    +
    + + +
    +

    First sample is assigned to the first location, second +sample is assigned to the second location, etc.

    +
    + +
    +
    assign_in_order(batch_container, samples = NULL)
    +
    + +
    +

    Arguments

    +
    batch_container
    +

    Instance of BatchContainer class

    + + +
    samples
    +

    data.frame with samples.

    + +
    +
    +

    Value

    + + +

    Returns BatchContainer, invisibly.

    +
    + +
    +

    Examples

    +
    samples <- data.frame(sampId = 1:3, sampName = letters[1:3])
    +samples
    +#>   sampId sampName
    +#> 1      1        a
    +#> 2      2        b
    +#> 3      3        c
    +
    +bc <- BatchContainer$new(dimensions = c("row" = 3, "column" = 2))
    +bc
    +#> Batch container with 6 locations.
    +#>   Dimensions: row, column
    +
    +set.seed(42)
    +# assigns samples randomly
    +assign_random(bc, samples)
    +bc$get_samples()
    +#> # A tibble: 6 × 4
    +#>     row column sampId sampName
    +#>   <int>  <int>  <int> <chr>   
    +#> 1     1      1      1 a       
    +#> 2     1      2     NA NA      
    +#> 3     2      1     NA NA      
    +#> 4     2      2     NA NA      
    +#> 5     3      1      2 b       
    +#> 6     3      2      3 c       
    +
    +# assigns samples in order
    +assign_in_order(bc)
    +bc$get_samples()
    +#> # A tibble: 6 × 4
    +#>     row column sampId sampName
    +#>   <int>  <int>  <int> <chr>   
    +#> 1     1      1      1 a       
    +#> 2     1      2      2 b       
    +#> 3     2      1      3 c       
    +#> 4     2      2     NA NA      
    +#> 5     3      1     NA NA      
    +#> 6     3      2     NA NA      
    +
    +
    +
    + +
    + + +
    + +
    +

    Site built with pkgdown 2.0.7.

    +
    + +
    + + + + + + + + diff --git a/dev/reference/assign_random.html b/dev/reference/assign_random.html new file mode 100644 index 00000000..319acaab --- /dev/null +++ b/dev/reference/assign_random.html @@ -0,0 +1,178 @@ + +Assignment function which distributes samples randomly. — assign_random • designit + + +
    +
    + + + +
    +
    + + +
    +

    Assignment function which distributes samples randomly.

    +
    + +
    +
    assign_random(batch_container, samples = NULL)
    +
    + +
    +

    Arguments

    +
    batch_container
    +

    Instance of BatchContainer class

    + + +
    samples
    +

    data.frame with samples.

    + +
    +
    +

    Value

    + + +

    Returns BatchContainer, invisibly.

    +
    + +
    +

    Examples

    +
    samples <- data.frame(sampId = 1:3, sampName = letters[1:3])
    +samples
    +#>   sampId sampName
    +#> 1      1        a
    +#> 2      2        b
    +#> 3      3        c
    +
    +bc <- BatchContainer$new(dimensions = c("row" = 3, "column" = 2))
    +bc
    +#> Batch container with 6 locations.
    +#>   Dimensions: row, column
    +
    +set.seed(42)
    +# assigns samples randomly
    +assign_random(bc, samples)
    +bc$get_samples()
    +#> # A tibble: 6 × 4
    +#>     row column sampId sampName
    +#>   <int>  <int>  <int> <chr>   
    +#> 1     1      1      1 a       
    +#> 2     1      2     NA NA      
    +#> 3     2      1     NA NA      
    +#> 4     2      2     NA NA      
    +#> 5     3      1      2 b       
    +#> 6     3      2      3 c       
    +
    +# assigns samples in order
    +assign_in_order(bc)
    +bc$get_samples()
    +#> # A tibble: 6 × 4
    +#>     row column sampId sampName
    +#>   <int>  <int>  <int> <chr>   
    +#> 1     1      1      1 a       
    +#> 2     1      2      2 b       
    +#> 3     2      1      3 c       
    +#> 4     2      2     NA NA      
    +#> 5     3      1     NA NA      
    +#> 6     3      2     NA NA      
    +
    +
    +
    + +
    + + +
    + +
    +

    Site built with pkgdown 2.0.7.

    +
    + +
    + + + + + + + + diff --git a/dev/reference/batch_container_from_table.html b/dev/reference/batch_container_from_table.html new file mode 100644 index 00000000..b11f88b3 --- /dev/null +++ b/dev/reference/batch_container_from_table.html @@ -0,0 +1,153 @@ + +Creates a BatchContainer from a table +(data.frame/tibble::tibble) containing sample and location information. — batch_container_from_table • designit + + +
    +
    + + + +
    +
    + + +
    +

    Creates a BatchContainer from a table +(data.frame/tibble::tibble) containing sample and location information.

    +
    + +
    +
    batch_container_from_table(tab, location_cols)
    +
    + +
    +

    Arguments

    +
    tab
    +

    A table with location and sample information. +Table rows with all NAs in sample information columns are treated as empty +locations.

    + + +
    location_cols
    +

    Names of columns containing information about locations.

    + +
    +
    +

    Value

    + + +

    A BatchContainer assigned samples.

    +
    + +
    +

    Examples

    +
    tab <- data.frame(
    +  row = rep(1:3, each = 3),
    +  column = rep(1:3, 3),
    +  sample_id = c(1, 2, 3, NA, 5, 6, 7, NA, 9)
    +)
    +bc <- batch_container_from_table(tab, location_cols = c("row", "column"))
    +
    +
    +
    + +
    + + +
    + +
    +

    Site built with pkgdown 2.0.7.

    +
    + +
    + + + + + + + + diff --git a/dev/reference/compile_possible_subgroup_allocation.html b/dev/reference/compile_possible_subgroup_allocation.html new file mode 100644 index 00000000..0862c02e --- /dev/null +++ b/dev/reference/compile_possible_subgroup_allocation.html @@ -0,0 +1,146 @@ + +Compile list of all possible ways to assign levels of the allocation variable to a given set of subgroups — compile_possible_subgroup_allocation • designit + + +
    +
    + + + +
    +
    + + +
    +

    All information needed to perform this function (primarily the number and size of subgroups plus the levels of the +allocation variable) are contained in and extracted from the subgroup object.

    +
    + +
    +
    compile_possible_subgroup_allocation(
    +  subgroup_object,
    +  fullTree = FALSE,
    +  maxCalls = 1e+06
    +)
    +
    + +
    +

    Arguments

    +
    subgroup_object
    +

    A subgrouping object as returned by form_homogeneous_subgroups()

    + + +
    fullTree
    +

    Boolean: Enforce full search of the possibility tree, independent of the value of maxCalls

    + + +
    maxCalls
    +

    Maximum number of recursive calls in the search tree, to avoid long run times with very large trees

    + +
    +
    +

    Value

    + + +

    List of possible allocations; Each allocation is an integer vector of allocation levels that are assigned in that order to the subgroups with given sizes

    +
    + +
    + +
    + + +
    + +
    +

    Site built with pkgdown 2.0.7.

    +
    + +
    + + + + + + + + diff --git a/dev/reference/complete_random_shuffling.html b/dev/reference/complete_random_shuffling.html new file mode 100644 index 00000000..8bb33afd --- /dev/null +++ b/dev/reference/complete_random_shuffling.html @@ -0,0 +1,161 @@ + +Reshuffle sample indices completely randomly — complete_random_shuffling • designit + + +
    +
    + + + +
    +
    + + +
    +

    This function was just added to test early on the functionality of optimize_design() to accept a +permutation vector rather than a list with src and dst indices.

    +
    + +
    +
    complete_random_shuffling(batch_container, ...)
    +
    + +
    +

    Arguments

    +
    batch_container
    +

    The batch-container.

    + + +
    ...
    +

    Other params that are passed to a generic shuffling function (like the iteration number).

    + +
    +
    +

    Value

    + + +

    A random permutation of the sample assignment in the container.

    +
    + +
    +

    Examples

    +
    data("invivo_study_samples")
    +bc <- BatchContainer$new(
    +  dimensions = c("plate" = 2, "column" = 5, "row" = 6)
    +)
    +bc$scoring_f <- osat_score_generator("plate", "Sex")
    +optimize_design(
    +  bc, invivo_study_samples,
    +  max_iter = 100,
    +  shuffle_proposal_func = complete_random_shuffling
    +)
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Checking variances of 1-dim. score vector.
    +#> ... (142.337) - OK
    +#> Initial score: 182.5
    +#> Achieved score: 42.5 at iteration 1
    +#> Achieved score: 0.5 at iteration 2
    +#> Optimization trace (101 score values, elapsed 1.146403 secs).
    +#>   Starting score: 182.5
    +#>   Final score   : 0.5
    +
    +
    +
    + +
    + + +
    + +
    +

    Site built with pkgdown 2.0.7.

    +
    + +
    + + + + + + + + diff --git a/dev/reference/countGini.html b/dev/reference/countGini.html new file mode 100644 index 00000000..3a91a081 --- /dev/null +++ b/dev/reference/countGini.html @@ -0,0 +1,138 @@ + +Gini index on counts — countGini • designit + + +
    +
    + + + +
    +
    + + +
    +

    Gini index on a factor vector of counts using the Gini function +from the package ineq

    +
    + +
    +
    countGini(m)
    +
    + +
    +

    Arguments

    +
    m
    +

    a factor vector

    + +
    +
    +

    Value

    + + +

    the value of the Gini index

    +
    +
    +

    Author

    +

    Juliane Siebourg-Polster

    +
    + +
    + +
    + + +
    + +
    +

    Site built with pkgdown 2.0.7.

    +
    + +
    + + + + + + + + diff --git a/dev/reference/designit-package.html b/dev/reference/designit-package.html new file mode 100644 index 00000000..eae8fd8b --- /dev/null +++ b/dev/reference/designit-package.html @@ -0,0 +1,132 @@ + +designit: Blocking and Randomization for Experimental Design — designit-package • designit + + +
    +
    + + + +
    +
    + + +
    +

    Reducing batch effect by intellegently assigning samples to batches. Batch-effect have a strong influence in data analysis, especially when samples-to-batches assignent is coinciding with contrast groups. By defining your batch container and a scoring function reflecting the contrasts, you can assign samples in such a way that the potential batch-effect has minimal effect on the comparison of interest.

    +
    + + + +
    +

    Author

    +

    Maintainer: Iakov I. Davydov iakov.davydov@roche.com (ORCID) [copyright holder]

    +

    Authors:

    Other contributors:

    • F. Hoffman-La Roche [copyright holder, funder]

    • +
    + +
    + +
    + + +
    + +
    +

    Site built with pkgdown 2.0.7.

    +
    + +
    + + + + + + + + diff --git a/dev/reference/dot-datatable.aware.html b/dev/reference/dot-datatable.aware.html new file mode 100644 index 00000000..a6b7baed --- /dev/null +++ b/dev/reference/dot-datatable.aware.html @@ -0,0 +1,137 @@ + +This undocumented (?) flag allows us to use := +without getting an error. — .datatable.aware • designit + + +
    +
    + + + +
    +
    + + +
    +

    This undocumented (?) flag allows us to use := +without getting an error.

    +
    + +
    +
    .datatable.aware
    +
    + +
    +

    Format

    +

    An object of class logical of length 1.

    +
    + +
    +

    Examples

    +
    if (FALSE) {
    +dt <- data.table::data.table(a = 1, b = 2)
    +dt[, a := NULL]
    +}
    +
    +
    +
    + +
    + + +
    + +
    +

    Site built with pkgdown 2.0.7.

    +
    + +
    + + + + + + + + diff --git a/dev/reference/drop_order.html b/dev/reference/drop_order.html new file mode 100644 index 00000000..eccb1912 --- /dev/null +++ b/dev/reference/drop_order.html @@ -0,0 +1,130 @@ + +Drop highest order interactions — drop_order • designit + + +
    +
    + + + +
    +
    + + +
    +

    Drop highest order interactions

    +
    + +
    +
    drop_order(.terms, m = -1)
    +
    + +
    +

    Arguments

    +
    .terms
    +

    terms.object

    + + +
    m
    +

    order of interaction (highest available if -1)

    + +
    + +
    + +
    + + +
    + +
    +

    Site built with pkgdown 2.0.7.

    +
    + +
    + + + + + + + + diff --git a/dev/reference/extract_shuffle_params.html b/dev/reference/extract_shuffle_params.html new file mode 100644 index 00000000..5940572c --- /dev/null +++ b/dev/reference/extract_shuffle_params.html @@ -0,0 +1,149 @@ + +Extract relevant parameters from a generic shuffle function output — extract_shuffle_params • designit + + +
    +
    + + + +
    +
    + + +
    +

    Any shuffling function should return one of the following:

    1. atomic index vector for a direct location assignment

    2. +
    3. a list with src and dst vector

    4. +
    5. a list with locations vector (for location assignment) and optional sample_attr data frame/tibble

    6. +
    + +
    +
    extract_shuffle_params(shuffle, attributes_expected)
    +
    + +
    +

    Arguments

    +
    shuffle
    +

    Return value of a shuffle function

    + + +
    attributes_expected
    +

    Logical; if TRUE, sample attributes are expected from the shuffling result and the +function dies if they are not provided.

    + +
    +
    +

    Value

    + + +

    A list with components src, dst, location_assignment and samples_attr, depending on the output +of the specific shuffling function

    +
    +
    +

    Details

    +

    This function parses the output, performs a few checks and returns results in a simple-to-use list.

    +
    + +
    + +
    + + +
    + +
    +

    Site built with pkgdown 2.0.7.

    +
    + +
    + + + + + + + + diff --git a/dev/reference/figures/README-optimized_assignment-1.png b/dev/reference/figures/README-optimized_assignment-1.png new file mode 100644 index 00000000..d2f931ee Binary files /dev/null and b/dev/reference/figures/README-optimized_assignment-1.png differ diff --git a/dev/reference/figures/README-optimized_assignment-2.png b/dev/reference/figures/README-optimized_assignment-2.png new file mode 100644 index 00000000..0b61a4b1 Binary files /dev/null and b/dev/reference/figures/README-optimized_assignment-2.png differ diff --git a/dev/reference/figures/README-random_assignment-1.png b/dev/reference/figures/README-random_assignment-1.png new file mode 100644 index 00000000..af7c6479 Binary files /dev/null and b/dev/reference/figures/README-random_assignment-1.png differ diff --git a/dev/reference/figures/logo-inkscape.svg b/dev/reference/figures/logo-inkscape.svg new file mode 100644 index 00000000..b6b73103 --- /dev/null +++ b/dev/reference/figures/logo-inkscape.svg @@ -0,0 +1,201 @@ + + + +designit diff --git a/dev/reference/figures/logo-web.svg b/dev/reference/figures/logo-web.svg new file mode 100644 index 00000000..8be4741a --- /dev/null +++ b/dev/reference/figures/logo-web.svg @@ -0,0 +1,2 @@ + + diff --git a/dev/reference/figures/logo.svg b/dev/reference/figures/logo.svg new file mode 100644 index 00000000..8be4741a --- /dev/null +++ b/dev/reference/figures/logo.svg @@ -0,0 +1,2 @@ + + diff --git a/dev/reference/find_possible_block_allocations.html b/dev/reference/find_possible_block_allocations.html new file mode 100644 index 00000000..12a11036 --- /dev/null +++ b/dev/reference/find_possible_block_allocations.html @@ -0,0 +1,151 @@ + +Internal function to generate possible subgroup combinations that add up to specific levels of an allocation variable — find_possible_block_allocations • designit + + +
    +
    + + + +
    +
    + + +
    +

    Internal function to generate possible subgroup combinations that add up to specific levels of an allocation variable

    +
    + +
    +
    find_possible_block_allocations(
    +  block_sizes,
    +  group_nums,
    +  fullTree = FALSE,
    +  maxCalls = 1e+06
    +)
    +
    + +
    +

    Arguments

    +
    block_sizes
    +

    (Integer) vector of sizes of the various subgroups that can be combined to form groups

    + + +
    group_nums
    +

    Vector of sizes of the different groups to be formed

    + + +
    fullTree
    +

    Boolean: Enforce full search of the possibility tree, independent of the value of maxCalls

    + + +
    maxCalls
    +

    Maximum number of recursive calls in the search tree, to avoid long run times with very large trees

    + +
    +
    +

    Value

    + + +

    List of possible allocations; Each allocation is an integer vector of allocation levels that are assigned in that order to the subgroups with sizes given by block sizes

    + + +
    + +
    + +
    + + +
    + +
    +

    Site built with pkgdown 2.0.7.

    +
    + +
    + + + + + + + + diff --git a/dev/reference/first_score_only.html b/dev/reference/first_score_only.html new file mode 100644 index 00000000..9d0f71b8 --- /dev/null +++ b/dev/reference/first_score_only.html @@ -0,0 +1,146 @@ + +Aggregation of scores: take first (primary) score only — first_score_only • designit + + +
    +
    + + + +
    +
    + + +
    +

    This function enables comparison of the results of two scoring functions by just basing +the decision on the first element. This reflects the original behavior of the optimization +function, just evaluating the 'auxiliary' scores for the user's information.

    +
    + +
    +
    first_score_only(scores, ...)
    +
    + +
    +

    Arguments

    +
    scores
    +

    A score or multiple component score vector

    + + +
    ...
    +

    Parameters to be ignored by this aggregation function

    + +
    +
    +

    Value

    + + +

    The aggregated score, i.e. the first element of a multiple-component score vector.

    +
    + +
    +

    Examples

    +
    first_score_only(c(1, 2, 3))
    +#> [1] 1
    +
    +
    +
    + +
    + + +
    + +
    +

    Site built with pkgdown 2.0.7.

    +
    + +
    + + + + + + + + diff --git a/dev/reference/form_homogeneous_subgroups.html b/dev/reference/form_homogeneous_subgroups.html new file mode 100644 index 00000000..3acd698c --- /dev/null +++ b/dev/reference/form_homogeneous_subgroups.html @@ -0,0 +1,176 @@ + +Form groups and subgroups of 'homogeneous' samples as defined by certain variables and size constraints — form_homogeneous_subgroups • designit + + +
    +
    + + + +
    +
    + + +
    +

    Form groups and subgroups of 'homogeneous' samples as defined by certain variables and size constraints

    +
    + +
    +
    form_homogeneous_subgroups(
    +  batch_container,
    +  allocate_var,
    +  keep_together_vars = c(),
    +  n_min = NA,
    +  n_max = NA,
    +  n_ideal = NA,
    +  subgroup_var_name = NULL,
    +  prefer_big_groups = TRUE,
    +  strict = TRUE
    +)
    +
    + +
    +

    Arguments

    +
    batch_container
    +

    Batch container with all samples assigned that are to be grouped and sub-grouped

    + + +
    allocate_var
    +

    Name of a variable in the samples table to inform possible groupings, as (sub)group sizes must add up to the correct totals

    + + +
    keep_together_vars
    +

    Vector of column names in sample table; groups are formed by pooling samples with identical values of all those variables

    + + +
    n_min
    +

    Minimal number of samples in one sub(!)group; by default 1

    + + +
    n_max
    +

    Maximal number of samples in one sub(!)group; by default the size of the biggest group

    + + +
    n_ideal
    +

    Ideal number of samples in one sub(!)group; by default the floor or ceiling of mean(n_min,n_max), depending on the setting of prefer_big_groups

    + + +
    subgroup_var_name
    +

    An optional column name for the subgroups which are formed (or NULL)

    + + +
    prefer_big_groups
    +

    Boolean; indicating whether or not bigger subgroups should be preferred in case of several possibilities

    + + +
    strict
    +

    Boolean; if TRUE, subgroup size constraints have to be met strictly, implying the possibility of finding no solution at all

    + +
    +
    +

    Value

    + + +

    Subgroup object to be used in subsequent calls to compile_possible_subgroup_allocation()

    + + +
    + +
    + +
    + + +
    + +
    +

    Site built with pkgdown 2.0.7.

    +
    + +
    + + + + + + + + diff --git a/dev/reference/generate_terms.html b/dev/reference/generate_terms.html new file mode 100644 index 00000000..fba8e193 --- /dev/null +++ b/dev/reference/generate_terms.html @@ -0,0 +1,138 @@ + +Generate terms.object (formula with attributes) — generate_terms • designit + + +
    +
    + + + +
    +
    + + +
    +

    Generate terms.object (formula with attributes)

    +
    + +
    +
    generate_terms(.tbl, ...)
    +
    + +
    +

    Arguments

    +
    .tbl
    +

    data

    + + +
    ...
    +

    columns to skip (unquoted)

    + +
    +
    +

    Value

    + + +

    terms.object

    + + +
    + +
    + +
    + + +
    + +
    +

    Site built with pkgdown 2.0.7.

    +
    + +
    + + + + + + + + diff --git a/dev/reference/getScore.html b/dev/reference/getScore.html new file mode 100644 index 00000000..9436fbd2 --- /dev/null +++ b/dev/reference/getScore.html @@ -0,0 +1,165 @@ + +get Score — getScore • designit + + +
    +
    + + + +
    +
    + + +
    +

    Summary score for an experimental layout based on the distribution of levels +of the factors to be balanced.

    +
    + +
    +
    getScore(
    +  layout,
    +  balance,
    +  sc_groups,
    +  sc_tests,
    +  bal_weights = rep(1, length(balance)),
    +  sc_weights = rep(1, length(sc_groups))
    +)
    +
    + +
    +

    Arguments

    +
    layout
    +

    a data.frame with the factors to be balanced and their current positions

    + + +
    balance
    +

    a vector with the names of experimental conditions to be balanced

    + + +
    sc_groups
    +

    list of dimension name groups to be used jointly for scoring

    + + +
    sc_tests
    +

    list of tests to use for each scoring group

    + + +
    bal_weights
    +

    named vector of weights for the factors to be balanced (default all 1)

    + + +
    sc_weights
    +

    named vector of weights for the dimensions (default all 1)

    + +
    +
    +

    Value

    + + +

    the summarized penalty score

    +
    +
    +

    Author

    +

    Juliane Siebourg-Polster

    +
    + +
    + +
    + + +
    + +
    +

    Site built with pkgdown 2.0.7.

    +
    + +
    + + + + + + + + diff --git a/dev/reference/get_order.html b/dev/reference/get_order.html new file mode 100644 index 00000000..f00af5ca --- /dev/null +++ b/dev/reference/get_order.html @@ -0,0 +1,132 @@ + +Get highest order interaction — get_order • designit + + +
    +
    + + + +
    +
    + + +
    +

    Get highest order interaction

    +
    + +
    +
    get_order(.terms)
    +
    + +
    +

    Arguments

    +
    .terms
    +

    terms.object

    + +
    +
    +

    Value

    + + +

    highest order (numeric).

    +
    + +
    + +
    + + +
    + +
    +

    Site built with pkgdown 2.0.7.

    +
    + +
    + + + + + + + + diff --git a/dev/reference/index.html b/dev/reference/index.html new file mode 100644 index 00000000..6e54370f --- /dev/null +++ b/dev/reference/index.html @@ -0,0 +1,296 @@ + +Function reference • designit + + +
    +
    + + + +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +

    All functions

    +

    +
    +

    BatchContainer

    +

    R6 Class representing a batch container.

    +

    BatchContainerDimension

    +

    R6 Class representing a batch container dimension.

    +

    L1_norm()

    +

    Aggregation of scores: L1 norm

    +

    L2s_norm()

    +

    Aggregation of scores: L2 norm squared

    +

    OptimizationTrace

    +

    OptimizationTrace represents optimization trace.

    +

    accept_leftmost_improvement()

    +

    Alternative acceptance function for multi-dimensional scores in which order (left to right, e.g. first to last) denotes relevance.

    +

    assign_from_table()

    +

    Distributes samples based on a sample sheet.

    +

    assign_in_order()

    +

    Distributes samples in order.

    +

    assign_random()

    +

    Assignment function which distributes samples randomly.

    +

    batch_container_from_table()

    +

    Creates a BatchContainer from a table +(data.frame/tibble::tibble) containing sample and location information.

    +

    compile_possible_subgroup_allocation()

    +

    Compile list of all possible ways to assign levels of the allocation variable to a given set of subgroups

    +

    complete_random_shuffling()

    +

    Reshuffle sample indices completely randomly

    +

    countGini()

    +

    Gini index on counts

    +

    drop_order()

    +

    Drop highest order interactions

    +

    first_score_only()

    +

    Aggregation of scores: take first (primary) score only

    +

    form_homogeneous_subgroups()

    +

    Form groups and subgroups of 'homogeneous' samples as defined by certain variables and size constraints

    +

    generate_terms()

    +

    Generate terms.object (formula with attributes)

    +

    getScore()

    +

    get Score

    +

    get_order()

    +

    Get highest order interaction

    +

    invivo_study_samples

    +

    A sample list from an in vivo experiment with multiple treatments and 2 strains

    +

    invivo_study_treatments

    +

    A treatment list together with additional constraints on the strain and sex of animals

    +

    kruskal()

    +

    Kruskal Wallis on Layout dimension

    +

    locations_table_from_dimensions()

    +

    Create locations table from dimensions and exclude table

    +

    longitudinal_subject_samples

    +

    Subject sample list with group and time plus controls

    +

    meanDiff()

    +

    Mean difference

    +

    mk_exponentially_weighted_acceptance_func()

    +

    Alternative acceptance function for multi-dimensional scores with exponentially downweighted score improvements from left to right

    +

    mk_plate_scoring_functions()

    +

    Create a list of scoring functions (one per plate) that quantify the spatially homogeneous distribution of conditions across the plate

    +

    mk_simanneal_acceptance_func()

    +

    Generate acceptance function for an optimization protocol based on simulated annealing

    +

    mk_simanneal_temp_func()

    +

    Create a temperature function that returns the annealing temperature at a given step (iteration)

    +

    mk_subgroup_shuffling_function()

    +

    Created a shuffling function that permutes samples within certain subgroups of the container locations

    +

    mk_swapping_function()

    +

    Create function to propose swaps of samples on each call, either with a constant number of swaps or following +a user defined protocol

    +

    multi_trt_day_samples

    +

    Unbalanced treatment and time sample list

    +

    neighbors()

    +

    Penalty for neighbors with same level

    +

    optimize_design()

    +

    Generic optimizer that can be customized by user provided functions for generating shuffles and progressing towards the minimal score

    +

    optimize_multi_plate_design()

    +

    Convenience wrapper to optimize a typical multi-plate design

    +

    osat_score()

    +

    Compute OSAT score for sample assignment.

    +

    osat_score_generator()

    +

    Convenience wrapper for the OSAT score

    +

    plot_plate()

    +

    Plot plate layouts

    +

    randomize()

    +

    randomize experimental layout

    +

    shuffle_grouped_data()

    +

    Generate in one go a shuffling function that produces permutations with specific constraints on multiple sample variables and group sizes fitting one specific allocation variable

    +

    shuffle_with_constraints()

    +

    Shuffling proposal function with constraints.

    +

    shuffle_with_subgroup_formation()

    +

    Compose shuffling function based on already available subgrouping and allocation information

    +

    sum_scores()

    +

    Aggregation of scores: sum up all individual scores

    +

    validate_samples()

    +

    Validates sample data.frame.

    +

    worst_score()

    +

    Aggregation of scores: take the maximum (i.e. worst score only)

    + + +
    + + +
    + +
    +

    Site built with pkgdown 2.0.7.

    +
    + +
    + + + + + + + + diff --git a/dev/reference/invivo_study_samples.html b/dev/reference/invivo_study_samples.html new file mode 100644 index 00000000..207ac3c0 --- /dev/null +++ b/dev/reference/invivo_study_samples.html @@ -0,0 +1,152 @@ + +A sample list from an in vivo experiment with multiple treatments and 2 strains — invivo_study_samples • designit + + +
    +
    + + + +
    +
    + + +
    +

    This sample list is intended to be used in connection with the "invivo_study_treatments" data object

    +
    + +
    +
    data(invivo_study_samples)
    +
    + +
    +

    Format

    +

    An object of class "tibble"

    AnimalID
    +

    The animal IDs, i.e. unique identifiers for each animal

    + +
    Strain
    +

    Strain (A or B)

    + +
    Sex
    +

    Female (F) or Male (M)

    + +
    BirthDate
    +

    Date of birth, not available for all the animals

    + +
    Earmark
    +

    Markings to distinguish individual animals, applied on the left (L), right (R) or both(B) ears

    + +
    ArrivalWeight
    +

    Initial body weight of the animal

    + +
    Arrival weight Unit
    +

    Unit of the body weight, here: grams

    + +
    Litter
    +

    The litter IDs, grouping offspring from one set of parents

    + + +
    +
    +

    Author

    +

    Guido Steiner

    +
    + +
    + +
    + + +
    + +
    +

    Site built with pkgdown 2.0.7.

    +
    + +
    + + + + + + + + diff --git a/dev/reference/invivo_study_treatments.html b/dev/reference/invivo_study_treatments.html new file mode 100644 index 00000000..b1259607 --- /dev/null +++ b/dev/reference/invivo_study_treatments.html @@ -0,0 +1,137 @@ + +A treatment list together with additional constraints on the strain and sex of animals — invivo_study_treatments • designit + + +
    +
    + + + +
    +
    + + +
    +

    This treatment list is intended to be used in connection with the "invivo_study_samples" data object

    +
    + +
    +
    data(invivo_study_treatments)
    +
    + +
    +

    Format

    +

    An object of class "tibble"

    Treatment
    +

    The treatment to be given to an individual animal (1-3, plus a few untreated cases)

    + +
    Strain
    +

    Strain (A or B) - a constraint which kind of animal may receive the respective treatment

    + +
    Sex
    +

    Female (F) or Male (M) - a constraint which kind of animal may receive the respective treatment

    + + +
    +
    +

    Author

    +

    Guido Steiner

    +
    + +
    + +
    + + +
    + +
    +

    Site built with pkgdown 2.0.7.

    +
    + +
    + + + + + + + + diff --git a/dev/reference/kruskal.html b/dev/reference/kruskal.html new file mode 100644 index 00000000..dea5f7a5 --- /dev/null +++ b/dev/reference/kruskal.html @@ -0,0 +1,138 @@ + +Kruskal Wallis on Layout dimension — kruskal • designit + + +
    +
    + + + +
    +
    + + +
    +

    Kruskal-Wallis test statistic from the ranking of a factor vector +TODO: This is currently not used, it does not optimize for the correct layout

    +
    + +
    +
    kruskal(m)
    +
    + +
    +

    Arguments

    +
    m
    +

    a factor vector

    + +
    +
    +

    Value

    + + +

    the Kruskal-Wallis rank sum statistic

    +
    +
    +

    Author

    +

    Juliane Siebourg-Polster

    +
    + +
    + +
    + + +
    + +
    +

    Site built with pkgdown 2.0.7.

    +
    + +
    + + + + + + + + diff --git a/dev/reference/locations_table_from_dimensions.html b/dev/reference/locations_table_from_dimensions.html new file mode 100644 index 00000000..0a9651ff --- /dev/null +++ b/dev/reference/locations_table_from_dimensions.html @@ -0,0 +1,139 @@ + +Create locations table from dimensions and exclude table — locations_table_from_dimensions • designit + + +
    +
    + + + +
    +
    + + +
    +

    Create locations table from dimensions and exclude table

    +
    + +
    +
    locations_table_from_dimensions(dimensions, exclude)
    +
    + +
    +

    Arguments

    +
    dimensions
    +

    A vector or list of dimensions. Every dimension +should have a name. Could be an integer vector of dimensions or +a named list. Every value of a list could be either dimension size +or parameters for BatchContainerDimension$new().

    + + +
    exclude
    +

    data.frame with excluded locations of a container.

    + +
    +
    +

    Value

    + + +

    a tibble::tibble() with all the available locations.

    +
    + +
    + +
    + + +
    + +
    +

    Site built with pkgdown 2.0.7.

    +
    + +
    + + + + + + + + diff --git a/dev/reference/longitudinal_subject_samples.html b/dev/reference/longitudinal_subject_samples.html new file mode 100644 index 00000000..80509a77 --- /dev/null +++ b/dev/reference/longitudinal_subject_samples.html @@ -0,0 +1,166 @@ + +Subject sample list with group and time plus controls — longitudinal_subject_samples • designit + + +
    +
    + + + +
    +
    + + +
    +

    A sample list with 9 columns as described below. +There are 3 types of records (rows) indicated by the SampleType variable. +Patient samples, controls and spike-in standards. +Patient samples were collected over up to 7 time points. +Controls and SpikeIns are QC samples for distribution of the samples on +96 well plates.

    +
    + +
    +
    data(longitudinal_subject_samples)
    +
    + +
    +

    Format

    +

    An object of class "tibble"

    SampleID
    +

    A unique sample identifier.

    + +
    SampleType
    +

    Indicates whether the sample is a patient sample, control oder spike-in.

    + +
    SubjectID
    +

    The subject identifier.

    + +
    Group
    +

    Indicates the treatment group of a subject.

    + +
    Week
    +

    Sampling time points in weeks of study.

    + +
    Sex
    +

    Subject Sex, Female (F) or Male (M).

    + +
    Age
    +

    Subject age.

    + +
    BMI
    +

    Subject Body Mass Index.

    + +
    SamplesPerSubject
    +

    Look up variable for the number of samples per subject. +This varies as not subject have samples from all weeks.

    + + +
    +
    +

    Author

    +

    Juliane Siebourg

    +
    + +
    + +
    + + +
    + +
    +

    Site built with pkgdown 2.0.7.

    +
    + +
    + + + + + + + + diff --git a/dev/reference/make_colnames.html b/dev/reference/make_colnames.html new file mode 100644 index 00000000..c9cf4c12 --- /dev/null +++ b/dev/reference/make_colnames.html @@ -0,0 +1,132 @@ + +Make matrix column names unique. — make_colnames • designit + + +
    +
    + + + +
    +
    + + +
    +

    Make matrix column names unique.

    +
    + +
    +
    make_colnames(m, prefix = "X")
    +
    + +
    +

    Arguments

    +
    prefix
    +

    Prefix to add if column names are empty.

    + +
    +
    +

    Value

    + + +

    A matrix with updated column names.

    +
    + +
    + +
    + + +
    + +
    +

    Site built with pkgdown 2.0.7.

    +
    + +
    + + + + + + + + diff --git a/dev/reference/meanDiff.html b/dev/reference/meanDiff.html new file mode 100644 index 00000000..569d384b --- /dev/null +++ b/dev/reference/meanDiff.html @@ -0,0 +1,136 @@ + +Mean difference — meanDiff • designit + + +
    +
    + + + +
    +
    + + +
    +

    Mean differens on vector to score continuous variables

    +
    + +
    +
    meanDiff(m)
    +
    + +
    +

    Arguments

    +
    m
    +

    a numeric vector

    + +
    +
    +

    Value

    + + +

    the mean difference

    +
    +
    +

    Author

    +

    Juliane Siebourg-Polster

    +
    + +
    + +
    + + +
    + +
    +

    Site built with pkgdown 2.0.7.

    +
    + +
    + + + + + + + + diff --git a/dev/reference/mk_autoscale_function.html b/dev/reference/mk_autoscale_function.html new file mode 100644 index 00000000..1cf8b3ba --- /dev/null +++ b/dev/reference/mk_autoscale_function.html @@ -0,0 +1,150 @@ + +Create a function that transforms a current (multi-dimensional) score into a boxcox normalized one — mk_autoscale_function • designit + + +
    +
    + + + +
    +
    + + +
    +

    Create a function that transforms a current (multi-dimensional) score into a boxcox normalized one

    +
    + +
    +
    mk_autoscale_function(
    +  batch_container,
    +  random_perm,
    +  use_boxcox = TRUE,
    +  sample_attributes_fixed = FALSE
    +)
    +
    + +
    +

    Arguments

    +
    batch_container
    +

    An instance of BatchContainer.

    + + +
    random_perm
    +

    Number of random sample permutations for the estimation of the scaling params.

    + + +
    use_boxcox
    +

    Logical; if TRUE and the bestNormalize package is available, boxcox transformations will be used to +normalize individual scores. If not possible, scores will just be transformed to a zero mean and unit standard deviation.

    + + +
    sample_attributes_fixed
    +

    Logical; if FALSE, simulate a shuffle function that alters sample attributes at each iteration.

    + +
    +
    +

    Value

    + + +

    The transformation function for a new score vector

    +
    + +
    + +
    + + +
    + +
    +

    Site built with pkgdown 2.0.7.

    +
    + +
    + + + + + + + + diff --git a/dev/reference/mk_constant_swapping_function.html b/dev/reference/mk_constant_swapping_function.html new file mode 100644 index 00000000..38a8e148 --- /dev/null +++ b/dev/reference/mk_constant_swapping_function.html @@ -0,0 +1,138 @@ + +Create function to propose n pairwise swaps of samples on each call (n is a constant across iterations) — mk_constant_swapping_function • designit + + +
    +
    + + + +
    +
    + + +
    +

    This internal function is wrapped by mk_swapping_function()

    +
    + +
    +
    mk_constant_swapping_function(n_swaps, quiet = FALSE)
    +
    + +
    +

    Arguments

    +
    n_swaps
    +

    Number of swaps to be proposed (valid range is 1..floor(n_samples/2))

    + + +
    quiet
    +

    Do not warn if number of swaps is too big.

    + +
    +
    +

    Value

    + + +

    Function accepting batch container & iteration number. +Return a list with length n vectors 'src' and 'dst', denoting source and destination index for +the swap operation on each call

    +
    + +
    + +
    + + +
    + +
    +

    Site built with pkgdown 2.0.7.

    +
    + +
    + + + + + + + + diff --git a/dev/reference/mk_dist_matrix.html b/dev/reference/mk_dist_matrix.html new file mode 100644 index 00000000..9044f1da --- /dev/null +++ b/dev/reference/mk_dist_matrix.html @@ -0,0 +1,156 @@ + +Internal helper function to set up an (n m) x (n m) pairwise distance matrix for a plate with n rows and m columns — mk_dist_matrix • designit + + +
    +
    + + + +
    +
    + + +
    +

    Internal helper function to set up an (n m) x (n m) pairwise distance matrix for a plate with n rows and m columns

    +
    + +
    +
    mk_dist_matrix(
    +  plate_x = 12,
    +  plate_y = 8,
    +  dist = "minkowski",
    +  p = 2,
    +  penalize_lines = "soft"
    +)
    +
    + +
    +

    Arguments

    +
    plate_x
    +

    Dimension of plate in x direction (i.e number of columns)

    + + +
    plate_y
    +

    Dimension of plate in y direction (i.e number of rows)

    + + +
    dist
    +

    Distance function as understood by stats::dist()

    + + +
    p
    +

    p parameter, used only if distance metric is 'minkowski'. Special cases: p=1 - Manhattan distance; p=2 - Euclidean distance

    + + +
    penalize_lines
    +

    How to penalize samples of the same group in one row or column of the plate. Valid options are: +'none' - there is no penalty and the pure distance metric counts, 'soft' - penalty will depend on the well distance within the +shared plate row or column, 'hard' - samples in the same row/column will score a zero distance

    + +
    +
    +

    Value

    + + +

    The matrix with pairwise distances between any wells on the plate

    +
    + +
    + +
    + + +
    + +
    +

    Site built with pkgdown 2.0.7.

    +
    + +
    + + + + + + + + diff --git a/dev/reference/mk_exponentially_weighted_acceptance_func.html b/dev/reference/mk_exponentially_weighted_acceptance_func.html new file mode 100644 index 00000000..50a670e6 --- /dev/null +++ b/dev/reference/mk_exponentially_weighted_acceptance_func.html @@ -0,0 +1,145 @@ + +Alternative acceptance function for multi-dimensional scores with exponentially downweighted score improvements from left to right — mk_exponentially_weighted_acceptance_func • designit + + +
    +
    + + + +
    +
    + + +
    +

    Alternative acceptance function for multi-dimensional scores with exponentially downweighted score improvements from left to right

    +
    + +
    +
    mk_exponentially_weighted_acceptance_func(
    +  kappa = 0.5,
    +  simulated_annealing = FALSE,
    +  temp_function = mk_simanneal_temp_func(T0 = 500, alpha = 0.8)
    +)
    +
    + +
    +

    Arguments

    +
    kappa
    +

    Coefficient that determines how quickly the weights for the individual score improvements drop when going from left to right +(i.e. first to last score). Weight for the first score's delta is 1, then the original delta multiplied with kappa^(p-1) for the p'th score

    + + +
    simulated_annealing
    +

    Boolean; if TRUE, simulated annealing (SA) will be used to minimize the weighted improved score

    + + +
    temp_function
    +

    In case SA is used, a temperature function that returns the annealing temperature for a certain iteration number

    + +
    +
    +

    Value

    + + +

    Acceptance function which returns TRUE if current score should be taken as the new optimal score, FALSE otherwise

    +
    + +
    + +
    + + +
    + +
    +

    Site built with pkgdown 2.0.7.

    +
    + +
    + + + + + + + + diff --git a/dev/reference/mk_plate_scoring_functions-1.png b/dev/reference/mk_plate_scoring_functions-1.png new file mode 100644 index 00000000..7fbcde24 Binary files /dev/null and b/dev/reference/mk_plate_scoring_functions-1.png differ diff --git a/dev/reference/mk_plate_scoring_functions.html b/dev/reference/mk_plate_scoring_functions.html new file mode 100644 index 00000000..2d866e49 --- /dev/null +++ b/dev/reference/mk_plate_scoring_functions.html @@ -0,0 +1,197 @@ + +Create a list of scoring functions (one per plate) that quantify the spatially homogeneous distribution of conditions across the plate — mk_plate_scoring_functions • designit + + +
    +
    + + + +
    +
    + + +
    +

    Create a list of scoring functions (one per plate) that quantify the spatially homogeneous distribution of conditions across the plate

    +
    + +
    +
    mk_plate_scoring_functions(
    +  batch_container,
    +  plate = NULL,
    +  row,
    +  column,
    +  group,
    +  p = 2,
    +  penalize_lines = "soft"
    +)
    +
    + +
    +

    Arguments

    +
    batch_container
    +

    Batch container (bc) with all columns that denote plate related information

    + + +
    plate
    +

    Name of the bc column that holds the plate identifier (may be missing or NULL in case just one plate is used)

    + + +
    row
    +

    Name of the bc column that holds the plate row number (integer values starting at 1)

    + + +
    column
    +

    Name of the bc column that holds the plate column number (integer values starting at 1)

    + + +
    group
    +

    Name of the bc column that denotes a group/condition that should be distributed on the plate

    + + +
    p
    +

    p parameter for minkowski type of distance metrics. Special cases: p=1 - Manhattan distance; p=2 - Euclidean distance

    + + +
    penalize_lines
    +

    How to penalize samples of the same group in one row or column of the plate. Valid options are: +'none' - there is no penalty and the pure distance metric counts, 'soft' - penalty will depend on the well distance within the +shared plate row or column, 'hard' - samples in the same row/column will score a zero distance

    + +
    +
    +

    Value

    + + +

    List of scoring functions, one per plate, that calculate a real valued measure for the quality of the group distribution (the lower the better).

    +
    + +
    +

    Examples

    +
    data("invivo_study_samples")
    +bc <- BatchContainer$new(
    +  dimensions = c("column" = 6, "row" = 10)
    +)
    +assign_random(bc, invivo_study_samples)
    +bc$scoring_f <- mk_plate_scoring_functions(
    +  bc,
    +  row = "row", column = "column", group = "Sex"
    +)
    +optimize_design(bc, max_iter = 100)
    +#> Checking variances of 1-dim. score vector.
    +#> ... (0.15) - OK
    +#> Initial score: 9.413
    +#> Achieved score: 9.364 at iteration 5
    +#> Achieved score: 9.351 at iteration 7
    +#> Achieved score: 9.312 at iteration 15
    +#> Achieved score: 9.266 at iteration 37
    +#> Achieved score: 9.257 at iteration 38
    +#> Achieved score: 9.257 at iteration 42
    +#> Achieved score: 9.24 at iteration 47
    +#> Achieved score: 9.235 at iteration 83
    +#> Optimization trace (101 score values, elapsed 0.6008818 secs).
    +#>   Starting score: 9.413
    +#>   Final score   : 9.235
    +plot_plate(bc$get_samples(), .col = Sex)
    +
    +
    +
    +
    +
    + +
    + + +
    + +
    +

    Site built with pkgdown 2.0.7.

    +
    + +
    + + + + + + + + diff --git a/dev/reference/mk_simanneal_acceptance_func.html b/dev/reference/mk_simanneal_acceptance_func.html new file mode 100644 index 00000000..37e7ded4 --- /dev/null +++ b/dev/reference/mk_simanneal_acceptance_func.html @@ -0,0 +1,134 @@ + +Generate acceptance function for an optimization protocol based on simulated annealing — mk_simanneal_acceptance_func • designit + + +
    +
    + + + +
    +
    + + +
    +

    Generate acceptance function for an optimization protocol based on simulated annealing

    +
    + +
    +
    mk_simanneal_acceptance_func(
    +  temp_function = mk_simanneal_temp_func(T0 = 500, alpha = 0.8)
    +)
    +
    + +
    +

    Arguments

    +
    temp_function
    +

    A temperature function that returns the annealing temperature for a certain cycle k

    + +
    +
    +

    Value

    + + +

    A function that takes parameters (current_score, best_score, iteration) for an optimization step and return a Boolean indicating whether the current solution should be accepted or dismissed. Acceptance probability of a worse solution decreases with annealing temperature.

    +
    + +
    + +
    + + +
    + +
    +

    Site built with pkgdown 2.0.7.

    +
    + +
    + + + + + + + + diff --git a/dev/reference/mk_simanneal_temp_func.html b/dev/reference/mk_simanneal_temp_func.html new file mode 100644 index 00000000..e326f373 --- /dev/null +++ b/dev/reference/mk_simanneal_temp_func.html @@ -0,0 +1,140 @@ + +Create a temperature function that returns the annealing temperature at a given step (iteration) — mk_simanneal_temp_func • designit + + +
    +
    + + + +
    +
    + + +
    +

    Supported annealing types are currently "Exponential multiplicative", "Logarithmic multiplicative", "Quadratic multiplicative" and "Linear multiplicative", each with dedicated constraints on alpha. For information, see http://what-when-how.com/artificial-intelligence/a-comparison-of-cooling-schedules-for-simulated-annealing-artificial-intelligence/

    +
    + +
    +
    mk_simanneal_temp_func(T0, alpha, type = "Quadratic multiplicative")
    +
    + +
    +

    Arguments

    +
    T0
    +

    Initial temperature at step 1 (when k=0)

    + + +
    alpha
    +

    Rate of cooling

    + + +
    type
    +

    Type of annealing protocol. Defaults to the quadratic multiplicative method which seems to perform well.

    + +
    +
    +

    Value

    + + +

    Temperature at cycle k.

    +
    + +
    + +
    + + +
    + +
    +

    Site built with pkgdown 2.0.7.

    +
    + +
    + + + + + + + + diff --git a/dev/reference/mk_subgroup_shuffling_function-1.png b/dev/reference/mk_subgroup_shuffling_function-1.png new file mode 100644 index 00000000..f926c15a Binary files /dev/null and b/dev/reference/mk_subgroup_shuffling_function-1.png differ diff --git a/dev/reference/mk_subgroup_shuffling_function-2.png b/dev/reference/mk_subgroup_shuffling_function-2.png new file mode 100644 index 00000000..af24064b Binary files /dev/null and b/dev/reference/mk_subgroup_shuffling_function-2.png differ diff --git a/dev/reference/mk_subgroup_shuffling_function-3.png b/dev/reference/mk_subgroup_shuffling_function-3.png new file mode 100644 index 00000000..f6d6e5be Binary files /dev/null and b/dev/reference/mk_subgroup_shuffling_function-3.png differ diff --git a/dev/reference/mk_subgroup_shuffling_function.html b/dev/reference/mk_subgroup_shuffling_function.html new file mode 100644 index 00000000..06d58b7e --- /dev/null +++ b/dev/reference/mk_subgroup_shuffling_function.html @@ -0,0 +1,209 @@ + +Created a shuffling function that permutes samples within certain subgroups of the container locations — mk_subgroup_shuffling_function • designit + + +
    +
    + + + +
    +
    + + +
    +

    If length(n_swaps)==1, the returned function may be called an arbitrary number of times. +If length(n_swaps)>1 the returned function may be called length(n_swaps) timed before returning NULL, which would be the stopping criterion if all requested swaps have been exhausted.

    +
    + +
    +
    mk_subgroup_shuffling_function(
    +  subgroup_vars,
    +  restrain_on_subgroup_levels = c(),
    +  n_swaps = 1
    +)
    +
    + +
    +

    Arguments

    +
    subgroup_vars
    +

    Column names of the variables that together define the relevant subgroups

    + + +
    restrain_on_subgroup_levels
    +

    Permutations can be forced to take place only within a level of the factor of the subgrouping variable. In this case, the user must pass only one subgrouping variable and a number of levels that together define the permuted subgroup.

    + + +
    n_swaps
    +

    Vector with number of swaps to be proposed in successive calls to the returned function (each value should be in valid range from 1..floor(n_locations/2))

    + +
    +
    +

    Value

    + + +

    Function to return a list with length n vectors src and dst, denoting source and destination index for the swap operation, or NULL if the user provided a defined protocol for the number of swaps and the last iteration has been reached

    +
    + +
    +

    Examples

    +
    set.seed(42)
    +
    +bc <- BatchContainer$new(
    +  dimensions = c(
    +    plate = 2,
    +    row = 4, col = 4
    +  )
    +)
    +
    +assign_in_order(bc, samples = tibble::tibble(
    +  Group = c(rep(c("Grp 1", "Grp 2", "Grp 3", "Grp 4"), each = 8)),
    +  ID = 1:32
    +))
    +
    +# here we use a 2-step approach:
    +# 1. Assign samples to plates.
    +# 2. Arrange samples within plates.
    +
    +# overview of sample assagnment before optimization
    +plot_plate(bc,
    +  plate = plate, row = row, column = col, .color = Group
    +)
    +
    +
    +# Step 1, assign samples to plates
    +bc$scoring_f <- osat_score_generator(
    +  batch_vars = c("plate"), feature_vars = c("Group")
    +)
    +optimize_design(bc,
    +  max_iter = 10, # the real number of iterations should be bigger
    +  n_shuffle = 2,
    +  quiet = TRUE
    +)
    +#> Optimization trace (11 score values, elapsed 0.5918381 secs).
    +#>   Starting score: 128
    +#>   Final score   : 4
    +plot_plate(bc,
    +  plate = plate, row = row, column = col, .color = Group
    +)
    +
    +
    +# Step 2, distribute samples within plates
    +bc$scoring_f <- mk_plate_scoring_functions(
    +  bc,
    +  plate = "plate", row = "row", column = "col", group = "Group"
    +)
    +optimize_design(bc,
    +  max_iter = 50,
    +  shuffle_proposal_func = mk_subgroup_shuffling_function(subgroup_vars = c("plate")),
    +  aggregate_scores_func = L2s_norm,
    +  quiet = TRUE
    +)
    +#> Optimization trace (51 score values, elapsed 0.5982196 secs).
    +#>   Starting score: 15.632,34.242
    +#>   Final score   : 8.617,9.182
    +plot_plate(bc,
    +  plate = plate, row = row, column = col, .color = Group
    +)
    +
    +
    +
    +
    + +
    + + +
    + +
    +

    Site built with pkgdown 2.0.7.

    +
    + +
    + + + + + + + + diff --git a/dev/reference/mk_swapping_function.html b/dev/reference/mk_swapping_function.html new file mode 100644 index 00000000..9d83fd06 --- /dev/null +++ b/dev/reference/mk_swapping_function.html @@ -0,0 +1,165 @@ + +Create function to propose swaps of samples on each call, either with a constant number of swaps or following +a user defined protocol — mk_swapping_function • designit + + +
    +
    + + + +
    +
    + + +
    +

    If length(n_swaps)==1, the returned function may be called an arbitrary number of times. +If length(n_swaps)>1 and called without argument, the returned function may be called length(n_swaps) timed before returning NULL, which would be the stopping criterion if all requested swaps have been exhausted. Alternatively, the function may be called with an iteration number as the only argument, giving the user some freedom how to iterate over the sample swapping protocol.

    +
    + +
    +
    mk_swapping_function(n_swaps = 1)
    +
    + +
    +

    Arguments

    +
    n_swaps
    +

    Vector with number of swaps to be proposed in successive calls to the returned function (each value should be in valid range from 1..floor(n_samples/2))

    + +
    +
    +

    Value

    + + +

    Function to return a list with length n vectors src and dst, denoting source and destination index for the swap operation, or NULL if the user provided a defined protocol for the number of swaps and the last iteration has been reached.

    +
    + +
    +

    Examples

    +
    data("invivo_study_samples")
    +bc <- BatchContainer$new(
    +  dimensions = c("plate" = 2, "column" = 5, "row" = 6)
    +)
    +bc$scoring_f <- osat_score_generator("plate", "Sex")
    +optimize_design(
    +  bc, invivo_study_samples,
    +  max_iter = 100,
    +  shuffle_proposal_func = mk_swapping_function(1)
    +)
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Checking variances of 1-dim. score vector.
    +#> ... (418.374) - OK
    +#> Initial score: 182.5
    +#> Achieved score: 132.5 at iteration 1
    +#> Achieved score: 90.5 at iteration 5
    +#> Achieved score: 56.5 at iteration 11
    +#> Achieved score: 30.5 at iteration 23
    +#> Achieved score: 12.5 at iteration 24
    +#> Achieved score: 2.5 at iteration 26
    +#> Achieved score: 0.5 at iteration 36
    +#> Optimization trace (101 score values, elapsed 1.230023 secs).
    +#>   Starting score: 182.5
    +#>   Final score   : 0.5
    +
    +
    +
    + +
    + + +
    + +
    +

    Site built with pkgdown 2.0.7.

    +
    + +
    + + + + + + + + diff --git a/dev/reference/multi_trt_day_samples.html b/dev/reference/multi_trt_day_samples.html new file mode 100644 index 00000000..ba516012 --- /dev/null +++ b/dev/reference/multi_trt_day_samples.html @@ -0,0 +1,132 @@ + +Unbalanced treatment and time sample list — multi_trt_day_samples • designit + + +
    +
    + + + +
    +
    + + +
    +

    A sample list with 4 columns SampleName, Well, Time and Treatment +Not all treatments are avaliable at all time points. +All samples are placed on the same plate.

    +
    + +
    +
    data(multi_trt_day_samples)
    +
    + +
    +

    Format

    +

    An object of class "tibble"

    +
    +
    +

    Author

    +

    siebourj

    +
    + +
    + +
    + + +
    + +
    +

    Site built with pkgdown 2.0.7.

    +
    + +
    + + + + + + + + diff --git a/dev/reference/neighbors.html b/dev/reference/neighbors.html new file mode 100644 index 00000000..5b5be6c2 --- /dev/null +++ b/dev/reference/neighbors.html @@ -0,0 +1,138 @@ + +Penalty for neighbors with same level — neighbors • designit + + +
    +
    + + + +
    +
    + + +
    +

    Penalty score for number of neighboring pairs with the same level of a factor. +The number of such pairs is summed.

    +
    + +
    +
    neighbors(m)
    +
    + +
    +

    Arguments

    +
    m
    +

    a factor vector

    + +
    +
    +

    Value

    + + +

    the number of pairs

    +
    +
    +

    Author

    +

    Juliane Siebourg-Polster

    +
    + +
    + +
    + + +
    + +
    +

    Site built with pkgdown 2.0.7.

    +
    + +
    + + + + + + + + diff --git a/dev/reference/optimize_design-1.png b/dev/reference/optimize_design-1.png new file mode 100644 index 00000000..430b0a4b Binary files /dev/null and b/dev/reference/optimize_design-1.png differ diff --git a/dev/reference/optimize_design.html b/dev/reference/optimize_design.html new file mode 100644 index 00000000..025285ff --- /dev/null +++ b/dev/reference/optimize_design.html @@ -0,0 +1,251 @@ + +Generic optimizer that can be customized by user provided functions for generating shuffles and progressing towards the minimal score — optimize_design • designit + + +
    +
    + + + +
    +
    + + +
    +

    Generic optimizer that can be customized by user provided functions for generating shuffles and progressing towards the minimal score

    +
    + +
    +
    optimize_design(
    +  batch_container,
    +  samples = NULL,
    +  n_shuffle = NULL,
    +  shuffle_proposal_func = NULL,
    +  acceptance_func = accept_strict_improvement,
    +  aggregate_scores_func = identity,
    +  check_score_variance = TRUE,
    +  autoscale_scores = FALSE,
    +  autoscaling_permutations = 100,
    +  autoscale_useboxcox = TRUE,
    +  sample_attributes_fixed = FALSE,
    +  max_iter = 10000,
    +  min_delta = NA,
    +  quiet = FALSE
    +)
    +
    + +
    +

    Arguments

    +
    batch_container
    +

    An instance of BatchContainer.

    + + +
    samples
    +

    A data.frame with sample information. +Should be NULL if the BatchContainer already has samples in it.

    + + +
    n_shuffle
    +

    Vector of length 1 or larger, defining how many random sample +swaps should be performed in each iteration. If length(n_shuffle)==1, +this sets no limit to the number of iterations. Otherwise, the optimization +stops if the swapping protocol is exhausted.

    + + +
    shuffle_proposal_func
    +

    A user defined function to propose the next shuffling of samples. +Takes priority over n_shuffle if both are provided. The function is called with +a BatchContainer bc and an integer parameter iteration for the current iteration number, +allowing very flexible shuffling strategies. +Mapper syntax is supported (see purrr::as_mapper()). +The returned function must either return a list with fields srcand dst (for pairwise sample swapping) +or a numeric vector with a complete re-assigned sample order.

    + + +
    acceptance_func
    +

    Alternative function to select a new score as the best one. +Defaults to strict improvement rule, i.e. all elements of a score have to be smaller or equal in order to accept the solution as better. +This may be replaced with an alternative acceptance function included in the package +(e.g. mk_simanneal_acceptance_func()) or a user provided function. +Mapper syntax is supported (see purrr::as_mapper()).

    + + +
    aggregate_scores_func
    +

    A function to aggregate multiple scores AFTER (potential) auto-scaling and BEFORE acceptance evaluation. +If a function is passed, (multi-dimensional) scores will be transformed (often to a single double value) before calling the acceptance function. +E.g., see first_score_only() or worst_score(). +Note that particular acceptance functions may require aggregation of a score to a single scalar in order to work, see for example those +generated by mk_simanneal_acceptance_func(). +Mapper syntax is supported (see purrr::as_mapper()).

    + + +
    check_score_variance
    +

    Logical: if TRUE, scores will be checked for variability under sample permutation +and the optimization is not performed if at least one subscore appears to have a zero variance.

    + + +
    autoscale_scores
    +

    Logical: if TRUE, perform a transformation on the fly to equally scale scores +to a standard normal. This makes scores more directly comparable and easier to aggregate.

    + + +
    autoscaling_permutations
    +

    How many random sample permutations should be done to estimate autoscaling parameters. +(Note: minimum will be 20, regardless of the specified value)

    + + +
    autoscale_useboxcox
    +

    Logical; if TRUE, use a boxcox transformation for the autoscaling if possible at all. +Requires installation of the bestNormalize package.

    + + +
    sample_attributes_fixed
    +

    Logical; if TRUE, sample shuffle function may generate altered sample attributes at each iteration. +This affects estimation of score distributions. (Parameter only relevant if shuffle function does introduce attributes!)

    + + +
    max_iter
    +

    Stop optimization after a maximum number of iterations, +independent from other stopping criteria (user defined shuffle proposal or min_delta).

    + + +
    min_delta
    +

    If not NA, optimization is stopped as soon as successive improvement (i.e. euclidean distance between score vectors +from current best and previously best solution) drops below min_delta.

    + + +
    quiet
    +

    If TRUE, suppress non-critical warnings or messages.

    + +
    +
    +

    Value

    + + +

    A trace object

    +
    + +
    +

    Examples

    +
    data("invivo_study_samples")
    +bc <- BatchContainer$new(
    +  dimensions = c("plate" = 2, "column" = 5, "row" = 6)
    +)
    +bc$scoring_f <- osat_score_generator("plate", "Sex")
    +optimize_design(bc, invivo_study_samples, max_iter = 100)
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Checking variances of 1-dim. score vector.
    +#> ... (141.154) - OK
    +#> Initial score: 182.5
    +#> Achieved score: 132.5 at iteration 1
    +#> Achieved score: 90.5 at iteration 2
    +#> Achieved score: 56.5 at iteration 6
    +#> Achieved score: 30.5 at iteration 11
    +#> Achieved score: 12.5 at iteration 15
    +#> Achieved score: 2.5 at iteration 16
    +#> Achieved score: 0.5 at iteration 31
    +#> Optimization trace (101 score values, elapsed 1.236129 secs).
    +#>   Starting score: 182.5
    +#>   Final score   : 0.5
    +plot_plate(bc$get_samples(), .col = Sex)
    +
    +
    +
    +
    + +
    + + +
    + +
    +

    Site built with pkgdown 2.0.7.

    +
    + +
    + + + + + + + + diff --git a/dev/reference/optimize_multi_plate_design.html b/dev/reference/optimize_multi_plate_design.html new file mode 100644 index 00000000..c040e36a --- /dev/null +++ b/dev/reference/optimize_multi_plate_design.html @@ -0,0 +1,177 @@ + +Convenience wrapper to optimize a typical multi-plate design — optimize_multi_plate_design • designit + + +
    +
    + + + +
    +
    + + +
    +

    The batch container will in the end contain the updated experimental layout

    +
    + +
    +
    optimize_multi_plate_design(
    +  batch_container,
    +  across_plates_variables = NULL,
    +  within_plate_variables = NULL,
    +  plate = "plate",
    +  row = "row",
    +  column = "column",
    +  n_shuffle = 1,
    +  max_iter = 1000,
    +  quiet = FALSE
    +)
    +
    + +
    +

    Arguments

    +
    batch_container
    +

    Batch container (bc) with all columns that denote plate related information

    + + +
    across_plates_variables
    +

    Vector with bc column name(s) that denote(s) groups/conditions to be balanced across plates, +sorted by relative importance of the factors

    + + +
    within_plate_variables
    +

    Vector with bc column name(s) that denote(s) groups/conditions to be spaced out within each plate, +sorted by relative importance of the factors

    + + +
    plate
    +

    Name of the bc column that holds the plate identifier

    + + +
    row
    +

    Name of the bc column that holds the plate row number (integer values starting at 1)

    + + +
    column
    +

    Name of the bc column that holds the plate column number (integer values starting at 1)

    + + +
    n_shuffle
    +

    Vector of length 1 or larger, defining how many random sample +swaps should be performed in each iteration. See optimize_design().

    + + +
    max_iter
    +

    Stop any of the optimization runs after this maximum number of iterations. See optimize_design().

    + + +
    quiet
    +

    If TRUE, suppress informative messages.

    + +
    +
    +

    Value

    + + +

    A list with named traces, one for each optimization step

    +
    + +
    + +
    + + +
    + +
    +

    Site built with pkgdown 2.0.7.

    +
    + +
    + + + + + + + + diff --git a/dev/reference/osat_score.html b/dev/reference/osat_score.html new file mode 100644 index 00000000..2971943d --- /dev/null +++ b/dev/reference/osat_score.html @@ -0,0 +1,192 @@ + +Compute OSAT score for sample assignment. — osat_score • designit + + +
    +
    + + + +
    +
    + + +
    +

    Compute OSAT score for sample assignment.

    +
    + +
    +
    osat_score(bc, batch_vars, feature_vars, expected_dt = NULL, quiet = FALSE)
    +
    + +
    +

    Arguments

    +
    bc
    +

    BatchContainer with samples +or data.table/data.frame where every row is a location +in a container and a sample in this location.

    + + +
    batch_vars
    +

    character vector with batch variable names to take into account for the +score computation.

    + + +
    feature_vars
    +

    character vector with sample variable names to take into account for +score computation.

    + + +
    expected_dt
    +

    A data.table with expected number of samples sample +variables and batch variables combination. This is not required, however it does not change +during the optimization process. So it is a good idea to cache this value.

    + + +
    quiet
    +

    Do not warn about NAs in feature columns.

    + +
    +
    +

    Value

    + + +

    a list with two attributes: $score (numeric score value), $expected_dt

    + + +

    (expected counts data.table for reuse)

    +
    + +
    +

    Examples

    +
    sample_assignment <- tibble::tribble(
    +  ~ID, ~SampleType, ~Sex, ~plate,
    +  1, "Case", "Female", 1,
    +  2, "Case", "Female", 1,
    +  3, "Case", "Male", 2,
    +  4, "Control", "Female", 2,
    +  5, "Control", "Female", 1,
    +  6, "Control", "Male", 2,
    +  NA, NA, NA, 1,
    +  NA, NA, NA, 2,
    +)
    +
    +osat_score(sample_assignment,
    +  batch_vars = "plate",
    +  feature_vars = c("SampleType", "Sex")
    +)
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> $score
    +#> [1] 3
    +#> 
    +#> $expected_dt
    +#>    plate SampleType    Sex .n_expected
    +#> 1:     1       Case Female         1.0
    +#> 2:     1       Case   Male         0.5
    +#> 3:     1    Control Female         1.0
    +#> 4:     1    Control   Male         0.5
    +#> 5:     2       Case Female         1.0
    +#> 6:     2       Case   Male         0.5
    +#> 7:     2    Control Female         1.0
    +#> 8:     2    Control   Male         0.5
    +#> 
    +
    +
    +
    + +
    + + +
    + +
    +

    Site built with pkgdown 2.0.7.

    +
    + +
    + + + + + + + + diff --git a/dev/reference/osat_score_generator.html b/dev/reference/osat_score_generator.html new file mode 100644 index 00000000..91812620 --- /dev/null +++ b/dev/reference/osat_score_generator.html @@ -0,0 +1,168 @@ + +Convenience wrapper for the OSAT score — osat_score_generator • designit + + +
    +
    + + + +
    +
    + + +
    +

    This function wraps osat_score() in order to take full advantage of the speed gain without +managing the buffered objects in the user code.

    +
    + +
    +
    osat_score_generator(batch_vars, feature_vars, quiet = FALSE)
    +
    + +
    +

    Arguments

    +
    batch_vars
    +

    character vector with batch variable names to take into account for the +score computation.

    + + +
    feature_vars
    +

    character vector with sample variable names to take into account for +score computation.

    + + +
    quiet
    +

    Do not warn about NAs in feature columns.

    + +
    +
    +

    Value

    + + +

    A function that returns the OSAT score for a specific sample arrangement

    +
    + +
    +

    Examples

    +
    sample_assignment <- tibble::tribble(
    +  ~ID, ~SampleType, ~Sex, ~plate,
    +  1, "Case", "Female", 1,
    +  2, "Case", "Female", 1,
    +  3, "Case", "Male", 2,
    +  4, "Control", "Female", 2,
    +  5, "Control", "Female", 1,
    +  6, "Control", "Male", 2,
    +  NA, NA, NA, 1,
    +  NA, NA, NA, 2,
    +)
    +
    +osat_scoring_function <- osat_score_generator(
    +  batch_vars = "plate",
    +  feature_vars = c("SampleType", "Sex")
    +)
    +
    +osat_scoring_function(sample_assignment)
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> [1] 3
    +
    +
    +
    + +
    + + +
    + +
    +

    Site built with pkgdown 2.0.7.

    +
    + +
    + + + + + + + + diff --git a/dev/reference/pairwise_swapping.html b/dev/reference/pairwise_swapping.html new file mode 100644 index 00000000..e077949a --- /dev/null +++ b/dev/reference/pairwise_swapping.html @@ -0,0 +1,138 @@ + +Proposes pairwise swap of samples on each call. — pairwise_swapping • designit + + +
    +
    + + + +
    +
    + + +
    +

    This function will ensure that one of the locations is always non-empty. It should not +return trivial permutations (e.g., src=c(1,2) and dst=c(1,2)).

    +
    + +
    +
    pairwise_swapping(batch_container, iteration)
    +
    + +
    +

    Arguments

    +
    batch_container
    +

    The batch-container.

    + + +
    iteration
    +

    The current iteration number.

    + +
    +
    +

    Value

    + + +

    Function accepting batch container & iteration number. It returns a list with length 1 vectors 'src' and 'dst', denoting source and destination index for the swap operation

    +
    + +
    + +
    + + +
    + +
    +

    Site built with pkgdown 2.0.7.

    +
    + +
    + + + + + + + + diff --git a/dev/reference/pipe.html b/dev/reference/pipe.html new file mode 100644 index 00000000..a0826d5b --- /dev/null +++ b/dev/reference/pipe.html @@ -0,0 +1,120 @@ + +Pipe operator — %>% • designit + + +
    +
    + + + +
    +
    + + +
    +

    See magrittr::%>% for details.

    +
    + +
    +
    lhs %>% rhs
    +
    + + +
    + +
    + + +
    + +
    +

    Site built with pkgdown 2.0.7.

    +
    + +
    + + + + + + + + diff --git a/dev/reference/plot_plate-1.png b/dev/reference/plot_plate-1.png new file mode 100644 index 00000000..084c445b Binary files /dev/null and b/dev/reference/plot_plate-1.png differ diff --git a/dev/reference/plot_plate.html b/dev/reference/plot_plate.html new file mode 100644 index 00000000..27664751 --- /dev/null +++ b/dev/reference/plot_plate.html @@ -0,0 +1,226 @@ + +Plot plate layouts — plot_plate • designit + + +
    +
    + + + +
    +
    + + +
    +

    Plot plate layouts

    +
    + +
    +
    plot_plate(
    +  .tbl,
    +  plate = plate,
    +  row = row,
    +  column = column,
    +  .color,
    +  .alpha = NULL,
    +  .pattern = NULL,
    +  title = paste("Layout by", rlang::as_name(rlang::enquo(plate))),
    +  add_excluded = FALSE,
    +  rename_empty = FALSE
    +)
    +
    + +
    +

    Arguments

    +
    .tbl
    +

    a tibble (or data.frame) with the samples assigned to locations. +Alternatively a BatchContainter with samples can be supplied here.

    + + +
    plate
    +

    optional dimension variable used for the plate ids

    + + +
    row
    +

    the dimension variable used for the row ids

    + + +
    column
    +

    the dimension variable used for the column ids

    + + +
    .color
    +

    the continuous or discrete variable to color by

    + + +
    .alpha
    +

    a continuous variable encoding transparency

    + + +
    .pattern
    +

    a discrete variable encoding tile pattern (needs ggpattern)

    + + +
    title
    +

    string for the plot title

    + + +
    add_excluded
    +

    flag to add excluded wells (in bc$exclude) to the plot. +A BatchContainer must be provided for this.

    + + +
    rename_empty
    +

    whether NA entries in sample table should be renamed to 'empty`.

    + +
    +
    +

    Value

    + + +

    the ggplot object

    +
    +
    +

    Author

    +

    siebourj

    +
    + +
    +

    Examples

    +
    nPlate <- 3
    +nColumn <- 4
    +nRow <- 6
    +
    +treatments <- c("CTRL", "TRT1", "TRT2")
    +timepoints <- c(1, 2, 3)
    +
    +
    +bc <- BatchContainer$new(
    +  dimensions = list(
    +    plate = nPlate,
    +    column = list(values = letters[1:nColumn]),
    +    row = nRow
    +  )
    +)
    +
    +sample_sheet <- tibble::tibble(
    +  sampleID = 1:(nPlate * nColumn * nRow),
    +  Treatment = rep(treatments, each = floor(nPlate * nColumn * nRow) / length(treatments)),
    +  Timepoint = rep(timepoints, floor(nPlate * nColumn * nRow) / length(treatments))
    +)
    +
    +# assign samples from the sample sheet
    +assign_random(bc, samples = sample_sheet)
    +
    +plot_plate(bc$get_samples(),
    +  plate = plate, column = column, row = row,
    +  .color = Treatment, .alpha = Timepoint
    +)
    +
    +
    +if (FALSE) {
    +plot_plate(bc$get_samples(),
    +  plate = plate, column = column, row = row,
    +  .color = Treatment, .pattern = Timepoint
    +)
    +}
    +
    +
    +
    + +
    + + +
    + +
    +

    Site built with pkgdown 2.0.7.

    +
    + +
    + + + + + + + + diff --git a/dev/reference/random_score_variances.html b/dev/reference/random_score_variances.html new file mode 100644 index 00000000..b5a14273 --- /dev/null +++ b/dev/reference/random_score_variances.html @@ -0,0 +1,140 @@ + +Estimate the variance of individual scores by a series of completely random sample permutations — random_score_variances • designit + + +
    +
    + + + +
    +
    + + +
    +

    Estimate the variance of individual scores by a series of completely random sample permutations

    +
    + +
    +
    random_score_variances(batch_container, random_perm, sample_attributes_fixed)
    +
    + +
    +

    Arguments

    +
    batch_container
    +

    An instance of BatchContainer.

    + + +
    random_perm
    +

    Number of random sample permutations to be done.

    + + +
    sample_attributes_fixed
    +

    Logical; if FALSE, simulate a shuffle function that alters sample attributes at each iteration.

    + +
    +
    +

    Value

    + + +

    Vector of length m (=dimensionality of score) with estimated variances of each subscore

    +
    + +
    + +
    + + +
    + +
    +

    Site built with pkgdown 2.0.7.

    +
    + +
    + + + + + + + + diff --git a/dev/reference/randomize.html b/dev/reference/randomize.html new file mode 100644 index 00000000..3333bf11 --- /dev/null +++ b/dev/reference/randomize.html @@ -0,0 +1,277 @@ + +randomize experimental layout — randomize • designit + + +
    +
    + + + +
    +
    + + +
    +

    This function generates a randomized experimental layout based on given +experimental dimensions and factors to be balanced

    +
    + +
    +
    randomize(
    +  design,
    +  report,
    +  layout_dim,
    +  balance,
    +  scoring_groups = as.list(names(layout_dim)),
    +  scoring_tests = as.list(rep("countGini", length(layout_dim))),
    +  burnin = 100,
    +  annealprotocol,
    +  scoring_weights = rep(1, length(scoring_groups)),
    +  balance_weights = rep(1, length(balance)),
    +  distribute = 1:(prod(layout_dim))
    +)
    +
    + +
    +

    Arguments

    +
    design
    +

    a data.frame with the sample ids, experimental conditions and +information about fixed samples (columns with 'Fix' prefix and then the dimension name)

    + + +
    report
    +

    a string with the sample identifier

    + + +
    layout_dim
    +

    a named vector with the experimental dimensions

    + + +
    balance
    +

    a vector with the names of experimental conditions to be balanced

    + + +
    scoring_groups
    +

    list of dimension name groups to be used jointly for scoring

    + + +
    scoring_tests
    +

    list of dimension name groups to be used jointly for scoring

    + + +
    burnin
    +

    a number of initial burnin runs (default=100)

    + + +
    annealprotocol
    +

    a vector with the number of pairs to swap in each annealing step

    + + +
    scoring_weights
    +

    named vector of weights for the dimensions (default all 1)

    + + +
    balance_weights
    +

    named vector of weights for the factors to be balanced (default all 1)

    + + +
    distribute
    +

    a starting distribution

    + +
    +
    +

    Value

    + + +

    the value of the Gini index

    +
    +
    +

    Author

    +

    Juliane Siebourg-Polster

    +
    + +
    +

    Examples

    +
    if (FALSE) {
    +# samples to use
    +samples <- data.frame(
    +  Group = c(1, 2, 3, 4, 5),
    +  Treatment = c(
    +    "vehicle", "RTR24", "RTR25",
    +    "RTR26", "RTR27"
    +  ),
    +  Dose = c(0, 25, 25, 25, 25),
    +  animals = c(2, 2, 2, 2, 2)
    +)
    +
    +# generate initial sample table (2 animals per group with 3 replicates)
    +samples <- dplyr::bind_rows(samples %>% dplyr::mutate(animals = 1), samples) %>%
    +  dplyr::rename(animal = animals)
    +samples <- dplyr::bind_rows(list(samples, samples, samples)) %>%
    +  dplyr::mutate(
    +    replicate = rep(1:3, each = 10),
    +    SampleID = paste0(Treatment, "_", animal, "_", replicate),
    +    AnimalID = paste0(Treatment, "_", animal)
    +  )
    +
    +# to be put on a 96 well plate
    +# (empty wells: first and last column plus two more wells)
    +empty <- 8 * 4 - nrow(samples) # n locations - n samples
    +emptydf <- data.frame(
    +  Treatment = "empty",
    +  FixColumn = 4, FixRow = 8 + 1 - (1:empty)
    +)
    +
    +# final sample table
    +design <- dplyr::full_join(samples, emptydf)
    +
    +# set parameters
    +layout_dim <- c(Row = 8, Column = 4)
    +scoring_groups <- list(c("Row"), c("Column"))
    +scoring_tests <- list("countGini", "countGini")
    +scoring_weights <- c(Row = 1, Column = 2)
    +balance <- c("AnimalID")
    +balance_weights <- c(1, 1)
    +names(balance_weights) <- balance
    +report <- "SampleID" # column with a unique ID
    +# annealprotocol <- rep(c(10,5,2,1), c(500,1000,2000,5000))
    +annealprotocol <- rep(c(10, 5, 2, 1), c(50, 100, 200, 300))
    +
    +# run randomization
    +result <- randomize(design, report, layout_dim, balance,
    +  scoring_groups = scoring_groups,
    +  scoring_tests = scoring_tests,
    +  burnin = 200, annealprotocol = annealprotocol,
    +  scoring_weights = scoring_weights,
    +  balance_weights = balance_weights,
    +  distribute = sample(1:(prod(layout_dim)))
    +)
    +
    +final_design <- result$design %>%
    +  dplyr::mutate(Column = Column + 1) # first column empty
    +
    +# plot
    +library(ggplot)
    +ggplot(
    +  final_design,
    +  aes(x = Column, y = Row, fill = Treatment, alpha = factor(animal))
    +) +
    +  theme_minimal() +
    +  geom_tile() +
    +  scale_x_continuous(breaks = unique(final_design$Column)) +
    +  scale_y_reverse(breaks = rev(unique(final_design$Row))) +
    +  scale_alpha_manual(values = c(1, 0.5))
    +
    +kable(table(final_design$Treatment, final_design$Column),
    +  digits = 0,
    +  caption = "Treatment distribution across Columns."
    +)
    +
    +# optimization curve
    +plot(score ~ iteration,
    +  data = result$opti,
    +  log = "x", ylab = "penalty", type = "b"
    +)
    +}
    +
    +
    +
    +
    + +
    + + +
    + +
    +

    Site built with pkgdown 2.0.7.

    +
    + +
    + + + + + + + + diff --git a/dev/reference/report_scores.html b/dev/reference/report_scores.html new file mode 100644 index 00000000..c7601745 --- /dev/null +++ b/dev/reference/report_scores.html @@ -0,0 +1,134 @@ + +Helper function to print out one set of scores plus (if needed) aggregated values — report_scores • designit + + +
    +
    + + + +
    +
    + + +
    +

    Helper function to print out one set of scores plus (if needed) aggregated values

    +
    + +
    +
    report_scores(score, agg_score, iteration)
    +
    + +
    +

    Arguments

    +
    score
    +

    Vector of (non-aggregated) scores (may be a single value as well)

    + + +
    agg_score
    +

    Vector of aggregated scores (may be a single value as well)

    + + +
    iteration
    +

    Iteration number

    + +
    + +
    + +
    + + +
    + +
    +

    Site built with pkgdown 2.0.7.

    +
    + +
    + + + + + + + + diff --git a/dev/reference/sample_random_scores.html b/dev/reference/sample_random_scores.html new file mode 100644 index 00000000..f0e006c4 --- /dev/null +++ b/dev/reference/sample_random_scores.html @@ -0,0 +1,140 @@ + +Sample scores from a number of completely random sample permutations — sample_random_scores • designit + + +
    +
    + + + +
    +
    + + +
    +

    Sample scores from a number of completely random sample permutations

    +
    + +
    +
    sample_random_scores(batch_container, random_perm, sample_attributes_fixed)
    +
    + +
    +

    Arguments

    +
    batch_container
    +

    An instance of BatchContainer.

    + + +
    random_perm
    +

    Number of random sample permutations to be done.

    + + +
    sample_attributes_fixed
    +

    Logical; if FALSE, simulate a shuffle function that alters sample attributes at each iteration.

    + +
    +
    +

    Value

    + + +

    A score matrix with n (# of permutations) rows and m (dimensionality of score) columns.

    +
    + +
    + +
    + + +
    + +
    +

    Site built with pkgdown 2.0.7.

    +
    + +
    + + + + + + + + diff --git a/dev/reference/shuffle_grouped_data.html b/dev/reference/shuffle_grouped_data.html new file mode 100644 index 00000000..96bbde7a --- /dev/null +++ b/dev/reference/shuffle_grouped_data.html @@ -0,0 +1,194 @@ + +Generate in one go a shuffling function that produces permutations with specific constraints on multiple sample variables and group sizes fitting one specific allocation variable — shuffle_grouped_data • designit + + +
    +
    + + + +
    +
    + + +
    +

    Generate in one go a shuffling function that produces permutations with specific constraints on multiple sample variables and group sizes fitting one specific allocation variable

    +
    + +
    +
    shuffle_grouped_data(
    +  batch_container,
    +  allocate_var,
    +  keep_together_vars = c(),
    +  keep_separate_vars = c(),
    +  n_min = NA,
    +  n_max = NA,
    +  n_ideal = NA,
    +  subgroup_var_name = NULL,
    +  report_grouping_as_attribute = FALSE,
    +  prefer_big_groups = FALSE,
    +  strict = TRUE,
    +  fullTree = FALSE,
    +  maxCalls = 1e+06
    +)
    +
    + +
    +

    Arguments

    +
    batch_container
    +

    Batch container with all samples assigned that are to be grouped and sub-grouped

    + + +
    allocate_var
    +

    Name of a variable in the samples table to inform possible groupings, as (sub)group sizes must add up to the correct totals

    + + +
    keep_together_vars
    +

    Vector of column names in sample table; groups are formed by pooling samples with identical values of all those variables

    + + +
    keep_separate_vars
    +

    Vector of column names in sample table; items with identical values in those variables will not be put into the same subgroup if at all possible

    + + +
    n_min
    +

    Minimal number of samples in one sub(!)group; by default 1

    + + +
    n_max
    +

    Maximal number of samples in one sub(!)group; by default the size of the biggest group

    + + +
    n_ideal
    +

    Ideal number of samples in one sub(!)group; by default the floor or ceiling of mean(n_min,n_max), depending on the setting of prefer_big_groups

    + + +
    subgroup_var_name
    +

    An optional column name for the subgroups which are formed (or NULL)

    + + +
    report_grouping_as_attribute
    +

    Boolean, if TRUE, add an attribute table to the permutation functions' output, to be used in scoring during the design optimization

    + + +
    prefer_big_groups
    +

    Boolean; indicating whether or not bigger subgroups should be preferred in case of several possibilities

    + + +
    strict
    +

    Boolean; if TRUE, subgroup size constraints have to be met strictly, implying the possibility of finding no solution at all

    + + +
    fullTree
    +

    Boolean: Enforce full search of the possibility tree, independent of the value of maxCalls

    + + +
    maxCalls
    +

    Maximum number of recursive calls in the search tree, to avoid long run times with very large trees

    + +
    +
    +

    Value

    + + +

    Shuffling function that on each call returns an index vector for a valid sample permutation

    +
    + +
    + +
    + + +
    + +
    +

    Site built with pkgdown 2.0.7.

    +
    + +
    + + + + + + + + diff --git a/dev/reference/shuffle_with_constraints.html b/dev/reference/shuffle_with_constraints.html new file mode 100644 index 00000000..47650e35 --- /dev/null +++ b/dev/reference/shuffle_with_constraints.html @@ -0,0 +1,305 @@ + +Shuffling proposal function with constraints. — shuffle_with_constraints • designit + + +
    +
    + + + +
    +
    + + +
    +

    Can be used with optimize_design to improve convergence speed.

    +
    + +
    +
    shuffle_with_constraints(src = TRUE, dst = TRUE)
    +
    + +
    +

    Arguments

    +
    src
    +

    Expression to define possible source locations in the samples/locations +table. Usually evaluated based on +BatchContainer$get_samples(include_id = TRUE, as_tibble = FALSE) as an environment +(see also with()). A single source location is selected from rows where the +expression evaluates toTRUE.

    + + +
    dst
    +

    Expression to define possible destination locations in the +samples/locations table. Usually evaluated based on BatchContainer$get_samples() as an +environment. +Additionally a special variable .src is available in this environment which +describes the selected source row from the table.

    + +
    +
    +

    Value

    + + +

    Returns a function which accepts a BatchContainer and an iteration +number (i). This function returns a list with two names: src vector of length +2 and dst vector of length two. See BatchContainer$move_samples().

    +
    + +
    +

    Examples

    +
    set.seed(43)
    +
    +samples <- data.frame(
    +  id = 1:100,
    +  sex = sample(c("F", "M"), 100, replace = TRUE),
    +  group = sample(c("treatment", "control"), 100, replace = TRUE)
    +)
    +
    +bc <- BatchContainer$new(
    +  dimensions = c("plate" = 5, "position" = 25)
    +)
    +
    +bc$scoring_f <- function(samples) {
    +  osat_score(
    +    samples,
    +    "plate",
    +    c("sex", "group")
    +  )$score
    +}
    +
    +# in this example we treat all the positions in the plate as equal.
    +# when shuffling we enforce that source location is non-empty,
    +# and destination location has a different plate number
    +optimize_design(
    +  bc,
    +  samples,
    +  shuffle_proposal = shuffle_with_constraints(
    +    # source is non-empty location
    +    !is.na(.sample_id),
    +    # destination has a different plate
    +    plate != .src$plate
    +  ),
    +  max_iter = 10
    +)
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Checking variances of 1-dim. score vector.
    +#> ... (455.222) - OK
    +#> Initial score: 172.8
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Achieved score: 158.8 at iteration 3
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Achieved score: 138.8 at iteration 4
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Achieved score: 136.8 at iteration 8
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Optimization trace (11 score values, elapsed 1.385776 secs).
    +#>   Starting score: 172.8
    +#>   Final score   : 136.8
    +
    +
    +
    + +
    + + +
    + +
    +

    Site built with pkgdown 2.0.7.

    +
    + +
    + + + + + + + + diff --git a/dev/reference/shuffle_with_subgroup_formation.html b/dev/reference/shuffle_with_subgroup_formation.html new file mode 100644 index 00000000..e570c325 --- /dev/null +++ b/dev/reference/shuffle_with_subgroup_formation.html @@ -0,0 +1,149 @@ + +Compose shuffling function based on already available subgrouping and allocation information — shuffle_with_subgroup_formation • designit + + +
    +
    + + + +
    +
    + + +
    +

    Compose shuffling function based on already available subgrouping and allocation information

    +
    + +
    +
    shuffle_with_subgroup_formation(
    +  subgroup_object,
    +  subgroup_allocations,
    +  keep_separate_vars = c(),
    +  report_grouping_as_attribute = FALSE
    +)
    +
    + +
    +

    Arguments

    +
    subgroup_object
    +

    A subgrouping object as returned by form_homogeneous_subgroups()

    + + +
    subgroup_allocations
    +

    A list of possible assignments of the allocation variable as returned by compile_possible_subgroup_allocation()

    + + +
    keep_separate_vars
    +

    Vector of column names in sample table; items with identical values in those variables will not be put into the same subgroup if at all possible

    + + +
    report_grouping_as_attribute
    +

    Boolean, if TRUE, add an attribute table to the permutation functions' output, to be used in scoring during the design optimization

    + +
    +
    +

    Value

    + + +

    Shuffling function that on each call returns an index vector for a valid sample permutation

    +
    + +
    + +
    + + +
    + +
    +

    Site built with pkgdown 2.0.7.

    +
    + +
    + + + + + + + + diff --git a/dev/reference/simanneal_acceptance_prob.html b/dev/reference/simanneal_acceptance_prob.html new file mode 100644 index 00000000..3d88644c --- /dev/null +++ b/dev/reference/simanneal_acceptance_prob.html @@ -0,0 +1,144 @@ + +Acceptance probability for a new solution — simanneal_acceptance_prob • designit + + +
    +
    + + + +
    +
    + + +
    +

    A solution is always to be accepted if it leads to a lower score. Worse solutions should be accepted with a probability given by this function.

    +
    + +
    +
    simanneal_acceptance_prob(current_score, best_score, temp, eps = 0.1)
    +
    + +
    +

    Arguments

    +
    current_score
    +

    Score from the current optimizing iteration (scalar value, double)

    + + +
    best_score
    +

    Score from the current optimizing iteration (scalar value, double)

    + + +
    temp
    +

    Current value of annealing temperature

    + + +
    eps
    +

    Small parameter eps(ilon), achieving that not always the new solution is taken when scores are exactly equal

    + +
    +
    +

    Value

    + + +

    Probability with which to accept the new score as the best one

    +
    + +
    + +
    + + +
    + +
    +

    Site built with pkgdown 2.0.7.

    +
    + +
    + + + + + + + + diff --git a/dev/reference/sum_scores.html b/dev/reference/sum_scores.html new file mode 100644 index 00000000..1981fbc1 --- /dev/null +++ b/dev/reference/sum_scores.html @@ -0,0 +1,146 @@ + +Aggregation of scores: sum up all individual scores — sum_scores • designit + + +
    +
    + + + +
    +
    + + +
    +

    Aggregation of scores: sum up all individual scores

    +
    + +
    +
    sum_scores(scores, na.rm = FALSE, ...)
    +
    + +
    +

    Arguments

    +
    scores
    +

    A score or multiple component score vector

    + + +
    na.rm
    +

    Boolean. Should NA values be ignored when obtaining the maximum? FALSE by default as ignoring NA values may render the sum meaningless.

    + + +
    ...
    +

    Parameters to be ignored by this aggregation function

    + +
    +
    +

    Value

    + + +

    The aggregated score, i.e. the sum of all indicidual scores.

    +
    + +
    +

    Examples

    +
    sum_scores(c(3, 2, 1))
    +#> [1] 6
    +
    +
    +
    + +
    + + +
    + +
    +

    Site built with pkgdown 2.0.7.

    +
    + +
    + + + + + + + + diff --git a/dev/reference/tidyeval.html b/dev/reference/tidyeval.html new file mode 100644 index 00000000..56be89d3 --- /dev/null +++ b/dev/reference/tidyeval.html @@ -0,0 +1,178 @@ + +Tidy eval helpers — tidyeval • designit + + +
    +
    + + + +
    +
    + + +
    + +
    • sym() creates a symbol from a string and +syms() creates a list of symbols from a +character vector.

    • +
    • enquo() and +enquos() delay the execution of one or +several function arguments. enquo() returns a single quoted +expression, which is like a blueprint for the delayed computation. +enquos() returns a list of such quoted expressions.

    • +
    • expr() quotes a new expression locally. It +is mostly useful to build new expressions around arguments +captured with enquo() or enquos(): +expr(mean(!!enquo(arg), na.rm = TRUE)).

    • +
    • as_name() transforms a quoted variable name +into a string. Supplying something else than a quoted variable +name is an error.

      +

      That's unlike as_label() which also returns +a single string but supports any kind of R object as input, +including quoted function calls and vectors. Its purpose is to +summarise that object into a single label. That label is often +suitable as a default name.

      +

      If you don't know what a quoted expression contains (for instance +expressions captured with enquo() could be a variable +name, a call to a function, or an unquoted constant), then use +as_label(). If you know you have quoted a simple variable +name, or would like to enforce this, use as_name().

    • +

    To learn more about tidy eval and how to use these tools, visit +https://tidyeval.tidyverse.org and the +Metaprogramming +section of Advanced R.

    +
    + + + +
    + +
    + + +
    + +
    +

    Site built with pkgdown 2.0.7.

    +
    + +
    + + + + + + + + diff --git a/dev/reference/update_batchcontainer.html b/dev/reference/update_batchcontainer.html new file mode 100644 index 00000000..43f39284 --- /dev/null +++ b/dev/reference/update_batchcontainer.html @@ -0,0 +1,136 @@ + +Updates a batch container by permuting samples according to a shuffling — update_batchcontainer • designit + + +
    +
    + + + +
    +
    + + +
    +

    As post-condition, the batch container is in a different state

    +
    + +
    +
    update_batchcontainer(bc, shuffle_params)
    +
    + +
    +

    Arguments

    +
    bc
    +

    The batch container to operate on.

    + + +
    shuffle_params
    +

    Shuffling parameters as returned by extract_shuffle_params().

    + +
    +
    +

    Value

    + + +

    TRUE if sample attributes have been assigned, FALSE otherwise

    +
    + +
    + +
    + + +
    + +
    +

    Site built with pkgdown 2.0.7.

    +
    + +
    + + + + + + + + diff --git a/dev/reference/validate_samples.html b/dev/reference/validate_samples.html new file mode 100644 index 00000000..3855a24c --- /dev/null +++ b/dev/reference/validate_samples.html @@ -0,0 +1,126 @@ + +Validates sample data.frame. — validate_samples • designit + + +
    +
    + + + +
    +
    + + +
    +

    Validates sample data.frame.

    +
    + +
    +
    validate_samples(samples)
    +
    + +
    +

    Arguments

    +
    samples
    +

    A data.frame having a sample annotation per row.

    + +
    + +
    + +
    + + +
    + +
    +

    Site built with pkgdown 2.0.7.

    +
    + +
    + + + + + + + + diff --git a/dev/reference/validate_subgrouping_object.html b/dev/reference/validate_subgrouping_object.html new file mode 100644 index 00000000..25fc67a2 --- /dev/null +++ b/dev/reference/validate_subgrouping_object.html @@ -0,0 +1,126 @@ + +Validate subgroup object and stop with error message if not all required fields are there — validate_subgrouping_object • designit + + +
    +
    + + + +
    +
    + + +
    +

    Validate subgroup object and stop with error message if not all required fields are there

    +
    + +
    +
    validate_subgrouping_object(subgroup_object)
    +
    + +
    +

    Arguments

    +
    subgroup_object
    +

    Subgrouping object as returned by form_homogeneous_subgroups()

    + +
    + +
    + +
    + + +
    + +
    +

    Site built with pkgdown 2.0.7.

    +
    + +
    + + + + + + + + diff --git a/dev/reference/worst_score.html b/dev/reference/worst_score.html new file mode 100644 index 00000000..e163680f --- /dev/null +++ b/dev/reference/worst_score.html @@ -0,0 +1,148 @@ + +Aggregation of scores: take the maximum (i.e. worst score only) — worst_score • designit + + +
    +
    + + + +
    +
    + + +
    +

    This function enables comparison of the results of two scoring functions by just basing +the decision on the largest element. This corresponds to the infinity-norm in ML terms.

    +
    + +
    +
    worst_score(scores, na.rm = FALSE, ...)
    +
    + +
    +

    Arguments

    +
    scores
    +

    A score or multiple component score vector

    + + +
    na.rm
    +

    Boolean. Should NA values be ignored when obtaining the maximum? FALSE by default as ignoring NA values may hide some issues with the provided scoring functions and also the aggregated value cannot be seen as the proper infinity norm anymore.

    + + +
    ...
    +

    Parameters to be ignored by this aggregation function

    + +
    +
    +

    Value

    + + +

    The aggregated score, i.e. the value of the largest element in a multiple-component score vector.

    +
    + +
    +

    Examples

    +
    worst_score(c(3, 2, 1))
    +#> [1] 3
    +
    +
    +
    + +
    + + +
    + +
    +

    Site built with pkgdown 2.0.7.

    +
    + +
    + + + + + + + + diff --git a/dev/sitemap.xml b/dev/sitemap.xml new file mode 100644 index 00000000..2f5a7f74 --- /dev/null +++ b/dev/sitemap.xml @@ -0,0 +1,249 @@ + + + + https://bedapub.github.io/designit/CODE_OF_CONDUCT.html + + + https://bedapub.github.io/designit/ISSUE_TEMPLATE.html + + + https://bedapub.github.io/designit/LICENSE-text.html + + + https://bedapub.github.io/designit/LICENSE.html + + + https://bedapub.github.io/designit/articles/NCS22_talk.html + + + https://bedapub.github.io/designit/articles/basic_examples.html + + + https://bedapub.github.io/designit/articles/custom_shuffle.html + + + https://bedapub.github.io/designit/articles/index.html + + + https://bedapub.github.io/designit/articles/invivo_study_design.html + + + https://bedapub.github.io/designit/articles/nested_dimensions_examples.html + + + https://bedapub.github.io/designit/articles/optimizer_examples.html + + + https://bedapub.github.io/designit/articles/osat.html + + + https://bedapub.github.io/designit/articles/plate_layouts.html + + + https://bedapub.github.io/designit/articles/plate_scoring_examples.html + + + https://bedapub.github.io/designit/articles/shuffling_with_constraints.html + + + https://bedapub.github.io/designit/authors.html + + + https://bedapub.github.io/designit/index.html + + + https://bedapub.github.io/designit/news/index.html + + + https://bedapub.github.io/designit/reference/BatchContainer.html + + + https://bedapub.github.io/designit/reference/BatchContainerDimension.html + + + https://bedapub.github.io/designit/reference/L1_norm.html + + + https://bedapub.github.io/designit/reference/L2s_norm.html + + + https://bedapub.github.io/designit/reference/OptimizationTrace.html + + + https://bedapub.github.io/designit/reference/accept_leftmost_improvement.html + + + https://bedapub.github.io/designit/reference/accept_strict_improvement.html + + + https://bedapub.github.io/designit/reference/assign_from_table.html + + + https://bedapub.github.io/designit/reference/assign_in_order.html + + + https://bedapub.github.io/designit/reference/assign_random.html + + + https://bedapub.github.io/designit/reference/batch_container_from_table.html + + + https://bedapub.github.io/designit/reference/compile_possible_subgroup_allocation.html + + + https://bedapub.github.io/designit/reference/complete_random_shuffling.html + + + https://bedapub.github.io/designit/reference/countGini.html + + + https://bedapub.github.io/designit/reference/designit-package.html + + + https://bedapub.github.io/designit/reference/dot-datatable.aware.html + + + https://bedapub.github.io/designit/reference/drop_order.html + + + https://bedapub.github.io/designit/reference/extract_shuffle_params.html + + + https://bedapub.github.io/designit/reference/find_possible_block_allocations.html + + + https://bedapub.github.io/designit/reference/first_score_only.html + + + https://bedapub.github.io/designit/reference/form_homogeneous_subgroups.html + + + https://bedapub.github.io/designit/reference/generate_terms.html + + + https://bedapub.github.io/designit/reference/getScore.html + + + https://bedapub.github.io/designit/reference/get_order.html + + + https://bedapub.github.io/designit/reference/index.html + + + https://bedapub.github.io/designit/reference/invivo_study_samples.html + + + https://bedapub.github.io/designit/reference/invivo_study_treatments.html + + + https://bedapub.github.io/designit/reference/kruskal.html + + + https://bedapub.github.io/designit/reference/locations_table_from_dimensions.html + + + https://bedapub.github.io/designit/reference/longitudinal_subject_samples.html + + + https://bedapub.github.io/designit/reference/make_colnames.html + + + https://bedapub.github.io/designit/reference/meanDiff.html + + + https://bedapub.github.io/designit/reference/mk_autoscale_function.html + + + https://bedapub.github.io/designit/reference/mk_constant_swapping_function.html + + + https://bedapub.github.io/designit/reference/mk_dist_matrix.html + + + https://bedapub.github.io/designit/reference/mk_exponentially_weighted_acceptance_func.html + + + https://bedapub.github.io/designit/reference/mk_plate_scoring_functions.html + + + https://bedapub.github.io/designit/reference/mk_simanneal_acceptance_func.html + + + https://bedapub.github.io/designit/reference/mk_simanneal_temp_func.html + + + https://bedapub.github.io/designit/reference/mk_subgroup_shuffling_function.html + + + https://bedapub.github.io/designit/reference/mk_swapping_function.html + + + https://bedapub.github.io/designit/reference/multi_trt_day_samples.html + + + https://bedapub.github.io/designit/reference/neighbors.html + + + https://bedapub.github.io/designit/reference/optimize_design.html + + + https://bedapub.github.io/designit/reference/optimize_multi_plate_design.html + + + https://bedapub.github.io/designit/reference/osat_score.html + + + https://bedapub.github.io/designit/reference/osat_score_generator.html + + + https://bedapub.github.io/designit/reference/pairwise_swapping.html + + + https://bedapub.github.io/designit/reference/pipe.html + + + https://bedapub.github.io/designit/reference/plot_plate.html + + + https://bedapub.github.io/designit/reference/random_score_variances.html + + + https://bedapub.github.io/designit/reference/randomize.html + + + https://bedapub.github.io/designit/reference/report_scores.html + + + https://bedapub.github.io/designit/reference/sample_random_scores.html + + + https://bedapub.github.io/designit/reference/shuffle_grouped_data.html + + + https://bedapub.github.io/designit/reference/shuffle_with_constraints.html + + + https://bedapub.github.io/designit/reference/shuffle_with_subgroup_formation.html + + + https://bedapub.github.io/designit/reference/simanneal_acceptance_prob.html + + + https://bedapub.github.io/designit/reference/sum_scores.html + + + https://bedapub.github.io/designit/reference/tidyeval.html + + + https://bedapub.github.io/designit/reference/update_batchcontainer.html + + + https://bedapub.github.io/designit/reference/validate_samples.html + + + https://bedapub.github.io/designit/reference/validate_subgrouping_object.html + + + https://bedapub.github.io/designit/reference/worst_score.html + + diff --git a/docsearch.css b/docsearch.css new file mode 100644 index 00000000..e5f1fe1d --- /dev/null +++ b/docsearch.css @@ -0,0 +1,148 @@ +/* Docsearch -------------------------------------------------------------- */ +/* + Source: https://github.com/algolia/docsearch/ + License: MIT +*/ + +.algolia-autocomplete { + display: block; + -webkit-box-flex: 1; + -ms-flex: 1; + flex: 1 +} + +.algolia-autocomplete .ds-dropdown-menu { + width: 100%; + min-width: none; + max-width: none; + padding: .75rem 0; + background-color: #fff; + background-clip: padding-box; + border: 1px solid rgba(0, 0, 0, .1); + box-shadow: 0 .5rem 1rem rgba(0, 0, 0, .175); +} + +@media (min-width:768px) { + .algolia-autocomplete .ds-dropdown-menu { + width: 175% + } +} + +.algolia-autocomplete .ds-dropdown-menu::before { + display: none +} + +.algolia-autocomplete .ds-dropdown-menu [class^=ds-dataset-] { + padding: 0; + background-color: rgb(255,255,255); + border: 0; + max-height: 80vh; +} + +.algolia-autocomplete .ds-dropdown-menu .ds-suggestions { + margin-top: 0 +} + +.algolia-autocomplete .algolia-docsearch-suggestion { + padding: 0; + overflow: visible +} + +.algolia-autocomplete .algolia-docsearch-suggestion--category-header { + padding: .125rem 1rem; + margin-top: 0; + font-size: 1.3em; + font-weight: 500; + color: #00008B; + border-bottom: 0 +} + +.algolia-autocomplete .algolia-docsearch-suggestion--wrapper { + float: none; + padding-top: 0 +} + +.algolia-autocomplete .algolia-docsearch-suggestion--subcategory-column { + float: none; + width: auto; + padding: 0; + text-align: left +} + +.algolia-autocomplete .algolia-docsearch-suggestion--content { + float: none; + width: auto; + padding: 0 +} + +.algolia-autocomplete .algolia-docsearch-suggestion--content::before { + display: none +} + +.algolia-autocomplete .ds-suggestion:not(:first-child) .algolia-docsearch-suggestion--category-header { + padding-top: .75rem; + margin-top: .75rem; + border-top: 1px solid rgba(0, 0, 0, .1) +} + +.algolia-autocomplete .ds-suggestion .algolia-docsearch-suggestion--subcategory-column { + display: block; + padding: .1rem 1rem; + margin-bottom: 0.1; + font-size: 1.0em; + font-weight: 400 + /* display: none */ +} + +.algolia-autocomplete .algolia-docsearch-suggestion--title { + display: block; + padding: .25rem 1rem; + margin-bottom: 0; + font-size: 0.9em; + font-weight: 400 +} + +.algolia-autocomplete .algolia-docsearch-suggestion--text { + padding: 0 1rem .5rem; + margin-top: -.25rem; + font-size: 0.8em; + font-weight: 400; + line-height: 1.25 +} + +.algolia-autocomplete .algolia-docsearch-footer { + width: 110px; + height: 20px; + z-index: 3; + margin-top: 10.66667px; + float: right; + font-size: 0; + line-height: 0; +} + +.algolia-autocomplete .algolia-docsearch-footer--logo { + background-image: url("data:image/svg+xml;utf8,"); + background-repeat: no-repeat; + background-position: 50%; + background-size: 100%; + overflow: hidden; + text-indent: -9000px; + width: 100%; + height: 100%; + display: block; + transform: translate(-8px); +} + +.algolia-autocomplete .algolia-docsearch-suggestion--highlight { + color: #FF8C00; + background: rgba(232, 189, 54, 0.1) +} + + +.algolia-autocomplete .algolia-docsearch-suggestion--text .algolia-docsearch-suggestion--highlight { + box-shadow: inset 0 -2px 0 0 rgba(105, 105, 105, .5) +} + +.algolia-autocomplete .ds-suggestion.ds-cursor .algolia-docsearch-suggestion--content { + background-color: rgba(192, 192, 192, .15) +} diff --git a/docsearch.js b/docsearch.js new file mode 100644 index 00000000..b35504cd --- /dev/null +++ b/docsearch.js @@ -0,0 +1,85 @@ +$(function() { + + // register a handler to move the focus to the search bar + // upon pressing shift + "/" (i.e. "?") + $(document).on('keydown', function(e) { + if (e.shiftKey && e.keyCode == 191) { + e.preventDefault(); + $("#search-input").focus(); + } + }); + + $(document).ready(function() { + // do keyword highlighting + /* modified from https://jsfiddle.net/julmot/bL6bb5oo/ */ + var mark = function() { + + var referrer = document.URL ; + var paramKey = "q" ; + + if (referrer.indexOf("?") !== -1) { + var qs = referrer.substr(referrer.indexOf('?') + 1); + var qs_noanchor = qs.split('#')[0]; + var qsa = qs_noanchor.split('&'); + var keyword = ""; + + for (var i = 0; i < qsa.length; i++) { + var currentParam = qsa[i].split('='); + + if (currentParam.length !== 2) { + continue; + } + + if (currentParam[0] == paramKey) { + keyword = decodeURIComponent(currentParam[1].replace(/\+/g, "%20")); + } + } + + if (keyword !== "") { + $(".contents").unmark({ + done: function() { + $(".contents").mark(keyword); + } + }); + } + } + }; + + mark(); + }); +}); + +/* Search term highlighting ------------------------------*/ + +function matchedWords(hit) { + var words = []; + + var hierarchy = hit._highlightResult.hierarchy; + // loop to fetch from lvl0, lvl1, etc. + for (var idx in hierarchy) { + words = words.concat(hierarchy[idx].matchedWords); + } + + var content = hit._highlightResult.content; + if (content) { + words = words.concat(content.matchedWords); + } + + // return unique words + var words_uniq = [...new Set(words)]; + return words_uniq; +} + +function updateHitURL(hit) { + + var words = matchedWords(hit); + var url = ""; + + if (hit.anchor) { + url = hit.url_without_anchor + '?q=' + escape(words.join(" ")) + '#' + hit.anchor; + } else { + url = hit.url + '?q=' + escape(words.join(" ")); + } + + return url; +} diff --git a/favicon-16x16.png b/favicon-16x16.png new file mode 100644 index 00000000..d599928a Binary files /dev/null and b/favicon-16x16.png differ diff --git a/favicon-32x32.png b/favicon-32x32.png new file mode 100644 index 00000000..5de52d8c Binary files /dev/null and b/favicon-32x32.png differ diff --git a/favicon.ico b/favicon.ico new file mode 100644 index 00000000..52522cdd Binary files /dev/null and b/favicon.ico differ diff --git a/index.html b/index.html new file mode 100644 index 00000000..8e9a43a6 --- /dev/null +++ b/index.html @@ -0,0 +1,310 @@ + + + + + + + +Blocking and Randomization for Experimental Design • designit + + + + + + + + + + + + + + + + + + + +
    +
    + + + + +
    +
    +
    + + + +

    The goal of designit is to generate optimal sample allocations for experimental designs.

    +
    +

    Installation +

    +

    You can install the development version from GitHub with:

    +
    +# install.packages("devtools")
    +devtools::install_github("BEDApub/designit")
    +
    +
    +

    Usage +

    +
    +

    R in Pharma presentation +

    +

    Designit: a flexible engine to generate experiment layouts, R in Pharma presentation

    +
    +
    +

    Batch container +

    +

    The main class used is BatchContainer, which holds the dimensions for sample allocation. After creating such a container, a list of samples can be allocated in it using a given assignment function.

    +
    +
    +

    Creating a table with sample information +

    +
    +library(tidyverse)
    +library(designit)
    +
    +data("longitudinal_subject_samples")
    +
    +# we use a subset of longitudinal_subject_samples data
    +subject_data <- longitudinal_subject_samples %>% 
    +  filter(Group %in% 1:5, Week %in% c(1,4)) %>% 
    +  select(SampleID, SubjectID, Group, Sex, Week) %>%
    +  # with two observations per patient
    +  group_by(SubjectID) %>%
    +  filter(n() == 2) %>%
    +  ungroup() %>%
    +  select(SubjectID, Group, Sex) %>%
    +  distinct()
    +
    +head(subject_data)
    +#> # A tibble: 6 × 3
    +#>   SubjectID Group Sex  
    +#>   <chr>     <chr> <chr>
    +#> 1 P01       1     F    
    +#> 2 P02       1     M    
    +#> 3 P03       1     M    
    +#> 4 P04       1     F    
    +#> 5 P19       1     M    
    +#> 6 P20       1     F
    +
    +
    +

    Creating a BatchContainer and assigning samples +

    +
    +# a batch container with 3 batches and 11 locations per batch
    +bc <- BatchContainer$new(
    +  dimensions = list("batch" = 3, "location" = 11),
    +)
    +
    +# assign samples randomly
    +set.seed(17)
    +bc <- assign_random(bc, subject_data)
    +
    +bc$get_samples() %>%
    +  ggplot() +
    +  aes(x = batch, fill = Group) +
    +  geom_bar()
    +

    +

    Random assignmet of samples to batches produced an uneven distribution.

    +
    +
    +

    Optimizing the assignemnt +

    +
    +# set scoring functions
    +scoring_f <- list(
    +  # first priority, groups are evenly distributed
    +  group = osat_score_generator(batch_vars = "batch", 
    +                               feature_vars = "Group"),
    +  # second priority, sexes are evenly distributed
    +  sex = osat_score_generator(batch_vars = "batch", 
    +                             feature_vars = "Sex")
    +)
    +
    +bc <- optimize_design(
    +  bc, scoring = scoring_f, max_iter = 150, quiet = TRUE
    +)
    +
    +bc$get_samples() %>%
    +  ggplot() +
    +  aes(x = batch, fill = Group) +
    +  geom_bar()
    +

    +
    +
    +# show optimization trace
    +bc$plot_trace()
    +

    +
    +
    +
    +

    Examples +

    +

    See vignettes vignette("basic_examples").

    +
    +
    +

    Acknowledgement +

    +

    The logo is inspired by DALL-E 2 and pipette icon by gsagri04.

    +
    +
    +
    + + +
    + + +
    + +
    +

    +

    Site built with pkgdown 2.0.7.

    +
    + +
    +
    + + + + + + + + diff --git a/link.svg b/link.svg new file mode 100644 index 00000000..88ad8276 --- /dev/null +++ b/link.svg @@ -0,0 +1,12 @@ + + + + + + diff --git a/logo.svg b/logo.svg new file mode 100644 index 00000000..8be4741a --- /dev/null +++ b/logo.svg @@ -0,0 +1,2 @@ + + diff --git a/news/index.html b/news/index.html new file mode 100644 index 00000000..57027d7c --- /dev/null +++ b/news/index.html @@ -0,0 +1,170 @@ + +Changelog • designit + + +
    +
    + + + +
    +
    + + +
    + +
    • mainly github action changes
    • +
    +
    + +
    • multiplate wrapper
    • +
    • fixes in the OptimizationTrace
    • +
    • cleanup
    • +
    +
    + +
    • +BatchContainer stores locations table (dimensions & excluded)
    • +
    • +BatchContainer$new() accepts locations table
    • +
    • +BatchContainer with samples can be created using batch_container_from_table +
    • +
    • +bc$n_available was removed (use bc$n_locations instead)
    • +
    • minor improvements to print(bc) +
    • +
    +
    + +
    • fix dplyr filter issue (once again)
    • +
    • migrate from BEDA to PMDA
    • +
    +
    + +
    • fix dplyr filter issue
    • +
    +
    + +
    • fix plate scoring example vignette caching
    • +
    +
    + +
    • plate scoring
    • +
    +
    + +
    +
    + +
    • +BatchContainer major API update
    • +
    • rename fields for consistency
    • +
    • hide cachind ($samples_dt) behind $get_samples() +
    • +
    • +$sample_attr for sample attributes
    • +
    • unified $move_samples() for moving samples
    • +
    +
    + + + +
    + + +
    + +
    +

    Site built with pkgdown 2.0.7.

    +
    + +
    + + + + + + + + diff --git a/pkgdown.css b/pkgdown.css new file mode 100644 index 00000000..80ea5b83 --- /dev/null +++ b/pkgdown.css @@ -0,0 +1,384 @@ +/* Sticky footer */ + +/** + * Basic idea: https://philipwalton.github.io/solved-by-flexbox/demos/sticky-footer/ + * Details: https://github.com/philipwalton/solved-by-flexbox/blob/master/assets/css/components/site.css + * + * .Site -> body > .container + * .Site-content -> body > .container .row + * .footer -> footer + * + * Key idea seems to be to ensure that .container and __all its parents__ + * have height set to 100% + * + */ + +html, body { + height: 100%; +} + +body { + position: relative; +} + +body > .container { + display: flex; + height: 100%; + flex-direction: column; +} + +body > .container .row { + flex: 1 0 auto; +} + +footer { + margin-top: 45px; + padding: 35px 0 36px; + border-top: 1px solid #e5e5e5; + color: #666; + display: flex; + flex-shrink: 0; +} +footer p { + margin-bottom: 0; +} +footer div { + flex: 1; +} +footer .pkgdown { + text-align: right; +} +footer p { + margin-bottom: 0; +} + +img.icon { + float: right; +} + +/* Ensure in-page images don't run outside their container */ +.contents img { + max-width: 100%; + height: auto; +} + +/* Fix bug in bootstrap (only seen in firefox) */ +summary { + display: list-item; +} + +/* Typographic tweaking ---------------------------------*/ + +.contents .page-header { + margin-top: calc(-60px + 1em); +} + +dd { + margin-left: 3em; +} + +/* Section anchors ---------------------------------*/ + +a.anchor { + display: none; + margin-left: 5px; + width: 20px; + height: 20px; + + background-image: url(./link.svg); + background-repeat: no-repeat; + background-size: 20px 20px; + background-position: center center; +} + +h1:hover .anchor, +h2:hover .anchor, +h3:hover .anchor, +h4:hover .anchor, +h5:hover .anchor, +h6:hover .anchor { + display: inline-block; +} + +/* Fixes for fixed navbar --------------------------*/ + +.contents h1, .contents h2, .contents h3, .contents h4 { + padding-top: 60px; + margin-top: -40px; +} + +/* Navbar submenu --------------------------*/ + +.dropdown-submenu { + position: relative; +} + +.dropdown-submenu>.dropdown-menu { + top: 0; + left: 100%; + margin-top: -6px; + margin-left: -1px; + border-radius: 0 6px 6px 6px; +} + +.dropdown-submenu:hover>.dropdown-menu { + display: block; +} + +.dropdown-submenu>a:after { + display: block; + content: " "; + float: right; + width: 0; + height: 0; + border-color: transparent; + border-style: solid; + border-width: 5px 0 5px 5px; + border-left-color: #cccccc; + margin-top: 5px; + margin-right: -10px; +} + +.dropdown-submenu:hover>a:after { + border-left-color: #ffffff; +} + +.dropdown-submenu.pull-left { + float: none; +} + +.dropdown-submenu.pull-left>.dropdown-menu { + left: -100%; + margin-left: 10px; + border-radius: 6px 0 6px 6px; +} + +/* Sidebar --------------------------*/ + +#pkgdown-sidebar { + margin-top: 30px; + position: -webkit-sticky; + position: sticky; + top: 70px; +} + +#pkgdown-sidebar h2 { + font-size: 1.5em; + margin-top: 1em; +} + +#pkgdown-sidebar h2:first-child { + margin-top: 0; +} + +#pkgdown-sidebar .list-unstyled li { + margin-bottom: 0.5em; +} + +/* bootstrap-toc tweaks ------------------------------------------------------*/ + +/* All levels of nav */ + +nav[data-toggle='toc'] .nav > li > a { + padding: 4px 20px 4px 6px; + font-size: 1.5rem; + font-weight: 400; + color: inherit; +} + +nav[data-toggle='toc'] .nav > li > a:hover, +nav[data-toggle='toc'] .nav > li > a:focus { + padding-left: 5px; + color: inherit; + border-left: 1px solid #878787; +} + +nav[data-toggle='toc'] .nav > .active > a, +nav[data-toggle='toc'] .nav > .active:hover > a, +nav[data-toggle='toc'] .nav > .active:focus > a { + padding-left: 5px; + font-size: 1.5rem; + font-weight: 400; + color: inherit; + border-left: 2px solid #878787; +} + +/* Nav: second level (shown on .active) */ + +nav[data-toggle='toc'] .nav .nav { + display: none; /* Hide by default, but at >768px, show it */ + padding-bottom: 10px; +} + +nav[data-toggle='toc'] .nav .nav > li > a { + padding-left: 16px; + font-size: 1.35rem; +} + +nav[data-toggle='toc'] .nav .nav > li > a:hover, +nav[data-toggle='toc'] .nav .nav > li > a:focus { + padding-left: 15px; +} + +nav[data-toggle='toc'] .nav .nav > .active > a, +nav[data-toggle='toc'] .nav .nav > .active:hover > a, +nav[data-toggle='toc'] .nav .nav > .active:focus > a { + padding-left: 15px; + font-weight: 500; + font-size: 1.35rem; +} + +/* orcid ------------------------------------------------------------------- */ + +.orcid { + font-size: 16px; + color: #A6CE39; + /* margins are required by official ORCID trademark and display guidelines */ + margin-left:4px; + margin-right:4px; + vertical-align: middle; +} + +/* Reference index & topics ----------------------------------------------- */ + +.ref-index th {font-weight: normal;} + +.ref-index td {vertical-align: top; min-width: 100px} +.ref-index .icon {width: 40px;} +.ref-index .alias {width: 40%;} +.ref-index-icons .alias {width: calc(40% - 40px);} +.ref-index .title {width: 60%;} + +.ref-arguments th {text-align: right; padding-right: 10px;} +.ref-arguments th, .ref-arguments td {vertical-align: top; min-width: 100px} +.ref-arguments .name {width: 20%;} +.ref-arguments .desc {width: 80%;} + +/* Nice scrolling for wide elements --------------------------------------- */ + +table { + display: block; + overflow: auto; +} + +/* Syntax highlighting ---------------------------------------------------- */ + +pre, code, pre code { + background-color: #f8f8f8; + color: #333; +} +pre, pre code { + white-space: pre-wrap; + word-break: break-all; + overflow-wrap: break-word; +} + +pre { + border: 1px solid #eee; +} + +pre .img, pre .r-plt { + margin: 5px 0; +} + +pre .img img, pre .r-plt img { + background-color: #fff; +} + +code a, pre a { + color: #375f84; +} + +a.sourceLine:hover { + text-decoration: none; +} + +.fl {color: #1514b5;} +.fu {color: #000000;} /* function */ +.ch,.st {color: #036a07;} /* string */ +.kw {color: #264D66;} /* keyword */ +.co {color: #888888;} /* comment */ + +.error {font-weight: bolder;} +.warning {font-weight: bolder;} + +/* Clipboard --------------------------*/ + +.hasCopyButton { + position: relative; +} + +.btn-copy-ex { + position: absolute; + right: 0; + top: 0; + visibility: hidden; +} + +.hasCopyButton:hover button.btn-copy-ex { + visibility: visible; +} + +/* headroom.js ------------------------ */ + +.headroom { + will-change: transform; + transition: transform 200ms linear; +} +.headroom--pinned { + transform: translateY(0%); +} +.headroom--unpinned { + transform: translateY(-100%); +} + +/* mark.js ----------------------------*/ + +mark { + background-color: rgba(255, 255, 51, 0.5); + border-bottom: 2px solid rgba(255, 153, 51, 0.3); + padding: 1px; +} + +/* vertical spacing after htmlwidgets */ +.html-widget { + margin-bottom: 10px; +} + +/* fontawesome ------------------------ */ + +.fab { + font-family: "Font Awesome 5 Brands" !important; +} + +/* don't display links in code chunks when printing */ +/* source: https://stackoverflow.com/a/10781533 */ +@media print { + code a:link:after, code a:visited:after { + content: ""; + } +} + +/* Section anchors --------------------------------- + Added in pandoc 2.11: https://github.com/jgm/pandoc-templates/commit/9904bf71 +*/ + +div.csl-bib-body { } +div.csl-entry { + clear: both; +} +.hanging-indent div.csl-entry { + margin-left:2em; + text-indent:-2em; +} +div.csl-left-margin { + min-width:2em; + float:left; +} +div.csl-right-inline { + margin-left:2em; + padding-left:1em; +} +div.csl-indent { + margin-left: 2em; +} diff --git a/pkgdown.js b/pkgdown.js new file mode 100644 index 00000000..6f0eee40 --- /dev/null +++ b/pkgdown.js @@ -0,0 +1,108 @@ +/* http://gregfranko.com/blog/jquery-best-practices/ */ +(function($) { + $(function() { + + $('.navbar-fixed-top').headroom(); + + $('body').css('padding-top', $('.navbar').height() + 10); + $(window).resize(function(){ + $('body').css('padding-top', $('.navbar').height() + 10); + }); + + $('[data-toggle="tooltip"]').tooltip(); + + var cur_path = paths(location.pathname); + var links = $("#navbar ul li a"); + var max_length = -1; + var pos = -1; + for (var i = 0; i < links.length; i++) { + if (links[i].getAttribute("href") === "#") + continue; + // Ignore external links + if (links[i].host !== location.host) + continue; + + var nav_path = paths(links[i].pathname); + + var length = prefix_length(nav_path, cur_path); + if (length > max_length) { + max_length = length; + pos = i; + } + } + + // Add class to parent
  • , and enclosing
  • if in dropdown + if (pos >= 0) { + var menu_anchor = $(links[pos]); + menu_anchor.parent().addClass("active"); + menu_anchor.closest("li.dropdown").addClass("active"); + } + }); + + function paths(pathname) { + var pieces = pathname.split("/"); + pieces.shift(); // always starts with / + + var end = pieces[pieces.length - 1]; + if (end === "index.html" || end === "") + pieces.pop(); + return(pieces); + } + + // Returns -1 if not found + function prefix_length(needle, haystack) { + if (needle.length > haystack.length) + return(-1); + + // Special case for length-0 haystack, since for loop won't run + if (haystack.length === 0) { + return(needle.length === 0 ? 0 : -1); + } + + for (var i = 0; i < haystack.length; i++) { + if (needle[i] != haystack[i]) + return(i); + } + + return(haystack.length); + } + + /* Clipboard --------------------------*/ + + function changeTooltipMessage(element, msg) { + var tooltipOriginalTitle=element.getAttribute('data-original-title'); + element.setAttribute('data-original-title', msg); + $(element).tooltip('show'); + element.setAttribute('data-original-title', tooltipOriginalTitle); + } + + if(ClipboardJS.isSupported()) { + $(document).ready(function() { + var copyButton = ""; + + $("div.sourceCode").addClass("hasCopyButton"); + + // Insert copy buttons: + $(copyButton).prependTo(".hasCopyButton"); + + // Initialize tooltips: + $('.btn-copy-ex').tooltip({container: 'body'}); + + // Initialize clipboard: + var clipboardBtnCopies = new ClipboardJS('[data-clipboard-copy]', { + text: function(trigger) { + return trigger.parentNode.textContent.replace(/\n#>[^\n]*/g, ""); + } + }); + + clipboardBtnCopies.on('success', function(e) { + changeTooltipMessage(e.trigger, 'Copied!'); + e.clearSelection(); + }); + + clipboardBtnCopies.on('error', function() { + changeTooltipMessage(e.trigger,'Press Ctrl+C or Command+C to copy'); + }); + }); + } +})(window.jQuery || window.$) diff --git a/pkgdown.yml b/pkgdown.yml new file mode 100644 index 00000000..ff32bc97 --- /dev/null +++ b/pkgdown.yml @@ -0,0 +1,19 @@ +pandoc: 2.19.2 +pkgdown: 2.0.7 +pkgdown_sha: ~ +articles: + NCS22_talk: NCS22_talk.html + basic_examples: basic_examples.html + custom_shuffle: custom_shuffle.html + invivo_study_design: invivo_study_design.html + nested_dimensions_examples: nested_dimensions_examples.html + optimizer_examples: optimizer_examples.html + osat: osat.html + plate_layouts: plate_layouts.html + plate_scoring_examples: plate_scoring_examples.html + shuffling_with_constraints: shuffling_with_constraints.html +last_built: 2023-11-13T17:35Z +urls: + reference: https://bedapub.github.io/designit/reference + article: https://bedapub.github.io/designit/articles + diff --git a/reference/BatchContainer.html b/reference/BatchContainer.html new file mode 100644 index 00000000..788d7278 --- /dev/null +++ b/reference/BatchContainer.html @@ -0,0 +1,456 @@ + +R6 Class representing a batch container. — BatchContainer • designit + + +
    +
    + + + +
    +
    + + +
    +

    Describes container dimensions and samples to container location assignment.

    +
    + + +
    +

    Details

    +

    A typical workflow starts with creating a BatchContainer. Then +samples can be assigned to locations in that container.

    +
    +
    +

    Public fields

    +

    trace
    +

    Optimization trace, a tibble::tibble()

    + + +

    +
    +
    +

    Active bindings

    +

    scoring_f
    +

    Scoring functions used for optimization. +Each scoring function should receive a BatchContainer. +This function should return a floating +point score value for the assignment. This a list of functions. +Upon assignment a single function will be automatically converted to a list +In the later case each function is called.

    + + +
    has_samples
    +

    Returns TRUE if BatchContainer has samples.

    + + +
    has_samples_attr
    +

    Returns TRUE if BatchContainer has sample atrributes assigned.

    + + +
    n_locations
    +

    Returns number of locations in a BatchContainer.

    + + +
    n_dimensions
    +

    Returns number of dimensions in a BatchContainer. +This field cannot be assigned.

    + + +
    dimension_names
    +

    character vector with dimension names. +This field cannot be assigned.

    + + +
    samples
    +

    Samples in the batch container. +When assigning data.frame should not have column named .sample_id column.

    + + +
    samples_attr
    +

    Extra attributes of samples. If set, this is included into +BatchContainer$get_samples() output.

    + + +
    assignment
    +

    Sample assignment vector. Should contain NAs for empty locations.

    +

    Assigning this field is deprecated, please use $move_samples() instead.

    + + +

    +
    +
    +

    Methods

    + +


    +

    Method new()

    +

    Create a new BatchContainer object.

    +

    Usage

    +

    BatchContainer$new(locations_table, dimensions, exclude = NULL)

    +
    + +
    +

    Arguments

    +

    locations_table
    +

    A table with available locations.

    + + +
    dimensions
    +

    A vector or list of dimensions. Every dimension +should have a name. Could be an integer vector of dimensions or +a named list. Every value of a list could be either dimension size +or parameters for +BatchContainerDimension$new(). +Can be used as an alternative to passing locations_table.

    + + +
    exclude
    +

    data.frame with excluded locations of a container. +Only used together with dimensions.

    + + +

    +
    +
    +

    Examples

    +

    bc <- BatchContainer$new(
    +  dimensions = list(
    +    "plate" = 3,
    +    "row" = list(values = letters[1:3]),
    +    "column" = list(values = c(1, 3))
    +  ),
    +  exclude = data.frame(plate = 1, row = "a", column = c(1, 3), stringsAsFactors = FALSE)
    +)
    +
    +bc

    +
    + + +


    +

    Method get_samples()

    +

    Return table with samples and sample assignment.

    +

    Usage

    +

    BatchContainer$get_samples(
    +  assignment = TRUE,
    +  include_id = FALSE,
    +  remove_empty_locations = FALSE,
    +  as_tibble = TRUE
    +)

    +
    + +
    +

    Arguments

    +

    assignment
    +

    Return sample assignment. If FALSE, only +samples table is returned, with out batch assignment.

    + + +
    include_id
    +

    Keep .sample_id in the table. Use TRUE for +lower overhead.

    + + +
    remove_empty_locations
    +

    Removes empty locations +from the result tibble.

    + + +
    as_tibble
    +

    Return tibble. +If FALSE returns data.table. This should have +lower overhead, as internally there is a cached data.table.

    + + +

    +
    +
    +

    Returns

    +

    table with samples and sample assignment.

    +
    + +


    +

    Method get_locations()

    +

    Get a table with all the locations in a BatchContainer.

    +

    Usage

    +

    BatchContainer$get_locations()

    +
    + +
    +

    Returns

    +

    A tibble with all the available locations.

    +
    + +


    +

    Method move_samples()

    +

    Move samples between locations

    +

    This method can receive either src and dst or locations_assignment.

    +

    Usage

    +

    BatchContainer$move_samples(src, dst, location_assignment)

    +
    + +
    +

    Arguments

    +

    src
    +

    integer vector of source locations

    + + +
    dst
    +

    integer vector of destination locations (the same length as src).

    + + +
    location_assignment
    +

    integer vector with location assignment. +The length of the vector should match the number of locations, +NA should be used for empty locations.

    + + +

    +
    +
    +

    Returns

    +

    BatchContainer, invisibly

    +
    + +


    +

    Method score()

    +

    Score current sample assignment,

    +

    Usage

    +

    BatchContainer$score(scoring)

    +
    + +
    +

    Arguments

    +

    scoring
    +

    a function or a names list of scoring functions. +Each function should return a numeric vector.

    + + +

    +
    +
    +

    Returns

    +

    Returns a named vector of all scoring functions values.

    +
    + +


    +

    Method copy()

    +

    Create an independent copy (clone) of a BatchContainer

    +

    Usage

    +

    BatchContainer$copy()

    +
    + +
    +

    Returns

    +

    Returns a new BatchContainer

    +
    + +


    +

    Method print()

    +

    Prints information about BatchContainer.

    +

    Usage

    +

    BatchContainer$print(...)

    +
    + +
    +

    Arguments

    +

    ...
    +

    not used.

    + + +

    +
    + +


    +

    Method scores_table()

    +

    Return a table with scores from an optimization.

    +

    Usage

    +

    BatchContainer$scores_table(index = NULL, include_aggregated = FALSE)

    +
    + +
    +

    Arguments

    +

    index
    +

    optimization index, all by default

    + + +
    include_aggregated
    +

    include aggregated scores

    + + +

    +
    +
    +

    Returns

    +

    a tibble::tibble() with scores

    +
    + +


    +

    Method plot_trace()

    +

    Plot trace

    +

    Usage

    +

    BatchContainer$plot_trace(index = NULL, include_aggregated = FALSE, ...)

    +
    + +
    +

    Arguments

    +

    index
    +

    optimization index, all by default

    + + +
    include_aggregated
    +

    include aggregated scores

    + + +
    ...
    +

    not used.

    + + +

    +
    +
    +

    Returns

    +

    a ggplot2::ggplot() object +List of scoring functions. +Tibble with batch container locations. +Tibble with sample information and sample ids. +Sample attributes, a data.table. +Vector with assignment of sample ids to locations. +Cached data.table with samples assignment. +Validate sample assignment.

    +
    + +
    + +
    + +
    +

    Examples

    +
    
    +## ------------------------------------------------
    +## Method `BatchContainer$new`
    +## ------------------------------------------------
    +
    +bc <- BatchContainer$new(
    +  dimensions = list(
    +    "plate" = 3,
    +    "row" = list(values = letters[1:3]),
    +    "column" = list(values = c(1, 3))
    +  ),
    +  exclude = data.frame(plate = 1, row = "a", column = c(1, 3), stringsAsFactors = FALSE)
    +)
    +
    +bc
    +#> Batch container with 16 locations.
    +#>   Dimensions: plate, row, column
    +
    +
    +
    + +
    + + +
    + +
    +

    Site built with pkgdown 2.0.7.

    +
    + +
    + + + + + + + + diff --git a/reference/BatchContainerDimension.html b/reference/BatchContainerDimension.html new file mode 100644 index 00000000..eefe4353 --- /dev/null +++ b/reference/BatchContainerDimension.html @@ -0,0 +1,232 @@ + +R6 Class representing a batch container dimension. — BatchContainerDimension • designit + + +
    +
    + + + +
    +
    + + +
    +

    R6 Class representing a batch container dimension.

    +

    R6 Class representing a batch container dimension.

    +
    + + +
    +

    Public fields

    +

    name
    +

    dimension name.

    + + +
    values
    +

    vector of dimension values.

    + + +

    +
    +
    +

    Active bindings

    +

    size
    +

    Returns size of a dimension.

    + + +
    short_info
    +

    Returns a string summarizing the dimension. +E.g., "mydim<size=10>".

    + + +

    +
    +
    +

    Methods

    + +


    +

    Method new()

    +

    Create a new BatchContainerDimension object.

    +

    This is usually used implicitly via BatchContainer$new().

    +

    Usage

    +

    BatchContainerDimension$new(name, size = NULL, values = NULL)

    +
    + +
    +

    Arguments

    +

    name
    +

    Dimension name, a character string. Requiered.

    + + +
    size
    +

    Dimension size. Setting this implies that dimension values are 1:size.

    + + +
    values
    +

    Explicit list of dimension values. Could be numeric, character or factor.

    +

    It is required to provide dimension namd and either size of values.

    + + +

    +
    +
    +

    Examples

    +

    plate_dimension <- BatchContainerDimension$new("plate", size=3)
    +row_dimension <- BatchContainerDimension$new("row", values = letters[1:3])
    +column_dimension <- BatchContainerDimension$new("column", values = 1:3)
    +
    +bc <- BatchContainer$new(
    +  dimensions = list(plate_dimension, row_dimension, column_dimension),
    +  exclude = data.frame(plate = 1, row = "a", column = c(1, 3), stringsAsFactors = FALSE)
    +)
    +
    +bc

    +
    + + +


    +

    Method clone()

    +

    The objects of this class are cloneable with this method.

    +

    Usage

    +

    BatchContainerDimension$clone(deep = FALSE)

    +
    + +
    +

    Arguments

    +

    deep
    +

    Whether to make a deep clone.

    + + +

    +
    + +
    + +
    + +
    +

    Examples

    +
    
    +## ------------------------------------------------
    +## Method `BatchContainerDimension$new`
    +## ------------------------------------------------
    +
    +plate_dimension <- BatchContainerDimension$new("plate", size=3)
    +row_dimension <- BatchContainerDimension$new("row", values = letters[1:3])
    +column_dimension <- BatchContainerDimension$new("column", values = 1:3)
    +
    +bc <- BatchContainer$new(
    +  dimensions = list(plate_dimension, row_dimension, column_dimension),
    +  exclude = data.frame(plate = 1, row = "a", column = c(1, 3), stringsAsFactors = FALSE)
    +)
    +
    +bc
    +#> Batch container with 25 locations.
    +#>   Dimensions: plate, row, column
    +
    +
    +
    + +
    + + +
    + +
    +

    Site built with pkgdown 2.0.7.

    +
    + +
    + + + + + + + + diff --git a/reference/L1_norm.html b/reference/L1_norm.html new file mode 100644 index 00000000..8d868ab6 --- /dev/null +++ b/reference/L1_norm.html @@ -0,0 +1,144 @@ + +Aggregation of scores: L1 norm — L1_norm • designit + + +
    +
    + + + +
    +
    + + +
    +

    This function enables comparison of the results of two scoring functions by calculating +an L1 norm (Manhattan distance from origin).

    +
    + +
    +
    L1_norm(scores, ...)
    +
    + +
    +

    Arguments

    +
    scores
    +

    A score or multiple component score vector

    + + +
    ...
    +

    Parameters to be ignored by this aggregation function

    + +
    +
    +

    Value

    + + +

    The L1 norm as an aggregated score.

    +
    + +
    +

    Examples

    +
    L1_norm(c(2, 2))
    +#> [1] 4
    +
    +
    +
    + +
    + + +
    + +
    +

    Site built with pkgdown 2.0.7.

    +
    + +
    + + + + + + + + diff --git a/reference/L2s_norm.html b/reference/L2s_norm.html new file mode 100644 index 00000000..6dbc59f1 --- /dev/null +++ b/reference/L2s_norm.html @@ -0,0 +1,146 @@ + +Aggregation of scores: L2 norm squared — L2s_norm • designit + + +
    +
    + + + +
    +
    + + +
    +

    This function enables comparison of the results of two scoring functions by calculating +an L2 norm (euclidean distance from origin). Since this is only used for ranking solutions, +the squared L2 norm is returned.

    +
    + +
    +
    L2s_norm(scores, ...)
    +
    + +
    +

    Arguments

    +
    scores
    +

    A score or multiple component score vector

    + + +
    ...
    +

    Parameters to be ignored by this aggregation function

    + +
    +
    +

    Value

    + + +

    The squared L2 norm as an aggregated score.

    +
    + +
    +

    Examples

    +
    L2s_norm(c(2, 2))
    +#> [1] 8
    +
    +
    +
    + +
    + + +
    + +
    +

    Site built with pkgdown 2.0.7.

    +
    + +
    + + + + + + + + diff --git a/reference/Rplot001.png b/reference/Rplot001.png new file mode 100644 index 00000000..17a35806 Binary files /dev/null and b/reference/Rplot001.png differ diff --git a/reference/Rplot002.png b/reference/Rplot002.png new file mode 100644 index 00000000..0bbcdf4e Binary files /dev/null and b/reference/Rplot002.png differ diff --git a/reference/Rplot003.png b/reference/Rplot003.png new file mode 100644 index 00000000..9a94946e Binary files /dev/null and b/reference/Rplot003.png differ diff --git a/reference/accept_leftmost_improvement.html b/reference/accept_leftmost_improvement.html new file mode 100644 index 00000000..c6b8a9f7 --- /dev/null +++ b/reference/accept_leftmost_improvement.html @@ -0,0 +1,145 @@ + +Alternative acceptance function for multi-dimensional scores in which order (left to right, e.g. first to last) denotes relevance. — accept_leftmost_improvement • designit + + +
    +
    + + + +
    +
    + + +
    +

    Alternative acceptance function for multi-dimensional scores in which order (left to right, e.g. first to last) denotes relevance.

    +
    + +
    +
    accept_leftmost_improvement(current_score, best_score, ..., tolerance = 0)
    +
    + +
    +

    Arguments

    +
    current_score
    +

    One- or multi-dimensional score from the current optimizing iteration (double or vector of doubles)

    + + +
    best_score
    +

    Best one- or multi-dimensional score found so far (double or vector of doubles)

    + + +
    ...
    +

    Ignored arguments that may be used by alternative acceptance functions

    + + +
    tolerance
    +

    Tolerance value: When comparing score vectors from left to right, differences within +/- tol won't immediately +shortcut the comparison at this point, allowing improvement in a less important score to exhibit some influence

    + +
    +
    +

    Value

    + + +

    Boolean, TRUE if current score should be taken as the new optimal score, FALSE otherwise

    +
    + +
    + +
    + + +
    + +
    +

    Site built with pkgdown 2.0.7.

    +
    + +
    + + + + + + + + diff --git a/reference/accept_strict_improvement.html b/reference/accept_strict_improvement.html new file mode 100644 index 00000000..93f7af0b --- /dev/null +++ b/reference/accept_strict_improvement.html @@ -0,0 +1,145 @@ + +Default acceptance function. Accept current score if and only if all elements are less than or equal than in best score +and there's at least one improvement. — accept_strict_improvement • designit + + +
    +
    + + + +
    +
    + + +
    +

    Default acceptance function. Accept current score if and only if all elements are less than or equal than in best score +and there's at least one improvement.

    +
    + +
    +
    accept_strict_improvement(current_score, best_score, ...)
    +
    + +
    +

    Arguments

    +
    current_score
    +

    One- or multi-dimensional score from the current optimizing iteration (double or vector of doubles)

    + + +
    best_score
    +

    Best one- or multi-dimensional score found so far (double or vector of doubles)

    + + +
    ...
    +

    Ignored arguments that may be used by alternative acceptance functions

    + +
    +
    +

    Value

    + + +

    Boolean, TRUE if current score should be taken as the new optimal score, FALSE otherwise

    +
    + +
    + +
    + + +
    + +
    +

    Site built with pkgdown 2.0.7.

    +
    + +
    + + + + + + + + diff --git a/reference/all_equal_df.html b/reference/all_equal_df.html new file mode 100644 index 00000000..5292d810 --- /dev/null +++ b/reference/all_equal_df.html @@ -0,0 +1,138 @@ + +Compare two data.frames. — all_equal_df • designit + + +
    +
    + + + +
    +
    + + +
    +

    This will convert factors to characters and disregard +row and column order

    +
    + +
    +
    all_equal_df(df1, df2)
    +
    + +
    +

    Arguments

    +
    df1
    +

    first data.frame() to compare

    + + +
    df2
    +

    second data.frame() to compare

    + +
    +
    +

    Value

    + + +

    TRUE or FALSE in case differences are present

    +
    + +
    + +
    + + +
    + +
    +

    Site built with pkgdown 2.0.7.

    +
    + +
    + + + + + + + + diff --git a/reference/assign_from_table.html b/reference/assign_from_table.html new file mode 100644 index 00000000..843c150e --- /dev/null +++ b/reference/assign_from_table.html @@ -0,0 +1,173 @@ + +Distributes samples based on a sample sheet. — assign_from_table • designit + + +
    +
    + + + +
    +
    + + +
    +

    Distributes samples based on a sample sheet.

    +
    + +
    +
    assign_from_table(batch_container, samples)
    +
    + +
    +

    Arguments

    +
    batch_container
    +

    Instance of BatchContainer class

    + + +
    samples
    +

    data.frame with samples (a sample sheet). This data.frame +(or tibble::tibble()) should contain samples together with their locations. No .sample_id +column can be present in the sample sheet. In batch_container already has samples assigned, +the function will check if samples in batch_container are identical to the ones in the +samples argument.

    + +
    +
    +

    Value

    + + +

    Returns a new BatchContainer.

    +
    + +
    +

    Examples

    +
    bc <- BatchContainer$new(
    +  dimensions = list(
    +    plate = 2,
    +    column = list(values = letters[1:3]),
    +    row = 3
    +  )
    +)
    +
    +sample_sheet <- tibble::tribble(
    +  ~plate, ~column, ~row, ~sampleID, ~group,
    +  1, "a", 1, 1, "TRT",
    +  1, "b", 2, 2, "CNTRL",
    +  2, "a", 1, 3, "TRT",
    +  2, "b", 2, 4, "CNTRL",
    +  2, "a", 3, 5, "TRT",
    +)
    +# assign samples from the sample sheet
    +bc <- assign_from_table(bc, sample_sheet)
    +
    +bc$get_samples(remove_empty_locations = TRUE)
    +#> # A tibble: 5 × 5
    +#>   plate column   row sampleID group
    +#>   <int> <fct>  <int>    <dbl> <chr>
    +#> 1     1 a          1        1 TRT  
    +#> 2     1 b          2        2 CNTRL
    +#> 3     2 a          1        3 TRT  
    +#> 4     2 a          3        5 TRT  
    +#> 5     2 b          2        4 CNTRL
    +
    +
    +
    +
    + +
    + + +
    + +
    +

    Site built with pkgdown 2.0.7.

    +
    + +
    + + + + + + + + diff --git a/reference/assign_in_order.html b/reference/assign_in_order.html new file mode 100644 index 00000000..821af477 --- /dev/null +++ b/reference/assign_in_order.html @@ -0,0 +1,180 @@ + +Distributes samples in order. — assign_in_order • designit + + +
    +
    + + + +
    +
    + + +
    +

    First sample is assigned to the first location, second +sample is assigned to the second location, etc.

    +
    + +
    +
    assign_in_order(batch_container, samples = NULL)
    +
    + +
    +

    Arguments

    +
    batch_container
    +

    Instance of BatchContainer class

    + + +
    samples
    +

    data.frame with samples.

    + +
    +
    +

    Value

    + + +

    Returns a new BatchContainer.

    +
    + +
    +

    Examples

    +
    samples <- data.frame(sampId = 1:3, sampName = letters[1:3])
    +samples
    +#>   sampId sampName
    +#> 1      1        a
    +#> 2      2        b
    +#> 3      3        c
    +
    +bc <- BatchContainer$new(dimensions = c("row" = 3, "column" = 2))
    +bc
    +#> Batch container with 6 locations.
    +#>   Dimensions: row, column
    +
    +set.seed(42)
    +# assigns samples randomly
    +bc <- assign_random(bc, samples)
    +bc$get_samples()
    +#> # A tibble: 6 × 4
    +#>     row column sampId sampName
    +#>   <int>  <int>  <int> <chr>   
    +#> 1     1      1      1 a       
    +#> 2     1      2     NA NA      
    +#> 3     2      1     NA NA      
    +#> 4     2      2     NA NA      
    +#> 5     3      1      2 b       
    +#> 6     3      2      3 c       
    +
    +# assigns samples in order
    +bc <- assign_in_order(bc)
    +bc$get_samples()
    +#> # A tibble: 6 × 4
    +#>     row column sampId sampName
    +#>   <int>  <int>  <int> <chr>   
    +#> 1     1      1      1 a       
    +#> 2     1      2      2 b       
    +#> 3     2      1      3 c       
    +#> 4     2      2     NA NA      
    +#> 5     3      1     NA NA      
    +#> 6     3      2     NA NA      
    +
    +
    +
    + +
    + + +
    + +
    +

    Site built with pkgdown 2.0.7.

    +
    + +
    + + + + + + + + diff --git a/reference/assign_random.html b/reference/assign_random.html new file mode 100644 index 00000000..331d24bb --- /dev/null +++ b/reference/assign_random.html @@ -0,0 +1,178 @@ + +Assignment function which distributes samples randomly. — assign_random • designit + + +
    +
    + + + +
    +
    + + +
    +

    Assignment function which distributes samples randomly.

    +
    + +
    +
    assign_random(batch_container, samples = NULL)
    +
    + +
    +

    Arguments

    +
    batch_container
    +

    Instance of BatchContainer class

    + + +
    samples
    +

    data.frame with samples.

    + +
    +
    +

    Value

    + + +

    Returns a new BatchContainer.

    +
    + +
    +

    Examples

    +
    samples <- data.frame(sampId = 1:3, sampName = letters[1:3])
    +samples
    +#>   sampId sampName
    +#> 1      1        a
    +#> 2      2        b
    +#> 3      3        c
    +
    +bc <- BatchContainer$new(dimensions = c("row" = 3, "column" = 2))
    +bc
    +#> Batch container with 6 locations.
    +#>   Dimensions: row, column
    +
    +set.seed(42)
    +# assigns samples randomly
    +bc <- assign_random(bc, samples)
    +bc$get_samples()
    +#> # A tibble: 6 × 4
    +#>     row column sampId sampName
    +#>   <int>  <int>  <int> <chr>   
    +#> 1     1      1      1 a       
    +#> 2     1      2     NA NA      
    +#> 3     2      1     NA NA      
    +#> 4     2      2     NA NA      
    +#> 5     3      1      2 b       
    +#> 6     3      2      3 c       
    +
    +# assigns samples in order
    +bc <- assign_in_order(bc)
    +bc$get_samples()
    +#> # A tibble: 6 × 4
    +#>     row column sampId sampName
    +#>   <int>  <int>  <int> <chr>   
    +#> 1     1      1      1 a       
    +#> 2     1      2      2 b       
    +#> 3     2      1      3 c       
    +#> 4     2      2     NA NA      
    +#> 5     3      1     NA NA      
    +#> 6     3      2     NA NA      
    +
    +
    +
    + +
    + + +
    + +
    +

    Site built with pkgdown 2.0.7.

    +
    + +
    + + + + + + + + diff --git a/reference/batch_container_from_table.html b/reference/batch_container_from_table.html new file mode 100644 index 00000000..01fdb722 --- /dev/null +++ b/reference/batch_container_from_table.html @@ -0,0 +1,153 @@ + +Creates a BatchContainer from a table +(data.frame/tibble::tibble) containing sample and location information. — batch_container_from_table • designit + + +
    +
    + + + +
    +
    + + +
    +

    Creates a BatchContainer from a table +(data.frame/tibble::tibble) containing sample and location information.

    +
    + +
    +
    batch_container_from_table(tab, location_cols)
    +
    + +
    +

    Arguments

    +
    tab
    +

    A table with location and sample information. +Table rows with all NAs in sample information columns are treated as empty +locations.

    + + +
    location_cols
    +

    Names of columns containing information about locations.

    + +
    +
    +

    Value

    + + +

    A BatchContainer assigned samples.

    +
    + +
    +

    Examples

    +
    tab <- data.frame(
    +  row = rep(1:3, each = 3),
    +  column = rep(1:3, 3),
    +  sample_id = c(1, 2, 3, NA, 5, 6, 7, NA, 9)
    +)
    +bc <- batch_container_from_table(tab, location_cols = c("row", "column"))
    +
    +
    +
    + +
    + + +
    + +
    +

    Site built with pkgdown 2.0.7.

    +
    + +
    + + + + + + + + diff --git a/reference/compile_possible_subgroup_allocation.html b/reference/compile_possible_subgroup_allocation.html new file mode 100644 index 00000000..80f3f36b --- /dev/null +++ b/reference/compile_possible_subgroup_allocation.html @@ -0,0 +1,146 @@ + +Compile list of all possible ways to assign levels of the allocation variable to a given set of subgroups — compile_possible_subgroup_allocation • designit + + +
    +
    + + + +
    +
    + + +
    +

    All information needed to perform this function (primarily the number and size of subgroups plus the levels of the +allocation variable) are contained in and extracted from the subgroup object.

    +
    + +
    +
    compile_possible_subgroup_allocation(
    +  subgroup_object,
    +  fullTree = FALSE,
    +  maxCalls = 1e+06
    +)
    +
    + +
    +

    Arguments

    +
    subgroup_object
    +

    A subgrouping object as returned by form_homogeneous_subgroups()

    + + +
    fullTree
    +

    Boolean: Enforce full search of the possibility tree, independent of the value of maxCalls

    + + +
    maxCalls
    +

    Maximum number of recursive calls in the search tree, to avoid long run times with very large trees

    + +
    +
    +

    Value

    + + +

    List of possible allocations; Each allocation is an integer vector of allocation levels that are assigned in that order to the subgroups with given sizes

    +
    + +
    + +
    + + +
    + +
    +

    Site built with pkgdown 2.0.7.

    +
    + +
    + + + + + + + + diff --git a/reference/complete_random_shuffling.html b/reference/complete_random_shuffling.html new file mode 100644 index 00000000..6efa3ad8 --- /dev/null +++ b/reference/complete_random_shuffling.html @@ -0,0 +1,158 @@ + +Reshuffle sample indices completely randomly — complete_random_shuffling • designit + + +
    +
    + + + +
    +
    + + +
    +

    This function was just added to test early on the functionality of optimize_design() to accept a +permutation vector rather than a list with src and dst indices.

    +
    + +
    +
    complete_random_shuffling(batch_container, ...)
    +
    + +
    +

    Arguments

    +
    batch_container
    +

    The batch-container.

    + + +
    ...
    +

    Other params that are passed to a generic shuffling function (like the iteration number).

    + +
    +
    +

    Value

    + + +

    A random permutation of the sample assignment in the container.

    +
    + +
    +

    Examples

    +
    data("invivo_study_samples")
    +bc <- BatchContainer$new(
    +  dimensions = c("plate" = 2, "column" = 5, "row" = 6)
    +)
    +scoring_f <- osat_score_generator("plate", "Sex")
    +bc <- optimize_design(
    +  bc, scoring = scoring_f, invivo_study_samples,
    +  max_iter = 100,
    +  shuffle_proposal_func = complete_random_shuffling
    +)
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Checking variances of 1-dim. score vector.
    +#> ... (142.337) - OK
    +#> Initial score: 182.5
    +#> Achieved score: 42.5 at iteration 1
    +#> Achieved score: 0.5 at iteration 2
    +
    +
    +
    + +
    + + +
    + +
    +

    Site built with pkgdown 2.0.7.

    +
    + +
    + + + + + + + + diff --git a/reference/countGini.html b/reference/countGini.html new file mode 100644 index 00000000..c3033491 --- /dev/null +++ b/reference/countGini.html @@ -0,0 +1,138 @@ + +Gini index on counts — countGini • designit + + +
    +
    + + + +
    +
    + + +
    +

    Gini index on a factor vector of counts using the Gini function +from the package ineq

    +
    + +
    +
    countGini(m)
    +
    + +
    +

    Arguments

    +
    m
    +

    a factor vector

    + +
    +
    +

    Value

    + + +

    the value of the Gini index

    +
    +
    +

    Author

    +

    Juliane Siebourg-Polster

    +
    + +
    + +
    + + +
    + +
    +

    Site built with pkgdown 2.0.7.

    +
    + +
    + + + + + + + + diff --git a/reference/designit-package.html b/reference/designit-package.html new file mode 100644 index 00000000..13c4fe03 --- /dev/null +++ b/reference/designit-package.html @@ -0,0 +1,132 @@ + +designit: Blocking and Randomization for Experimental Design — designit-package • designit + + +
    +
    + + + +
    +
    + + +
    +

    Reducing batch effect by intellegently assigning samples to batches. Batch-effect have a strong influence in data analysis, especially when samples-to-batches assignent is coinciding with contrast groups. By defining your batch container and a scoring function reflecting the contrasts, you can assign samples in such a way that the potential batch-effect has minimal effect on the comparison of interest.

    +
    + + + +
    +

    Author

    +

    Maintainer: Iakov I. Davydov iakov.davydov@roche.com (ORCID) [copyright holder]

    +

    Authors:

    Other contributors:

    • F. Hoffman-La Roche [copyright holder, funder]

    • +
    + +
    + +
    + + +
    + +
    +

    Site built with pkgdown 2.0.7.

    +
    + +
    + + + + + + + + diff --git a/reference/dot-datatable.aware.html b/reference/dot-datatable.aware.html new file mode 100644 index 00000000..9e799fc8 --- /dev/null +++ b/reference/dot-datatable.aware.html @@ -0,0 +1,137 @@ + +This undocumented (?) flag allows us to use := +without getting an error. — .datatable.aware • designit + + +
    +
    + + + +
    +
    + + +
    +

    This undocumented (?) flag allows us to use := +without getting an error.

    +
    + +
    +
    .datatable.aware
    +
    + +
    +

    Format

    +

    An object of class logical of length 1.

    +
    + +
    +

    Examples

    +
    if (FALSE) {
    +dt <- data.table::data.table(a = 1, b = 2)
    +dt[, a := NULL]
    +}
    +
    +
    +
    + +
    + + +
    + +
    +

    Site built with pkgdown 2.0.7.

    +
    + +
    + + + + + + + + diff --git a/reference/drop_order.html b/reference/drop_order.html new file mode 100644 index 00000000..2bb3bb1d --- /dev/null +++ b/reference/drop_order.html @@ -0,0 +1,130 @@ + +Drop highest order interactions — drop_order • designit + + +
    +
    + + + +
    +
    + + +
    +

    Drop highest order interactions

    +
    + +
    +
    drop_order(.terms, m = -1)
    +
    + +
    +

    Arguments

    +
    .terms
    +

    terms.object

    + + +
    m
    +

    order of interaction (highest available if -1)

    + +
    + +
    + +
    + + +
    + +
    +

    Site built with pkgdown 2.0.7.

    +
    + +
    + + + + + + + + diff --git a/reference/extract_shuffle_params.html b/reference/extract_shuffle_params.html new file mode 100644 index 00000000..bdf008ad --- /dev/null +++ b/reference/extract_shuffle_params.html @@ -0,0 +1,149 @@ + +Extract relevant parameters from a generic shuffle function output — extract_shuffle_params • designit + + +
    +
    + + + +
    +
    + + +
    +

    Any shuffling function should return one of the following:

    1. atomic index vector for a direct location assignment

    2. +
    3. a list with src and dst vector

    4. +
    5. a list with locations vector (for location assignment) and optional sample_attr data frame/tibble

    6. +
    + +
    +
    extract_shuffle_params(shuffle, attributes_expected)
    +
    + +
    +

    Arguments

    +
    shuffle
    +

    Return value of a shuffle function

    + + +
    attributes_expected
    +

    Logical; if TRUE, sample attributes are expected from the shuffling result and the +function dies if they are not provided.

    + +
    +
    +

    Value

    + + +

    A list with components src, dst, location_assignment and samples_attr, depending on the output +of the specific shuffling function

    +
    +
    +

    Details

    +

    This function parses the output, performs a few checks and returns results in a simple-to-use list.

    +
    + +
    + +
    + + +
    + +
    +

    Site built with pkgdown 2.0.7.

    +
    + +
    + + + + + + + + diff --git a/reference/figures/README-optimized_assignment-1.png b/reference/figures/README-optimized_assignment-1.png new file mode 100644 index 00000000..cc5cd780 Binary files /dev/null and b/reference/figures/README-optimized_assignment-1.png differ diff --git a/reference/figures/README-optimized_assignment-2.png b/reference/figures/README-optimized_assignment-2.png new file mode 100644 index 00000000..78ac8243 Binary files /dev/null and b/reference/figures/README-optimized_assignment-2.png differ diff --git a/reference/figures/README-random_assignment-1.png b/reference/figures/README-random_assignment-1.png new file mode 100644 index 00000000..9ad8551c Binary files /dev/null and b/reference/figures/README-random_assignment-1.png differ diff --git a/reference/figures/logo-inkscape.svg b/reference/figures/logo-inkscape.svg new file mode 100644 index 00000000..b6b73103 --- /dev/null +++ b/reference/figures/logo-inkscape.svg @@ -0,0 +1,201 @@ + + + +designit diff --git a/reference/figures/logo-web.svg b/reference/figures/logo-web.svg new file mode 100644 index 00000000..8be4741a --- /dev/null +++ b/reference/figures/logo-web.svg @@ -0,0 +1,2 @@ + + diff --git a/reference/figures/logo.svg b/reference/figures/logo.svg new file mode 100644 index 00000000..8be4741a --- /dev/null +++ b/reference/figures/logo.svg @@ -0,0 +1,2 @@ + + diff --git a/reference/find_possible_block_allocations.html b/reference/find_possible_block_allocations.html new file mode 100644 index 00000000..2d659144 --- /dev/null +++ b/reference/find_possible_block_allocations.html @@ -0,0 +1,151 @@ + +Internal function to generate possible subgroup combinations that add up to specific levels of an allocation variable — find_possible_block_allocations • designit + + +
    +
    + + + +
    +
    + + +
    +

    Internal function to generate possible subgroup combinations that add up to specific levels of an allocation variable

    +
    + +
    +
    find_possible_block_allocations(
    +  block_sizes,
    +  group_nums,
    +  fullTree = FALSE,
    +  maxCalls = 1e+06
    +)
    +
    + +
    +

    Arguments

    +
    block_sizes
    +

    (Integer) vector of sizes of the various subgroups that can be combined to form groups

    + + +
    group_nums
    +

    Vector of sizes of the different groups to be formed

    + + +
    fullTree
    +

    Boolean: Enforce full search of the possibility tree, independent of the value of maxCalls

    + + +
    maxCalls
    +

    Maximum number of recursive calls in the search tree, to avoid long run times with very large trees

    + +
    +
    +

    Value

    + + +

    List of possible allocations; Each allocation is an integer vector of allocation levels that are assigned in that order to the subgroups with sizes given by block sizes

    + + +
    + +
    + +
    + + +
    + +
    +

    Site built with pkgdown 2.0.7.

    +
    + +
    + + + + + + + + diff --git a/reference/first_score_only.html b/reference/first_score_only.html new file mode 100644 index 00000000..d8105538 --- /dev/null +++ b/reference/first_score_only.html @@ -0,0 +1,146 @@ + +Aggregation of scores: take first (primary) score only — first_score_only • designit + + +
    +
    + + + +
    +
    + + +
    +

    This function enables comparison of the results of two scoring functions by just basing +the decision on the first element. This reflects the original behavior of the optimization +function, just evaluating the 'auxiliary' scores for the user's information.

    +
    + +
    +
    first_score_only(scores, ...)
    +
    + +
    +

    Arguments

    +
    scores
    +

    A score or multiple component score vector

    + + +
    ...
    +

    Parameters to be ignored by this aggregation function

    + +
    +
    +

    Value

    + + +

    The aggregated score, i.e. the first element of a multiple-component score vector.

    +
    + +
    +

    Examples

    +
    first_score_only(c(1, 2, 3))
    +#> [1] 1
    +
    +
    +
    + +
    + + +
    + +
    +

    Site built with pkgdown 2.0.7.

    +
    + +
    + + + + + + + + diff --git a/reference/form_homogeneous_subgroups.html b/reference/form_homogeneous_subgroups.html new file mode 100644 index 00000000..ec325f2f --- /dev/null +++ b/reference/form_homogeneous_subgroups.html @@ -0,0 +1,176 @@ + +Form groups and subgroups of 'homogeneous' samples as defined by certain variables and size constraints — form_homogeneous_subgroups • designit + + +
    +
    + + + +
    +
    + + +
    +

    Form groups and subgroups of 'homogeneous' samples as defined by certain variables and size constraints

    +
    + +
    +
    form_homogeneous_subgroups(
    +  batch_container,
    +  allocate_var,
    +  keep_together_vars = c(),
    +  n_min = NA,
    +  n_max = NA,
    +  n_ideal = NA,
    +  subgroup_var_name = NULL,
    +  prefer_big_groups = TRUE,
    +  strict = TRUE
    +)
    +
    + +
    +

    Arguments

    +
    batch_container
    +

    Batch container with all samples assigned that are to be grouped and sub-grouped

    + + +
    allocate_var
    +

    Name of a variable in the samples table to inform possible groupings, as (sub)group sizes must add up to the correct totals

    + + +
    keep_together_vars
    +

    Vector of column names in sample table; groups are formed by pooling samples with identical values of all those variables

    + + +
    n_min
    +

    Minimal number of samples in one sub(!)group; by default 1

    + + +
    n_max
    +

    Maximal number of samples in one sub(!)group; by default the size of the biggest group

    + + +
    n_ideal
    +

    Ideal number of samples in one sub(!)group; by default the floor or ceiling of mean(n_min,n_max), depending on the setting of prefer_big_groups

    + + +
    subgroup_var_name
    +

    An optional column name for the subgroups which are formed (or NULL)

    + + +
    prefer_big_groups
    +

    Boolean; indicating whether or not bigger subgroups should be preferred in case of several possibilities

    + + +
    strict
    +

    Boolean; if TRUE, subgroup size constraints have to be met strictly, implying the possibility of finding no solution at all

    + +
    +
    +

    Value

    + + +

    Subgroup object to be used in subsequent calls to compile_possible_subgroup_allocation()

    + + +
    + +
    + +
    + + +
    + +
    +

    Site built with pkgdown 2.0.7.

    +
    + +
    + + + + + + + + diff --git a/reference/generate_terms.html b/reference/generate_terms.html new file mode 100644 index 00000000..29871626 --- /dev/null +++ b/reference/generate_terms.html @@ -0,0 +1,138 @@ + +Generate terms.object (formula with attributes) — generate_terms • designit + + +
    +
    + + + +
    +
    + + +
    +

    Generate terms.object (formula with attributes)

    +
    + +
    +
    generate_terms(.tbl, ...)
    +
    + +
    +

    Arguments

    +
    .tbl
    +

    data

    + + +
    ...
    +

    columns to skip (unquoted)

    + +
    +
    +

    Value

    + + +

    terms.object

    + + +
    + +
    + +
    + + +
    + +
    +

    Site built with pkgdown 2.0.7.

    +
    + +
    + + + + + + + + diff --git a/reference/getScore.html b/reference/getScore.html new file mode 100644 index 00000000..adb2be90 --- /dev/null +++ b/reference/getScore.html @@ -0,0 +1,165 @@ + +get Score — getScore • designit + + +
    +
    + + + +
    +
    + + +
    +

    Summary score for an experimental layout based on the distribution of levels +of the factors to be balanced.

    +
    + +
    +
    getScore(
    +  layout,
    +  balance,
    +  sc_groups,
    +  sc_tests,
    +  bal_weights = rep(1, length(balance)),
    +  sc_weights = rep(1, length(sc_groups))
    +)
    +
    + +
    +

    Arguments

    +
    layout
    +

    a data.frame with the factors to be balanced and their current positions

    + + +
    balance
    +

    a vector with the names of experimental conditions to be balanced

    + + +
    sc_groups
    +

    list of dimension name groups to be used jointly for scoring

    + + +
    sc_tests
    +

    list of tests to use for each scoring group

    + + +
    bal_weights
    +

    named vector of weights for the factors to be balanced (default all 1)

    + + +
    sc_weights
    +

    named vector of weights for the dimensions (default all 1)

    + +
    +
    +

    Value

    + + +

    the summarized penalty score

    +
    +
    +

    Author

    +

    Juliane Siebourg-Polster

    +
    + +
    + +
    + + +
    + +
    +

    Site built with pkgdown 2.0.7.

    +
    + +
    + + + + + + + + diff --git a/reference/get_order.html b/reference/get_order.html new file mode 100644 index 00000000..1fa6b730 --- /dev/null +++ b/reference/get_order.html @@ -0,0 +1,132 @@ + +Get highest order interaction — get_order • designit + + +
    +
    + + + +
    +
    + + +
    +

    Get highest order interaction

    +
    + +
    +
    get_order(.terms)
    +
    + +
    +

    Arguments

    +
    .terms
    +

    terms.object

    + +
    +
    +

    Value

    + + +

    highest order (numeric).

    +
    + +
    + +
    + + +
    + +
    +

    Site built with pkgdown 2.0.7.

    +
    + +
    + + + + + + + + diff --git a/reference/index.html b/reference/index.html new file mode 100644 index 00000000..2d1df059 --- /dev/null +++ b/reference/index.html @@ -0,0 +1,296 @@ + +Function reference • designit + + +
    +
    + + + +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +

    All functions

    +

    +
    +

    BatchContainer

    +

    R6 Class representing a batch container.

    +

    BatchContainerDimension

    +

    R6 Class representing a batch container dimension.

    +

    L1_norm()

    +

    Aggregation of scores: L1 norm

    +

    L2s_norm()

    +

    Aggregation of scores: L2 norm squared

    +

    accept_leftmost_improvement()

    +

    Alternative acceptance function for multi-dimensional scores in which order (left to right, e.g. first to last) denotes relevance.

    +

    assign_from_table()

    +

    Distributes samples based on a sample sheet.

    +

    assign_in_order()

    +

    Distributes samples in order.

    +

    assign_random()

    +

    Assignment function which distributes samples randomly.

    +

    batch_container_from_table()

    +

    Creates a BatchContainer from a table +(data.frame/tibble::tibble) containing sample and location information.

    +

    compile_possible_subgroup_allocation()

    +

    Compile list of all possible ways to assign levels of the allocation variable to a given set of subgroups

    +

    complete_random_shuffling()

    +

    Reshuffle sample indices completely randomly

    +

    countGini()

    +

    Gini index on counts

    +

    drop_order()

    +

    Drop highest order interactions

    +

    first_score_only()

    +

    Aggregation of scores: take first (primary) score only

    +

    form_homogeneous_subgroups()

    +

    Form groups and subgroups of 'homogeneous' samples as defined by certain variables and size constraints

    +

    generate_terms()

    +

    Generate terms.object (formula with attributes)

    +

    getScore()

    +

    get Score

    +

    get_order()

    +

    Get highest order interaction

    +

    invivo_study_samples

    +

    A sample list from an in vivo experiment with multiple treatments and 2 strains

    +

    invivo_study_treatments

    +

    A treatment list together with additional constraints on the strain and sex of animals

    +

    kruskal()

    +

    Kruskal Wallis on Layout dimension

    +

    locations_table_from_dimensions()

    +

    Create locations table from dimensions and exclude table

    +

    longitudinal_subject_samples

    +

    Subject sample list with group and time plus controls

    +

    meanDiff()

    +

    Mean difference

    +

    mk_exponentially_weighted_acceptance_func()

    +

    Alternative acceptance function for multi-dimensional scores with exponentially downweighted score improvements from left to right

    +

    mk_plate_scoring_functions()

    +

    Create a list of scoring functions (one per plate) that quantify the spatially homogeneous distribution of conditions across the plate

    +

    mk_simanneal_acceptance_func()

    +

    Generate acceptance function for an optimization protocol based on simulated annealing

    +

    mk_simanneal_temp_func()

    +

    Create a temperature function that returns the annealing temperature at a given step (iteration)

    +

    mk_subgroup_shuffling_function()

    +

    Created a shuffling function that permutes samples within certain subgroups of the container locations

    +

    mk_swapping_function()

    +

    Create function to propose swaps of samples on each call, either with a constant number of swaps or following +a user defined protocol

    +

    multi_trt_day_samples

    +

    Unbalanced treatment and time sample list

    +

    neighbors()

    +

    Penalty for neighbors with same level

    +

    optimize_design()

    +

    Generic optimizer that can be customized by user provided functions for generating shuffles and progressing towards the minimal score

    +

    optimize_multi_plate_design()

    +

    Convenience wrapper to optimize a typical multi-plate design

    +

    osat_score()

    +

    Compute OSAT score for sample assignment.

    +

    osat_score_generator()

    +

    Convenience wrapper for the OSAT score

    +

    plate_effect_example

    +

    Example dataset with a plate effect

    +

    plot_plate()

    +

    Plot plate layouts

    +

    randomize()

    +

    randomize experimental layout

    +

    shuffle_grouped_data()

    +

    Generate in one go a shuffling function that produces permutations with specific constraints on multiple sample variables and group sizes fitting one specific allocation variable

    +

    shuffle_with_constraints()

    +

    Shuffling proposal function with constraints.

    +

    shuffle_with_subgroup_formation()

    +

    Compose shuffling function based on already available subgrouping and allocation information

    +

    sum_scores()

    +

    Aggregation of scores: sum up all individual scores

    +

    validate_samples()

    +

    Validates sample data.frame.

    +

    worst_score()

    +

    Aggregation of scores: take the maximum (i.e. worst score only)

    + + +
    + + +
    + +
    +

    Site built with pkgdown 2.0.7.

    +
    + +
    + + + + + + + + diff --git a/reference/invivo_study_samples.html b/reference/invivo_study_samples.html new file mode 100644 index 00000000..a38ceb6f --- /dev/null +++ b/reference/invivo_study_samples.html @@ -0,0 +1,152 @@ + +A sample list from an in vivo experiment with multiple treatments and 2 strains — invivo_study_samples • designit + + +
    +
    + + + +
    +
    + + +
    +

    This sample list is intended to be used in connection with the "invivo_study_treatments" data object

    +
    + +
    +
    data(invivo_study_samples)
    +
    + +
    +

    Format

    +

    An object of class "tibble"

    AnimalID
    +

    The animal IDs, i.e. unique identifiers for each animal

    + +
    Strain
    +

    Strain (A or B)

    + +
    Sex
    +

    Female (F) or Male (M)

    + +
    BirthDate
    +

    Date of birth, not available for all the animals

    + +
    Earmark
    +

    Markings to distinguish individual animals, applied on the left (L), right (R) or both(B) ears

    + +
    ArrivalWeight
    +

    Initial body weight of the animal

    + +
    Arrival weight Unit
    +

    Unit of the body weight, here: grams

    + +
    Litter
    +

    The litter IDs, grouping offspring from one set of parents

    + + +
    +
    +

    Author

    +

    Guido Steiner

    +
    + +
    + +
    + + +
    + +
    +

    Site built with pkgdown 2.0.7.

    +
    + +
    + + + + + + + + diff --git a/reference/invivo_study_treatments.html b/reference/invivo_study_treatments.html new file mode 100644 index 00000000..59beb15c --- /dev/null +++ b/reference/invivo_study_treatments.html @@ -0,0 +1,137 @@ + +A treatment list together with additional constraints on the strain and sex of animals — invivo_study_treatments • designit + + +
    +
    + + + +
    +
    + + +
    +

    This treatment list is intended to be used in connection with the "invivo_study_samples" data object

    +
    + +
    +
    data(invivo_study_treatments)
    +
    + +
    +

    Format

    +

    An object of class "tibble"

    Treatment
    +

    The treatment to be given to an individual animal (1-3, plus a few untreated cases)

    + +
    Strain
    +

    Strain (A or B) - a constraint which kind of animal may receive the respective treatment

    + +
    Sex
    +

    Female (F) or Male (M) - a constraint which kind of animal may receive the respective treatment

    + + +
    +
    +

    Author

    +

    Guido Steiner

    +
    + +
    + +
    + + +
    + +
    +

    Site built with pkgdown 2.0.7.

    +
    + +
    + + + + + + + + diff --git a/reference/kruskal.html b/reference/kruskal.html new file mode 100644 index 00000000..3468a3be --- /dev/null +++ b/reference/kruskal.html @@ -0,0 +1,138 @@ + +Kruskal Wallis on Layout dimension — kruskal • designit + + +
    +
    + + + +
    +
    + + +
    +

    Kruskal-Wallis test statistic from the ranking of a factor vector +TODO: This is currently not used, it does not optimize for the correct layout

    +
    + +
    +
    kruskal(m)
    +
    + +
    +

    Arguments

    +
    m
    +

    a factor vector

    + +
    +
    +

    Value

    + + +

    the Kruskal-Wallis rank sum statistic

    +
    +
    +

    Author

    +

    Juliane Siebourg-Polster

    +
    + +
    + +
    + + +
    + +
    +

    Site built with pkgdown 2.0.7.

    +
    + +
    + + + + + + + + diff --git a/reference/locations_table_from_dimensions.html b/reference/locations_table_from_dimensions.html new file mode 100644 index 00000000..e627b817 --- /dev/null +++ b/reference/locations_table_from_dimensions.html @@ -0,0 +1,139 @@ + +Create locations table from dimensions and exclude table — locations_table_from_dimensions • designit + + +
    +
    + + + +
    +
    + + +
    +

    Create locations table from dimensions and exclude table

    +
    + +
    +
    locations_table_from_dimensions(dimensions, exclude)
    +
    + +
    +

    Arguments

    +
    dimensions
    +

    A vector or list of dimensions. Every dimension +should have a name. Could be an integer vector of dimensions or +a named list. Every value of a list could be either dimension size +or parameters for BatchContainerDimension$new().

    + + +
    exclude
    +

    data.frame with excluded locations of a container.

    + +
    +
    +

    Value

    + + +

    a tibble::tibble() with all the available locations.

    +
    + +
    + +
    + + +
    + +
    +

    Site built with pkgdown 2.0.7.

    +
    + +
    + + + + + + + + diff --git a/reference/longitudinal_subject_samples.html b/reference/longitudinal_subject_samples.html new file mode 100644 index 00000000..2c909189 --- /dev/null +++ b/reference/longitudinal_subject_samples.html @@ -0,0 +1,166 @@ + +Subject sample list with group and time plus controls — longitudinal_subject_samples • designit + + +
    +
    + + + +
    +
    + + +
    +

    A sample list with 9 columns as described below. +There are 3 types of records (rows) indicated by the SampleType variable. +Patient samples, controls and spike-in standards. +Patient samples were collected over up to 7 time points. +Controls and SpikeIns are QC samples for distribution of the samples on +96 well plates.

    +
    + +
    +
    data(longitudinal_subject_samples)
    +
    + +
    +

    Format

    +

    An object of class "tibble"

    SampleID
    +

    A unique sample identifier.

    + +
    SampleType
    +

    Indicates whether the sample is a patient sample, control oder spike-in.

    + +
    SubjectID
    +

    The subject identifier.

    + +
    Group
    +

    Indicates the treatment group of a subject.

    + +
    Week
    +

    Sampling time points in weeks of study.

    + +
    Sex
    +

    Subject Sex, Female (F) or Male (M).

    + +
    Age
    +

    Subject age.

    + +
    BMI
    +

    Subject Body Mass Index.

    + +
    SamplesPerSubject
    +

    Look up variable for the number of samples per subject. +This varies as not subject have samples from all weeks.

    + + +
    +
    +

    Author

    +

    Juliane Siebourg

    +
    + +
    + +
    + + +
    + +
    +

    Site built with pkgdown 2.0.7.

    +
    + +
    + + + + + + + + diff --git a/reference/make_colnames.html b/reference/make_colnames.html new file mode 100644 index 00000000..0544c583 --- /dev/null +++ b/reference/make_colnames.html @@ -0,0 +1,132 @@ + +Make matrix column names unique. — make_colnames • designit + + +
    +
    + + + +
    +
    + + +
    +

    Make matrix column names unique.

    +
    + +
    +
    make_colnames(m, prefix = "X")
    +
    + +
    +

    Arguments

    +
    prefix
    +

    Prefix to add if column names are empty.

    + +
    +
    +

    Value

    + + +

    A matrix with updated column names.

    +
    + +
    + +
    + + +
    + +
    +

    Site built with pkgdown 2.0.7.

    +
    + +
    + + + + + + + + diff --git a/reference/meanDiff.html b/reference/meanDiff.html new file mode 100644 index 00000000..0f56ccb7 --- /dev/null +++ b/reference/meanDiff.html @@ -0,0 +1,136 @@ + +Mean difference — meanDiff • designit + + +
    +
    + + + +
    +
    + + +
    +

    Mean differens on vector to score continuous variables

    +
    + +
    +
    meanDiff(m)
    +
    + +
    +

    Arguments

    +
    m
    +

    a numeric vector

    + +
    +
    +

    Value

    + + +

    the mean difference

    +
    +
    +

    Author

    +

    Juliane Siebourg-Polster

    +
    + +
    + +
    + + +
    + +
    +

    Site built with pkgdown 2.0.7.

    +
    + +
    + + + + + + + + diff --git a/reference/mk_autoscale_function.html b/reference/mk_autoscale_function.html new file mode 100644 index 00000000..71538d0f --- /dev/null +++ b/reference/mk_autoscale_function.html @@ -0,0 +1,156 @@ + +Create a function that transforms a current (multi-dimensional) score into a boxcox normalized one — mk_autoscale_function • designit + + +
    +
    + + + +
    +
    + + +
    +

    Create a function that transforms a current (multi-dimensional) score into a boxcox normalized one

    +
    + +
    +
    mk_autoscale_function(
    +  batch_container,
    +  scoring,
    +  random_perm,
    +  use_boxcox = TRUE,
    +  sample_attributes_fixed = FALSE
    +)
    +
    + +
    +

    Arguments

    +
    batch_container
    +

    An instance of BatchContainer.

    + + +
    scoring
    +

    A named list() of scoring function. Each function should +return a vector of non-zero length.

    + + +
    random_perm
    +

    Number of random sample permutations for the estimation of the scaling params.

    + + +
    use_boxcox
    +

    Logical; if TRUE and the bestNormalize package is available, boxcox transformations will be used to +normalize individual scores. If not possible, scores will just be transformed to a zero mean and unit standard deviation.

    + + +
    sample_attributes_fixed
    +

    Logical; if FALSE, simulate a shuffle function that alters sample attributes at each iteration.

    + +
    +
    +

    Value

    + + +

    The transformation function for a new score vector

    +
    + +
    + +
    + + +
    + +
    +

    Site built with pkgdown 2.0.7.

    +
    + +
    + + + + + + + + diff --git a/reference/mk_constant_swapping_function.html b/reference/mk_constant_swapping_function.html new file mode 100644 index 00000000..b7200aaf --- /dev/null +++ b/reference/mk_constant_swapping_function.html @@ -0,0 +1,138 @@ + +Create function to propose n pairwise swaps of samples on each call (n is a constant across iterations) — mk_constant_swapping_function • designit + + +
    +
    + + + +
    +
    + + +
    +

    This internal function is wrapped by mk_swapping_function()

    +
    + +
    +
    mk_constant_swapping_function(n_swaps, quiet = FALSE)
    +
    + +
    +

    Arguments

    +
    n_swaps
    +

    Number of swaps to be proposed (valid range is 1..floor(n_samples/2))

    + + +
    quiet
    +

    Do not warn if number of swaps is too big.

    + +
    +
    +

    Value

    + + +

    Function accepting batch container & iteration number. +Return a list with length n vectors 'src' and 'dst', denoting source and destination index for +the swap operation on each call

    +
    + +
    + +
    + + +
    + +
    +

    Site built with pkgdown 2.0.7.

    +
    + +
    + + + + + + + + diff --git a/reference/mk_dist_matrix.html b/reference/mk_dist_matrix.html new file mode 100644 index 00000000..02967f97 --- /dev/null +++ b/reference/mk_dist_matrix.html @@ -0,0 +1,156 @@ + +Internal helper function to set up an (n m) x (n m) pairwise distance matrix for a plate with n rows and m columns — mk_dist_matrix • designit + + +
    +
    + + + +
    +
    + + +
    +

    Internal helper function to set up an (n m) x (n m) pairwise distance matrix for a plate with n rows and m columns

    +
    + +
    +
    mk_dist_matrix(
    +  plate_x = 12,
    +  plate_y = 8,
    +  dist = "minkowski",
    +  p = 2,
    +  penalize_lines = "soft"
    +)
    +
    + +
    +

    Arguments

    +
    plate_x
    +

    Dimension of plate in x direction (i.e number of columns)

    + + +
    plate_y
    +

    Dimension of plate in y direction (i.e number of rows)

    + + +
    dist
    +

    Distance function as understood by stats::dist()

    + + +
    p
    +

    p parameter, used only if distance metric is 'minkowski'. Special cases: p=1 - Manhattan distance; p=2 - Euclidean distance

    + + +
    penalize_lines
    +

    How to penalize samples of the same group in one row or column of the plate. Valid options are: +'none' - there is no penalty and the pure distance metric counts, 'soft' - penalty will depend on the well distance within the +shared plate row or column, 'hard' - samples in the same row/column will score a zero distance

    + +
    +
    +

    Value

    + + +

    The matrix with pairwise distances between any wells on the plate

    +
    + +
    + +
    + + +
    + +
    +

    Site built with pkgdown 2.0.7.

    +
    + +
    + + + + + + + + diff --git a/reference/mk_exponentially_weighted_acceptance_func.html b/reference/mk_exponentially_weighted_acceptance_func.html new file mode 100644 index 00000000..7174cb91 --- /dev/null +++ b/reference/mk_exponentially_weighted_acceptance_func.html @@ -0,0 +1,145 @@ + +Alternative acceptance function for multi-dimensional scores with exponentially downweighted score improvements from left to right — mk_exponentially_weighted_acceptance_func • designit + + +
    +
    + + + +
    +
    + + +
    +

    Alternative acceptance function for multi-dimensional scores with exponentially downweighted score improvements from left to right

    +
    + +
    +
    mk_exponentially_weighted_acceptance_func(
    +  kappa = 0.5,
    +  simulated_annealing = FALSE,
    +  temp_function = mk_simanneal_temp_func(T0 = 500, alpha = 0.8)
    +)
    +
    + +
    +

    Arguments

    +
    kappa
    +

    Coefficient that determines how quickly the weights for the individual score improvements drop when going from left to right +(i.e. first to last score). Weight for the first score's delta is 1, then the original delta multiplied with kappa^(p-1) for the p'th score

    + + +
    simulated_annealing
    +

    Boolean; if TRUE, simulated annealing (SA) will be used to minimize the weighted improved score

    + + +
    temp_function
    +

    In case SA is used, a temperature function that returns the annealing temperature for a certain iteration number

    + +
    +
    +

    Value

    + + +

    Acceptance function which returns TRUE if current score should be taken as the new optimal score, FALSE otherwise

    +
    + +
    + +
    + + +
    + +
    +

    Site built with pkgdown 2.0.7.

    +
    + +
    + + + + + + + + diff --git a/reference/mk_plate_scoring_functions-1.png b/reference/mk_plate_scoring_functions-1.png new file mode 100644 index 00000000..7fbcde24 Binary files /dev/null and b/reference/mk_plate_scoring_functions-1.png differ diff --git a/reference/mk_plate_scoring_functions.html b/reference/mk_plate_scoring_functions.html new file mode 100644 index 00000000..d4d16104 --- /dev/null +++ b/reference/mk_plate_scoring_functions.html @@ -0,0 +1,194 @@ + +Create a list of scoring functions (one per plate) that quantify the spatially homogeneous distribution of conditions across the plate — mk_plate_scoring_functions • designit + + +
    +
    + + + +
    +
    + + +
    +

    Create a list of scoring functions (one per plate) that quantify the spatially homogeneous distribution of conditions across the plate

    +
    + +
    +
    mk_plate_scoring_functions(
    +  batch_container,
    +  plate = NULL,
    +  row,
    +  column,
    +  group,
    +  p = 2,
    +  penalize_lines = "soft"
    +)
    +
    + +
    +

    Arguments

    +
    batch_container
    +

    Batch container (bc) with all columns that denote plate related information

    + + +
    plate
    +

    Name of the bc column that holds the plate identifier (may be missing or NULL in case just one plate is used)

    + + +
    row
    +

    Name of the bc column that holds the plate row number (integer values starting at 1)

    + + +
    column
    +

    Name of the bc column that holds the plate column number (integer values starting at 1)

    + + +
    group
    +

    Name of the bc column that denotes a group/condition that should be distributed on the plate

    + + +
    p
    +

    p parameter for minkowski type of distance metrics. Special cases: p=1 - Manhattan distance; p=2 - Euclidean distance

    + + +
    penalize_lines
    +

    How to penalize samples of the same group in one row or column of the plate. Valid options are: +'none' - there is no penalty and the pure distance metric counts, 'soft' - penalty will depend on the well distance within the +shared plate row or column, 'hard' - samples in the same row/column will score a zero distance

    + +
    +
    +

    Value

    + + +

    List of scoring functions, one per plate, that calculate a real valued measure for the quality of the group distribution (the lower the better).

    +
    + +
    +

    Examples

    +
    data("invivo_study_samples")
    +bc <- BatchContainer$new(
    +  dimensions = c("column" = 6, "row" = 10)
    +)
    +bc <- assign_random(bc, invivo_study_samples)
    +scoring_f <- mk_plate_scoring_functions(
    +  bc,
    +  row = "row", column = "column", group = "Sex"
    +)
    +bc <- optimize_design(bc, scoring = scoring_f, max_iter = 100)
    +#> Checking variances of 1-dim. score vector.
    +#> ... (0.15) - OK
    +#> Initial score: 9.413
    +#> Achieved score: 9.364 at iteration 5
    +#> Achieved score: 9.351 at iteration 7
    +#> Achieved score: 9.312 at iteration 15
    +#> Achieved score: 9.266 at iteration 37
    +#> Achieved score: 9.257 at iteration 38
    +#> Achieved score: 9.257 at iteration 42
    +#> Achieved score: 9.24 at iteration 47
    +#> Achieved score: 9.235 at iteration 83
    +plot_plate(bc$get_samples(), .col = Sex)
    +
    +
    +
    +
    +
    + +
    + + +
    + +
    +

    Site built with pkgdown 2.0.7.

    +
    + +
    + + + + + + + + diff --git a/reference/mk_simanneal_acceptance_func.html b/reference/mk_simanneal_acceptance_func.html new file mode 100644 index 00000000..536d75fd --- /dev/null +++ b/reference/mk_simanneal_acceptance_func.html @@ -0,0 +1,134 @@ + +Generate acceptance function for an optimization protocol based on simulated annealing — mk_simanneal_acceptance_func • designit + + +
    +
    + + + +
    +
    + + +
    +

    Generate acceptance function for an optimization protocol based on simulated annealing

    +
    + +
    +
    mk_simanneal_acceptance_func(
    +  temp_function = mk_simanneal_temp_func(T0 = 500, alpha = 0.8)
    +)
    +
    + +
    +

    Arguments

    +
    temp_function
    +

    A temperature function that returns the annealing temperature for a certain cycle k

    + +
    +
    +

    Value

    + + +

    A function that takes parameters (current_score, best_score, iteration) for an optimization step and return a Boolean indicating whether the current solution should be accepted or dismissed. Acceptance probability of a worse solution decreases with annealing temperature.

    +
    + +
    + +
    + + +
    + +
    +

    Site built with pkgdown 2.0.7.

    +
    + +
    + + + + + + + + diff --git a/reference/mk_simanneal_temp_func.html b/reference/mk_simanneal_temp_func.html new file mode 100644 index 00000000..d2f7fc7d --- /dev/null +++ b/reference/mk_simanneal_temp_func.html @@ -0,0 +1,140 @@ + +Create a temperature function that returns the annealing temperature at a given step (iteration) — mk_simanneal_temp_func • designit + + +
    +
    + + + +
    +
    + + +
    +

    Supported annealing types are currently "Exponential multiplicative", "Logarithmic multiplicative", "Quadratic multiplicative" and "Linear multiplicative", each with dedicated constraints on alpha. For information, see http://what-when-how.com/artificial-intelligence/a-comparison-of-cooling-schedules-for-simulated-annealing-artificial-intelligence/

    +
    + +
    +
    mk_simanneal_temp_func(T0, alpha, type = "Quadratic multiplicative")
    +
    + +
    +

    Arguments

    +
    T0
    +

    Initial temperature at step 1 (when k=0)

    + + +
    alpha
    +

    Rate of cooling

    + + +
    type
    +

    Type of annealing protocol. Defaults to the quadratic multiplicative method which seems to perform well.

    + +
    +
    +

    Value

    + + +

    Temperature at cycle k.

    +
    + +
    + +
    + + +
    + +
    +

    Site built with pkgdown 2.0.7.

    +
    + +
    + + + + + + + + diff --git a/reference/mk_subgroup_shuffling_function-1.png b/reference/mk_subgroup_shuffling_function-1.png new file mode 100644 index 00000000..f926c15a Binary files /dev/null and b/reference/mk_subgroup_shuffling_function-1.png differ diff --git a/reference/mk_subgroup_shuffling_function-2.png b/reference/mk_subgroup_shuffling_function-2.png new file mode 100644 index 00000000..af24064b Binary files /dev/null and b/reference/mk_subgroup_shuffling_function-2.png differ diff --git a/reference/mk_subgroup_shuffling_function-3.png b/reference/mk_subgroup_shuffling_function-3.png new file mode 100644 index 00000000..f6d6e5be Binary files /dev/null and b/reference/mk_subgroup_shuffling_function-3.png differ diff --git a/reference/mk_subgroup_shuffling_function.html b/reference/mk_subgroup_shuffling_function.html new file mode 100644 index 00000000..c52b4039 --- /dev/null +++ b/reference/mk_subgroup_shuffling_function.html @@ -0,0 +1,208 @@ + +Created a shuffling function that permutes samples within certain subgroups of the container locations — mk_subgroup_shuffling_function • designit + + +
    +
    + + + +
    +
    + + +
    +

    If length(n_swaps)==1, the returned function may be called an arbitrary number of times. +If length(n_swaps)>1 the returned function may be called length(n_swaps) timed before returning NULL, which would be the stopping criterion if all requested swaps have been exhausted.

    +
    + +
    +
    mk_subgroup_shuffling_function(
    +  subgroup_vars,
    +  restrain_on_subgroup_levels = c(),
    +  n_swaps = 1
    +)
    +
    + +
    +

    Arguments

    +
    subgroup_vars
    +

    Column names of the variables that together define the relevant subgroups

    + + +
    restrain_on_subgroup_levels
    +

    Permutations can be forced to take place only within a level of the factor of the subgrouping variable. In this case, the user must pass only one subgrouping variable and a number of levels that together define the permuted subgroup.

    + + +
    n_swaps
    +

    Vector with number of swaps to be proposed in successive calls to the returned function (each value should be in valid range from 1..floor(n_locations/2))

    + +
    +
    +

    Value

    + + +

    Function to return a list with length n vectors src and dst, denoting source and destination index for the swap operation, or NULL if the user provided a defined protocol for the number of swaps and the last iteration has been reached

    +
    + +
    +

    Examples

    +
    set.seed(42)
    +
    +bc <- BatchContainer$new(
    +  dimensions = c(
    +    plate = 2,
    +    row = 4, col = 4
    +  )
    +)
    +
    +bc <- assign_in_order(bc, samples = tibble::tibble(
    +  Group = c(rep(c("Grp 1", "Grp 2", "Grp 3", "Grp 4"), each = 8)),
    +  ID = 1:32
    +))
    +
    +# here we use a 2-step approach:
    +# 1. Assign samples to plates.
    +# 2. Arrange samples within plates.
    +
    +# overview of sample assagnment before optimization
    +plot_plate(bc,
    +  plate = plate, row = row, column = col, .color = Group
    +)
    +
    +
    +# Step 1, assign samples to plates
    +scoring_f <- osat_score_generator(
    +  batch_vars = c("plate"), feature_vars = c("Group")
    +)
    +bc <- optimize_design(
    +  bc,
    +  scoring = scoring_f,
    +  max_iter = 10, # the real number of iterations should be bigger
    +  n_shuffle = 2,
    +  quiet = TRUE
    +)
    +plot_plate(
    +  bc,
    +  plate = plate, row = row, column = col, .color = Group
    +)
    +
    +
    +# Step 2, distribute samples within plates
    +scoring_f <- mk_plate_scoring_functions(
    +  bc,
    +  plate = "plate", row = "row", column = "col", group = "Group"
    +)
    +bc <- optimize_design(
    +  bc,
    +  scoring = scoring_f,
    +  max_iter = 50,
    +  shuffle_proposal_func = mk_subgroup_shuffling_function(subgroup_vars = c("plate")),
    +  aggregate_scores_func = L2s_norm,
    +  quiet = TRUE
    +)
    +plot_plate(bc,
    +  plate = plate, row = row, column = col, .color = Group
    +)
    +
    +
    +
    +
    + +
    + + +
    + +
    +

    Site built with pkgdown 2.0.7.

    +
    + +
    + + + + + + + + diff --git a/reference/mk_swapping_function.html b/reference/mk_swapping_function.html new file mode 100644 index 00000000..a5c08647 --- /dev/null +++ b/reference/mk_swapping_function.html @@ -0,0 +1,164 @@ + +Create function to propose swaps of samples on each call, either with a constant number of swaps or following +a user defined protocol — mk_swapping_function • designit + + +
    +
    + + + +
    +
    + + +
    +

    If length(n_swaps)==1, the returned function may be called an arbitrary number of times. +If length(n_swaps)>1 and called without argument, the returned function may be called length(n_swaps) timed before returning NULL, which would be the stopping criterion if all requested swaps have been exhausted. Alternatively, the function may be called with an iteration number as the only argument, giving the user some freedom how to iterate over the sample swapping protocol.

    +
    + +
    +
    mk_swapping_function(n_swaps = 1)
    +
    + +
    +

    Arguments

    +
    n_swaps
    +

    Vector with number of swaps to be proposed in successive calls to the returned function (each value should be in valid range from 1..floor(n_samples/2))

    + +
    +
    +

    Value

    + + +

    Function to return a list with length n vectors src and dst, denoting source and destination index for the swap operation, or NULL if the user provided a defined protocol for the number of swaps and the last iteration has been reached.

    +
    + +
    +

    Examples

    +
    data("invivo_study_samples")
    +bc <- BatchContainer$new(
    +  dimensions = c("plate" = 2, "column" = 5, "row" = 6)
    +)
    +scoring_f <- osat_score_generator("plate", "Sex")
    +optimize_design(
    +  bc, scoring = scoring_f, invivo_study_samples,
    +  max_iter = 100,
    +  shuffle_proposal_func = mk_swapping_function(1)
    +)
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Checking variances of 1-dim. score vector.
    +#> ... (418.374) - OK
    +#> Initial score: 182.5
    +#> Achieved score: 132.5 at iteration 1
    +#> Achieved score: 90.5 at iteration 5
    +#> Achieved score: 56.5 at iteration 11
    +#> Achieved score: 30.5 at iteration 23
    +#> Achieved score: 12.5 at iteration 24
    +#> Achieved score: 2.5 at iteration 26
    +#> Achieved score: 0.5 at iteration 36
    +#> Batch container with 60 locations and 59 samples (assigned).
    +#>   Dimensions: plate, column, row
    +
    +
    +
    + +
    + + +
    + +
    +

    Site built with pkgdown 2.0.7.

    +
    + +
    + + + + + + + + diff --git a/reference/multi_trt_day_samples.html b/reference/multi_trt_day_samples.html new file mode 100644 index 00000000..dbfca4c9 --- /dev/null +++ b/reference/multi_trt_day_samples.html @@ -0,0 +1,132 @@ + +Unbalanced treatment and time sample list — multi_trt_day_samples • designit + + +
    +
    + + + +
    +
    + + +
    +

    A sample list with 4 columns SampleName, Well, Time and Treatment +Not all treatments are avaliable at all time points. +All samples are placed on the same plate.

    +
    + +
    +
    data(multi_trt_day_samples)
    +
    + +
    +

    Format

    +

    An object of class "tibble"

    +
    +
    +

    Author

    +

    siebourj

    +
    + +
    + +
    + + +
    + +
    +

    Site built with pkgdown 2.0.7.

    +
    + +
    + + + + + + + + diff --git a/reference/neighbors.html b/reference/neighbors.html new file mode 100644 index 00000000..f95fce89 --- /dev/null +++ b/reference/neighbors.html @@ -0,0 +1,138 @@ + +Penalty for neighbors with same level — neighbors • designit + + +
    +
    + + + +
    +
    + + +
    +

    Penalty score for number of neighboring pairs with the same level of a factor. +The number of such pairs is summed.

    +
    + +
    +
    neighbors(m)
    +
    + +
    +

    Arguments

    +
    m
    +

    a factor vector

    + +
    +
    +

    Value

    + + +

    the number of pairs

    +
    +
    +

    Author

    +

    Juliane Siebourg-Polster

    +
    + +
    + +
    + + +
    + +
    +

    Site built with pkgdown 2.0.7.

    +
    + +
    + + + + + + + + diff --git a/reference/optimize_design-1.png b/reference/optimize_design-1.png new file mode 100644 index 00000000..430b0a4b Binary files /dev/null and b/reference/optimize_design-1.png differ diff --git a/reference/optimize_design.html b/reference/optimize_design.html new file mode 100644 index 00000000..4d5b082f --- /dev/null +++ b/reference/optimize_design.html @@ -0,0 +1,255 @@ + +Generic optimizer that can be customized by user provided functions for generating shuffles and progressing towards the minimal score — optimize_design • designit + + +
    +
    + + + +
    +
    + + +
    +

    Generic optimizer that can be customized by user provided functions for generating shuffles and progressing towards the minimal score

    +
    + +
    +
    optimize_design(
    +  batch_container,
    +  samples = NULL,
    +  scoring = NULL,
    +  n_shuffle = NULL,
    +  shuffle_proposal_func = NULL,
    +  acceptance_func = accept_strict_improvement,
    +  aggregate_scores_func = identity,
    +  check_score_variance = TRUE,
    +  autoscale_scores = FALSE,
    +  autoscaling_permutations = 100,
    +  autoscale_useboxcox = TRUE,
    +  sample_attributes_fixed = FALSE,
    +  max_iter = 10000,
    +  min_delta = NA,
    +  quiet = FALSE
    +)
    +
    + +
    +

    Arguments

    +
    batch_container
    +

    An instance of BatchContainer.

    + + +
    samples
    +

    A data.frame with sample information. +Should be NULL if the BatchContainer already has samples in it.

    + + +
    scoring
    +

    Scoring function or a named list() of scoring functions.

    + + +
    n_shuffle
    +

    Vector of length 1 or larger, defining how many random sample +swaps should be performed in each iteration. If length(n_shuffle)==1, +this sets no limit to the number of iterations. Otherwise, the optimization +stops if the swapping protocol is exhausted.

    + + +
    shuffle_proposal_func
    +

    A user defined function to propose the next shuffling of samples. +Takes priority over n_shuffle if both are provided. The function is called with +a BatchContainer bc and an integer parameter iteration for the current iteration number, +allowing very flexible shuffling strategies. +Mapper syntax is supported (see purrr::as_mapper()). +The returned function must either return a list with fields srcand dst (for pairwise sample swapping) +or a numeric vector with a complete re-assigned sample order.

    + + +
    acceptance_func
    +

    Alternative function to select a new score as the best one. +Defaults to strict improvement rule, i.e. all elements of a score have to be smaller or equal in order to accept the solution as better. +This may be replaced with an alternative acceptance function included in the package +(e.g. mk_simanneal_acceptance_func()) or a user provided function. +Mapper syntax is supported (see purrr::as_mapper()).

    + + +
    aggregate_scores_func
    +

    A function to aggregate multiple scores AFTER (potential) auto-scaling and BEFORE acceptance evaluation. +If a function is passed, (multi-dimensional) scores will be transformed (often to a single double value) before calling the acceptance function. +E.g., see first_score_only() or worst_score(). +Note that particular acceptance functions may require aggregation of a score to a single scalar in order to work, see for example those +generated by mk_simanneal_acceptance_func(). +Mapper syntax is supported (see purrr::as_mapper()).

    + + +
    check_score_variance
    +

    Logical: if TRUE, scores will be checked for variability under sample permutation +and the optimization is not performed if at least one subscore appears to have a zero variance.

    + + +
    autoscale_scores
    +

    Logical: if TRUE, perform a transformation on the fly to equally scale scores +to a standard normal. This makes scores more directly comparable and easier to aggregate.

    + + +
    autoscaling_permutations
    +

    How many random sample permutations should be done to estimate autoscaling parameters. +(Note: minimum will be 20, regardless of the specified value)

    + + +
    autoscale_useboxcox
    +

    Logical; if TRUE, use a boxcox transformation for the autoscaling if possible at all. +Requires installation of the bestNormalize package.

    + + +
    sample_attributes_fixed
    +

    Logical; if TRUE, sample shuffle function may generate altered sample attributes at each iteration. +This affects estimation of score distributions. (Parameter only relevant if shuffle function does introduce attributes!)

    + + +
    max_iter
    +

    Stop optimization after a maximum number of iterations, +independent from other stopping criteria (user defined shuffle proposal or min_delta).

    + + +
    min_delta
    +

    If not NA, optimization is stopped as soon as successive improvement (i.e. euclidean distance between score vectors +from current best and previously best solution) drops below min_delta.

    + + +
    quiet
    +

    If TRUE, suppress non-critical warnings or messages.

    + +
    +
    +

    Value

    + + +

    A trace object

    +
    + +
    +

    Examples

    +
    data("invivo_study_samples")
    +bc <- BatchContainer$new(
    +  dimensions = c("plate" = 2, "column" = 5, "row" = 6)
    +)
    +bc <- optimize_design(bc, invivo_study_samples,
    +  scoring = osat_score_generator("plate", "Sex"),
    +  max_iter = 100
    +)
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Checking variances of 1-dim. score vector.
    +#> ... (141.154) - OK
    +#> Initial score: 182.5
    +#> Achieved score: 132.5 at iteration 1
    +#> Achieved score: 90.5 at iteration 2
    +#> Achieved score: 56.5 at iteration 6
    +#> Achieved score: 30.5 at iteration 11
    +#> Achieved score: 12.5 at iteration 15
    +#> Achieved score: 2.5 at iteration 16
    +#> Achieved score: 0.5 at iteration 31
    +plot_plate(bc$get_samples(), .col = Sex)
    +
    +
    +
    +
    + +
    + + +
    + +
    +

    Site built with pkgdown 2.0.7.

    +
    + +
    + + + + + + + + diff --git a/reference/optimize_multi_plate_design.html b/reference/optimize_multi_plate_design.html new file mode 100644 index 00000000..4b03ef86 --- /dev/null +++ b/reference/optimize_multi_plate_design.html @@ -0,0 +1,177 @@ + +Convenience wrapper to optimize a typical multi-plate design — optimize_multi_plate_design • designit + + +
    +
    + + + +
    +
    + + +
    +

    The batch container will in the end contain the updated experimental layout

    +
    + +
    +
    optimize_multi_plate_design(
    +  batch_container,
    +  across_plates_variables = NULL,
    +  within_plate_variables = NULL,
    +  plate = "plate",
    +  row = "row",
    +  column = "column",
    +  n_shuffle = 1,
    +  max_iter = 1000,
    +  quiet = FALSE
    +)
    +
    + +
    +

    Arguments

    +
    batch_container
    +

    Batch container (bc) with all columns that denote plate related information

    + + +
    across_plates_variables
    +

    Vector with bc column name(s) that denote(s) groups/conditions to be balanced across plates, +sorted by relative importance of the factors

    + + +
    within_plate_variables
    +

    Vector with bc column name(s) that denote(s) groups/conditions to be spaced out within each plate, +sorted by relative importance of the factors

    + + +
    plate
    +

    Name of the bc column that holds the plate identifier

    + + +
    row
    +

    Name of the bc column that holds the plate row number (integer values starting at 1)

    + + +
    column
    +

    Name of the bc column that holds the plate column number (integer values starting at 1)

    + + +
    n_shuffle
    +

    Vector of length 1 or larger, defining how many random sample +swaps should be performed in each iteration. See optimize_design().

    + + +
    max_iter
    +

    Stop any of the optimization runs after this maximum number of iterations. See optimize_design().

    + + +
    quiet
    +

    If TRUE, suppress informative messages.

    + +
    +
    +

    Value

    + + +

    A list with named traces, one for each optimization step

    +
    + +
    + +
    + + +
    + +
    +

    Site built with pkgdown 2.0.7.

    +
    + +
    + + + + + + + + diff --git a/reference/osat_score.html b/reference/osat_score.html new file mode 100644 index 00000000..01714289 --- /dev/null +++ b/reference/osat_score.html @@ -0,0 +1,192 @@ + +Compute OSAT score for sample assignment. — osat_score • designit + + +
    +
    + + + +
    +
    + + +
    +

    Compute OSAT score for sample assignment.

    +
    + +
    +
    osat_score(bc, batch_vars, feature_vars, expected_dt = NULL, quiet = FALSE)
    +
    + +
    +

    Arguments

    +
    bc
    +

    BatchContainer with samples +or data.table/data.frame where every row is a location +in a container and a sample in this location.

    + + +
    batch_vars
    +

    character vector with batch variable names to take into account for the +score computation.

    + + +
    feature_vars
    +

    character vector with sample variable names to take into account for +score computation.

    + + +
    expected_dt
    +

    A data.table with expected number of samples sample +variables and batch variables combination. This is not required, however it does not change +during the optimization process. So it is a good idea to cache this value.

    + + +
    quiet
    +

    Do not warn about NAs in feature columns.

    + +
    +
    +

    Value

    + + +

    a list with two attributes: $score (numeric score value), $expected_dt

    + + +

    (expected counts data.table for reuse)

    +
    + +
    +

    Examples

    +
    sample_assignment <- tibble::tribble(
    +  ~ID, ~SampleType, ~Sex, ~plate,
    +  1, "Case", "Female", 1,
    +  2, "Case", "Female", 1,
    +  3, "Case", "Male", 2,
    +  4, "Control", "Female", 2,
    +  5, "Control", "Female", 1,
    +  6, "Control", "Male", 2,
    +  NA, NA, NA, 1,
    +  NA, NA, NA, 2,
    +)
    +
    +osat_score(sample_assignment,
    +  batch_vars = "plate",
    +  feature_vars = c("SampleType", "Sex")
    +)
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> $score
    +#> [1] 3
    +#> 
    +#> $expected_dt
    +#>    plate SampleType    Sex .n_expected
    +#> 1:     1       Case Female         1.0
    +#> 2:     1       Case   Male         0.5
    +#> 3:     1    Control Female         1.0
    +#> 4:     1    Control   Male         0.5
    +#> 5:     2       Case Female         1.0
    +#> 6:     2       Case   Male         0.5
    +#> 7:     2    Control Female         1.0
    +#> 8:     2    Control   Male         0.5
    +#> 
    +
    +
    +
    + +
    + + +
    + +
    +

    Site built with pkgdown 2.0.7.

    +
    + +
    + + + + + + + + diff --git a/reference/osat_score_generator.html b/reference/osat_score_generator.html new file mode 100644 index 00000000..94da5f3f --- /dev/null +++ b/reference/osat_score_generator.html @@ -0,0 +1,168 @@ + +Convenience wrapper for the OSAT score — osat_score_generator • designit + + +
    +
    + + + +
    +
    + + +
    +

    This function wraps osat_score() in order to take full advantage of the speed gain without +managing the buffered objects in the user code.

    +
    + +
    +
    osat_score_generator(batch_vars, feature_vars, quiet = FALSE)
    +
    + +
    +

    Arguments

    +
    batch_vars
    +

    character vector with batch variable names to take into account for the +score computation.

    + + +
    feature_vars
    +

    character vector with sample variable names to take into account for +score computation.

    + + +
    quiet
    +

    Do not warn about NAs in feature columns.

    + +
    +
    +

    Value

    + + +

    A function that returns the OSAT score for a specific sample arrangement

    +
    + +
    +

    Examples

    +
    sample_assignment <- tibble::tribble(
    +  ~ID, ~SampleType, ~Sex, ~plate,
    +  1, "Case", "Female", 1,
    +  2, "Case", "Female", 1,
    +  3, "Case", "Male", 2,
    +  4, "Control", "Female", 2,
    +  5, "Control", "Female", 1,
    +  6, "Control", "Male", 2,
    +  NA, NA, NA, 1,
    +  NA, NA, NA, 2,
    +)
    +
    +osat_scoring_function <- osat_score_generator(
    +  batch_vars = "plate",
    +  feature_vars = c("SampleType", "Sex")
    +)
    +
    +osat_scoring_function(sample_assignment)
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> [1] 3
    +
    +
    +
    + +
    + + +
    + +
    +

    Site built with pkgdown 2.0.7.

    +
    + +
    + + + + + + + + diff --git a/reference/pairwise_swapping.html b/reference/pairwise_swapping.html new file mode 100644 index 00000000..78b5d5c7 --- /dev/null +++ b/reference/pairwise_swapping.html @@ -0,0 +1,138 @@ + +Proposes pairwise swap of samples on each call. — pairwise_swapping • designit + + +
    +
    + + + +
    +
    + + +
    +

    This function will ensure that one of the locations is always non-empty. It should not +return trivial permutations (e.g., src=c(1,2) and dst=c(1,2)).

    +
    + +
    +
    pairwise_swapping(batch_container, iteration)
    +
    + +
    +

    Arguments

    +
    batch_container
    +

    The batch-container.

    + + +
    iteration
    +

    The current iteration number.

    + +
    +
    +

    Value

    + + +

    Function accepting batch container & iteration number. It returns a list with length 1 vectors 'src' and 'dst', denoting source and destination index for the swap operation

    +
    + +
    + +
    + + +
    + +
    +

    Site built with pkgdown 2.0.7.

    +
    + +
    + + + + + + + + diff --git a/reference/pipe.html b/reference/pipe.html new file mode 100644 index 00000000..204d2865 --- /dev/null +++ b/reference/pipe.html @@ -0,0 +1,120 @@ + +Pipe operator — %>% • designit + + +
    +
    + + + +
    +
    + + +
    +

    See magrittr::%>% for details.

    +
    + +
    +
    lhs %>% rhs
    +
    + + +
    + +
    + + +
    + +
    +

    Site built with pkgdown 2.0.7.

    +
    + +
    + + + + + + + + diff --git a/reference/plate_effect_example.html b/reference/plate_effect_example.html new file mode 100644 index 00000000..230e5d9e --- /dev/null +++ b/reference/plate_effect_example.html @@ -0,0 +1,150 @@ + +Example dataset with a plate effect — plate_effect_example • designit + + +
    +
    + + + +
    +
    + + +
    +

    Here top and bottom row were both used as controls (in dilutions). The top +row however was affected differently than the bottom one. This makes +normalization virtually impossible.

    +
    + +
    +
    data(plate_effect_example)
    +
    + +
    +

    Format

    +

    An object of class "tibble"

    row
    +

    Plate row

    + +
    column
    +

    Plate column

    + +
    conc
    +

    Sample concentration

    + +
    log_conc
    +

    Logarithm of sample concentration

    + +
    treatment
    +

    Sample treatment

    + +
    readout
    +

    Readout from experiment

    + + +
    +
    +

    Author

    +

    Balazs Banfai

    +
    + +
    + +
    + + +
    + +
    +

    Site built with pkgdown 2.0.7.

    +
    + +
    + + + + + + + + diff --git a/reference/plot_plate-1.png b/reference/plot_plate-1.png new file mode 100644 index 00000000..084c445b Binary files /dev/null and b/reference/plot_plate-1.png differ diff --git a/reference/plot_plate.html b/reference/plot_plate.html new file mode 100644 index 00000000..d5381c94 --- /dev/null +++ b/reference/plot_plate.html @@ -0,0 +1,226 @@ + +Plot plate layouts — plot_plate • designit + + +
    +
    + + + +
    +
    + + +
    +

    Plot plate layouts

    +
    + +
    +
    plot_plate(
    +  .tbl,
    +  plate = plate,
    +  row = row,
    +  column = column,
    +  .color,
    +  .alpha = NULL,
    +  .pattern = NULL,
    +  title = paste("Layout by", rlang::as_name(rlang::enquo(plate))),
    +  add_excluded = FALSE,
    +  rename_empty = FALSE
    +)
    +
    + +
    +

    Arguments

    +
    .tbl
    +

    a tibble (or data.frame) with the samples assigned to locations. +Alternatively a BatchContainter with samples can be supplied here.

    + + +
    plate
    +

    optional dimension variable used for the plate ids

    + + +
    row
    +

    the dimension variable used for the row ids

    + + +
    column
    +

    the dimension variable used for the column ids

    + + +
    .color
    +

    the continuous or discrete variable to color by

    + + +
    .alpha
    +

    a continuous variable encoding transparency

    + + +
    .pattern
    +

    a discrete variable encoding tile pattern (needs ggpattern)

    + + +
    title
    +

    string for the plot title

    + + +
    add_excluded
    +

    flag to add excluded wells (in bc$exclude) to the plot. +A BatchContainer must be provided for this.

    + + +
    rename_empty
    +

    whether NA entries in sample table should be renamed to 'empty`.

    + +
    +
    +

    Value

    + + +

    the ggplot object

    +
    +
    +

    Author

    +

    siebourj

    +
    + +
    +

    Examples

    +
    nPlate <- 3
    +nColumn <- 4
    +nRow <- 6
    +
    +treatments <- c("CTRL", "TRT1", "TRT2")
    +timepoints <- c(1, 2, 3)
    +
    +
    +bc <- BatchContainer$new(
    +  dimensions = list(
    +    plate = nPlate,
    +    column = list(values = letters[1:nColumn]),
    +    row = nRow
    +  )
    +)
    +
    +sample_sheet <- tibble::tibble(
    +  sampleID = 1:(nPlate * nColumn * nRow),
    +  Treatment = rep(treatments, each = floor(nPlate * nColumn * nRow) / length(treatments)),
    +  Timepoint = rep(timepoints, floor(nPlate * nColumn * nRow) / length(treatments))
    +)
    +
    +# assign samples from the sample sheet
    +bc <- assign_random(bc, samples = sample_sheet)
    +
    +plot_plate(bc$get_samples(),
    +  plate = plate, column = column, row = row,
    +  .color = Treatment, .alpha = Timepoint
    +)
    +
    +
    +if (FALSE) {
    +plot_plate(bc$get_samples(),
    +  plate = plate, column = column, row = row,
    +  .color = Treatment, .pattern = Timepoint
    +)
    +}
    +
    +
    +
    + +
    + + +
    + +
    +

    Site built with pkgdown 2.0.7.

    +
    + +
    + + + + + + + + diff --git a/reference/random_score_variances.html b/reference/random_score_variances.html new file mode 100644 index 00000000..1c9d391e --- /dev/null +++ b/reference/random_score_variances.html @@ -0,0 +1,150 @@ + +Estimate the variance of individual scores by a series of completely random sample permutations — random_score_variances • designit + + +
    +
    + + + +
    +
    + + +
    +

    Estimate the variance of individual scores by a series of completely random sample permutations

    +
    + +
    +
    random_score_variances(
    +  batch_container,
    +  scoring,
    +  random_perm,
    +  sample_attributes_fixed
    +)
    +
    + +
    +

    Arguments

    +
    batch_container
    +

    An instance of BatchContainer.

    + + +
    scoring
    +

    A named list() of scoring function. Each function should +return a vector of non-zero length.

    + + +
    random_perm
    +

    Number of random sample permutations to be done.

    + + +
    sample_attributes_fixed
    +

    Logical; if FALSE, simulate a shuffle function that alters sample attributes at each iteration.

    + +
    +
    +

    Value

    + + +

    Vector of length m (=dimensionality of score) with estimated variances of each subscore

    +
    + +
    + +
    + + +
    + +
    +

    Site built with pkgdown 2.0.7.

    +
    + +
    + + + + + + + + diff --git a/reference/randomize.html b/reference/randomize.html new file mode 100644 index 00000000..80dd3b55 --- /dev/null +++ b/reference/randomize.html @@ -0,0 +1,277 @@ + +randomize experimental layout — randomize • designit + + +
    +
    + + + +
    +
    + + +
    +

    This function generates a randomized experimental layout based on given +experimental dimensions and factors to be balanced

    +
    + +
    +
    randomize(
    +  design,
    +  report,
    +  layout_dim,
    +  balance,
    +  scoring_groups = as.list(names(layout_dim)),
    +  scoring_tests = as.list(rep("countGini", length(layout_dim))),
    +  burnin = 100,
    +  annealprotocol,
    +  scoring_weights = rep(1, length(scoring_groups)),
    +  balance_weights = rep(1, length(balance)),
    +  distribute = 1:(prod(layout_dim))
    +)
    +
    + +
    +

    Arguments

    +
    design
    +

    a data.frame with the sample ids, experimental conditions and +information about fixed samples (columns with 'Fix' prefix and then the dimension name)

    + + +
    report
    +

    a string with the sample identifier

    + + +
    layout_dim
    +

    a named vector with the experimental dimensions

    + + +
    balance
    +

    a vector with the names of experimental conditions to be balanced

    + + +
    scoring_groups
    +

    list of dimension name groups to be used jointly for scoring

    + + +
    scoring_tests
    +

    list of dimension name groups to be used jointly for scoring

    + + +
    burnin
    +

    a number of initial burnin runs (default=100)

    + + +
    annealprotocol
    +

    a vector with the number of pairs to swap in each annealing step

    + + +
    scoring_weights
    +

    named vector of weights for the dimensions (default all 1)

    + + +
    balance_weights
    +

    named vector of weights for the factors to be balanced (default all 1)

    + + +
    distribute
    +

    a starting distribution

    + +
    +
    +

    Value

    + + +

    the value of the Gini index

    +
    +
    +

    Author

    +

    Juliane Siebourg-Polster

    +
    + +
    +

    Examples

    +
    if (FALSE) {
    +# samples to use
    +samples <- data.frame(
    +  Group = c(1, 2, 3, 4, 5),
    +  Treatment = c(
    +    "vehicle", "RTR24", "RTR25",
    +    "RTR26", "RTR27"
    +  ),
    +  Dose = c(0, 25, 25, 25, 25),
    +  animals = c(2, 2, 2, 2, 2)
    +)
    +
    +# generate initial sample table (2 animals per group with 3 replicates)
    +samples <- dplyr::bind_rows(samples %>% dplyr::mutate(animals = 1), samples) %>%
    +  dplyr::rename(animal = animals)
    +samples <- dplyr::bind_rows(list(samples, samples, samples)) %>%
    +  dplyr::mutate(
    +    replicate = rep(1:3, each = 10),
    +    SampleID = paste0(Treatment, "_", animal, "_", replicate),
    +    AnimalID = paste0(Treatment, "_", animal)
    +  )
    +
    +# to be put on a 96 well plate
    +# (empty wells: first and last column plus two more wells)
    +empty <- 8 * 4 - nrow(samples) # n locations - n samples
    +emptydf <- data.frame(
    +  Treatment = "empty",
    +  FixColumn = 4, FixRow = 8 + 1 - (1:empty)
    +)
    +
    +# final sample table
    +design <- dplyr::full_join(samples, emptydf)
    +
    +# set parameters
    +layout_dim <- c(Row = 8, Column = 4)
    +scoring_groups <- list(c("Row"), c("Column"))
    +scoring_tests <- list("countGini", "countGini")
    +scoring_weights <- c(Row = 1, Column = 2)
    +balance <- c("AnimalID")
    +balance_weights <- c(1, 1)
    +names(balance_weights) <- balance
    +report <- "SampleID" # column with a unique ID
    +# annealprotocol <- rep(c(10,5,2,1), c(500,1000,2000,5000))
    +annealprotocol <- rep(c(10, 5, 2, 1), c(50, 100, 200, 300))
    +
    +# run randomization
    +result <- randomize(design, report, layout_dim, balance,
    +  scoring_groups = scoring_groups,
    +  scoring_tests = scoring_tests,
    +  burnin = 200, annealprotocol = annealprotocol,
    +  scoring_weights = scoring_weights,
    +  balance_weights = balance_weights,
    +  distribute = sample(1:(prod(layout_dim)))
    +)
    +
    +final_design <- result$design %>%
    +  dplyr::mutate(Column = Column + 1) # first column empty
    +
    +# plot
    +library(ggplot)
    +ggplot(
    +  final_design,
    +  aes(x = Column, y = Row, fill = Treatment, alpha = factor(animal))
    +) +
    +  theme_minimal() +
    +  geom_tile() +
    +  scale_x_continuous(breaks = unique(final_design$Column)) +
    +  scale_y_reverse(breaks = rev(unique(final_design$Row))) +
    +  scale_alpha_manual(values = c(1, 0.5))
    +
    +kable(table(final_design$Treatment, final_design$Column),
    +  digits = 0,
    +  caption = "Treatment distribution across Columns."
    +)
    +
    +# optimization curve
    +plot(score ~ iteration,
    +  data = result$opti,
    +  log = "x", ylab = "penalty", type = "b"
    +)
    +}
    +
    +
    +
    +
    + +
    + + +
    + +
    +

    Site built with pkgdown 2.0.7.

    +
    + +
    + + + + + + + + diff --git a/reference/report_scores.html b/reference/report_scores.html new file mode 100644 index 00000000..c6e9822b --- /dev/null +++ b/reference/report_scores.html @@ -0,0 +1,134 @@ + +Helper function to print out one set of scores plus (if needed) aggregated values — report_scores • designit + + +
    +
    + + + +
    +
    + + +
    +

    Helper function to print out one set of scores plus (if needed) aggregated values

    +
    + +
    +
    report_scores(score, agg_score, iteration)
    +
    + +
    +

    Arguments

    +
    score
    +

    Vector of (non-aggregated) scores (may be a single value as well)

    + + +
    agg_score
    +

    Vector of aggregated scores (may be a single value as well)

    + + +
    iteration
    +

    Iteration number

    + +
    + +
    + +
    + + +
    + +
    +

    Site built with pkgdown 2.0.7.

    +
    + +
    + + + + + + + + diff --git a/reference/sample_random_scores.html b/reference/sample_random_scores.html new file mode 100644 index 00000000..fb406366 --- /dev/null +++ b/reference/sample_random_scores.html @@ -0,0 +1,150 @@ + +Sample scores from a number of completely random sample permutations — sample_random_scores • designit + + +
    +
    + + + +
    +
    + + +
    +

    Sample scores from a number of completely random sample permutations

    +
    + +
    +
    sample_random_scores(
    +  batch_container,
    +  scoring,
    +  random_perm,
    +  sample_attributes_fixed
    +)
    +
    + +
    +

    Arguments

    +
    batch_container
    +

    An instance of BatchContainer.

    + + +
    scoring
    +

    A named list() of scoring function. Each function should +return a vector of non-zero length.

    + + +
    random_perm
    +

    Number of random sample permutations to be done.

    + + +
    sample_attributes_fixed
    +

    Logical; if FALSE, simulate a shuffle function that alters sample attributes at each iteration.

    + +
    +
    +

    Value

    + + +

    A score matrix with n (# of permutations) rows and m (dimensionality of score) columns.

    +
    + +
    + +
    + + +
    + +
    +

    Site built with pkgdown 2.0.7.

    +
    + +
    + + + + + + + + diff --git a/reference/shrink_mat.html b/reference/shrink_mat.html new file mode 100644 index 00000000..d00ba285 --- /dev/null +++ b/reference/shrink_mat.html @@ -0,0 +1,136 @@ + +Shrinks a matrix with scores and adds an iteration column. — shrink_mat • designit + + +
    +
    + + + +
    +
    + + +
    +

    Shrinks a matrix with scores and adds an iteration column.

    +
    + +
    +
    shrink_mat(m, last_iteration)
    +
    + +
    +

    Arguments

    +
    m
    +

    input matrix

    + + +
    last_iteration
    +

    last iteration

    + +
    +
    +

    Value

    + + +

    a tibble::tibble() wrapped in a list

    +
    + +
    + +
    + + +
    + +
    +

    Site built with pkgdown 2.0.7.

    +
    + +
    + + + + + + + + diff --git a/reference/shuffle_grouped_data.html b/reference/shuffle_grouped_data.html new file mode 100644 index 00000000..7b8adc4b --- /dev/null +++ b/reference/shuffle_grouped_data.html @@ -0,0 +1,194 @@ + +Generate in one go a shuffling function that produces permutations with specific constraints on multiple sample variables and group sizes fitting one specific allocation variable — shuffle_grouped_data • designit + + +
    +
    + + + +
    +
    + + +
    +

    Generate in one go a shuffling function that produces permutations with specific constraints on multiple sample variables and group sizes fitting one specific allocation variable

    +
    + +
    +
    shuffle_grouped_data(
    +  batch_container,
    +  allocate_var,
    +  keep_together_vars = c(),
    +  keep_separate_vars = c(),
    +  n_min = NA,
    +  n_max = NA,
    +  n_ideal = NA,
    +  subgroup_var_name = NULL,
    +  report_grouping_as_attribute = FALSE,
    +  prefer_big_groups = FALSE,
    +  strict = TRUE,
    +  fullTree = FALSE,
    +  maxCalls = 1e+06
    +)
    +
    + +
    +

    Arguments

    +
    batch_container
    +

    Batch container with all samples assigned that are to be grouped and sub-grouped

    + + +
    allocate_var
    +

    Name of a variable in the samples table to inform possible groupings, as (sub)group sizes must add up to the correct totals

    + + +
    keep_together_vars
    +

    Vector of column names in sample table; groups are formed by pooling samples with identical values of all those variables

    + + +
    keep_separate_vars
    +

    Vector of column names in sample table; items with identical values in those variables will not be put into the same subgroup if at all possible

    + + +
    n_min
    +

    Minimal number of samples in one sub(!)group; by default 1

    + + +
    n_max
    +

    Maximal number of samples in one sub(!)group; by default the size of the biggest group

    + + +
    n_ideal
    +

    Ideal number of samples in one sub(!)group; by default the floor or ceiling of mean(n_min,n_max), depending on the setting of prefer_big_groups

    + + +
    subgroup_var_name
    +

    An optional column name for the subgroups which are formed (or NULL)

    + + +
    report_grouping_as_attribute
    +

    Boolean, if TRUE, add an attribute table to the permutation functions' output, to be used in scoring during the design optimization

    + + +
    prefer_big_groups
    +

    Boolean; indicating whether or not bigger subgroups should be preferred in case of several possibilities

    + + +
    strict
    +

    Boolean; if TRUE, subgroup size constraints have to be met strictly, implying the possibility of finding no solution at all

    + + +
    fullTree
    +

    Boolean: Enforce full search of the possibility tree, independent of the value of maxCalls

    + + +
    maxCalls
    +

    Maximum number of recursive calls in the search tree, to avoid long run times with very large trees

    + +
    +
    +

    Value

    + + +

    Shuffling function that on each call returns an index vector for a valid sample permutation

    +
    + +
    + +
    + + +
    + +
    +

    Site built with pkgdown 2.0.7.

    +
    + +
    + + + + + + + + diff --git a/reference/shuffle_with_constraints.html b/reference/shuffle_with_constraints.html new file mode 100644 index 00000000..4cef2cb7 --- /dev/null +++ b/reference/shuffle_with_constraints.html @@ -0,0 +1,303 @@ + +Shuffling proposal function with constraints. — shuffle_with_constraints • designit + + +
    +
    + + + +
    +
    + + +
    +

    Can be used with optimize_design to improve convergence speed.

    +
    + +
    +
    shuffle_with_constraints(src = TRUE, dst = TRUE)
    +
    + +
    +

    Arguments

    +
    src
    +

    Expression to define possible source locations in the samples/locations +table. Usually evaluated based on +BatchContainer$get_samples(include_id = TRUE, as_tibble = FALSE) as an environment +(see also with()). A single source location is selected from rows where the +expression evaluates toTRUE.

    + + +
    dst
    +

    Expression to define possible destination locations in the +samples/locations table. Usually evaluated based on BatchContainer$get_samples() as an +environment. +Additionally a special variable .src is available in this environment which +describes the selected source row from the table.

    + +
    +
    +

    Value

    + + +

    Returns a function which accepts a BatchContainer and an iteration +number (i). This function returns a list with two names: src vector of length +2 and dst vector of length two. See BatchContainer$move_samples().

    +
    + +
    +

    Examples

    +
    set.seed(43)
    +
    +samples <- data.frame(
    +  id = 1:100,
    +  sex = sample(c("F", "M"), 100, replace = TRUE),
    +  group = sample(c("treatment", "control"), 100, replace = TRUE)
    +)
    +
    +bc <- BatchContainer$new(
    +  dimensions = c("plate" = 5, "position" = 25)
    +)
    +
    +scoring_f <- function(samples) {
    +  osat_score(
    +    samples,
    +    "plate",
    +    c("sex", "group")
    +  )$score
    +}
    +
    +# in this example we treat all the positions in the plate as equal.
    +# when shuffling we enforce that source location is non-empty,
    +# and destination location has a different plate number
    +bc <- optimize_design(
    +  bc,
    +  scoring = scoring_f,
    +  samples,
    +  shuffle_proposal = shuffle_with_constraints(
    +    # source is non-empty location
    +    !is.na(.sample_id),
    +    # destination has a different plate
    +    plate != .src$plate
    +  ),
    +  max_iter = 10
    +)
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Checking variances of 1-dim. score vector.
    +#> ... (455.222) - OK
    +#> Initial score: 172.8
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Achieved score: 158.8 at iteration 3
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Achieved score: 138.8 at iteration 4
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Achieved score: 136.8 at iteration 8
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +#> Warning: NAs in features / batch columns; they will be excluded from scoring
    +
    +
    +
    + +
    + + +
    + +
    +

    Site built with pkgdown 2.0.7.

    +
    + +
    + + + + + + + + diff --git a/reference/shuffle_with_subgroup_formation.html b/reference/shuffle_with_subgroup_formation.html new file mode 100644 index 00000000..1802dcb4 --- /dev/null +++ b/reference/shuffle_with_subgroup_formation.html @@ -0,0 +1,149 @@ + +Compose shuffling function based on already available subgrouping and allocation information — shuffle_with_subgroup_formation • designit + + +
    +
    + + + +
    +
    + + +
    +

    Compose shuffling function based on already available subgrouping and allocation information

    +
    + +
    +
    shuffle_with_subgroup_formation(
    +  subgroup_object,
    +  subgroup_allocations,
    +  keep_separate_vars = c(),
    +  report_grouping_as_attribute = FALSE
    +)
    +
    + +
    +

    Arguments

    +
    subgroup_object
    +

    A subgrouping object as returned by form_homogeneous_subgroups()

    + + +
    subgroup_allocations
    +

    A list of possible assignments of the allocation variable as returned by compile_possible_subgroup_allocation()

    + + +
    keep_separate_vars
    +

    Vector of column names in sample table; items with identical values in those variables will not be put into the same subgroup if at all possible

    + + +
    report_grouping_as_attribute
    +

    Boolean, if TRUE, add an attribute table to the permutation functions' output, to be used in scoring during the design optimization

    + +
    +
    +

    Value

    + + +

    Shuffling function that on each call returns an index vector for a valid sample permutation

    +
    + +
    + +
    + + +
    + +
    +

    Site built with pkgdown 2.0.7.

    +
    + +
    + + + + + + + + diff --git a/reference/simanneal_acceptance_prob.html b/reference/simanneal_acceptance_prob.html new file mode 100644 index 00000000..048c4df4 --- /dev/null +++ b/reference/simanneal_acceptance_prob.html @@ -0,0 +1,144 @@ + +Acceptance probability for a new solution — simanneal_acceptance_prob • designit + + +
    +
    + + + +
    +
    + + +
    +

    A solution is always to be accepted if it leads to a lower score. Worse solutions should be accepted with a probability given by this function.

    +
    + +
    +
    simanneal_acceptance_prob(current_score, best_score, temp, eps = 0.1)
    +
    + +
    +

    Arguments

    +
    current_score
    +

    Score from the current optimizing iteration (scalar value, double)

    + + +
    best_score
    +

    Score from the current optimizing iteration (scalar value, double)

    + + +
    temp
    +

    Current value of annealing temperature

    + + +
    eps
    +

    Small parameter eps(ilon), achieving that not always the new solution is taken when scores are exactly equal

    + +
    +
    +

    Value

    + + +

    Probability with which to accept the new score as the best one

    +
    + +
    + +
    + + +
    + +
    +

    Site built with pkgdown 2.0.7.

    +
    + +
    + + + + + + + + diff --git a/reference/sum_scores.html b/reference/sum_scores.html new file mode 100644 index 00000000..43ef94b5 --- /dev/null +++ b/reference/sum_scores.html @@ -0,0 +1,146 @@ + +Aggregation of scores: sum up all individual scores — sum_scores • designit + + +
    +
    + + + +
    +
    + + +
    +

    Aggregation of scores: sum up all individual scores

    +
    + +
    +
    sum_scores(scores, na.rm = FALSE, ...)
    +
    + +
    +

    Arguments

    +
    scores
    +

    A score or multiple component score vector

    + + +
    na.rm
    +

    Boolean. Should NA values be ignored when obtaining the maximum? FALSE by default as ignoring NA values may render the sum meaningless.

    + + +
    ...
    +

    Parameters to be ignored by this aggregation function

    + +
    +
    +

    Value

    + + +

    The aggregated score, i.e. the sum of all indicidual scores.

    +
    + +
    +

    Examples

    +
    sum_scores(c(3, 2, 1))
    +#> [1] 6
    +
    +
    +
    + +
    + + +
    + +
    +

    Site built with pkgdown 2.0.7.

    +
    + +
    + + + + + + + + diff --git a/reference/tidyeval.html b/reference/tidyeval.html new file mode 100644 index 00000000..5361eee6 --- /dev/null +++ b/reference/tidyeval.html @@ -0,0 +1,178 @@ + +Tidy eval helpers — tidyeval • designit + + +
    +
    + + + +
    +
    + + +
    + +
    • sym() creates a symbol from a string and +syms() creates a list of symbols from a +character vector.

    • +
    • enquo() and +enquos() delay the execution of one or +several function arguments. enquo() returns a single quoted +expression, which is like a blueprint for the delayed computation. +enquos() returns a list of such quoted expressions.

    • +
    • expr() quotes a new expression locally. It +is mostly useful to build new expressions around arguments +captured with enquo() or enquos(): +expr(mean(!!enquo(arg), na.rm = TRUE)).

    • +
    • as_name() transforms a quoted variable name +into a string. Supplying something else than a quoted variable +name is an error.

      +

      That's unlike as_label() which also returns +a single string but supports any kind of R object as input, +including quoted function calls and vectors. Its purpose is to +summarise that object into a single label. That label is often +suitable as a default name.

      +

      If you don't know what a quoted expression contains (for instance +expressions captured with enquo() could be a variable +name, a call to a function, or an unquoted constant), then use +as_label(). If you know you have quoted a simple variable +name, or would like to enforce this, use as_name().

    • +

    To learn more about tidy eval and how to use these tools, visit +https://tidyeval.tidyverse.org and the +Metaprogramming +section of Advanced R.

    +
    + + + +
    + +
    + + +
    + +
    +

    Site built with pkgdown 2.0.7.

    +
    + +
    + + + + + + + + diff --git a/reference/update_batchcontainer.html b/reference/update_batchcontainer.html new file mode 100644 index 00000000..7f18a525 --- /dev/null +++ b/reference/update_batchcontainer.html @@ -0,0 +1,136 @@ + +Updates a batch container by permuting samples according to a shuffling — update_batchcontainer • designit + + +
    +
    + + + +
    +
    + + +
    +

    As post-condition, the batch container is in a different state

    +
    + +
    +
    update_batchcontainer(bc, shuffle_params)
    +
    + +
    +

    Arguments

    +
    bc
    +

    The batch container to operate on.

    + + +
    shuffle_params
    +

    Shuffling parameters as returned by extract_shuffle_params().

    + +
    +
    +

    Value

    + + +

    TRUE if sample attributes have been assigned, FALSE otherwise

    +
    + +
    + +
    + + +
    + +
    +

    Site built with pkgdown 2.0.7.

    +
    + +
    + + + + + + + + diff --git a/reference/validate_samples.html b/reference/validate_samples.html new file mode 100644 index 00000000..b8c44618 --- /dev/null +++ b/reference/validate_samples.html @@ -0,0 +1,126 @@ + +Validates sample data.frame. — validate_samples • designit + + +
    +
    + + + +
    +
    + + +
    +

    Validates sample data.frame.

    +
    + +
    +
    validate_samples(samples)
    +
    + +
    +

    Arguments

    +
    samples
    +

    A data.frame having a sample annotation per row.

    + +
    + +
    + +
    + + +
    + +
    +

    Site built with pkgdown 2.0.7.

    +
    + +
    + + + + + + + + diff --git a/reference/validate_subgrouping_object.html b/reference/validate_subgrouping_object.html new file mode 100644 index 00000000..0268791a --- /dev/null +++ b/reference/validate_subgrouping_object.html @@ -0,0 +1,126 @@ + +Validate subgroup object and stop with error message if not all required fields are there — validate_subgrouping_object • designit + + +
    +
    + + + +
    +
    + + +
    +

    Validate subgroup object and stop with error message if not all required fields are there

    +
    + +
    +
    validate_subgrouping_object(subgroup_object)
    +
    + +
    +

    Arguments

    +
    subgroup_object
    +

    Subgrouping object as returned by form_homogeneous_subgroups()

    + +
    + +
    + +
    + + +
    + +
    +

    Site built with pkgdown 2.0.7.

    +
    + +
    + + + + + + + + diff --git a/reference/worst_score.html b/reference/worst_score.html new file mode 100644 index 00000000..f962bf58 --- /dev/null +++ b/reference/worst_score.html @@ -0,0 +1,148 @@ + +Aggregation of scores: take the maximum (i.e. worst score only) — worst_score • designit + + +
    +
    + + + +
    +
    + + +
    +

    This function enables comparison of the results of two scoring functions by just basing +the decision on the largest element. This corresponds to the infinity-norm in ML terms.

    +
    + +
    +
    worst_score(scores, na.rm = FALSE, ...)
    +
    + +
    +

    Arguments

    +
    scores
    +

    A score or multiple component score vector

    + + +
    na.rm
    +

    Boolean. Should NA values be ignored when obtaining the maximum? FALSE by default as ignoring NA values may hide some issues with the provided scoring functions and also the aggregated value cannot be seen as the proper infinity norm anymore.

    + + +
    ...
    +

    Parameters to be ignored by this aggregation function

    + +
    +
    +

    Value

    + + +

    The aggregated score, i.e. the value of the largest element in a multiple-component score vector.

    +
    + +
    +

    Examples

    +
    worst_score(c(3, 2, 1))
    +#> [1] 3
    +
    +
    +
    + +
    + + +
    + +
    +

    Site built with pkgdown 2.0.7.

    +
    + +
    + + + + + + + + diff --git a/sitemap.xml b/sitemap.xml new file mode 100644 index 00000000..717ccaca --- /dev/null +++ b/sitemap.xml @@ -0,0 +1,258 @@ + + + + https://bedapub.github.io/designit/404.html + + + https://bedapub.github.io/designit/CODE_OF_CONDUCT.html + + + https://bedapub.github.io/designit/ISSUE_TEMPLATE.html + + + https://bedapub.github.io/designit/LICENSE-text.html + + + https://bedapub.github.io/designit/LICENSE.html + + + https://bedapub.github.io/designit/articles/NCS22_talk.html + + + https://bedapub.github.io/designit/articles/basic_examples.html + + + https://bedapub.github.io/designit/articles/custom_shuffle.html + + + https://bedapub.github.io/designit/articles/index.html + + + https://bedapub.github.io/designit/articles/invivo_study_design.html + + + https://bedapub.github.io/designit/articles/nested_dimensions_examples.html + + + https://bedapub.github.io/designit/articles/optimizer_examples.html + + + https://bedapub.github.io/designit/articles/osat.html + + + https://bedapub.github.io/designit/articles/plate_layouts.html + + + https://bedapub.github.io/designit/articles/plate_scoring_examples.html + + + https://bedapub.github.io/designit/articles/shuffling_with_constraints.html + + + https://bedapub.github.io/designit/authors.html + + + https://bedapub.github.io/designit/index.html + + + https://bedapub.github.io/designit/news/index.html + + + https://bedapub.github.io/designit/reference/BatchContainer.html + + + https://bedapub.github.io/designit/reference/BatchContainerDimension.html + + + https://bedapub.github.io/designit/reference/L1_norm.html + + + https://bedapub.github.io/designit/reference/L2s_norm.html + + + https://bedapub.github.io/designit/reference/accept_leftmost_improvement.html + + + https://bedapub.github.io/designit/reference/accept_strict_improvement.html + + + https://bedapub.github.io/designit/reference/all_equal_df.html + + + https://bedapub.github.io/designit/reference/assign_from_table.html + + + https://bedapub.github.io/designit/reference/assign_in_order.html + + + https://bedapub.github.io/designit/reference/assign_random.html + + + https://bedapub.github.io/designit/reference/batch_container_from_table.html + + + https://bedapub.github.io/designit/reference/compile_possible_subgroup_allocation.html + + + https://bedapub.github.io/designit/reference/complete_random_shuffling.html + + + https://bedapub.github.io/designit/reference/countGini.html + + + https://bedapub.github.io/designit/reference/designit-package.html + + + https://bedapub.github.io/designit/reference/dot-datatable.aware.html + + + https://bedapub.github.io/designit/reference/drop_order.html + + + https://bedapub.github.io/designit/reference/extract_shuffle_params.html + + + https://bedapub.github.io/designit/reference/find_possible_block_allocations.html + + + https://bedapub.github.io/designit/reference/first_score_only.html + + + https://bedapub.github.io/designit/reference/form_homogeneous_subgroups.html + + + https://bedapub.github.io/designit/reference/generate_terms.html + + + https://bedapub.github.io/designit/reference/getScore.html + + + https://bedapub.github.io/designit/reference/get_order.html + + + https://bedapub.github.io/designit/reference/index.html + + + https://bedapub.github.io/designit/reference/invivo_study_samples.html + + + https://bedapub.github.io/designit/reference/invivo_study_treatments.html + + + https://bedapub.github.io/designit/reference/kruskal.html + + + https://bedapub.github.io/designit/reference/locations_table_from_dimensions.html + + + https://bedapub.github.io/designit/reference/longitudinal_subject_samples.html + + + https://bedapub.github.io/designit/reference/make_colnames.html + + + https://bedapub.github.io/designit/reference/meanDiff.html + + + https://bedapub.github.io/designit/reference/mk_autoscale_function.html + + + https://bedapub.github.io/designit/reference/mk_constant_swapping_function.html + + + https://bedapub.github.io/designit/reference/mk_dist_matrix.html + + + https://bedapub.github.io/designit/reference/mk_exponentially_weighted_acceptance_func.html + + + https://bedapub.github.io/designit/reference/mk_plate_scoring_functions.html + + + https://bedapub.github.io/designit/reference/mk_simanneal_acceptance_func.html + + + https://bedapub.github.io/designit/reference/mk_simanneal_temp_func.html + + + https://bedapub.github.io/designit/reference/mk_subgroup_shuffling_function.html + + + https://bedapub.github.io/designit/reference/mk_swapping_function.html + + + https://bedapub.github.io/designit/reference/multi_trt_day_samples.html + + + https://bedapub.github.io/designit/reference/neighbors.html + + + https://bedapub.github.io/designit/reference/optimize_design.html + + + https://bedapub.github.io/designit/reference/optimize_multi_plate_design.html + + + https://bedapub.github.io/designit/reference/osat_score.html + + + https://bedapub.github.io/designit/reference/osat_score_generator.html + + + https://bedapub.github.io/designit/reference/pairwise_swapping.html + + + https://bedapub.github.io/designit/reference/pipe.html + + + https://bedapub.github.io/designit/reference/plate_effect_example.html + + + https://bedapub.github.io/designit/reference/plot_plate.html + + + https://bedapub.github.io/designit/reference/random_score_variances.html + + + https://bedapub.github.io/designit/reference/randomize.html + + + https://bedapub.github.io/designit/reference/report_scores.html + + + https://bedapub.github.io/designit/reference/sample_random_scores.html + + + https://bedapub.github.io/designit/reference/shrink_mat.html + + + https://bedapub.github.io/designit/reference/shuffle_grouped_data.html + + + https://bedapub.github.io/designit/reference/shuffle_with_constraints.html + + + https://bedapub.github.io/designit/reference/shuffle_with_subgroup_formation.html + + + https://bedapub.github.io/designit/reference/simanneal_acceptance_prob.html + + + https://bedapub.github.io/designit/reference/sum_scores.html + + + https://bedapub.github.io/designit/reference/tidyeval.html + + + https://bedapub.github.io/designit/reference/update_batchcontainer.html + + + https://bedapub.github.io/designit/reference/validate_samples.html + + + https://bedapub.github.io/designit/reference/validate_subgrouping_object.html + + + https://bedapub.github.io/designit/reference/worst_score.html + +