6

I have roughly this function:

plot_pca_models <- function(models, id) {
  library(lattice)

  splom(models, groups=id)
}

and I'm calling it like this:

plot_pca_models(data.pca, log$id)

wich results in this error:

Error in eval(expr, envir, enclos) : object 'id' not found

when I call it without the wrapping function:

splom(data.pca, groups=log$id)

it raises this error:

Error in log$id : object of type 'special' is not subsettable

but when I do this:

 id <- log$id
 splom(models, groups=id)

it behaves as expected.

Please can anybody explain why it behaves like this and how to correct it? Thanks.

btw: I'm aware of similar questions here, eg:

but none of them helped me.

edit: As requested, there is full "plot_pca_models" function:

plot_pca_models <- function(data, id, sel=c(1:4), comp=1) {
  # 'data' ... princomp objects
  # 'id'   ... list of samples id (classes)
  # 'sel'  ... list of models to compare
  # 'comp' ... which pca component to compare

  library(lattice)

  models <- c()
  models.size <- 1:length(data)
  for(model in models.size) {
    models <- c(models, list(data[[model]]$scores[,comp]))
  }
  names(models) <- 1:length(data)

  models <- do.call(cbind, models[sel])

  splom(models, groups=id)
}

edit2: I've managed to make the problem reproducible.

require(lattice)
my.data <- data.frame(pca1 = rnorm(100), pca2 = rnorm(100), pca3 = rnorm(100))
my.id <- data.frame(id = sample(letters[1:4], 100, replace = TRUE))

plot_pca_models2 <- function(x, ajdi) {
  splom(x, group = ajdi)
}

plot_pca_models2(x = my.data, ajdi = my.id$id)

which produce the same error like above.

Community
  • 1
  • 1
WestFlame
  • 435
  • 1
  • 7
  • 16
  • 1
    `log` is a function in base R. Good practice is to not name objects after functions...it can create confusion. – Thomas Aug 01 '13 at 11:17
  • Do not call your objects `log`. `log` is a function from the `base` package. Change the name and tell us if the problem still occurs. – shadow Aug 01 '13 at 11:17
  • This is because lattice uses non-standard evaluation. You don't actually say what you want, but try `print(splom(models, groups=id))` – hadley Aug 01 '13 at 12:50
  • 3
    How about making your problem reproducible? It will shorten the war by 5 years and save thousands of lives. – Roman Luštrik Aug 01 '13 at 12:54
  • @Roman Luštrik: OK :D, it is described at the end of my Question. – WestFlame Aug 01 '13 at 13:16

3 Answers3

2

log is a function in base R. Good practice is to not name objects after functions...it can create confusion. Type log$test into a clean R session and you'll see what's happening:

object of type 'special' is not subsettable

Thomas
  • 43,637
  • 12
  • 109
  • 140
  • OK, thanks for advice, I renamed log and now it behaves slightly differently. The first error is the same, the second disappears (but the result looks like the param groups is not used at all... the colors in result graph are the same) – WestFlame Aug 01 '13 at 11:23
  • `log <- data.frame(a=1:5); log$a` – Roland Aug 01 '13 at 11:25
  • @WestFlame Do you reference `id` anywhere else inside `plot_pca_models`? – Thomas Aug 01 '13 at 11:38
  • no, this is the only use of this parameter within the function – WestFlame Aug 01 '13 at 11:50
  • @WestFlame What do you get from `traceback()` after the errors occur? – Thomas Aug 01 '13 at 11:55
  • this: `10: eval(expr, envir, enclos) 9: eval(substitute(groups), data, environment(formula)) 8: splom.formula(x = ~x, groups = id, data = ) 7: lattice::splom(x = ~x, groups = id, data = ) 6: eval(expr, envir, enclos) 5: eval(expr, p) 4: eval.parent(ccall) 3: splom.matrix(models, groups = id) 2: splom(models, groups = id) at models_analyze.R#66 1: plot_pca_models(data.pca, data$id)` – WestFlame Aug 01 '13 at 11:58
  • @WestFlame I think you might need to show us more of your function. – Thomas Aug 01 '13 at 12:23
  • OK, no problem... it is now at the end of my Question. – WestFlame Aug 01 '13 at 12:44
2

The problem is that splom evaluates its groups argument in a nonstandard way.A quick fix is to rewrite your function so that it constructs the call with the appropriate syntax:

f <- function(data, id)
eval(substitute(splom(data, groups=.id), list(.id=id)))

# test it
ir <- iris[-5]
sp <- iris[, 5]
f(ir, sp)
Hong Ooi
  • 56,353
  • 13
  • 134
  • 187
  • 1
    Great, thanks! Although it looks a bit ugly :) and I still don't understand why it needs to be done this way. But hey, at least it works :)... – WestFlame Aug 01 '13 at 13:56
2

Here's a modification of Hong Oi's answer. First I would recommend to include id in the main data frame, i.e

my.data <- data.frame(pca1 = rnorm(100), pca2 = rnorm(100), pca3 = rnorm(100), id = sample(letters[1:4], 100, replace = TRUE))

.. and then

plot_pca_models2 <- function(x, ajdi) {
    Call <- bquote(splom(x, group = x[[.(ajdi)]]))    
    eval(Call)
    }
plot_pca_models2(x = my.data, ajdi = "id")

The cause of the confusion is the following line in lattice:::splom.formula:

groups <- eval(substitute(groups), data, environment(formula))

... whose only point is to be able to specify groups without quotation marks, that is,

# instead of
splom(DATA, groups="ID")
# you can now be much shorter, thanks to eval and substitute:
splom(DATA, groups=ID)

But of course, this makes using splom (and other functions e.g. substitute which use "nonstandard evaluation") harder to use from within other functions, and is against the philosophy that is "mostly" followed in the rest of R.

lebatsnok
  • 6,329
  • 2
  • 21
  • 22