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
Related
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
I have a bar graph (created using ggplot2 package) coming from one set of yearly data (with multiple y values)and I want to overlay on it data from another set of yearly data in the form of a line. Here is my code:
library (zoo)
require(ggplot2)
library(reshape)
library(Cairo)
library(reshape2)
x<-c(2000,2001,2002,2003,2004)
y1<-c(41,62,71,316,172)
y2<-c(3018,2632,2643,2848,2738)
y3<-c(3065,2709,2721,3192,2925)
dat1 <- data.frame(Year=x, y1, y2)
dat.m1 <- melt(dat1, id.vars='Year')
a<-ggplot(dat.m1, aes(Year, value)) +
geom_bar(width=0.6,aes(fill = variable),stat = "identity")+
xlab("Year") + ylab("Water Depth (mm)")+
theme(legend.position="top")+
theme(panel.background = element_rect(fill = 'white', colour = 'black'))+
theme(axis.text=element_text(size=13),axis.title=element_text(size=14))+
theme(legend.text=element_text(size=14))+
theme(plot.margin=unit(c(0.2,0.7,0.5,0.2),"cm"))+
guides(fill = guide_legend(title="", title.position="top", direction="horizontal"))
a
At this stage, bar plot is running nicely but when I tried to add line plot from different data frame as follow:
dat2 <- data.frame(Year=x, y3)
dat.m2 <- melt(dat2, id.vars='Year')
b<-ggplot(dat.m1, aes(Year, value)) +
geom_bar(width=0.6,aes(fill = variable),stat = "identity")+
geom_line(dat.m2, aes(x = x, y = y3), size = 1.5, color="red") +
xlab("Year") + ylab("Water Depth (mm)")+
theme(legend.position="top")+
theme(panel.background = element_rect(fill = 'white', colour = 'black'))+
theme(axis.text=element_text(size=13),axis.title=element_text(size=14))+
theme(legend.text=element_text(size=14))+
theme(plot.margin=unit(c(0.2,0.7,0.5,0.2),"cm"))+
guides(fill = guide_legend(title="", title.position="top", direction="horizontal"))
b
It did not work and I received this error message:
"Error in validate_mapping():
! mapping must be created by aes()
Run rlang::last_error() to see where the error occurred."
Anyone can help me to fix this issue? Also, any suggestion to add a line plot with each bar in the first data frame?
You need to add argument name data in geom_line(). Otherwise dat.m2 is received as mapping to the geom_line function.
dat2 <- data.frame(Year = x, y3)
dat.m2 <- melt(dat2, id.vars = 'Year')
b <- ggplot(dat.m1, aes(Year, value)) +
geom_bar(width = 0.6, aes(fill = variable), stat = "identity") +
geom_line(data = dat.m2, aes(x = x, y = y3), size = 1.5, color = "red") + # adding data argument name
xlab("Year") + ylab("Water Depth (mm)") +
theme(legend.position = "top") +
theme(panel.background = element_rect(fill = 'white', colour = 'black')) +
theme(axis.text = element_text(size = 13),
axis.title = element_text(size = 14)) +
theme(legend.text = element_text(size = 14)) +
theme(plot.margin = unit(c(0.2, 0.7, 0.5, 0.2), "cm")) +
guides(fill = guide_legend(
title = "",
title.position = "top",
direction = "horizontal"
))
b
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
)
I want to write the x-axis on all facets but without the scale.
The output
I tried to use scales='free_x' with scale_x_discrete(drop=FALSE) but it didn't work .
plot2 <- ggplot(counter2, aes(x = as.character(week) , y = freq,group=Delivery.time)) +
geom_point(colour = "red") + geom_line(colour = "red") +
labs(x = "Month", y = "Number Of Customers") +
facet_grid(.~Delivery.time) +
theme(axis.text.x = element_text(angle = 45, hjust=1)) +
geom_text(aes(label = freq),size = 2.5, hjust = .5, vjust=-0.5) +
facet_wrap(~Delivery.time, ncol = 1, scales = x) +
scale_x_discrete(drop=FALSE)
Plot with scaled x-axis
I want all a-axis
I'm trying to make interaction plot with ggplot2. My code is below:
library(ggplot2)
p <- qplot(as.factor(dose), len, data=ToothGrowth, geom = "boxplot", color = supp) + theme_bw()
p <- p + labs(x="Dose", y="Response")
p <- p + stat_summary(fun.y = mean, geom = "point", color = "blue")
p <- p + stat_summary(fun.y = mean, geom = "line", aes(group = 1))
p <- p + opts(axis.title.x = theme_text(size = 12, hjust = 0.54, vjust = 0))
p <- p + opts(axis.title.y = theme_text(size = 12, angle = 90, vjust = 0.25))
print(p)
How can I plot dose-supp level combination means rather than only dose level means which I'm getting here? Thanks in advance for your help.
You can precalculate the values in their own data frame:
toothInt <- ddply(ToothGrowth,.(dose,supp),summarise, val = mean(len))
ggplot(ToothGrowth, aes(x = factor(dose), y = len, colour = supp)) +
geom_boxplot() +
geom_point(data = toothInt, aes(y = val)) +
geom_line(data = toothInt, aes(y = val, group = supp)) +
theme_bw()
Note that using ggplot rather than qplot makes the graph construction a lot clearer for more complex plots like these (IMHO).
You can compute your summaries by the appropriate groups (supp):
p <- qplot(as.factor(dose), len, data=ToothGrowth, geom = "boxplot", color = supp) + theme_bw()
p <- p + labs(x="Dose", y="Response")
p <- p + stat_summary(fun.y = mean, geom = "point", color = "blue", aes(group=supp))
p <- p + stat_summary(fun.y = mean, geom = "line", aes(group = supp))
p <- p + opts(axis.title.x = theme_text(size = 12, hjust = 0.54, vjust = 0))
p <- p + opts(axis.title.y = theme_text(size = 12, angle = 90, vjust = 0.25))
print(p)
Or converting to ggplot syntax (and combining into one expression)
ggplot(ToothGrowth, aes(as.factor(dose), len, colour=supp)) +
geom_boxplot() +
stat_summary(aes(group=supp), fun.y = mean, geom="point", colour="blue") +
stat_summary(aes(group=supp), fun.y = mean, geom="line") +
scale_x_discrete("Dose") +
scale_y_continuous("Response") +
theme_bw() +
opts(axis.title.x = theme_text(size = 12, hjust = 0.54, vjust = 0),
axis.title.y = theme_text(size = 12, angle = 90, vjust = 0.25))
EDIT:
To make this work with 0.9.3, it effectively becomes Joran's answer.
library("plyr")
summ <- ddply(ToothGrowth, .(supp, dose), summarise, len = mean(len))
ggplot(ToothGrowth, aes(as.factor(dose), len, colour=supp)) +
geom_boxplot() +
geom_point(data = summ, aes(group=supp), colour="blue",
position = position_dodge(width=0.75)) +
geom_line(data = summ, aes(group=supp),
position = position_dodge(width=0.75)) +
scale_x_discrete("Dose") +
scale_y_continuous("Response") +
theme_bw() +
theme(axis.title.x = element_text(size = 12, hjust = 0.54, vjust = 0),
axis.title.y = element_text(size = 12, angle = 90, vjust = 0.25))
If you think you might need a more general approach, you could try function rxnNorm in package HandyStuff (github.com/bryanhanson/HandyStuff). Disclaimer: I'm the author. Disclaimer #2: the box plot option doesn't quite work right, but all the other options are fine.
Here's an example using the ToothGrowth data:
p <- rxnNorm(data = ToothGrowth, res = "len", fac1 = "dose", fac2 = "supp", freckles = TRUE, method = "iqr", fac2cols = c("red", "green"))
print(p)
a much easier way. without ddply. directly with ggplot2.
ggplot(ToothGrowth, aes(x = factor(dose) , y=len , group = supp, color = supp)) +
geom_boxplot() +
geom_smooth(method = lm, se=F) +
xlab("dose") +
ylab("len")