[R] Problem with creating a PCA graph in a loop

Ivan Krylov |kry|ov @end|ng |rom d|@root@org
Wed May 8 09:16:38 CEST 2024


В Tue, 7 May 2024 16:57:14 +0200
gavin duley <gduley using gmail.com> пишет:

> aes(label=current_rownames,
>     colour=wine.data.filt$Treatment
> )

As you've noticed, aes() remembers variables by their name and
environment, not by value:

str(ggplot2::aes(label = foo))
# List of 1
#  $ label: language ~foo # <-- variable name recorded here
                               # and here is the environment
#   ..- attr(*, ".Environment")=<environment: R_GlobalEnv> 
#  - attr(*, "class")= chr "uneval"

One way to get around the problem is to ensure that the variables live
in different environments. Instead of making it a for loop, write a
function that would accept `i` and return a plot instead of assigning
it by name:

makeplot <- function(i) {
  print(i)
  wine.data.filt <- filter(wine.data,Time == i)
  current_rownames <- rownames(wine.data.filt)
  wine.data.filt.pca <- dudi.pca(wine.data.filt[3:11],
                                 nf=6,
                                 scannf=F)
  wine.data_quanti_sup <- wine.data.filt[,12, drop = FALSE]
  return(fviz_pca_ind(wine.data.filt.pca,
   # <the rest of the plot expression is omitted>
  )
}

individs <- lapply(levels(wine.data$Time), makeplot)
individs[[1]]

(In many languages, trying to use a variable as a variable name, while
possible, usually means you need to consider some kind of nested data
structure:
https://perldoc.perl.org/perlfaq7#How-can-I-use-a-variable-as-a-variable-name?
In R, this structure is a list.)

Why does this work? Calling a function creates a new environment every
time. The plots will all refer to the variable named current_rownames,
but the environments will be different:

attr((function() ggplot2::aes(label = foo))()$label, '.Environment')
# <environment: 0x5650ffc2bfd8>
attr((function() ggplot2::aes(label = foo))()$label, '.Environment')
# <environment: 0x5650ffc5c128>
attr((function() ggplot2::aes(label = foo))()$label, '.Environment')
# <environment: 0x5650ffc8a3d8>

Alternatively, supply a data= argument to geom_label_repel() and make
your mapping = aes(...) reference variables from the data (which will
be remembered), ignoring the environment (which is only referenced).
Something like the following should work, untested:

geom_label_repel(
 mapping = aes(label = current_rownames, colour = Treatment),
 data = data.frame(
  current_rownames = current_rownames,
  Treatment = wine.data.filt$Treatment
 ),
 # more arguments here
)

-- 
Best regards,
Ivan



More information about the R-help mailing list