Reputation: 71
Edited below with complete and functioning code:
I am trying to create a timeline similar to the one this code creates from the Timeline package, however, the options are not very flexible. For example, I would like to create space between each bar so they are not touching. Also, I am wondering if there is a way to add the "End_Status" column to the graph so that it it is obvious that the data stops there because the animal died. Any help is greatly appreciated.
Example dataset:
df <- data.frame(id = c(rep(1201, 10), rep(1202, 14), rep(1203, 6), rep(1204, 22)),
date = c(seq(1,5,1), seq(5,7,1), seq(7,8,1), seq(2,5,1), seq(7,9,1), seq(11,17,1), seq(1,8,1), seq(8,12, 1), seq(12,26,1 )),
schedule = as.factor(c(rep(1, 5,), rep(2, 3), rep(3, 6),
rep (1, 3), rep (2, 2), rep(3, 5),
rep(1,8), rep(2, 5), rep(1,3), rep(3, 12))),
status = c(rep("", 9), "Mort", rep("", 41), "Mort"))
Code to get the output table I am interested in:
library("data.table")
library(plyr)
library(dplyr)
df<-as.data.table(df)
z <- df[, unique(id)]
################
value_change_first <- function(x,a) { for(i in 1:length(x[,schedule])) {
ifelse(x[a,schedule] == x[a+1,schedule],
x <- x[-(a+1)],
a <- a+1)}
return(x)
}
value_change_second <- function(x,a) {
for(i in 1:length(x[,schedule])) {
ifelse(x[a,schedule] == x[a+1,schedule],
x <- x[-(a)],
a <- a+1)}
return(x)
}
#################
output_1 <- c()
for(i in 1:length(z)){
ids <- df[df$id==z[i],]
out<-value_change_first(ids,1)
output_1<-as.data.frame(rbind(output_1, out))}
#################
output_2 <- c()
for(i in 1:length(z)){
ids <- df[df$id==z[i],]
out<-value_change_second(ids,1)
output_2<-as.data.frame(rbind(output_2, out))}
################
output_1$End_Date <- output_2$date
output_1$End_Status <- output_2$status
names(output_1)[names(output_1)=="date"] <- "Start_Date"
output <- output_1[c(1:2, 5, 3, 6)]
From here I can use the Timeline Package to get something close to what I want:
require(timeline)
tl <- timeline(output,
label.col=names(output)[4],
text.color= NA,
group.col=names(output)[1],
start.col=names(output)[2],
end.col = names(output)[3])
tl + theme_bw() + theme(panel.grid.major = element_blank(), panel.grid.minor = element_blank())
My question is how to build something similar in ggplot. Furthermore, I want to specifically add the "Mort" message at a given date by individual from the output dataframe.
I ended up getting this to work like I want:
### creating a end status column that includes mortalities and failures
output$End_Status_Date<-NA
for(i in 1:nrow(output)){
if(output$End_Status[i] == "Mort"){
output$End_Status_Date[i]=as.character(output$End_Date)[i]
}
}
for(i in 1:nrow(output)){
if(output$End_Status[i] == "Failure"){
output$End_Status_Date[i]=as.character(output$End_Date)[i]
}
}
### data structuring
output$id<-as.factor(output$id)
output$End_Status_Date<-as.numeric(output$End_Status_Date)
output$End_Status[output$End_Status == ""] <- NA
output$End_Status<-as.character(output$End_Status)
output$End_Status<-as.factor(output$End_Status)
library(ggplot2)
g2 <- ggplot() +
geom_segment(data=output, aes(x=Start_Date, xend=End_Date, y=id, yend=id, color=schedule), linetype=1, size=2) +
geom_point(data=subset(output, is.na(End_Status)==FALSE),
mapping=aes(x=End_Status_Date, y=id, shape=End_Status, fill=End_Status), size=4)+
scale_colour_manual(values=c("blue4", "chartreuse4", "darkmagenta"))+
scale_fill_manual(values=c("white", "red"))+
scale_shape_manual(values=c(21,24))+
xlab("Time")+
ylab("Individuals")+
theme_bw() + theme(panel.grid.minor = element_blank(), panel.grid.major = element_blank())
g2
Upvotes: 1
Views: 2705
Reputation: 4109
You did most of the work already. The key here is just to use geom_rect
and take advantage of your y-axis labels to set the ymin and ymax values.
ggplot(output, aes(xmin = Start_Date, xmax = End_Date,
ymin = as.numeric(id) - 1, ymax = as.numeric(id),
fill = schedule)) +
geom_rect() +
geom_text(aes(x = End_Date, y = id, label = End_Status))
Upvotes: 3