The space above and below the legend using ggplot2 - r

If you look at the charts here! you can see there is a lot of white space above and below the legend. I wish to reduce the amount of space.
Example code:
library(ggplot2)
library(gridExtra)
library(reshape)
library(plyr)
library(scales)
theme_set(theme_bw())
rows <- 1:nrow(faithful)
data <- cbind(faithful, rows)
molten <- melt(data, id.vars='rows', measure.vars=c('eruptions', 'waiting'))
p <- ggplot() +
geom_line(data=molten,
mapping=aes(x=rows, y=value, group=variable, colour=variable), size=0.8) +
scale_colour_manual(values=c('red','blue')) +
opts(title='Title') +
xlab(NULL) + ylab('Meaningless Numbers') +
opts(
legend.position='bottom',
legend.direction='horizontal',
legend.title=theme_blank(),
legend.key=theme_blank(),
legend.text=theme_text(size=9),
legend.margin = unit(0, "line"),
legend.key.height=unit(0.6,"line"),
legend.background = theme_rect(colour='white', size=0)
)
ggsave(p, width=8, height=4, filename='crap.png', dpi=125)

To remove the margins of the legend (negative values reduce the white space even more):
p + theme(legend.margin=margin(t=0, r=0, b=0, l=0, unit="cm"))
p + theme(legend.margin=margin(t=0, r=0, b=-0.5, l=0, unit="cm"))
You can also remove the lower part of the plot margin by specifying negative numbers (but make sure that you don't cut off your legend):
p + theme(plot.margin = unit(x = c(0, 0, -0.2, 0), units = "cm"))
Illustrations: ggplot2, legend on top and margin

Here are two additional options that allow you to shrink the space surround the legend:
p + theme(
legend.key.height=unit(0, "cm"),
plot.margin = unit(c(1,0.5,0,0.5), "lines")
)
The option plot.margin describes how much space there is around the plot itself. The third argument describes the amount of space below the plot. Setting that to zero helps.

Related

Stacking multiple figures together in ggplot

I am attempting to make publication ready figures where the bottom axis (with tick marks) of one figure is cleanly combined with the top axis of the figure below it. Here is an example of what it might look like, although this one doesn't have tick marks on each panel:
Here is my attempt to do so, by simply using grid.arrange:
#Libraries:
library(ggplot2)
library(dplyr)
library(gridExtra)
#Filter to create two separate data sets:
dna1 <- DNase %>% filter(Run == 1)
dna2 <- DNase %>% filter(Run == 2)
#Figure 1:
dna1_plot <- ggplot(dna1, aes(x = conc, y = density)) + geom_point() + theme_classic() +
theme(axis.title.x = element_blank())
#Figure 2:
dna2_plot <- ggplot(dna2, aes(x = conc, y = density)) + geom_point() + theme_classic()
#Using grid.arrange to combine:
dna <- grid.arrange(dna1_plot, dna2_plot, nrow = 2)
And an attempt with some adjustments to the plot margins, although this didn't seem to work:
dna1_plot_round2 <- ggplot(dna1, aes(x = conc, y = density)) + geom_point() + theme_classic() +
theme(axis.title.x = element_blank(),
plot.margin = (0,0,0,0), "cm")
dna2_plot_round2 <- ggplot(dna2, aes(x = conc, y = density)) + geom_point() + theme_classic() +
theme(plot.margin = unit(c(-0.5,-1,0,0), "cm"))
dna_round2 <- grid.arrange(dna1_plot_round2, dna2_plot_round2, nrow = 2)
Does anyone know the best way to stack figures like this in ggplot? Is there a better way than using grid.arrange? If possible it would be great to see how to do it with/without tick marks on each x axis as well.
Thank you!
You don't need any non-native ggplot stuff. Keep your data in one data frame and use facet_grid.
dna <- DNase %>% filter(Run %in% 1:2)
ggplot(dna, aes(x = conc, y = density)) +
geom_point() +
theme_bw() +
facet_grid(rows = vars(Run)) +
theme(panel.spacing = unit(0, "mm"))
The R package deeptime has a function called ggarrange2 that can achieve this. Instead of just pasting the plots together like grid.arrange (and ggarrange), it lines up all of the axes and axis labels from all of the plots.
# remove bottom axis elements, reduce bottom margin, add panel border
dna1_plot_round2 <- ggplot(dna1, aes(x = conc, y = density)) + geom_point() + theme_classic() +
theme(axis.text.x = element_blank(), axis.ticks.x = element_blank(), axis.title.x = element_blank(),
plot.margin = margin(0,0,-.05,0, "cm"), panel.border = element_rect(fill = NA))
# reduce top margin (split the difference so the plots are the same height), add panel border
dna2_plot_round2 <- ggplot(dna2, aes(x = conc, y = density)) + geom_point() + theme_classic() +
theme(plot.margin = margin(-.05,0,0,0, "cm"), panel.border = element_rect(fill = NA))
dna_round2 <- ggarrange2(dna1_plot_round2, dna2_plot_round2, nrow = 2)
You might also try the fairly recent patchwork package, although I don't have much experience with it.
Note that while Gregor's answer may be fine for this specific example, this answer might be more appropriate for other folks that come across this question (and see the example at the top of the question).
For your purposes, I believe Gregor Thomas' answer is best. But if you are in a situation where facets aren't the best option for combining two plots, the newish package {{patchwork}} handles this more elegantly than any alternatives I've seen.
Patchwork also provides lots of options for adding annotations surrounding the combined plot. The readME and vignettes will get you started.
library(patchwork)
(dna1_plot / dna2_plot) +
plot_annotation(title = "Main title for combined plots")
Edit to better address #Cameron's question.
According to the package creator, {{patchwork}} does not add any space between the plots. The white space in the example above is due to the margins around each individual ggplot. These margins can be adjusted using the plot.margin argument in theme(), which takes a numeric vector of the top, right, bottom, and left margins.
In the example below, I set the bottom margin of dna1_plot to 0 and strip out all the bottom x-axis ticks and text. I also set the top margin of dna2_plot to 0. Doing this nearly makes the y-axis lines touch in the two plots.
dna1_plot <- ggplot(dna1, aes(x = conc, y = density)) + geom_point() + theme_classic() +
theme(axis.title.x = element_blank(),
axis.ticks.x = element_blank(),
axis.text.x = element_blank(),
plot.margin = unit(c(1,1,0,1), "mm"))
#Figure 2:
dna2_plot <- ggplot(dna2, aes(x = conc, y = density)) + geom_point() + theme_classic() +
theme(plot.margin = unit(c(0,1,1,1), "mm"))
(dna1_plot / dna2_plot)

changing axis size in ggplot

I'm working on a plot where I would like to change the axis thickness to match the boarder of the facet labels. Somehow axis.line = element_line(color="black", size=0.5) doesn't work - any ideas why?
This is my code...
ggplot(datgg_final, aes(y = total_GLS, x = timing)) +
geom_boxplot(aes(fill = genotype)) +
facet_grid(col=vars(genotype)) +
theme(legend.position = "none") +
scale_fill_manual(values=c("#0496FF", "#53A548")) +
ggtitle("Effect of Timing") +
xlab("Days since Defence Induction") +
ylab("Total Glucosinolates (µmol g^-1 DW)") +
theme(strip.background = element_rect(color = "black", fill ="white", size=0.5, linetype="solid"),
axis.line = element_line(color="black", size=0.5))
... and the plot:
enter image description here
Even in most basic plots I cannot change any axis settings (except the linetype), this code just shows the normal boxplot, no red axes, no change in line size:
ggplot(datgg_final, aes(y=total_GLS, x=timing)) +
geom_boxplot() +
theme(axis.line=element_line(size=0.5, color="red"))
Fortunately, this seems to be a simple clipping issue. Unfortunately, this can't be adressed with the normal ggplot interface (as far as I know), but you could mess around in the gtable to produce the plot you want.
Consider the following plot:
library(ggplot2)
library(grid)
g <- ggplot(iris, aes(Sepal.Width, Sepal.Length)) +
geom_point() +
facet_grid(~ Species) +
theme(strip.background.x = element_rect(colour = "black", fill = "white",
size = 0.5, linetype = "solid"),
axis.line = element_line(colour = "black", size = 0.5))
g
You can see that the apparent linewidths of the facet strips and the axes are unequal. We can turn of the clipping by messing around in the gtable:
# Convert plot to gtable
gt <- ggplotGrob(g)
# Find the strips
is_strip <- grep("strip", gt$layout$name)
# Turn off clipping at highest level
gt$layout$clip[is_strip] <- "off"
# Turn off clipping at the strip level
gt$grobs[is_strip] <- lapply(gt$grobs[is_strip], function(strip) {
strip$layout$clip <- "off"
strip
})
# Plot
grid.newpage(); grid.draw(gt)
Now the apparent linewidths are the intended linewidths, but it took quite some extra steps to get there. If somebody has a more elegant solution, be welcome to post an alternative.

Change orientation of grob background gradient

I was surprised that the following simple grob created from a vector of colors works almost as requested.
However, I would like to make the gradient left to right, not top to bottom.
library(ggplot2)
library(grid)
grad = colorRampPalette(c("red", "yellow"))(10)
ggplot(df, aes(x,y)) +
annotation_custom(rasterGrob(grad,
width=unit(1,"npc"),
height=unit(1,"npc"))) +
scale_x_continuous(limits = c(0,1)) +
scale_y_continuous(limits = c(0,1))
Answer is t
You have to transpose your grad vector (input to rasterGrob):
library(ggplot2)
ggplot() +
annotation_custom(rasterGrob(t(grad),
width = unit(1, "npc"), height = unit(1, "npc")))

How to remove margins in ggplot2 chart

I am currently creating plots with ggplot2 for a latex document and discovered that ggplot2 adds many unwanted margins:
painted red by plot.background=element_rect(fill="red"):
small margin on the left
small margin between image and legend
painted violet with photoshop:
margin on the left and the right
1px margin on the bottom
Which more rules are needed to remove these margins? It's really difficult to google all these configuration options. This is my actual chart:
library(ggplot2)
library(scales)
label <- c("A", "B", "C", "D")
value <- c(61, 26, 9, 4)
values <- data.frame(label, value)
myplot <- ggplot(values, aes(x = "", y=value, fill=label))
myplot <- myplot + theme(legend.position="bottom")
myplot <- myplot + labs(fill="")
myplot <- myplot + geom_bar(stat="identity", width=1)
myplot <- myplot + geom_text(
aes(x=1.3, y=value/2+c(0, cumsum(value)[-length(value)])),
label=percent(value/100),
size=2
)
myplot <- myplot + coord_polar(theta="y")
myplot <- myplot + theme(plot.background=element_rect(fill="red"))
myplot <- myplot + theme(
plot.margin=unit(c(0,0,0,0), "mm"),
legend.margin=unit(0, "mm"),
axis.title=element_blank(),
axis.ticks=element_blank()
)
ggsave("pie.pdf")
Adjust the plot.margin settings so that the bottom and left side are negative numbers.
plot.margin=unit(c(0,0,-12,-5), "mm")
If you do get rid of the margin on the bottom, you are also sacrificing the legend.
You can remove the rest of the axis space via the theme elements axis.text and axis.tick.length.
So you'd add something like the following to your theme code:
axis.text = element_blank(), axis.ticks.length = unit(0, "mm")
In the current development version of ggplot2, ggplot2_2.1.0.9001, there is a new theme element legend.box.spacing that could also be useful here to remove all space between the legend and the plot: legend.box.spacing = unit(0, "mm").

R: ggplot background gradient coloring

I would like to generate ggplot’s with gradient coloring, filling both plot panel and its background, as herein shown.
As you can see the gradient background coloring encompasses both plot panel and its background. At the moment, only an "approximation" of the required solution is known to me:
library(ggplot2)
library(grid)
library(gridExtra)
reds <- c("#7B0664", "#E32219")
g <- rasterGrob(reds, width = unit(1, "npc"), height = unit(1, "npc"),
interpolate = TRUE)
ggplot(data = economics, aes(x = date, y = unemploy)) +
annotation_custom(g, xmin=-Inf, xmax=Inf, ymin=-Inf, ymax=Inf) +
geom_line( alpha=1, color = "white", size = 0.5 ) +
xlab("Years") + ylab("Unemployed [thousands]") +
theme(plot.background = element_rect(fill=reds[2]))
Using aboveshown code, the plot panel results as gradient colored within axis boundaries, however it does not span the overall background with such gradient coloring. The theme(plot.background =...) is capable to fill the remaining background, however it does not seem to be able to take advantage of gradient coloring. To remark further that same gradient coloring should be applied to the overall plot background.
Any suggestions will be appreciated. Thanks.
you can print/draw the plot on top of a rasterGrob,
library(ggplot2)
library(grid)
library(ggthemes)
reds <- c("#7B0664", "#E32219")
g <- rasterGrob(reds, width = unit(1, "npc"), height = unit(1, "npc"), interpolate = TRUE)
p <- ggplot(data = economics, aes(x = date, y = unemploy)) +
geom_line( alpha=1, color = "white", size = 0.5 ) +
xlab("Years") + ylab("Unemployed [thousands]") +
theme_base() +
theme(panel.background=element_blank(),
panel.border = element_blank(),
plot.background=element_blank(),
text = element_text(colour="white"),
line = element_line(colour="white")) +
theme()
grid.newpage()
grid.draw(g)
print(p, newpage = FALSE)

Resources