How to arrange three ggplot2 plots with the same size - r

I have 3 plot that I want to arrange in 2 rows, 1 column, and all present the same size.
My problem is that the 3rd (row 2) plot present legend that is common to all plots, and it make just a little bit small that the rest.
library(phyloseq)
library(vegan)
library(ggplot2)
library(ggpubr)
data("GlobalPatterns")
GP <- GlobalPatterns
GP.ord <- ordinate(GP, "NMDS", "bray", k=3)
DF_ord <- plot_ordination(GP, GP.ord, axes=c(1:3), justDF = TRUE)
head(DF_ord)
NMDS1 NMDS2 NMDS3 X.SampleID Primer Final_Barcode Barcode_truncated_plus_T Barcode_full_length SampleType
CL3 -0.2128261 0.7818086 -1.12967604 CL3 ILBC_01 AACGCA TGCGTT CTAGCGTGCGT Soil
CC1 -0.5826017 0.7847393 -0.83925680 CC1 ILBC_02 AACTCG CGAGTT CATCGACGAGT Soil
SV1 -0.4011154 1.1073660 -0.90078134 SV1 ILBC_03 AACTGT ACAGTT GTACGCACAGT Soil
M31Fcsw 2.2390139 -0.1076734 0.03626119 M31Fcsw ILBC_04 AAGAGA TCTCTT TCGACATCTCT Feces
M11Fcsw 2.1733638 -0.2290418 0.33818019 M11Fcsw ILBC_05 AAGCTG CAGCTT CGACTGCAGCT Feces
M31Plmr 0.1611431 1.3583510 0.67498162 M31Plmr ILBC_07 AATCGT ACGATT CGAGTCACGAT Skin
Generate the plots
Plot1
p1 <- ggplot(DF_ord, aes(x = NMDS1, y = NMDS2)) +
geom_vline(xintercept = 0, linetype="dashed", size = 0.5, color= "#999999") +
geom_hline(yintercept = 0, linetype="dashed", size = 0.5, color= "#999999") +
geom_point( aes(colour= SampleType), size = 3.5, alpha=0.7) +
theme_bw() +
theme(panel.grid.major = element_blank(), panel.grid.minor = element_blank())
Plot2
p2 <- ggplot(DF_ord, aes(x = NMDS1, y = NMDS3)) +
geom_vline(xintercept = 0, linetype="dashed", size = 0.5, color= "#999999") +
geom_hline(yintercept = 0, linetype="dashed", size = 0.5, color= "#999999") +
geom_point( aes(colour= SampleType), size = 3.5, alpha=0.7) +
theme_bw() +
theme(panel.grid.major = element_blank(), panel.grid.minor = element_blank())
Plot3
p3 <- ggplot(DF_ord, aes(x = NMDS2, y = NMDS3)) +
geom_vline(xintercept = 0, linetype="dashed", size = 0.5, color= "#999999") +
geom_hline(yintercept = 0, linetype="dashed", size = 0.5, color= "#999999") +
geom_point( aes(colour= SampleType), size = 3.5, alpha=0.7) +
theme_bw() +
theme(panel.grid.major = element_blank(), panel.grid.minor = element_blank())
Eliminate the legend for p1 and p2
p1 <- p1 + theme(legend.position = "none")
p2 <- p2 + theme(legend.position = "none")
Arrange the 3 plots
top_row = ggarrange(p1, p2, ncol = 2, labels = c("A)", "B)"))
bottom_row = ggarrange(NULL, p3, NULL, ncol = 3, labels = c("", "C)", ""), widths = c(1,2,1))
myplot <- ggarrange(top_row, bottom_row, ncol = 1)
The top_row plots are little bit bigger (rectangle) than the bottom_row plot (square) !!
myplot
How to make all plots with the same size (square), and keep the legend common to all in the botton_row plot ?

A possible solution would be to "fake a legend" like in this example:
p1 <- iris |>
ggplot2::ggplot(
mapping = ggplot2::aes(
x = Sepal.Length,
y = Sepal.Width,
color = Species
)
) +
ggplot2::geom_point() +
ggplot2::theme_minimal() +
ggplot2::theme(legend.position = "none")
p4 <- iris |>
dplyr::count(Species) |> # no overplotting
ggplot2::ggplot(
mapping = ggplot2::aes(
x = 0,
y = Species,
color = Species,
label = Species
)
) +
ggplot2::geom_point() +
ggplot2::theme_void() +
ggplot2::geom_text(x = 0.1,
color = "#000000", hjust = "left") +
ggplot2::theme(legend.position = "none") +
ggplot2::xlim(-1,1)
lay <- rbind(
c(1,2),
c(3,4)
)
gridExtra::grid.arrange(
p1,
p1,
p1,
p4,
layout_matrix = lay
)

Related

Patchwork not aligning x axis with ggbreak

I was able to use patchwork to align two xaxis, but when I add ggbreak::scale_break(), it no longer aligns. What am I doing wrong here? Code of alignment issues follows. UnComment out scale_break() lines to see difference.
library(scales)
library(ggplot2)
library(ggbreak)
library(patchwork)
y <- as_tibble(c(rnorm(400,100,25),250) )
n= nrow(y)
cor = n/100
a.mean = mean(y$value)
a.median= quantile(y$value,0.5)
a.sd = sd(y$value)
binwidth = 5
upper.limit <- 260
plt1 <-ggplot(y, aes(x="", y = value) ) +
geom_boxplot(fill = "lightblue", color = "black", outlier.shape=NA) +
stat_boxplot(geom='errorbar',coef=NULL) +
stat_summary(fun=mean, geom="point", shape=23, size=7.6, color="black", fill = "blue") +
coord_flip() +
theme_classic() +
theme(panel.border = element_rect(color="black", fill = NA, size = 1),
axis.text = element_text(size=14)) +
xlab("") +
ylab("Value ($)") +
#scale_y_break(c(200,240 ) ) +
scale_y_continuous(breaks=pretty(c(0,upper.limit), n=10), limits=c(0,upper.limit) ) +
theme(axis.text.y=element_blank(),
axis.ticks.y=element_blank(),
axis.text.x.top=element_blank(),
axis.ticks.x.top=element_blank() )
plt2 <- ggplot(y, aes(x = value) ) +
geom_histogram(aes(y = (..count..)/sum(..count..)*100 ),
position = "identity", binwidth = 5,
fill = "lightblue", color = "black") +
stat_function(fun = function(x)
dnorm(x, mean = a.mean, sd = a.sd) * n * binwidth / cor,
color="darkblue", size =1) +
ylab("Percentage") +
xlab("") +
#scale_x_break(c(200,240 ) ) +
scale_x_continuous(breaks=pretty(c(0,upper.limit), n=10), limits=c(0,upper.limit) ) +
scale_y_continuous(breaks=seq(0,15, by=2.5)) +
theme(panel.border = element_rect(color="black", fill = NA, size = 1),
plot.title = element_text(hjust = 0.5),
text=element_text(size=20),
axis.text = element_text(size=14),
axis.text.x.top=element_blank(),
axis.ticks.x.top=element_blank() )
Fig01_01 <- plt2 / plt1 + plot_layout(nrow = 2, heights = c(10, 2) )
Fig01_01
One solution might be to manually/invisibly add in the y-axis labels and ticks for the bottom plot as exactly the same size as the upper plot. ggbreak does additionally seem to add in an immovable margin around the whole plotting area, so you may have some extra white space between plots doing it this way:
library(scales)
library(tidyverse)
library(ggbreak)
library(patchwork)
y <- as_tibble(c(rnorm(400,100,25),250) )
n= nrow(y)
cor = n/100
a.mean = mean(y$value)
a.median= quantile(y$value,0.5)
a.sd = sd(y$value)
binwidth = 5
upper.limit <- 260
plt1 <-ggplot(y, aes(x=1, y = value) ) +
geom_boxplot(fill = "lightblue", color = "black", outlier.shape=NA) +
stat_boxplot(geom='errorbar',coef=NULL) +
stat_summary(fun=mean, geom="point", shape=23, size=7.6, color="black", fill = "blue") +
coord_flip() +
theme_classic() +
theme(panel.border = element_rect(color="black", fill = NA, size = 1),
axis.text = element_text(size=14)) +
xlab(" ") +
ylab("Value ($)") +
scale_y_break(c(200,240 ) ) +
scale_y_continuous(breaks=pretty(c(0,upper.limit), n=10), limits=c(0,upper.limit) ) +
theme(axis.text.y=element_text(colour = "white", size = 14),
axis.ticks.y=element_line(colour = "white"),
axis.text.x.top=element_blank(),
axis.title.y=element_text(size=20),
axis.ticks.x.top=element_blank() )
plt2 <- ggplot(y, aes(x = value) ) +
geom_histogram(aes(y = (..count..)/sum(..count..)*100 ),
position = "identity", binwidth = 5,
fill = "lightblue", color = "black") +
stat_function(fun = function(x)
dnorm(x, mean = a.mean, sd = a.sd) * n * binwidth / cor,
color="darkblue", size =1) +
ylab("Percentage") +
xlab("") +
scale_x_break(c(200,240 ) ) +
scale_x_continuous(breaks=pretty(c(0,upper.limit), n=10), limits=c(0,upper.limit) ) +
scale_y_continuous(breaks=seq(0,15, by=2.5)) +
theme(panel.border = element_rect(color="black", fill = NA, size = 1),
plot.title = element_text(hjust = 0.5),
text=element_text(size=20),
axis.text = element_text(size=14),
axis.text.x.top=element_blank(),
axis.ticks.x.top=element_blank() )
Fig01_01 <- plt2 / plt1 + plot_layout(nrow = 2, heights = c(6, 2) )
Fig01_01

make a common legend and include unique legend attributes

I am attempting to combine a legend for two plots with a shared blue line and unique bar colors (read and yellow). When plotting the code below only two of the three colored id's show up in the combined legend (red and blue) but I want the third color to show up as well in the combined legend.
For example
red as beaver temp1
yellow as beaver temp2
blue as line
Here the line is a stand in for what I am using for a moving average. I don't think facet wrapping this will work as there are additional variable parameters in my code (i.e. scale_y_continuous that have different secondary axis scales) but below is a reproducible example of the basic idea.
library(datasets)
library(ggplot2)
library(cowplot)
data(beavers)
colour <- c("bevTemp1" = "red", "line" = "blue", "bevTemp2" = "yellow" )
bev1 <- ggplot(beaver1, aes(x=time, y = temp)) +
geom_bar(stat = "identity", aes(colour = "bevTemp1"), fill = "red")+
coord_cartesian(ylim = c(35, 38)) +
geom_line(size = 1.5, aes(color = "line"))+
scale_color_manual(values = colour,
guide = guide_legend(override.aes = list(
border=c(NA, NA),
fill=c("red","blue"))))+
theme(legend.title = element_blank(), legend.position = "none")
bev2<- ggplot(beaver2, aes(x=time, y = temp)) +
geom_bar(stat = "identity", aes(colour = "bevTemp2"), fill = "yellow")+
coord_cartesian(ylim = c(35, 38)) +
geom_line(size = 1.5, aes(color = "line"))+
scale_color_manual(values = colour,
guide = guide_legend(override.aes = list(
border=c(NA, NA),
fill=c("yellow","blue"))))+
theme(legend.title = element_blank(), legend.position = "none")
cowplot::plot_grid(
cowplot::plot_grid(
bev1 ,
bev2,
align = 'h'),
cowplot::get_legend(bev1 + theme(legend.position = "bottom")),
nrow = 2, rel_heights = c(4, 1))
Suggestions...
You could build a dummy plot just to get the desired legend and add it to the final plot. I would also suggest using the line legend for the geom_line.
library(ggplot2)
# Create dummy data
df <- data.frame(class = c("bevTemp1","bevTemp2"),
x = 1:2,
y = 2:3)
# Create dummy plot just to extract the desired legend
p1<- ggplot(df, aes(x=x,y=y)) +
geom_col(aes(fill = class))+
geom_line(aes(col = "line"), size = 1.5)+
scale_fill_manual(values = c("red","yellow")) +
scale_color_manual(values = "blue")+
theme(legend.title = element_blank())
cowplot::plot_grid(
cowplot::plot_grid(
bev1 ,
bev2,
align = 'h'),
# Add the legend of the dummy plot
cowplot::get_legend(p1 + theme(legend.position = "bottom")),
nrow = 2, rel_heights = c(4, 1))
get_legend just retrieves the legend from the plot passed to this function, here bev1. So you need to also show bev2Temp in the legend of plot 1. You can add an additional id column to your dataset, make it a factor variable but in both datasets include bevTemp1/bevTemp2 as levels. In ggplot in scale_fill_manual, if you set drop = FALSE, all levels are shown:
library(datasets)
library(ggplot2)
library(cowplot)
data(beavers)
colour <- c("bevTemp1" = "red", "bevTemp2" = "yellow")
beaver1$id <- "bevTemp1"
beaver1$id <- factor(beaver1$id, levels = c("bevTemp1", "bevTemp2"))
beaver2$id <- "bevTemp2"
beaver2$id <- factor(beaver2$id, levels = c("bevTemp1", "bevTemp2"))
bev1 <- ggplot(beaver1, aes(x=time, y = temp, fill = id)) +
geom_bar(stat = "identity")+
coord_cartesian(ylim = c(35, 38)) +
geom_line(size = 1.5, aes(color = "line"))+
theme(legend.title = element_blank(), legend.position = "none") +
scale_fill_manual(values = c("bevTemp1" = "red", "bevTemp2" = "yellow"),
drop = FALSE) +
scale_colour_manual(values = c("line" = "blue"))
bev2<- ggplot(beaver2, aes(x=time, y = temp, fill = id)) +
geom_bar(stat = "identity")+
coord_cartesian(ylim = c(35, 38)) +
geom_line(size = 1.5, aes(color = "line"))+
theme(legend.title = element_blank(), legend.position = "none") +
scale_fill_manual(values = c("bevTemp1" = "red", "bevTemp2" = "yellow"),
drop = FALSE) +
scale_colour_manual(values = c("line" = "blue"))
cowplot::plot_grid(
cowplot::plot_grid(
bev1 ,
bev2,
align = 'h'),
cowplot::get_legend(bev1 + theme(legend.position = "bottom")),
nrow = 2, rel_heights = c(4, 1))

How to remove x and y axis labels from a boxplot in R?

I have been writing some code for a class, and I have got stuck in how to remove the x and y labels from the boxplot. I am planning to place it within a 1st graph, so they are redundant.
If anyone also knows how to add a line at 0 to my line graph, that would be amazing aswell!
Code:
#load data up
library(readxl)
TempData <- read_excel("R Data/TempData.xlsx")
View(TempData)
#initiliase relevant packages #ggplot2 for creating data visulation and viridis to allow for colour gradients
library(ggplot2)
library(viridis)
#plot line graph
g1 <- ggplot(TempData, aes(x = Year, y = GAT, color = GAT)) +
geom_line(size = 1.5) +
geom_smooth(method=loess, se=TRUE, col = "black") +
scale_colour_gradient2(low = "green", mid = "yellow" , high = "red", midpoint=median(TempData$GAT)) +
labs(title = "Global Average Temperature", subtitle = "From 1850 to 2018") +
xlab("Year") + ylab ("Average Temperature") +
theme(plot.title = element_text(face = "bold", hjust = 0.5, size = 16)) +
theme(plot.subtitle = element_text(face = "italic", hjust = 0.5, size = 10, colour = "Orange")) +
theme_light()
plot(g1)
#plot boxplot
g2 <- ggplot(TempData, aes(x="Year", y=TempData$GAT)) + geom_boxplot(outlier.colour = "red", outlier.fill = "red",outlier.shape = 21, outlier.size = 1)
labs(x=" ", y=" ") +
stat_summary(fun.y = mean, geom = "point", size = 2.5, colour = "orange") +
theme_light()
plot(g2)
#arrange two graphs to boxplot sits in top corner of line graph
g1 + annotation_custom(ggplotGrob(g2), xmin = 1840, xmax = 1930, ymin = 0.20, ymax = 0.88)
you could use theme in the following way:
... + theme(axis.title.x=element_blank(), axis.title.y=element_blank())
This will remove the x,y labels of the plot

remove axis.ticks from some panels in facet_wrap

I am using ggplot to plot y versus x for two factors f1 and f2 using the facet_wrap. I want to keep the ticks for the y axis only for the first column (representing given value of factor f2) and remove the others. Is there away to do this? I tried many ways (including scale = free_y) but no success. Below is a simple code:
y = rnorm(100)
x = rnorm(100)
type = rep(1:5,20)
f1 = sample(LETTERS[1:3], 100, replace=TRUE, prob=c(0.3, 0.3, 0.4) )
f2 = sample(LETTERS[4:6], 100, replace=TRUE, prob=c(0.3, 0.3, 0.4) )
df = data.frame(cbind(x, y,f1,f2, type))
df$x = as.numeric(as.character(df$x)); df$y = as.numeric(as.character(df$y))
p1 = ggplot(data = df, aes(x, y, linetype = type)) +
geom_line(aes(linetype = type))+ scale_linetype_manual(values=c("solid", "F1", "dotted", "twodash","dashed")) +
scale_size_manual(values=c(0.5, 0.5, 0.5,0.5,0.5)) +
geom_point(size=0.5, shape=21, fill="black") +
labs(y="y") +
facet_wrap( ~ f1 + f2 , ncol=3, scales = "free_y") +
theme_bw() +
theme(panel.margin = unit(0.8, "lines")) +
theme(plot.title = element_text(size = rel(1.2))) +
theme(axis.ticks.length=unit(0.2,"cm")) +
theme(strip.text.x = element_text(size=11)) +
theme(strip.background = element_rect(colour="white", fill="gray"))
p1
Questions:
How to keep the ticks for the y axis only for the first column in the left (i.e factor f2 = "D"). I know the y axis have different levels but this is not an issue for me.
many thanks
Abderrahim
I think you are actually after facet_grid as opposed to facet_wrap.
See the below:
p1 <- ggplot(data = df, aes(x, y, linetype = type)) +
geom_line(aes(linetype = type))+ scale_linetype_manual(values=c("solid", "F1", "dotted", "twodash","dashed")) +
scale_size_manual(values=c(0.5, 0.5, 0.5,0.5,0.5)) +
geom_point(size=0.5, shape=21, fill="black") +
labs(y="y") +
facet_grid( f1~f2 ) +
theme_bw() +
theme(panel.margin = unit(0.8, "lines")) +
theme(plot.title = element_text(size = rel(1.2))) +
theme(axis.ticks.length=unit(0.2,"cm")) +
theme(strip.text.x = element_text(size=11)) +
theme(strip.background = element_rect(colour="white", fill="gray"))
p1

how to make plot scales the same when using ggplot2?

I am plotting regression lines using ggplot2. I also want to plot out the mean points with confidence interval to show if it is significant. For example:
library("ggplot2")
library("gridExtra")
library("epicalc")
options(digits=2)
subset1 <- subset(na.omit(iris), Species == "setosa")
subset2 <- subset(na.omit(iris), Species == "versicolor")
subset3 <- subset(na.omit(iris), Species == "virginica")
meanx <- c(ci(subset1$Sepal.Length)$mean,
ci(subset2$Sepal.Length)$mean,
ci(subset3$Sepal.Length)$mean)
meany <- c(ci(subset1$Sepal.Width)$mean,
ci(subset2$Sepal.Width)$mean,
ci(subset3$Sepal.Width)$mean)
Species <- factor(c("setosa", "versicolor", "virginica"))
meanmatrix <- as.data.frame(cbind(Species, meanx, meany))
lowerx <- c(ci(subset1$Sepal.Length)$lower95ci,
ci(subset2$Sepal.Length)$lower95ci,
ci(subset3$Sepal.Length)$lower95ci)
upperx <- c(ci(subset1$Sepal.Length)$upper95ci,
ci(subset2$Sepal.Length)$upper95ci,
ci(subset3$Sepal.Length)$upper95ci)
lowery <- c(ci(subset1$Sepal.Width)$lower95ci,
ci(subset2$Sepal.Width)$lower95ci,
ci(subset3$Sepal.Width)$lower95ci)
uppery <- c(ci(subset1$Sepal.Width)$upper95ci,
ci(subset2$Sepal.Width)$upper95ci,
ci(subset3$Sepal.Width)$upper95ci)
px <- ggplot(data = meanmatrix, geom = 'blank',
aes(y = meanx, x = meany,color = factor(Species)))
pbx <- px +
geom_point(size = 5) +
geom_errorbar(aes(ymin=lowerx, ymax=upperx), colour="black", width=.1) +
scale_color_manual(values = c("#00FFFF", "#FFFF00", "#00FF00")) +
theme(panel.background = element_rect(fill='white', colour='red'),
axis.title.x = element_blank(),
axis.title.y = element_blank(),
legend.position = "none") +
coord_flip()
py <- ggplot(data = meanmatrix, geom = 'blank',
aes(y = meany, x = meany,color = factor(Species)))
pby <- py +
geom_point(size = 5) +
geom_errorbar(aes(ymin=lowery, ymax=uppery), colour="black", width=.1) +
scale_color_manual(values = c("#00FFFF", "#FFFF00", "#00FF00")) +
theme(panel.background = element_rect(fill='white', colour='red'),
axis.title.x = element_blank(),
axis.title.y = element_blank(),
legend.position = "none")
p <- ggplot(iris, aes(x = Sepal.Length, y = Sepal.Width,
color = factor(Species)))
p0 <- p +
scale_color_manual(values = c("#00FFFF", "#FFFF00", "#00FF00")) +
scale_linetype_manual(breaks = c("0","1"), values = c(1,2), labels = c("male", "female")) +
geom_smooth(method = "lm",se = FALSE, size = 1.2) +
theme(panel.background = element_rect(fill='white', colour='red'),
axis.title.x = element_blank(),
axis.title.y = element_blank(),
legend.position = "none")
grid.newpage()
pushViewport(viewport(layout = grid.layout(nrow=3, ncol=3)))
print(p0,vp = viewport(layout.pos.row = 1:2, layout.pos.col = 2:3))
print(pby,vp = viewport(layout.pos.row = 1:2, layout.pos.col = 1))
print(pbx,vp = viewport(layout.pos.row = 3, layout.pos.col = 2:3))
The scales of the three plots are different. How can I make them universal so that I can compare them? Thanks.
Like Ernest A. commented, you can manually change the scales of the x and y-axis using scale_x_continuous and scale_y_continuous. Just set the breaks argument to the same values.
It could also be just easier to plot the uncertainty bars in the plot itself, or plot the regression lines including a 95% confidence interval.

Resources