8

Interactively, this example works fine:

p <- ggplot(mtcars, aes(mpg, wt)) + geom_point()
p + facet_grid(. ~ vs)

Now, make a function with a formula interface and use aes_string to do this same thing, and it doesn't work (error is: Error in layout_base(data, cols, drop = drop) : At least one layer must contain all variables used for facetting):

tf <- function(formula, data) {
res <- as.character(formula[[2]])
fac2 <- as.character(formula[[3]][3])
fac1 <- as.character(formula[[3]][2])

# p <- ggplot(aes_string(x = fac1, y = res), data = data)
# p <- p + geom_point() # original attempt
p <- ggplot() # This is Joran's trick, but it doesn't work here
p <- p + geom_point(aes_string(x = fac1, y = res), data = data)
p <- p + facet_grid(.~fac2) # comment this out, and it works but
# of course is not faceted
}

p <- tf(formula = wt ~ am*vs, data = mtcars)

By Joran's trick I refer to here, which is a similar question I posted recently. In this case ggplot2doesn't see my faceting request. Making it facet_grid(".~fac2") had no effect. Suggestions? I'm continually out-witted by these things. Thanks!

Community
  • 1
  • 1
Bryan Hanson
  • 6,055
  • 4
  • 41
  • 78
  • What is an example value of `fac2`? (Is it just a vector, or a more complicated formula?) – David Robinson Feb 07 '13 at 02:05
  • `fac2` would be like `fac1`, a character string giving the name of a data frame column which is a factor or coerces to one. It is reproducible, look at the last line using `mtcars`. – Bryan Hanson Feb 07 '13 at 02:09
  • I think it will be far easier to have the facetting formula as a second argument, otherwise you will have to build a new parser for however you are wishing to differentiate between faceting and coordinate variables – mnel Feb 07 '13 at 02:13
  • @mnel, not completely sure what you mean - move the faceting to where? – Bryan Hanson Feb 07 '13 at 02:15
  • See my answer. Hope it makes more sense now. – mnel Feb 07 '13 at 02:35

2 Answers2

6

You can use as.formula and paste:

p <- p + facet_grid(as.formula(paste(". ~", fac2)))

In your example, this gives:

enter image description here

David Robinson
  • 77,383
  • 16
  • 167
  • 187
6

I have used formula.tools for manipulating formulae.

I think you should have a separate argument for the faceting formula, otherwise you will have to create your own parser to work out what wt ~ am*vs means in terms of faceting

something like the lattice grouping idea might be useful

wt~am | vs

but you would have to delve into lattice to see how they parse their formulas (look atlatticeParseFormula - complicated!)

Easier just to separate the two formulae. You can pass a list of character variables as rhs and lhs for the facet argument to facet_grid

I've also used environment = parent.frame() which works in my small testing

library(formula.tools)

tf <- function(formula, faceting = NULL, data, print = TRUE) {
   y <- rhs(formula)
   x <- lhs(formula)

  p <- ggplot(environment = parent.frame()) 

  p <- p + geom_point(aes_string(x = x, y = y), data = data) 
   if (! is.null(faceting)){
     rhsfacet <- all.vars(rhs(faceting))
     lhsfacet <- all.vars(lhs(faceting))
     if(length(lhsfacet)==1 & any(lhsfacet %in% '.')) {lhsfacet <- NULL}
     if(length(rhsfacet)==1 & any(rhsfacet %in% '.')) {rhsfacet <- NULL}
     p <- p+ facet_grid(facet = list( lhsfacet, rhsfacet))}
  if(print) {print(p)}
  p 

}
tf(wt~mpg, faceting = ~am, data = mtcars, print = TRUE)

enter image description here

mnel
  • 113,303
  • 27
  • 265
  • 254
  • I see what you mean now. You are using a couple of interesting tools I need to look into. I'm also interested the idea of passing a list to `facet` which I hadn't seen before. Just checked, it's not documented in the current 0.9.3 pages. – Bryan Hanson Feb 07 '13 at 02:43
  • Yes. I got there from looking at the source. I presumed there would be a way given how `.` and `as.quoted` works in `plyr`. I've also edited to be more robust to complex faceting formula (and no faceting) – mnel Feb 07 '13 at 02:52