38

I'm looking for a way to use long variable names on the x axis of a plot. Of course I could use a smaller font or rotate them a little but I would like keep them vertical and readable.

As an example:

df <- data.frame(a=LETTERS[1:20], b=rnorm(20), c=rnorm(20), d=rnorm(20))
df_M <- melt(df, id="a")
plot <- ggplot(data=df_M, 
               aes(x=variable, y=a, fill=value)) + 
          geom_tile() + 
          scale_fill_gradient(low="green", high="red")
plot

here the x axis is just letters, but if I want to use the full name, the names use a disproportionate amount of space:

    plot +  
      theme(axis.text.x=element_text(angle=90)) + 
      scale_x_discrete(breaks=unique(df_M$variable), 
                       labels=c("Ambystoma mexicanum", 
                                "Daubentonia madagascariensis",
                                "Psychrolutes marcidus"))

So I would like to put a line break in the labels. Preferably in ggplot2 but other solutions are welcome of course.

Thanks!

Bertil Baron
  • 4,923
  • 1
  • 15
  • 24
debruinf
  • 587
  • 1
  • 5
  • 15

5 Answers5

52

You can add your own formatter ( see scales package for more examples). Here I replace any space in your x labels by a new line.

addline_format <- function(x,...){
    gsub('\\s','\n',x)
}

myplot + 
    scale_x_discrete(breaks=unique(df_M$variable), 
    labels=addline_format(c("Ambystoma mexicanum", 
                        "Daubentonia madagascariensis", "Psychrolutes marcidus")))

enter image description here

agstudy
  • 119,832
  • 17
  • 199
  • 261
  • 4
    Not sure why the `addline_format` function is needed. Can't one just specify line-breaks directly in the labels? e.g., `c("Ambystoma\nmexicanum",...` – Fuhrmanator Aug 30 '16 at 15:11
  • 7
    Don't even need to type in the labels, this works `scale_x_discrete(labels=function(x){sub("\\s", "\n", x)})` – Alex Thomas Feb 14 '19 at 23:05
35

via str_replace_all(), replace 'foo_your_symbol_delim' with a space delim ' '

via str_wrap from stringr library, with width prespecified at 40, split at space delimiter ' ', wrap the pieces, and paste

library(stringr)
...
+ scale_x_discrete(labels = function(x) str_wrap(str_replace_all(x, "foo" , " "),
                                                 width = 40))
Dima Lituiev
  • 12,544
  • 10
  • 41
  • 58
MKJCKTZN
  • 361
  • 3
  • 2
  • 11
    Because I was looking for a similar solution and created this more general AND efficient one. – MKJCKTZN Sep 09 '15 at 23:35
  • 5
    Nothing wrong with trying to improve on answers to old questions! That said, your answer would be improved further if you used a less terse writing style. – John Wickerson Dec 04 '15 at 16:52
24

If you don't want a break at each space, you could alternatively use the \n (new line) within the call to scale_x_continuous:

my.labels <- c("Ambystoma\nmexicanum",
               "Daubentonia madagascariensis", 
               "Psychrolutes marcidus") # first create labels, add \n where appropriate.

myplot + 
    scale_x_discrete(labels= my.labels)

Note that only the first name (Ambystoma mexicanum) will break using the new line command (\n).

derelict
  • 3,657
  • 3
  • 24
  • 29
7

In addition to Joe's answer this also works

myplot + scale_x_discrete(labels = c("Ambystoma\nmexicanum")
mila
  • 79
  • 1
  • 2
  • When answering an old question, your answer would be much more useful to other StackOverflow users if you included some context to explain how your answer helps, particularly for a question that already has an accepted answer. See: [How do I write a good answer](https://stackoverflow.com/help/how-to-answer). – David Buck Nov 28 '19 at 18:24
5

I'd also add to @SoilSciGuy's answer that if you only want to modify one label, you can do it inside scale_x_discrete().

myplot + scale_x_discrete(labels = c("Ambystoma mexicanum" = "Ambystoma\nmexicanum")
Joe
  • 8,073
  • 1
  • 52
  • 58