I find some R code to do forest plot using ggplot2, combining figure with text. However, when I run the code, there is an error reported and text frame did not come out, although the figure looks good. I will very appreciate any suggestions on how to correct the code. Thanks!
library(ggplot2)
library(gridExtra)
dat <- data.frame(group = factor(c("A","B","C","D","E","F","G"),
levels=c("F","E","D","C","B","A","G")),
cen = c(3.1,2.0,1.6,3.2,3.6,7.6,NA),
low = c(2,0.9,0.8,1.5,2,4.2,NA),
high = c(6,4,2,6,5,14.5,NA))
theme_set(theme_bw())
theme_update(
axis.line = element_line(colour = "black"),
panel.grid.major = element_blank(),
panel.grid.minor = element_blank(),
panel.border = element_blank(),
panel.background = element_blank(),
axis.text.y = element_blank(),
axis.ticks.y = element_blank(),
plot.margin = unit(c(0,0,0,0), "lines")
)
lab <- data.frame(
V0 = factor(c("A","B","C","D","E","F","G","A","B","C","D","E","F","G",
"A","B","C","D","E","F","G","A","B","C","D","E","F","G"),
levels=c("G","F","E","D","C","B","A")),
V05 = rep(c(1,2,3,4),each=7),
V1=c("Occuption","Active","","Inactive","","Inactive","","Recreation",
"Inactive","", "Active","","Inactive","",
"Gender","Men","Women","Men","Women","Men","Women",
"OR",3.1,2.0,1.6,3.2,3.6,7.6))
data_table <- ggplot(lab, aes(x = V05, y = V0,
label = format(V1, nsmall = 1))) +
geom_text(size = 4, hjust=0, vjust=0.5) + theme_bw() +
geom_hline(aes(yintercept=c(6.5,7.5))) +
theme(panel.grid.major = element_blank(),
legend.position = "none",
panel.border = element_blank(),
axis.text.x = element_text(colour="white"),#element_blank(),
axis.text.y = element_blank(),
axis.ticks = element_line(colour="white"),#element_blank(),
plot.margin = unit(c(0,0,0,0), "lines")) +
labs(x="",y="") +
coord_cartesian(xlim=c(1,4.5))
p
data_table
##{r forest_plot_1, fig.width=8, fig.height=4, tidy=F}
grid.arrange(data_table, p, ncol=2)
Something wrong here as shown below:
Warning messages:
1: Removed 1 rows containing missing values (geom_point).
2: Removed 1 rows containing missing values (geom_errorbarh).
data_table
Error: Aesthetics must be either length 1 or the same as the data (28): yintercept
{r forest_plot_1, fig.width=8, fig.height=4, tidy=F}
grid.arrange(data_table, p, ncol=2)
Error: Aesthetics must be either length 1 or the same as the data (28): yintercept
I think the error is in the horizontal line layer. Here is the code that worked for me
data_table <- ggplot(lab, aes(x = lab$V05, y = lab$V0, label = format(V1, nsmall = 1))) +
geom_text(size = 4, hjust=0, vjust=0.5) + theme_bw() +
geom_hline(aes(yintercept=6.5)) +
geom_hline(aes(yintercept=3))
Related
This is my script for the plot,
data = data.frame(Kingdom = c("Bacteria", "Archaea"),
Total = c(273523, 2616))
sizeRange <- c(0,30)
library(ggplot2)
ggplot(data, aes(x=0,y=Kingdom,color=Kingdom)) +
geom_point(aes(size = Total,alpha=10),colour="blue",stroke=2) +
scale_size(range = sizeRange)+
theme_bw() +
theme(panel.border = element_blank(),
panel.grid.major = element_blank(),
panel.grid.minor = element_blank(),
axis.line = element_line(colour = "white"))
somebody, please tell me how can I get a connecting line between my y-axis label and the plot
My plot looks like this
I want something like this
A clean alternative would be to label the points directly, and remove the y-axis if wanted. e.g.:
ggplot(data, aes(x=0,y=Kingdom,color=Kingdom)) +
ggrepel::geom_text_repel(aes(label = Kingdom), vjust = -1,colour="black") +
geom_point(aes(size = Total),colour="blue",stroke=2) +
scale_size(range = sizeRange)+
theme_bw() +
theme(panel.border = element_blank(),
panel.grid.major = element_blank(),
panel.grid.minor = element_blank(),
axis.line = element_line(colour = "white"),
axis.text.y=element_blank(),
axis.title.y = element_blank(),
axis.ticks.y=element_blank())
you can manually add segments, but then the alpha of your points will kind of show them.
Here is a try, altought it's not perfect if the x axis expend.
ggplot(data, aes(x=0,y=Kingdom,color=Kingdom)) +
# Added the segments here before the points.
# I tried to alpha it but I can't figure out how to limit the
# segment to the point border.
geom_segment(x = rep(-100,2), xend = rep(0,2),
y = c(1, 2), yend = c(1,2),colour="blue", alpha = 10) +
geom_point(aes(size = Total,alpha=10),colour="blue",stroke=2) +
scale_size(range = sizeRange)+
theme_bw() + guides(alpha = "none") + # remove alpha from legend.
theme(panel.border = element_blank(),
panel.grid.major = element_blank(),
panel.grid.minor = element_blank(),
axis.line = element_line(colour = "white"))
I have two plots I would like to combine. My data looks like this:
Year<-rep(2001:2005, each = 5)
name<-c("John","Ellen","Mark","Randy","Luisa")
Name<-c(rep(name,5))
Value<-sample(seq(0,25,by=1),25)
mydata<-data.frame(Year,Name,Value)
This is the first barplot:
tot<-aggregate(mydata$Value,list(mydata$Year),FUN=sum)
tot_y<-tot$x
tot_x<-tot$Group.1
tot_barplot <- ggplot(tot, aes(x=tot_x,y=tot_y)) +
geom_bar(stat = "identity",fill="#73D055FF") +
scale_y_continuous(limits = c(0, 125), breaks = seq(0, 125, by = 25)) +
#xlab("Pathways") +
#ylab("N° of species") +
theme(axis.line = element_blank(),
axis.text.x=element_blank(),
axis.text.y=element_text(size=14,margin=margin(l=10),colour="black"),
axis.ticks = element_blank(),
axis.title=element_blank(),
panel.grid.major = element_blank(),
panel.grid.minor = element_blank(),
panel.background = element_blank())
tot_barplot
And this is the second plot:
p <- ggplot(mydata, aes(x=Year, y=Name, size = Value)) +
geom_point(aes(fill = Value,
alpha = I(as.numeric(Value > 0))), shape=21, colour = "black") +
scale_fill_viridis_c(option = "D", direction = -1,limits = c(1, 25), breaks=seq(1, 25, 5))+
scale_size_area(guide = "none") +
ylab("Name") +
theme(axis.line = element_blank(),
axis.text.x=element_text(size=11,margin=margin(b=10),colour="black"),
axis.text.y=element_text(size=13,margin=margin(l=10),colour="black",
face="italic"),
axis.ticks = element_blank(),
axis.title=element_text(size=18,face="bold"),
panel.grid.major = element_blank(), panel.grid.minor = element_blank(),
panel.background = element_blank(),
legend.text = element_text(size=14),
legend.title = element_text(size=18))
p
I combine them like this:
grid.arrange(arrangeGrob(tot_barplot,p,nrow=2))
Now I would like to re-size the barplot to fit it better to the second plot (imagine that the original data produce a wider barplot where the bars start above the Name and end above the legend Value). I would like the bars of the barplot to be exactly centred above the line of points and the Year, but I am not very familiar with ggplot aesthetics.
Any suggestion would be appreciated. Thanks!
I'd like to make a forest plot for my project. Since it is not a typical forest plot built-in any R package, I found the first figure of this page is helpful to my goal, a side table accompanied with the forest plot:
https://mcfromnz.wordpress.com/2012/11/06/forest-plots-in-r-ggplot-with-side-table/
The code which produces that particular figure is pasted below (the original link:https://github.com/nzcoops/blog_code/blob/master/forest_plot.Rmd)
The problem that I ran into is in the "data_table" step. An error pop up when I type the following in R:
data_table
Error: Aesthetics must be either length 1 or the same as the data (28): yintercept
I guess the issue came from geom_hlinein data_table.
After some online search and some try-and-error, I still cannot get rid of that error message and wonder if I can get some help here. Thanks in advance for your help.
--Code that particular produce the first figure:
library(ggplot2)
library(gridExtra)
dat <- data.frame(group = factor(c("A","B","C","D","E","F","G"), levels=c("F","E","D","C","B","A","G")),
cen = c(3.1,2.0,1.6,3.2,3.6,7.6,NA),
low = c(2,0.9,0.8,1.5,2,4.2,NA),
high = c(6,4,2,6,5,14.5,NA))
theme_set(theme_bw())
theme_update(
axis.line = element_line(colour = "black"),
panel.grid.major = element_blank(),
panel.grid.minor = element_blank(),
panel.border = element_blank(),
panel.background = element_blank(),
axis.text.y = element_blank(),
axis.ticks.y = element_blank(),
plot.margin = unit(c(0,0,0,0), "lines"))
p <- ggplot(dat,aes(cen,group)) +
geom_point(size=5, shape=18) +
geom_errorbarh(aes(xmax = high, xmin = low), height = 0.15) +
geom_vline(xintercept = 1, linetype = "longdash") +
scale_x_continuous(breaks = seq(0,14,1), labels = seq(0,14,1)) +
labs(x="Adjusted Odds Ratio", y="")
data_table <- ggplot(lab, aes(x = V05, y = V0, label = format(V1, nsmall = 1))) +
geom_text(size = 4, hjust=0, vjust=0.5) + theme_bw() +
geom_hline(aes(yintercept=c(6.5,7.5))) +
theme(panel.grid.major = element_blank(),
legend.position = "none",
panel.border = element_blank(),
axis.text.x = element_text(colour="white"),#element_blank(),
axis.text.y = element_blank(),
axis.ticks = element_line(colour="white"),#element_blank(),
plot.margin = unit(c(0,0,0,0), "lines")) +
labs(x="",y="") +
coord_cartesian(xlim=c(1,4.5))
lab <- data.frame(V0 = factor(c("A","B","C","D","E","F","G","A","B","C","D","E","F","G","A","B","C","D","E","F","G","A","B","C","D","E","F","G"),, levels=c("G","F","E","D","C","B","A")),
V05 = rep(c(1,2,3,4),each=7),
V1 = c("Occuption","Active","","Inactive","","Inactive","","Recreation","Inactive","","Active","","Inactive","","Gender","Men","Women","Men","Women","Men","Women","OR",3.1,2.0,1.6,3.2,3.6,7.6))
data_table <- ggplot(lab, aes(x = V05, y = V0, label = format(V1, nsmall = 1))) +
geom_text(size = 4, hjust=0, vjust=0.5) + theme_bw() +
geom_hline(aes(yintercept=c(6.5,7.5))) +
theme(panel.grid.major = element_blank(),
legend.position = "none",
panel.border = element_blank(),
axis.text.x = element_text(colour="white"),#element_blank(),
axis.text.y = element_blank(),
axis.ticks = element_line(colour="white"),#element_blank(),
plot.margin = unit(c(0,0,0,0), "lines")) +
labs(x="",y="") +
coord_cartesian(xlim=c(1,4.5))
The easiest fix would be separating geom_hline into 2 different calls
data_table <- ggplot(lab, aes(x = V05, y = V0, label = format(V1, nsmall = 1))) +
geom_text(size = 4, hjust=0, vjust=0.5) + theme_bw() +
geom_hline(aes(yintercept=c(6.5))) +
geom_hline(aes(yintercept=c(7.5))) +
theme(panel.grid.major = element_blank(),
legend.position = "none",
panel.border = element_blank(),
axis.text.x = element_text(colour="white"),#element_blank(),
axis.text.y = element_blank(),
axis.ticks = element_line(colour="white"),#element_blank(),
plot.margin = unit(c(0,0,0,0), "lines")) +
labs(x="",y="") +
coord_cartesian(xlim=c(1,4.5))
data_table
Created on 2018-03-31 by the reprex package (v0.2.0).
You don't need to use aes() with geom_hline (only use aes() if you want a horizontal line for every row of your data.) You can just do:
geom_hline(yintercept = c(6.5, 7.5))
This is explained in the help, see ?geom_hline for more details.
This is currently my code for the figure above
ggplot(AllData, aes(Year, AGResiduals, fill=Type)) +
geom_boxplot(outlier.size=0) +
scale_fill_manual(values=c("skyblue4", "skyblue"),
name="Male Type",
labels=c("Guarders","Sneakers")) +
labs(x=NULL, y = "Residual of Accessory Gland Mass x Total Mass") +
scale_x_discrete(limits=c("2007","2008","2010","2011","2013","2014","2015"),
labels=str_wrap(c("2007 (nG=37, nS=8)","2008 (nG=4, nS=6)","2010 (nG=31, nS=6)","2011 (nG=55, nS=5)","2013 (nG=202, nS=24)","2014 (nG=63)","2015 (nG=59, nS=3)"),
width=6)) +
theme(plot.title = element_text(size = rel(1.4)),
axis.title = element_text(size = rel(1.2)),
axis.text.x = element_text(size = rel(1.5)),
axis.text.y = element_text(size = rel(1.5)),
panel.grid.major = element_blank(),
panel.grid.minor = element_blank(),
panel.background = element_blank(),
axis.line = element_line(colour = "black"))
I want to make the "G" and "S"'s in each x-axis tick labels subscript (they designate sample size for two different groups, G and S).
Writing
expression(2007 (n[G]=37, n[S]=8)
works, but only if I remove the preceding
str_wrap
code for some reason.
I need to constrain the width of the text for each x-axis tick label, so I need to retain str_wrap or use line breaks within the expression function somehow.
I also can't replace my list of labels with a factor since I have to set limits on the years I want to show.
Can someone please help on how to make a 3-line x-axis tick label that allows for subscript?
I couldn't find a way to display expressions on multiple lines, but you could try rotating the labels:
library(stringr)
library(ggplot2)
library(scales)
library(dplyr)
n <- 100
y <- as.character(sample(2007:2015,n,replace=T))
t <- sample(c("Guarders","Guarders","Sneakers"),n,replace=T)
r <- rnorm(n,10,20)
nsk <- sum(t=="Sneakers")
r[ t=="Sneakers" ] <- rnorm(nsk,1,5)
AllData <- data.frame(Year=y,AGResiduals=r,Type=t)
sdf <- AllData %>% group_by( Year ) %>%
summarize( n=n(), ng=sum(Type=="Guarders") )
fmts <- rep("%s (n[G]==%d) ~~ (n[S]==%d)",nrow(sdf))
labs2 <- do.call(sprintf,list(fmts,sdf$Year,sdf$ng, sdf$n-sdf$ng ) )
ex2 <- parse(text=labs2)
ggplot(AllData, aes(Year, AGResiduals, fill=Type)) +
geom_boxplot(outlier.size=0) +
scale_fill_manual(values=c("skyblue4", "skyblue"),
name="Male Type",
labels=c("Guarders","Sneakers")) +
labs(x=NULL, y = "Residual of Accessory Gland Mass x Total Mass") +
scale_x_discrete(limits=c("2007","2008","2010","2011","2013","2014","2015"),
labels=ex2) +
theme(plot.title = element_text(size = rel(1.4)),
axis.title = element_text(size = rel(1.2)),
axis.text.x = element_text(size = rel(1.0),angle=-30,hjust=0),
axis.text.y = element_text(size = rel(1.5)),
panel.grid.major = element_blank(),
panel.grid.minor = element_blank(),
panel.background = element_blank(),
axis.line = element_line(colour = "black"))
Yields this:
Rawr made a suggestion that allows you to get two, but not three lines. Since it doesn't require rotation, I am entering it as a second solution.
This:
library(stringr)
library(ggplot2)
library(scales)
library(dplyr)
set.seed(23456)
n <- 100
y <- as.character(sample(2007:2015,n,replace=T))
t <- sample(c("Guarders","Guarders","Sneakers"),n,replace=T)
r <- rnorm(n,10,20)
nsk <- sum(t=="Sneakers")
r[ t=="Sneakers" ] <- rnorm(nsk,1,5)
AllData <- data.frame(Year=y,AGResiduals=r,Type=t)
sdf <- AllData %>% group_by( Year ) %>%
summarize( n=n(), ng=sum(Type=="Guarders") )
fmts <- rep("atop(%s, n[G]==%d ~~ n[S]==%d)",nrow(sdf)) # two rows
labs2 <- do.call(sprintf,list(fmts,sdf$Year,sdf$ng, sdf$n-sdf$ng ) )
ex2 <- parse(text=labs2)
ggplot(AllData, aes(Year, AGResiduals, fill=Type)) +
geom_boxplot(outlier.size=0) +
scale_fill_manual(values=c("skyblue4", "skyblue"),
name="Male Type",
labels=c("Guarders","Sneakers")) +
labs(x=NULL, y = "Residual of Accessory Gland Mass x Total Mass") +
scale_x_discrete(limits=c("2007","2008","2010","2011","2013","2014","2015"),
labels=ex2) +
theme(plot.title = element_text(size = rel(1.4)),
axis.title = element_text(size = rel(1.2)),
axis.text.x = element_text(size = rel(1.0),angle=0,hjust=0),
axis.text.y = element_text(size = rel(1.5)),
panel.grid.major = element_blank(),
panel.grid.minor = element_blank(),
panel.background = element_blank(),
axis.line = element_line(colour = "black"))
yields this:
I am using ggplot to plot a time series am running into a problem extending the extents of the x axis. I developed the following code to provide a reducible example.
#Dummy Data
Dates <- data.frame(Date = c("1992-11-21","1993-10-26","1995-05-12","1996-03-03","1999-05-22","2008-04-13"))
Volume <- data.frame(Volume = c("28947.548","29947.262","30842.333","27192.588","30209.414","24439.897"))
Errors <- data.frame(Errors = c("4118.903","1974.606","1843.382","1920.362","1905.469","1977.074"))
ID <- data.frame(ID = c("a","a","a","b","b","b"))
Merge_Data <- data.frame(Dates,Volume,Errors,ID)
#convert Dates to native format in R
Merge_Data$Date <- as.Date(Merge_Data$Date,"%Y-%m-%d")
#Convert Areas to numbers
Merge_Data$Volume <- as.numeric(as.character(Merge_Data$Volume))
Merge_Data$Errors <- as.numeric(as.character(Merge_Data$Errors))
#Plot the Data
ggplot(Merge_Data, aes(x = Date, y = Volume, color = ID)) +
scale_color_manual(values = c("#000000", "#0000BB")) +
geom_errorbar(aes(ymin=Volume-Errors,ymax=Volume+Errors), width=100,size=0.1) +
geom_point(size = 2) +
geom_line(size = 0.5)+
scale_x_date(labels = date_format("%Y"), breaks = date_breaks("2 year"))+
xlab("Date")+
ylab("Volume, in cubic meters")+
ylim(0,max(Merge_Data$Volume)+20000)+
theme(axis.line = element_line(colour = "black"),
panel.grid.major = element_blank(),
panel.grid.minor = element_blank(),
panel.border = element_blank(),
panel.background = element_rect(colour="black",fill = "white",),
axis.text = element_text(colour = "black"),
legend.background = element_rect(colour = "black"),
legend.key = element_rect(color=NA, fill="white"),
legend.title = element_blank(),
legend.position=c(0.9,0.9))
I need to extend the extents of the x axis to begin at 1990 and end at 2014. I have experimented using the limits expression in the scale_x_Date line but not had any luck.
Thanks in advance,
dubbbdan
I figured it out!!
You just need to change the scale_x_date line to include a lim= expression.
#Dummy Data
Dates <- data.frame(Date = c("1992-11-21","1993-10-26","1995-05-12","1996-03-03","1999-05-22","2008-04-13"))
Volume <- data.frame(Volume = c("28947.548","29947.262","30842.333","27192.588","30209.414","24439.897"))
Errors <- data.frame(Errors = c("4118.903","1974.606","1843.382","1920.362","1905.469","1977.074"))
ID <- data.frame(ID = c("a","a","a","b","b","b"))
Merge_Data <- data.frame(Dates,Volume,Errors,ID)
#convert Dates to native format in R
Merge_Data$Date <- as.Date(Merge_Data$Date,"%Y-%m-%d")
#Convert Areas to numbers
Merge_Data$Volume <- as.numeric(as.character(Merge_Data$Volume))
Merge_Data$Errors <- as.numeric(as.character(Merge_Data$Errors))
#Plot the Data
ggplot(Merge_Data, aes(x = Date, y = Volume, color = ID)) +
scale_color_manual(values = c("#000000", "#0000BB")) +
geom_errorbar(aes(ymin=Volume-Errors,ymax=Volume+Errors), width=100,size=0.1) +
geom_point(size = 2) +
geom_line(size = 0.5)+
scale_x_date(lim = c(as.Date("1990-1-1"), as.Date("2014-1-1")),labels = date_format("%Y"), breaks = date_breaks("2 year"))+
xlab("Date")+
ylab("Volume, in cubic meters")+
ylim(0,max(Merge_Data$Volume)+20000)+
theme(axis.line = element_line(colour = "black"),
panel.grid.major = element_blank(),
panel.grid.minor = element_blank(),
panel.border = element_blank(),
panel.background = element_rect(colour="black",fill = "white",),
axis.text = element_text(colour = "black"),
legend.background = element_rect(colour = "black"),
legend.key = element_rect(color=NA, fill="white"),
legend.title = element_blank(),
legend.position=c(0.9,0.9))