Home > Software engineering >  Split legend in ggarrange
Split legend in ggarrange

Time:02-03

I have a problem with scale of legend, because text of legend crosses borders of plot. Any idea, how can I fix it? Split or resize?

Data cleaning:

Filtering data

df <- df %>%
  filter(!(is.na(review)))

Changing state name to postal code

df <- df %>%
  mutate(state = case_when(state == 'California' ~ 'CA',
                           state == 'Texas' ~ 'TX',
                           state == 'New York' ~ 'NY',
                           state == 'Florida' ~ 'FL',
                           TRUE ~ state))

Coding review column and adding new high_review

df <- df %>%
  mutate(review = case_when(review == 'Poor' ~ 1,
                   review == 'Fair' ~ 2,
                   review == 'Good' ~ 3,
                   review == 'Great' ~ 4,
                   review == 'Excellent' ~ 5,),
         high_review = ifelse(review >= 4, TRUE, FALSE))

Code of frames:

California

ca <- df %>%
  filter(state == 'CA') %>%
  group_by(book) %>%
  summarize(books_sold = table(book)) %>%
  arrange(-books_sold) %>%
  mutate(rank = 1:5)

New York

ny <- df %>%
  filter(state == 'NY') %>%
  group_by(book) %>%
  summarize(books_sold = table(book)) %>%
  arrange(-books_sold) %>%
  mutate(rank = 1:5)

Florida

fl <- df %>%
  filter(state == 'FL') %>%
  group_by(book) %>%
  summarize(books_sold = table(book)) %>%
  arrange(-books_sold) %>%
  mutate(rank = 1:5)

Texas

tx <- df %>%
  filter(state == 'TX') %>%
  group_by(book) %>%
  summarize(books_sold = table(book)) %>%
  arrange(-books_sold) %>%
  mutate(rank = 1:5)

This is how I created data frames for each state.

Code of plots:

ca_plot <- ggplot(data = ca, aes(x = reorder(rank, -books_sold), y = books_sold, fill = book)) 
  geom_col() 
  geom_text(aes(label = books_sold), vjust = 1.1, size = 3) 
  ylab('Number of books sold') 
  xlab('Ranking') 
  ggtitle('California') 
  theme(legend.position = "none")

ny_plot <- ggplot(data = ny, aes(x = reorder(rank, -books_sold), y = books_sold, fill = book)) 
  geom_col() 
  geom_text(aes(label = books_sold), vjust = 1.1, size = 3) 
  ylab('') 
  xlab('Ranking') 
  ggtitle('New York') 
  theme(legend.position = "none")  

fl_plot <- ggplot(data = fl, aes(x = reorder(rank, -books_sold), y = books_sold, fill = book)) 
  geom_col() 
  geom_text(aes(label = books_sold), vjust = 1.1, size = 3) 
  ylab('Number of books sold') 
  xlab('Ranking') 
  ggtitle('Florida') 
  theme(legend.position = "none")  

tx_plot <- ggplot(data = tx, aes(x = reorder(rank, -books_sold), y = books_sold, fill = book)) 
  geom_col() 
  geom_text(aes(label = books_sold), vjust = 1.1, size = 3) 
  ylab('') 
  xlab('Ranking') 
  ggtitle('Texas') 
  theme(legend.position = "none")  

all_plot <- ggplot()

final_plot <- ggarrange(ca_plot, ny_plot, fl_plot, tx_plot, ncol = 2, nrow = 2,
                        common.legend = TRUE)
final_plot

And result:

multiple chart

CodePudding user response:

As I suggested in my comment adding guides(fill = guide_legend(nrow = ...)) to one of your plots would be one option to split the legend into multiple rows.

As you provided no example data I created my own.

library(ggplot2)
library(ggpubr)

dat <- data.frame(
  book <- c(
    "Lorem ipsum dolor sit amet",
    "sem in libero class",
    "et posuere vehicula imperdiet dapibus",
    "et ipsum id ac",
    "Eleifend torquent sed egestas"
  ),
  books_sold = 1:5
)

First, to reproduce your issue let's create some simple charts and use ggarrange to glue them together, which as you can see results in a legend clipped off at the plot margins because of the long legend text.

p1 <- p2 <- p3 <- p4 <- ggplot(dat, aes(as.numeric(factor(book)), books_sold, fill = book))  
  geom_col()  
  theme(legend.position = "none")

final_plot <- ggarrange(p1, p2, p3, p4,
  ncol = 2, nrow = 2,
  common.legend = TRUE
)
final_plot

Now, adding guides(fill = guide_legend(nrow = 3)) to just one of your plots will split the legend into three rows:

p1 <- p1   guides(fill = guide_legend(nrow = 3))

final_plot <- ggarrange(p1, p2, p3, p4,
  ncol = 2, nrow = 2,
  common.legend = TRUE
)
final_plot

  • Related