50

I have a large number of data series that I want to plot using small multiples. A combination of ggplot2 and facet_wrap does what I want, typically resulting a nice little block of 6 x 6 facets. Here's a simpler version:

facet_wrap

The problem is that I don't have adequate control over the labels in facet strips. The names of the columns in the data frame are short and I want to keep them that way, but I want the labels in the facets to be more descriptive. I can use facet_grid so that I can take advantage of the labeller function but then there seems to be no straightforward way to specify the number of columns and a long row of facets just doesn't work for this particular task. Am I missing something obvious?

facet_grid

Q. How can I change the facet labels when using facet_wrap without changing the column names? Alternatively, how can I specify the number of columns and rows when using facet_grid?

Code for a simplified example follows. In real life I am dealing with multiple groups each containing dozens of data series, each of which changes frequently, so any solution would have to be automated rather than relying on manually assigning values.

require(ggplot2)
require(reshape)

# Random data with short column names
set.seed(123)
myrows <- 30
mydf <- data.frame(date = seq(as.Date('2012-01-01'), by = "day", length.out = myrows),
                   aa = runif(myrows, min=1, max=2),
                   bb = runif(myrows, min=1, max=2),
                   cc = runif(myrows, min=1, max=2),
                   dd = runif(myrows, min=1, max=2),
                   ee = runif(myrows, min=1, max=2),
                   ff = runif(myrows, min=1, max=2))

# Plot using facet wrap - we want to specify the columns
# and the rows and this works just fine, we have a little block
# of 2 columns and 3 rows

mydf <- melt(mydf, id = c('date'))

p1 <- ggplot(mydf, aes(y = value, x = date, group = variable)) +
    geom_line() +
    facet_wrap( ~ variable, ncol = 2)
print (p1)

# Problem: we want more descriptive labels without changing column names.
# We can change the labels, but doing so requires us to
# switch from facet_wrap to facet_grid
# However, in facet_grid we can't specify the columns and rows...

mf_labeller <- function(var, value){ # lifted bodily from the R Cookbook
    value <- as.character(value)
    if (var=="variable") {
        value[value=="aa"]   <- "A long label"
        value[value=="bb"]   <- "B Partners"
        value[value=="cc"]   <- "CC Inc."
        value[value=="dd"]   <- "DD Company"
        value[value=="ee"]   <- "Eeeeeek!"
        value[value=="ff"]   <- "Final"
    }
    return(value)
}

p2 <- ggplot(mydf, aes(y = value, x = date, group = variable)) +
    geom_line() +
    facet_grid( ~ variable, labeller = mf_labeller)
print (p2)
Paul Hiemstra
  • 59,984
  • 12
  • 142
  • 149
SlowLearner
  • 7,907
  • 11
  • 49
  • 80
  • 4
    this is an [open issue](https://github.com/hadley/ggplot2/issues/25), but in your particular case (simple renaming, no bquote or plotmath) you can just rename the variables beforehand. – baptiste Apr 14 '12 at 07:50
  • 1
    @baptiste I was not aware of that it was an open issue (and has been that way for two years now, so probably unlikely to change any time soon). Suspect hadley needs more grad students to put on the project! – SlowLearner Apr 15 '12 at 00:14
  • 1
    Indeed. Sadly I think with my level of competence I probably wouldn't qualify. – SlowLearner Apr 15 '12 at 06:14

4 Answers4

27

I don't quite understand. You've already written a function that converts your short labels to long, descriptive labels. What is wrong with simply adding a new column and using facet_wrap on that column instead?

mydf <- melt(mydf, id = c('date'))
mydf$variableLab <- mf_labeller('variable',mydf$variable)

p1 <- ggplot(mydf, aes(y = value, x = date, group = variable)) +
    geom_line() +
    facet_wrap( ~ variableLab, ncol = 2)
print (p1)
joran
  • 169,992
  • 32
  • 429
  • 468
  • 12
    Nothing wrong with adding a new column - my brain gave up just before that one last step! I should have known to do that. "If in doubt, add column to data frame" is practically the default help statement for ggplot. Thanks. – SlowLearner Apr 15 '12 at 00:10
  • Please help, I'm using this function and the following error says: `In if (variable == value) { : the condition has length > 1 and only the first element will be used` where `variableLab` has 0 elements after execution. –  Feb 09 '14 at 02:53
  • i think you have to use if(variable[i] == value [i]) in a for loop over the length of your dataframe to overcome your error – alily Sep 05 '16 at 14:56
9

To change the label names, just change the factor levels of the factor you use in facet_wrap. These will be used in facet_wrap on the strips. You can use a similar setup as you would using the labeller function in facet_grid. Just do something like:

new_labels = sapply(levels(df$factor_variable), custom_labeller_function)
df$factor_variable = factor(df$factor_variable, levels = new_labels)

Now you can use factor_variable in facet_wrap.

Paul Hiemstra
  • 59,984
  • 12
  • 142
  • 149
0

Just add labeller = label_wrap_gen(width = 25, multi_line = TRUE) to the facet_wrap() arguments.

Eg.: ... + facet_wrap( ~ variable, ,labeller = label_wrap_gen(width = 25, multi_line = TRUE))

More info: ?ggplot2::label_wrap_gen

user3507584
  • 3,246
  • 5
  • 42
  • 66
0

Simply add labeller = label_both to the facet_wrap() arguments.

... + facet_wrap( ~ variable, labeller = label_both)
Saurabh
  • 1,566
  • 10
  • 23