RGLab / flowCore

Core flow cytometry infrastructure
43 stars 25 forks source link

Unexpected behavior of transformList #267

Open timmocking opened 8 months ago

timmocking commented 8 months ago

I want to create a transformList object by supplying a custom "w" parameter for every channel in a loop. However, when I create a list of transformations, the w-parameter is retro-actively modified for earlier items in the list.

transforms <- list()
for (i in 1:8){
  transforms[[LETTERS[i]]] <- flowCore::logicleTransform(w = i)
}
# Print the width of "A" (should be 1)
print(as.list(environment(transforms[1]$A@.Data))$w) # output: [1] 8

For some reason, this can be prevented by calling summary() on the list if flowCore is loaded. However, the list becomes a closure type if flowCore is not loaded...

library(flowCore)
transforms <- list()
for (i in 1:8){
  transforms[[LETTERS[i]]] <- flowCore::logicleTransform(w = i)
  summary(transforms[[LETTERS[i]]])
}
# Print the width of "A" (should be 1)
print(as.list(environment(transforms[1]$A@.Data))$w) # output: [1] 1

Is this the expected behavior?

R version 4.3.1 (2023-06-16)
Platform: x86_64-pc-linux-gnu (64-bit)
Running under: Ubuntu 20.04.6 LTS

Matrix products: default
BLAS:   /usr/lib/x86_64-linux-gnu/blas/libblas.so.3.9.0 
LAPACK: /usr/lib/x86_64-linux-gnu/lapack/liblapack.so.3.9.0

locale:
 [1] LC_CTYPE=en_US.UTF-8       LC_NUMERIC=C               LC_TIME=en_GB.UTF-8        LC_COLLATE=en_US.UTF-8     LC_MONETARY=en_GB.UTF-8    LC_MESSAGES=en_US.UTF-8   
 [7] LC_PAPER=en_GB.UTF-8       LC_NAME=C                  LC_ADDRESS=C               LC_TELEPHONE=C             LC_MEASUREMENT=en_GB.UTF-8 LC_IDENTIFICATION=C       

time zone: Europe/Amsterdam
tzcode source: system (glibc)

attached base packages:
[1] stats     graphics  grDevices utils     datasets  methods   base     

loaded via a namespace (and not attached):
 [1] compiler_4.3.1      RProtoBufLib_2.12.1 cytolib_2.12.1      tools_4.3.1         rstudioapi_0.15.0   Biobase_2.60.0      S4Vectors_0.38.2    flowCore_2.12.2     BiocGenerics_0.46.0
[10] matrixStats_1.2.0   stats4_4.3.1      
SamGG commented 8 months ago

There is maybe a better solution... @mikejiang ?

library(flowCore)
#> Warning: package 'flowCore' was built under R version 4.3.2
transforms <- list()
for (i in 1:8){
  transforms[[LETTERS[i]]] <- logicleTransform(w = i)
}
# Print the width of "A" (should be 1)
environment(transforms$A@.Data)$w # output: [1] 8
#> [1] 8
environment(transforms$H@.Data)$w # output: [1] 8
#> [1] 8
# each transform/function has its own environment
sapply(transforms, environment)
#> $A
#> <environment: 0x000001f0342bb308>
#> 
#> $B
#> <environment: 0x000001f0341d58f8>
#> 
#> $C
#> <environment: 0x000001f0341cac30>
#> 
#> $D
#> <environment: 0x000001f0340f9820>
#> 
#> $E
#> <environment: 0x000001f033db1740>
#> 
#> $F
#> <environment: 0x000001f033c91230>
#> 
#> $G
#> <environment: 0x000001f033c62d48>
#> 
#> $H
#> <environment: 0x000001f0336e89a0>
# 
# so we can assign a value in each environment and check
for (i in 1:8) {
  assign("w", i, envir = environment(transforms[[i]]))
}
for (i in 1:8) {
  print(get("w", envir = environment(transforms[[i]])))
}
#> [1] 1
#> [1] 2
#> [1] 3
#> [1] 4
#> [1] 5
#> [1] 6
#> [1] 7
#> [1] 8
environment(transforms$A@.Data)$w
#> [1] 1
environment(transforms$H@.Data)$w
#> [1] 8

Created on 2024-02-05 with reprex v2.1.0