2

I have a problem with combining ggplots using cowplot and ggpubr which is driving me crazy.

The problem is with the legend. When it's displayed with its original graph on its own, the spacing between the elements of the legend (guide title, key, key-label) are absolutely fine.

However, if I extract the legend from the original plot, and then display it in a combined plot (using either plot_grid from cowplot or ggarrange from ggpubr) then the spacing goes haywire. The longer the text, the more the spacing expands.

What is wrong here, and how do I fix it so that the legend in the combined plot looks exactly like the one in the original individual plot?

Example

This example uses ggarrange from ggpubr; my results with get_legend and plot_grid using cowplot are similar. Treatment names are entirely made up.

library(survival)
library(broom)
library(dplyr)
library(foreach)
library(ggpubr)

fit <- survfit(Surv(time,status == 2) ~ trt + sex, data=pbc)

time.xticks <- seq(0, 4000, 1000)
delta <- 0.00001

# Survival plot

kmdata <- tidy(fit) %>%
  mutate(trt=factor(gsub('trt=(.*),.*','\\1',strata)),
         sex=factor(gsub('.*sex=(.*)','\\1',strata), levels=levels(pbc$sex)))

p1 <- ggplot(data=filter(kmdata, time<=max(time.xticks)), aes(x=time, y=estimate, colour=sex, linetype=trt)) + geom_step() +
  scale_x_continuous(breaks = time.xticks,
                     limits = c(min(time.xticks), max(time.xticks))) +
  scale_colour_discrete(name="Sex", labels=c("Male","Female")) +
  scale_linetype_discrete(name="Treatment group", labels=c("Zyxatrxilbroh 35 mg", "Placebo 35 mg")) +
  theme(legend.position = "bottom", legend.box = "horizontal",
        legend.background = element_rect(fill="grey90", colour="black", size=0),
        legend.key.height=unit(0.2, "cm"),
        text=element_text(size=18))

tardata <- foreach(s=unique(kmdata$strata), .combine="rbind") %do% {
  filter(kmdata, strata==s)[findInterval(pmax(0, time.xticks-delta), filter(kmdata, strata==s)$time)+1,] %>%
    bind_cols(tibble(time.xticks))
} %>%
  mutate(ypos = -((as.integer(sex)-1)*(length(unique(pbc$trt))+2) + as.integer(trt) + 1))

tarheads <- tibble(xpos=0,
                   ypos=-(((1:length(unique(pbc$sex))) - 1)*(length(unique(pbc$trt)) + 2) + 1),
                   lab=levels(pbc$sex))

risk.yticks <- sort(unique(tardata$ypos))
risk.ylabels <- rep(rev(paste("trt =",levels(kmdata$trt))), length(unique(kmdata$sex)))

# Number-at-risk table

p2 <- ggplot(data=tardata, aes(x=time.xticks, y=ypos, label=n.risk, colour=sex)) + geom_text() +
  geom_text(data=tarheads, aes(x=xpos, y=ypos, label=lab), colour="black", hjust="left") +
  scale_x_continuous(breaks = time.xticks,
                     limits = c(min(time.xticks), max(time.xticks))) +
  scale_y_continuous(breaks = risk.yticks,
                      labels = risk.ylabels) +
  theme(text=element_text(size=18))

# put the two together

p.comb <- ggarrange(p1, p2, heights = c(2, 0.8), ncol=1,
                   align="v", common.legend = TRUE, legend="bottom")


# alternate version with guide headings at the top left instead of at the side
p1.a <- p1 + guides(colour = guide_legend(order=1,
                                          title.position = "top",
                                          title.hjust = 0),
                    linetype = guide_legend(order=1,
                                            title.position = "top",
                                            title.hjust = 0))

p.comb.a <- ggarrange(p1.a, p2, heights = c(2, 0.8), ncol=1,
                      align="v", common.legend = TRUE, legend="bottom")

# send to png
png("test-p1.png", width=8, height=4.5, units="in", res=200, type="cairo")
plot(p1)
dev.off()

png("test-pcomb.png", width=8, height=4.5, units="in", res=200, type="cairo")
plot(p.comb)
dev.off()

Results

Individual plot with correct legend spacing: [plot1

Combined plot with legend spacing expanded so much that the legend no longer fits in the image: plot2

Z.Lin
  • 28,055
  • 6
  • 54
  • 94
mpgrayer
  • 33
  • 4
  • I'm unable to replicate your result, using current R / package versions. Both `p1` and `p.comb` yielded tightly spaced legends in png form. Perhaps you want to check your package version? – Z.Lin Jun 17 '20 at 09:48

0 Answers0