Keeping plot spacing intact using Cowplot align - r

I am trying to make some 'close stacked' plots using Cowplot. I can get the effect I want using the following MWE:
library(ggplot2)
library(cowplot)
disp_plot <- ggplot(data=mtcars,aes(x= hp,y=disp)) + geom_point()+
theme(plot.margin = unit(c(0.3,0.3,0.0,0.15), "cm"),
axis.text.x =element_blank(),axis.title.x =element_blank())
mpg_plot <- ggplot(data=mtcars,aes(x= hp,y=mpg)) + geom_point()+
theme(plot.margin = unit(c(0.0,0.3,0.0,0.15), "cm"),
axis.text.x =element_blank(),axis.title.x =element_blank())
qsec_plot <- ggplot(data=mtcars,aes(x= hp,y=qsec)) + geom_point()+
theme(plot.margin = unit(c(0.0,0.3,0.3,0.15), "cm"))
mp <- plot_grid(disp_plot, mpg_plot, qsec_plot,ncol = 1,align='v', axis = 'l')
Notice that mpg is not the same vertical scale as the others. To get the plots to be the same vertical size as well, I'd like to use "align='hv'" in plot_grid. However, this causes the spacing set by the margins to revert and the figures fly apart again. Is there a way I can preserve my spacing?

Not cowplot, but this seems to work.
library(egg)
library(grid)
grid.draw(ggarrange(plots=list(disp_plot, mpg_plot, qsec_plot)))

Related

Increase the distance between x axis factor and the plot [duplicate]

The y-axis title appears too close to the axis text.
ggplot(mpg, aes(cty, hwy)) + geom_point()
I have tried changing the value of many parameters with theme() but none seems to help.
From ggplot2 2.0.0 you can use the margin = argument of element_text() to change the distance between the axis title and the numbers. Set the values of the margin on top, right, bottom, and left side of the element.
ggplot(mpg, aes(cty, hwy)) + geom_point()+
theme(axis.title.y = element_text(margin = margin(t = 0, r = 20, b = 0, l = 0)))
margin can also be used for other element_text elements (see ?theme), such as axis.text.x, axis.text.y and title.
addition
in order to set the margin for axis titles when the axis has a different position (e.g., with scale_x_...(position = "top"), you'll need a different theme setting - e.g. axis.title.x.top. See https://github.com/tidyverse/ggplot2/issues/4343.
Based on this forum post: https://groups.google.com/forum/#!topic/ggplot2/mK9DR3dKIBU
Sounds like the easiest thing to do is to add a line break (\n) before your x axis, and after your y axis labels. Seems a lot easier (although dumber) than the solutions posted above.
ggplot(mpg, aes(cty, hwy)) +
geom_point() +
xlab("\nYour_x_Label") + ylab("Your_y_Label\n")
A solution that offers more fine-grained control than \n but is less cumbersome than adding margins is to use vjust in the theme function.
For adjusting the position on the y-axis or (x-axis) to add space, this often requires using a positive value for vjust (y-axis) or a negative value for vjust (x-axis) as in theme(axis.title.y = element_text(vjust = 2)). See a fully worked example below.
# load patchwork to show plots side-by-side
library(patchwork)
library(ggplot2)
# Plot A: just for comparison, moving titles *inward*
p1 <- ggplot(mpg, aes(cty, hwy)) +
geom_point() +
theme_gray() +
theme(
axis.title.y = element_text(vjust = -3),
axis.title.x = element_text(vjust = +3)
)
# Plot B: what we want, moving titles *outward*
p2 <- ggplot(mpg, aes(cty, hwy)) +
geom_point() +
theme_gray() +
theme(
axis.title.y = element_text(vjust = +3),
axis.title.x = element_text(vjust = -0.75)
)
# show plots side-by-side with patchwork package
p1 + p2 +
plot_annotation(tag_levels = "A")
For some reason the margin argument suggested by Didzis Elferts did not work for me. So, I used a different hack that is more flexible than adding an empty line but needs giving up the axis ticks.
myplot + theme(axis.ticks.x = element_blank(), axis.ticks.length.x = unit(3.25, "cm")
I guess, one can add the tick marks manually with geom_segment. Another possibility might be [ggalt::annotation_ticks][1]but I didn't bother trying either (note the current version of ggalt on CRAN (0.4) does not support this function, the one on github (0.6) does).

Put legend under each facet using facet_grid; adding one title and one caption to plot

I'm working with a plot analogous to the following:
ggplot(data=mtcars, aes(x=wt, y=mpg, color=carb)) +
geom_line() + facet_grid(gear ~ .) +
ggtitle(expression("Title")) +
labs(caption = "Sources: Compustat, Author's Calculations") +
theme(plot.title = element_text(size = 20, hjust = 0.5),
plot.caption=element_text(size=8, hjust=.5),
strip.background = element_blank(),
strip.text = element_blank(),
legend.title = element_blank())
I'm trying to do the following:
Insert a legend beneath each of the 3 facets, each legend specific to the facet above it.
Insert one plot title (as opposed to the same title above each facet).
Insert one caption beneath the final facet (as opposed to three captions beneath each facet).
I was able to reproduce this example on assigning a legend to each facet.
However, the plot title was placed above and the caption below each facet. Also, this example uses facet_wrap and not facet_grid.
Thank you in advance.
library(dplyr)
library(ggplot2)
tempgg <- mtcars %>%
group_by(gear) %>%
do(gg = {ggplot(data=., aes(x=wt, y=mpg, color=carb)) +
geom_point() +
labs(x = NULL) +
guides(color = guide_colorbar(title.position = "left")) +
theme(plot.title = element_text(size = 20, hjust = 0.5),
plot.caption=element_text(size=8, hjust=.5),
legend.position = "bottom")})
tempgg$gg[1][[1]] <- tempgg$gg[1][[1]] + labs(title = "Top title")
tempgg$gg[3][[1]] <- tempgg$gg[3][[1]] + labs(x = "Axis label", caption = "Bottom caption")
tempgg %>% gridExtra::grid.arrange(grobs = .$gg)
This isn't the most elegant way to do it. Each of the three grobs gets an equal space when you grid.arrange them, so the first and last ones are squished from the title and caption taking up space. You could add something like heights = c(3,2,3) inside the grid.arrange call, but you'd have to fiddle with each of the heights to get it to look right, and even then it would be a visual approximation, not exact.
To do it the more precise way, you'd need to look at the underlying gtables in each of the grobs. https://stackoverflow.com/users/471093/baptiste is the expert on that.
Update:
I used a #baptiste solution, which is still not particularly elegant, but gives you the same plot space for each panel. Use this snippet in place of the last line above.
tempggt <- tempgg %>% do(ggt = ggplot_gtable(ggplot_build(.$gg))) %>% .$ggt
gg1 <- tempggt[[1]]
gg2 <- tempggt[[2]]
gg3 <- tempggt[[3]]
gridExtra::grid.arrange(gridExtra::rbind.gtable(gg1, gg2, gg3))

Drawing ggplot Footer Using linesGrob within grobTree

I have created an extensive theme to plot in ggplot similar to Five Thirty Eight. Without using ggthemes, how can I utilize linesGrob to draw a line above my footer that is centered and goes 85% of the way across the plot without touching the edges of the plot? I am striving for the footer similar to this plot.
I can edit the font text, color, and size so don't worry about that.
So far, what I have is this:
data(iris)
library(ggplot2)
library(grid)
library(gridExtra)
plot20 <- ggplot(iris,aes(x=Petal.Length,y=Sepal.Length,color=Species)) +
geom_point(alpha=0.5,size=5) +
ylab("") +
xlab("") +
theme(panel.grid.minor.y=element_blank(),
panel.grid.major.x=element_line(color="#D2D2D2",size=0.7),
panel.grid.major.y=element_line(color="#D2D2D2",size=0.7),
panel.grid.minor.x=element_blank(),
panel.background = element_rect(fill = '#F0F0F0',colour=NA),
plot.background = element_rect(fill = '#F0F0F0', colour=NA, size = 4),
legend.background=element_rect(fill="#F0F0F0"),
legend.key=element_blank(),
legend.title=element_text(face="bold"),
axis.text=element_text(face="bold"),
legend.position="none",
axis.ticks=element_blank())
#Plot Header
my_g2 <- grobTree(rectGrob(gp=gpar(fill='#F0F0F0',col=NA)),
textGrob("Iris Dataset",x=0.115, vjust = -0.5,gp=gpar(fontsize=18,fontface="bold")),
textGrob("This is a subheader for the iris dataset",x=0.235,vjust=1.5,gp=gpar(fontsize=14)))
#Plot Footer
my_g1 <- grobTree(rectGrob(gp=gpar(fill="#F0F0F0",col=NA)),
textGrob(" medavis6",x=0,hjust=0,gp=gpar(col="darkorange",fontsize=8,fontface="bold")),
textGrob("Source: R",x=.85,hjust=-1.06,gp=gpar(col="black",fontsize=8)))
#Plot All Together
allplot <- grid.arrange(my_g2,plot20,my_g1,heights=c(1.17,11,0.5))
Which gives me this.
I think I should be using linesGrob() within my footer grobTree(), but whenever I try to do it I cannot make it appear in my plots. I'm not sure if my rectGrob() is plotting over the top of it or what is happening.
Thanks for any and all help and please, let me know if you need any clarification. Also, if any of my code is poorly written, I'm always looking for constructive criticism to make it better!
I also used linesGrob
#Plot Footer
my_g1 <- grobTree(rectGrob(gp=gpar(fill="#F0F0F0",col=NA)),
linesGrob(unit(c(.05, .95), "npc"), unit(1, "npc"),
gp = gpar(col = 'lightgrey', lwd = 4)),
textGrob(" medavis6",x=0,hjust=0,gp=gpar(col="darkorange",fontsize=8,fontface="bold")),
textGrob("Source: R",x=.85,hjust=-1.06,gp=gpar(col="black",fontsize=8)))
#Plot All Together
allplot <- grid.arrange(my_g2,plot20,my_g1,heights=c(1.17,11,0.5))
grid.draw(allplot)

Increase distance between text and title on the y-axis

The y-axis title appears too close to the axis text.
ggplot(mpg, aes(cty, hwy)) + geom_point()
I have tried changing the value of many parameters with theme() but none seems to help.
From ggplot2 2.0.0 you can use the margin = argument of element_text() to change the distance between the axis title and the numbers. Set the values of the margin on top, right, bottom, and left side of the element.
ggplot(mpg, aes(cty, hwy)) + geom_point()+
theme(axis.title.y = element_text(margin = margin(t = 0, r = 20, b = 0, l = 0)))
margin can also be used for other element_text elements (see ?theme), such as axis.text.x, axis.text.y and title.
addition
in order to set the margin for axis titles when the axis has a different position (e.g., with scale_x_...(position = "top"), you'll need a different theme setting - e.g. axis.title.x.top. See https://github.com/tidyverse/ggplot2/issues/4343.
Based on this forum post: https://groups.google.com/forum/#!topic/ggplot2/mK9DR3dKIBU
Sounds like the easiest thing to do is to add a line break (\n) before your x axis, and after your y axis labels. Seems a lot easier (although dumber) than the solutions posted above.
ggplot(mpg, aes(cty, hwy)) +
geom_point() +
xlab("\nYour_x_Label") + ylab("Your_y_Label\n")
A solution that offers more fine-grained control than \n but is less cumbersome than adding margins is to use vjust in the theme function.
For adjusting the position on the y-axis or (x-axis) to add space, this often requires using a positive value for vjust (y-axis) or a negative value for vjust (x-axis) as in theme(axis.title.y = element_text(vjust = 2)). See a fully worked example below.
# load patchwork to show plots side-by-side
library(patchwork)
library(ggplot2)
# Plot A: just for comparison, moving titles *inward*
p1 <- ggplot(mpg, aes(cty, hwy)) +
geom_point() +
theme_gray() +
theme(
axis.title.y = element_text(vjust = -3),
axis.title.x = element_text(vjust = +3)
)
# Plot B: what we want, moving titles *outward*
p2 <- ggplot(mpg, aes(cty, hwy)) +
geom_point() +
theme_gray() +
theme(
axis.title.y = element_text(vjust = +3),
axis.title.x = element_text(vjust = -0.75)
)
# show plots side-by-side with patchwork package
p1 + p2 +
plot_annotation(tag_levels = "A")
For some reason the margin argument suggested by Didzis Elferts did not work for me. So, I used a different hack that is more flexible than adding an empty line but needs giving up the axis ticks.
myplot + theme(axis.ticks.x = element_blank(), axis.ticks.length.x = unit(3.25, "cm")
I guess, one can add the tick marks manually with geom_segment. Another possibility might be [ggalt::annotation_ticks][1]but I didn't bother trying either (note the current version of ggalt on CRAN (0.4) does not support this function, the one on github (0.6) does).

Remove facet_wrap labels completely

I'd like to remove the labels for the facets completely to create a sort of sparkline effect, as for the audience the labels are irrelevant, the best I can come up with is:
library(MASS)
library(ggplot2)
qplot(week,y,data=bacteria,group=ID, geom=c('point','line'), xlab='', ylab='') +
facet_wrap(~ID) +
theme(strip.text.x = element_text(size=0))
So can I get rid of the (now blank) strip.background completely to allow more space for the "sparklines"?
Or alternatively is there a better way to get this "sparkline" effect for a large number of binary valued time-series like this?
For ggplot v2.1.0 or higher, use element_blank() to remove unwanted elements:
library(MASS) # To get the data
library(ggplot2)
qplot(
week,
y,
data = bacteria,
group = ID,
geom = c('point', 'line'),
xlab = '',
ylab = ''
) +
facet_wrap(~ ID) +
theme(
strip.background = element_blank(),
strip.text.x = element_blank()
)
In this case, the element you're trying to remove is called strip.
Alternative using ggplot grob layout
In older versions of ggplot (before v2.1.0), the strip text occupies rows in the gtable layout.
element_blank removes the text and the background, but it does not remove the space that the row occupied.
This code removes those rows from the layout:
library(ggplot2)
library(grid)
p <- qplot(
week,
y,
data = bacteria,
group = ID,
geom = c('point', 'line'),
xlab = '',
ylab = ''
) +
facet_wrap(~ ID)
# Get the ggplot grob
gt <- ggplotGrob(p)
# Locate the tops of the plot panels
panels <- grep("panel", gt$layout$name)
top <- unique(gt$layout$t[panels])
# Remove the rows immediately above the plot panel
gt = gt[-(top-1), ]
# Draw it
grid.newpage()
grid.draw(gt)
I'm using ggplot2 version 1 and the commands required have changed.
Instead of
ggplot() ... +
opts(strip.background = theme_blank(), strip.text.x = theme_blank())
you now use
ggplot() ... +
theme(strip.background = element_blank(), strip.text = element_blank())
For more detail see http://docs.ggplot2.org/current/theme.html
Sandy's updated answer seems good but, possibly has been rendered obsolete by updates to ggplot? From what I can tell the following code (a simplified version of Sandy's original answer) reproduces Sean's original graph without any extra space:
library(ggplot2)
library(grid)
qplot(week,y,data=bacteria,group=ID, geom=c('point','line'), xlab='', ylab='') +
facet_wrap(~ID) +
theme(strip.text.x = element_blank())
I am using ggplot 2.0.0.
As near as I can tell, Sandy's answer is correct but I think it's worth mentioning that there seems to be a small difference the width of a plot with no facets and the width of a plot with the facets removed.
It isn't obvious unless you're looking for it but, if you stack plots using the viewport layouts that Wickham recommends in his book, the difference becomes apparent.

Resources