7

I have a series of ggplot graphs that I'm repeating with a few small variations. I would like to wrap these qplots with their options into a function to avoid a lot of repetition in the code.

My problem is that for some of the graphs I am using the + facet_wrap() option, but for others I am not. I.e. I need the facet wrap to be an optional argument. When it is included the code needs to call the +facet_wrap() with the variable supplied in the facets argument.

So ideally my function would look like this, with facets being an optional argument:

$ qhist(variable, df, heading, facets)

I have tried googling how to add optional arguments and they suggest either passing a default value or using an if loop with the missing() function. I haven't been able to get either to work.

Here is the function that I have written, with the desired functionality of the optional facets argument included too.

$ qhist <- function(variable, df, heading, facets) {
      qplot(variable, data = df, geom = "histogram", binwidth = 2000, 
            xlab = "Salary", ylab = "Noms") + 
      theme_bw() +
      scale_x_continuous(limits=c(40000,250000), 
                 breaks=c(50000,100000,150000,200000,250000), 
                 labels=c("50k","100k","150k","200k","250k")) +
      opts(title = heading, plot.title = theme_text(face = "bold", 
           size = 14), strip.text.x = theme_text(size = 10, face = 'bold')) 
      # If facets argument supplied add the following, else do not add this code
      + facet_wrap(~ facets)
2
  • Would facets be a logical? Or something else? (character vector of variables to facet on?) Commented Nov 7, 2011 at 22:14
  • No it would be a variable to facet on. So for example I have salary data histograms, and sometimes I want to facet that by industry. Commented Nov 7, 2011 at 22:20

3 Answers 3

11

the way to set up a default is like this:

testFunction <- function( requiredParam, optionalParam=TRUE, alsoOptional=123 ) {
  print(requiredParam)
  if (optionalParam==TRUE) print("you kept the default for optionalParam")
  paste("for alsoOptional you entered", alsoOptional)
}

*EDIT*

Oh, ok... so I think I have a better idea of what you are asking. It looks like you're not sure how to bring the optional facet into the ggplot object. How about this:

  qhist <- function(variable, df, heading, facets=NULL) {
  d <- qplot(variable, data = df, geom = "histogram", binwidth = 2000, 
        xlab = "Salary", ylab = "Noms") + 
  theme_bw() +
  scale_x_continuous(limits=c(40000,250000), 
             breaks=c(50000,100000,150000,200000,250000), 
             labels=c("50k","100k","150k","200k","250k")) +
  opts(title = heading, plot.title = theme_text(face = "bold", 
       size = 14), strip.text.x = theme_text(size = 10, face = 'bold')) 
  # If facets argument supplied add the following, else do not add this code
  if (is.null(facets)==FALSE) d <- d + facet_wrap(as.formula(paste("~", facets)))
  d
  return(d)
  }

I have not tested this code at all. But the general idea is that the facet_wrap expects a formula, so if the facets are passed as a character string you can build a formula with as.formula() and then add it to the plot object.

If I were doing it, I would have the function accept an optional facet formula and then pass that facet formula directly into the facet_wrap. That would negate the need for the as.formula() call to convert the text into a formula.

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

6 Comments

cheers, I think I get that, I guess I still don't understand how to use that structure to then include the option in the code that is called by the function. I'll update my question to reflect that.
In your function body, try something like res <- qplot(...) + ...; if (facets) res <- res + facet_wrap(~ facets); return(res)
Given the rather non-standard evaluation of variable in qplot, you would be better with ggplot syntax and using aes_string: d <- ggplot(data = df, aes_string(x=variable)) + geom_histogram(binwidth = 2000) + ...
@JD Long Great I'll have a play around with this and see if I can get it to work.
@JD Long this works. The only problem appears to have to do with the strings that are being sent to the as.formula() function. It appears that where there are commas or spaces in the text being passed it fails. I'm getting this error when I include a facet: Error in parse(text = x) : <text>:1:10: unexpected symbol 1: ~ Retail Trade ^
|
3

Probably, the best way is to stop using such unusual variable names including commas or spaces.

As a workaround, here is an extension of @JDLong's answer. The trick is to rename the facet variable.

f <- function(dat, facet = NULL) {
    if(!missing(facet)) {
        names(dat)[which(names(dat) == facet)] <- ".facet."
        ff <- facet_wrap(~.facet.)
    } else {
        ff <- list()
    }
    qplot(x, y, data = dat) + ff
}

d <- data.frame(x = 1:10, y = 1:10, "o,o" = gl(2,5), check.names=F)

f(d, "o,o")
f(d)

3 Comments

Sorry the 'Retail Trade' is actually one of the strings in the variable. The variable itself is named 'industry'.
Then, it does not induce any error. Maybe there are some mistakes in you way to use. Could you please attach a reproducible example?
you're right. My problem was that I wasn't enclosing the argument as a string.
2

Note that you can also use missing(facets) to check if the facets argument was specified or not. If you use @JD Long's solution, it would look something like this:

qhist <- function(variable, df, heading, facets) {
  ... insert @JD Longs' solution ...

  if (!missing(facets)) d <- d + facet_wrap(as.formula(paste("~", facets)))
  return(d)
}

...Note that I also changed the default argument from facets=NULL to just facets.

Many R functions use missing arguments like this, but in general I tend to prefer @JD Long's variant of using a default argument value (like NULL or NA) when possible. But sometimes there is no good default value...

1 Comment

Thanks for providing another option. I had seen this around, but I couldn't work out how to include it in my particular function.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.