How to change facet labels?

330,102

Solution 1

Change the underlying factor level names with something like:

# Using the Iris data
> i <- iris
> levels(i$Species)
[1] "setosa"     "versicolor" "virginica" 
> levels(i$Species) <- c("S", "Ve", "Vi")
> ggplot(i, aes(Petal.Length)) + stat_bin() + facet_grid(Species ~ .)

Solution 2

Here is a solution that avoids editing your data:

Say your plot is facetted by the group part of your dataframe, which has levels control, test1, test2, then create a list named by those values:

hospital_names <- list(
  'Hospital#1'="Some Hospital",
  'Hospital#2'="Another Hospital",
  'Hospital#3'="Hospital Number 3",
  'Hospital#4'="The Other Hospital"
)

Then create a 'labeller' function, and push it into your facet_grid call:

hospital_labeller <- function(variable,value){
  return(hospital_names[value])
}

ggplot(survey,aes(x=age)) + stat_bin(aes(n=nrow(h3),y=..count../n), binwidth=10)
 + facet_grid(hospital ~ ., labeller=hospital_labeller)
 ...

This uses the levels of the data frame to index the hospital_names list, returning the list values (the correct names).


Please note that this only works if you only have one faceting variable. If you have two facets, then your labeller function needs to return a different name vector for each facet. You can do this with something like :

plot_labeller <- function(variable,value){
  if (variable=='facet1') {
    return(facet1_names[value])
  } else {
    return(facet2_names[value])
  }
}

Where facet1_names and facet2_names are pre-defined lists of names indexed by the facet index names ('Hostpital#1', etc.).


Edit: The above method fails if you pass a variable/value combination that the labeller doesn't know. You can add a fail-safe for unknown variables like this:

plot_labeller <- function(variable,value){
  if (variable=='facet1') {
    return(facet1_names[value])
  } else if (variable=='facet2') {
    return(facet2_names[value])
  } else {
    return(as.character(value))
  }
}

Answer adapted from how to change strip.text labels in ggplot with facet and margin=TRUE


edit: WARNING: if you're using this method to facet by a character column, you may be getting incorrect labels. See this bug report. fixed in recent versions of ggplot2.

Solution 3

Here's another solution that's in the spirit of the one given by @naught101, but simpler and also does not throw a warning on the latest version of ggplot2.

Basically, you first create a named character vector

hospital_names <- c(
                    `Hospital#1` = "Some Hospital",
                    `Hospital#2` = "Another Hospital",
                    `Hospital#3` = "Hospital Number 3",
                    `Hospital#4` = "The Other Hospital"
                    )

And then you use it as a labeller, just by modifying the last line of the code given by @naught101 to

... + facet_grid(hospital ~ ., labeller = as_labeller(hospital_names))

Hope this helps.

Solution 4

Here's how I did it with facet_grid(yfacet~xfacet) using ggplot2, version 2.2.1:

facet_grid(
    yfacet~xfacet,
    labeller = labeller(
        yfacet = c(`0` = "an y label", `1` = "another y label"),
        xfacet = c(`10` = "an x label", `20` = "another x label")
    )
)

Note that this does not contain a call to as_labeller() -- something that I struggled with for a while.

This approach is inspired by the last example on the help page Coerce to labeller function.

Solution 5

The EASIEST way to change WITHOUT modifying the underlying data is:

  1. Create an object using as_labeller(). If the column names begin with a number or contain spaces or special characters, don't forget to use back tick marks:
# Necessary to put RH% into the facet labels
hum_names <- as_labeller(
     c(`50` = "RH% 50", `60` = "RH% 60",`70` = "RH% 70", 
       `80` = "RH% 80",`90` = "RH% 90", `100` = "RH% 100"))
  1. Add to the ggplot:
    ggplot(dataframe, aes(x = Temperature.C, y = fit)) + 
        geom_line() + 
        facet_wrap(~Humidity.RH., nrow = 2, labeller = hum_names)
Share:
330,102

Related videos on Youtube

wishihadabettername
Author by

wishihadabettername

Updated on January 30, 2022

Comments

  • wishihadabettername
    wishihadabettername over 2 years

    I have used the following ggplot command:

    ggplot(survey, aes(x = age)) + stat_bin(aes(n = nrow(h3), y = ..count.. / n), binwidth = 10)
      + scale_y_continuous(formatter = "percent", breaks = c(0, 0.1, 0.2))
      + facet_grid(hospital ~ .)
      + theme(panel.background = theme_blank())
    

    to produce

    alt text

    I'd like to change the facet labels, however, to something shorter (like Hosp 1, Hosp 2...) because they are too long now and look cramped (increasing the height of the graph is not an option, it would take too much space in the document). I looked at the facet_grid help page but cannot figure out how.

  • Arnaud A
    Arnaud A about 10 years
    Nice, but will not work with facet_wrap, whereas @Vince solution will work with facet_wrap too.
  • Arnaud A
    Arnaud A about 10 years
    @wishihadabettername: To avoid changing underlying data, you can use: ggplot(transform(iris, Species = c("S", "Ve", "Vi")[as.numeric(Species)]), aes(Petal.Length)) + stat_bin() + facet_grid(Species ~ .)
  • naught101
    naught101 about 10 years
    @ArnaudAmzallag: Correct, though if someone feels like donating some time, it could in the future.
  • naught101
    naught101 over 9 years
    Added a fail-safe for unknown facetting variables.
  • Andreas
    Andreas over 8 years
    Notice: This does not work in ggplot2 v.2 - the labeller function has changed. @mbirons answer works stackoverflow.com/a/34811062/162832
  • n1k31t4
    n1k31t4 over 8 years
    Which verison of ggplot2 is as_labeller in? I have found some source code for on the CRAN GitHub repository, but after upgrading to the latest version (on CRAN!) I don't seem to have the function.
  • mbiron
    mbiron over 8 years
    That's weird. I also updated through CRAN. Here is the documentation docs.ggplot2.org/dev/as_labeller.html
  • naught101
    naught101 almost 8 years
    This is cool. What happens when you have two variables in your facet grid though? Like hospital ~ gender or something? Is there a way to use labellers on both axes? I can't see anything obvious in the docs.
  • yanes
    yanes about 7 years
    this works!!! I wasn't able to apply the other solutions because some of the suggested solutions were deprecated on current ggplot2 versions.
  • PatrickT
    PatrickT over 6 years
    Interesting, but this doesn't always work, whereas editing the factors always does.
  • thomas88wp
    thomas88wp over 6 years
    Note if you started with naught's answer, this one only works with a c() not a list().
  • Brian D
    Brian D over 6 years
    related... if you want the panel label to be a bquote() expression (e.g., levels(x$measurements) <- c(bquote(Area ~~ (cm^2)), bquote(Length ~~ (cm)))) it will not appear in mathematical expression. How would one show expressions as facet labels?
  • Brian D
    Brian D over 6 years
    related for including expressions in the facet label, use labeller option to facet_grid: stackoverflow.com/questions/37089052/…
  • Jens
    Jens almost 6 years
    sorry, it does not work as it also changes the column content
  • jsta
    jsta almost 6 years
    You can construct these named vectors with setNames() stackoverflow.com/a/22428439/3362993
  • Calum You
    Calum You over 5 years
    One great part of this is that this works with both axes of the facet grid!
  • filups21
    filups21 over 5 years
    It may be a bit nicer to use: new_names <- c('setosa' = 'Bristle-pointed iris', 'versicolor' = 'Poison flag iris', 'virginica' = 'Virginia iris') and then in the mutate you could create a new column thusly: mutate(Spec = new_names[Species])
  • Tung
    Tung about 5 years
  • Landak
    Landak about 5 years
    This I think is the most elegant method -- it is effective and works with ggplot2 version 3.0.0.9000
  • 4rj4n
    4rj4n over 4 years
    an answer to @naught101 's question would be the answer by domi : stackoverflow.com/a/37778906/8124725 Without this addition, this doesn't work for me, yielding NA's for the variable that I did not include.
  • wolfsatthedoor
    wolfsatthedoor almost 4 years
    How to do this if you have two facets though?
  • wolfsatthedoor
    wolfsatthedoor almost 4 years
    This gives NAs for all the labels for me :(
  • wolfsatthedoor
    wolfsatthedoor almost 4 years
    Should the higher order variable be repeated in facet1_names?
  • mbiron
    mbiron almost 4 years
    @wolfsatthedoor check out @bovender's answer
  • wolfsatthedoor
    wolfsatthedoor almost 4 years
    @mbiron yeah but its two X facets not X and Y
  • stragu
    stragu almost 4 years
    This is incorrect, as: 1. the different Hosp1, Hosp2... variables do not exist. The original question uses one single column called "hospital" in which the strings are contained 2. even if you had different columns, your command would look for objects called Hospital1, Hospital2, etc. and would throw an error because they don't exist. 3. as @Jens said, if you used strings instead, i.e. "Hospital1", it would fill the whole column with that value. You might be looking for a mutate() combined with a case_when()? Not sure why this was upvoted as it definitely would not work.
  • Denis Cousineau
    Denis Cousineau over 3 years
    but it does not work when there are two facets, e.g., type~Humidity
  • ADF
    ADF over 2 years
    Can we update this since the labeller used here is now deprecated?
  • qdread
    qdread over 2 years
    @DenisCousineau in that case use labeller = labeller(Type = c(...), Humidity = c(...)) where the ... are the key value pairs
  • qdread
    qdread over 2 years
    Also I'd note that if you are just prefixing everything with RH%, a more robust solution would be to replace step 1 in this answer with hum_names <- as_labeller(function(x) paste('RH%', x))