2

Here is some example code, which provides a legend with 2 columns. I want to decrease the space between the two colums of the legend (see below).

library(ggplot2)

labels <- c(expression(""^13*CH[4]),
            expression(""^13*CH[4]~"+"~SO[4]^{2-''}),
            expression(""^13*CH[4]~"+"~MoO[4]^{2-''})) 

ggplot(aes(mpg, wt, colour = factor(cyl), shape=factor(cyl)), 
       data = mtcars) +
      geom_point() +
      scale_colour_manual(values=c("red", "green", "blue"), label=labels)+
      scale_shape_manual(values = c(4,5,6), label=labels)+
      theme(legend.position = "bottom",
            legend.text.align = 0,
            legend.text = element_text(size=8),
            legend.key.size = unit(0.8, 'lines')) + 
      guides(col = guide_legend("", ncol=2), shape=guide_legend("", col=2))

Here is my real life problem: enter image description here

Additional space is needed on the right side of the plot, because the three factor levels there contain much more characters. However, i am really constrained in the plot size. Hence, I would like to decrease the space between the two rows of the legend. I also would like to keep the most bottom factor level of the left hand side as is, without adding an extra line.

nouse
  • 3,315
  • 2
  • 29
  • 56
  • Please provide a reproducible example where we can get your problem. You can provide a dummy dataframe with a simple plot that creates the legend that is problematic to you, so others can help in providing a solution without worrying to reproduce the problem. See http://stackoverflow.com/q/5963269/446149 for how to provide a good reproducible example – zeehio Mar 17 '17 at 14:32
  • 1
    There is already reproducible toy code with a dummy data set. It encodes for a legend with two columns. I dont think that posting all the label expressions would help, but rather would inflate the question. – nouse Mar 17 '17 at 14:41
  • 1
    i added some expressions for clarification. – nouse Mar 17 '17 at 14:51

1 Answers1

3

Based on your example, I simplified it a bit:

Create the problematic plot:

library(ggplot2)

labels <- c("short1", "loooooooooooooooooong", "short2")

plt <- ggplot(aes(mpg, wt, colour = factor(cyl), shape=factor(cyl)), 
       data = mtcars) +
  geom_point() +
  scale_colour_manual(values=c("red", "green", "blue"), label=labels)+
  scale_shape_manual(values = c(4,5,6), label=labels)+
  theme(legend.position = "bottom",
        legend.text.align = 0,
        legend.text = element_text(size=8),
        legend.key.size = unit(0.8, 'lines')) + 
  guides(col = guide_legend("", ncol=2), shape=guide_legend("", col=2))
plot(plt)

plot with legend separated

Extract the legend and tweak it

I used this answer to extract the legend from the plot:

#Extract Legend 
g_legend<-function(a.gplot){ 
  tmp <- ggplot_gtable(ggplot_build(a.gplot)) 
  leg <- which(sapply(tmp$grobs, function(x) x$name) == "guide-box") 
  legend <- tmp$grobs[[leg]] 
  return(legend)} 

legend <- g_legend(plt) 

And print it:

grid.newpage()
grid.draw(legend) 

legend of the plot

Then I explored the grobs inside the legend and I found the widths field:

legend$grobs[[1]]$widths
 [1] 0.2cm              0cm                0.1524cm           0.4064cm           0.0762cm           3.22791666666667cm 0.0762cm           0.4064cm           0.0762cm          
[10] 0.79375cm          0.2cm             
> 

Apparently those 3.227 cm are too much so I just changed them:

legend$grobs[[1]]$widths[6] <- unit(1.5, "cm")

And plot it:

grid.newpage()
grid.draw(legend)

legend but more compact

Apply the fix to the global plot:

The final steps are to replicate that on the ggplot:

Apply that same manual correction to the global plot:

# this is how the legend was extracted:
plt_gtable <- ggplot_gtable(ggplot_build(plt)) 
leg <- which(sapply(plt_gtable$grobs, function(x) x$name) == "guide-box") 

# Replace the legend with our modified legend:
plt_gtable$grobs[[leg]] <- legend

And replot:

grid.newpage()
grid.draw(plt_gtable)

done

Community
  • 1
  • 1
zeehio
  • 4,023
  • 2
  • 34
  • 48
  • As a minor sidenote, the internal plot "Id" needs to be replaced, e.g. names(legend$grobs) – nouse Mar 17 '17 at 16:11
  • I replaced it with `$grobs[[1]]` which is universal. If the plot has more than one legend you may use `$grobs[[2]]` – zeehio Mar 17 '17 at 16:15