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!

5
  • What is an example value of fac2? (Is it just a vector, or a more complicated formula?) Commented Feb 7, 2013 at 2: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. Commented Feb 7, 2013 at 2: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 Commented Feb 7, 2013 at 2:13
  • @mnel, not completely sure what you mean - move the faceting to where? Commented Feb 7, 2013 at 2:15
  • See my answer. Hope it makes more sense now. Commented Feb 7, 2013 at 2:35

2 Answers 2

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

Sign up to request clarification or add additional context in comments.

2 Comments

Dang, the combination I never got around to! Thank you.
and you don't even need to convert to formula, the p <- p + facet_grid(paste(". ~", fac2)) will work just fine!
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

2 Comments

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.
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)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.