Caroline
Caroline

Reputation: 470

Determine the width of a ggplot2 plot area

I'm trying to use gridExtra to combine two ggplot2 bar plots (with coordinates flipped so that the labels take up horizontal space). The problem is that some of the labels are short and some are long. I want the width of the left and right columns to be the same, irrespective of the width of the labels. Here's an example:

library(ggplot2)
library(gridExtra)

datashort <- data.frame(ecks = c("Short1", "Short2", "Short3"), why = c(30, 20, 40))
datalong <- data.frame(ecks = c(paste0("Really, Really, Really, Really Long", c(1:3))), 
                       why = c(20, 30, 40))

plotshort <- ggplot(data = datashort, aes(x = ecks, y = why, width = .5)) +
  geom_bar(stat = "identity") +
  scale_y_continuous(breaks = c(10, 20, 30, 40, 50), limits = c(0, 50)) +
  coord_flip()

plotlong <- ggplot(data = datalong, aes(x = ecks, y = why, width = .5)) +
  geom_bar(stat = "identity") +
  scale_y_continuous(breaks = c(10, 20, 30, 40, 50), limits = c(0, 50)) +
  coord_flip()

grid.arrange(plotshort, plotlong, ncol = 2)

If you do that, you get a really wide left chart and a really squished right chart. I know that you can add widths to the grid arrange, but I'd like to know exactly what they should be. Here it looks like widths=c(.4, .6) works pretty well, but it's not exact. Also, you have to use trial and error to get there, which isn't ideal. Is there any way to figure out what the actual plot area is so that you can calculate the right widths?

Upvotes: 3

Views: 1389

Answers (2)

Timothy Martin
Timothy Martin

Reputation: 76

You can wrap the labels using stringr and modify your ggplot2 script to define your labels in st_wrap and plot as scale_x_discrete:

library(stringr)    

plotshort <- ggplot(data = datashort, aes(x = ecks, y = why, width = .5)) +
  geom_bar(stat = "identity") + coord_flip() +
  scale_x_discrete(labels = str_wrap(c("Short1", "Short2", "Short3"), width = 10))  

plotlong <- ggplot(data = datalong, aes(x = ecks, y = why, width = .5)) +
    geom_bar(stat = "identity") + coord_flip() +
    scale_x_discrete(labels = str_wrap(c("Really, Really, Really, Really Long1", "Really, Really, Really, Really Long2", "Really, Really, Really, Really Long3"), width = 10))  

grid.arrange(plotshort, plotlong, ncol = 2)

enter image description here

Upvotes: 0

AndS.
AndS.

Reputation: 8110

One very simple solution would be to use cowplot:

cowplot::plot_grid(plotshort, plotlong, ncol = 2,align = "v")

enter image description here

The argument align allows you to set the plot areas equal.

Or another option would be to add some breaks to the titles:

library(stringr)

plotlong <- datalong %>%
    mutate(ecks = str_replace_all(ecks, "[[:punct:]]\\s|\\s", "\\\n")) %>% 
    ggplot(aes(x = ecks, y = why, width = .5)) +
    geom_bar(stat = "identity") +
    scale_y_continuous(breaks = c(10, 20, 30, 40, 50), limits = c(0, 50)) +
    coord_flip()

cowplot::plot_grid(plotshort, plotlong, ncol = 2,align = "v")

enter image description here

If you add the breaks, then you could use grid.arrange

grid.arrange(plotshort, plotlong, ncol = 2)

enter image description here

Upvotes: 3

Related Questions