1
votes

I am trying to create a simple app for plate randomization. It takes some parameters as input from users (like number of subjects, visits, replicates).

In server.R I need to have a loop that creates plates with random subject ID numbers. Later I would need to use elements of the list for other calculations and plots. I can't get this function to work in Shiny. It works well otherwise. Code doesn't work starting with plates.w.subjects <- list()

Here is the server.R code:

n.subjects    <- reactive({ as.numeric(input$n.subjects) })
n.visits      <- reactive({ as.numeric(input$n.visits) })     
n.replicates  <- reactive({ as.numeric(input$n.replicates) }) 
n.buffers     <- reactive({ as.numeric(input$n.buffers) })    
n.ipc         <- reactive({ as.numeric(input$n.ipc) })
n.plates      <- reactive({    ceiling((n.subjects()*n.visits()*n.replicates())/(n.wells-sum(n.buffers(),n.ipc()))) })

subject.ids   <- reactive({ seq(1, n.subjects()) })
## other calculations here 

plates.w.subjects <- list()
plates.data <- reactive({

for(i in 1:n.plates()) {
local({
  if (i == 1) {
    used.samples <- NA
    left.samples <- subject.ids()
  } else {
    used.samples <- melt(plates.w.subjects)[,1]
    left.samples <- setdiff(subject.ids(), used.samples)
  }

  if(length(left.samples) > max.subjects.plate()) {
    c <- sample(left.samples, max.subjects.plate(), replace=FALSE, prob=NULL)
  } else {
    c <- sample(left.samples, length(left.samples), replace=FALSE, prob=NULL)
  }

  name <- paste0('Plate.', i)
  tmp <- list(subj.ids = c)
  plates.w.subjects[[name]] <- tmp

  #rm(tmp,name,c,used.samples,left.samples)
})
 }
})

output$result <- renderPrint({
  plates.data()$plates.w.subjects[[1]]
 })

Ideally the result should be:

$Plate.1
$Plate.1$subj.ids
[1] 23 16 13 20 24 10 19 25 3 21 4 12 9
$Plate.2
$Plate.2$subj.ids
[1] 14 22 8 18 2 17 6 11 1 15 5 7

I saw some solutions that use 'local' or 'lapply' but I cant get either one to work.. Would really appreciate any help! Thanks! Maria

2

2 Answers

0
votes

Not sure if this will solve the issue in full, but I broke it apart to try and find your bug.

plates.w.subjects <- list()
name <- paste0('Plate.', 1) # i = 1
tmp <- list(subj.ids = c(100, 200))
(plates.w.subjects[[name]] <- tmp)


name <- paste0('Plate.', 2) # i = 2
tmp <- list(subj.ids = c(2000, 3000))
(plates.w.subjects[[name]] <- tmp)

Instead of using plates.data()$plates.w.subjects[[1]], you may want to try plates.w.subjects instead.

plates.w.subjects
  # $Plate.1
  # $Plate.1$subj.ids
  # [1] 100 200

  # $Plate.2
  # $Plate.2$subj.ids
  # [1] 2000 3000

plates.w.subjects[[1]]
  # $subj.ids
  # [1] 100 200

!Note: Also, best to avoid c = ... as it may conflict with c(100,200) combines.

0
votes

I had to break the code into more pieces to get it do what i need. I ended up separating if i == 1 into a separate chunk. Here is what works. Not sure how efficient it is in term of programming though..

plates.w.subjects.1 <- reactive({
sample(subject.ids(), max.subjects.plate(), replace=FALSE, prob=NULL) 
})


plates.w.subjects <- reactive({

plates.data <- list()
plates.data$Plate.1 <- list(subj.ids = plates.w.subjects.1())

   for(i in 2:n.plates()) {

     used.samples <- melt(plates.data)[,1]
     left.samples <- setdiff(subject.ids(), used.samples)

     if(length(left.samples) > max.subjects.plate()) {
       z <- sample(left.samples, max.subjects.plate(), replace=FALSE, prob=NULL)
       } else {
       z <- sample(left.samples, length(left.samples), replace=FALSE, prob=NULL)
      }

     tmp <- list(subj.ids = z)
     plates.data[[paste0('Plate.', i)]] <- tmp
   } 
  plates.data
})


output$result <- renderPrint({
plates.w.subjects()

})