1

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

Timeline Example

2
  • Can you show what you've tried using ggplot? Commented Jan 20, 2017 at 2:43
  • Edited original post with final product. Commented Jan 20, 2017 at 22:50

1 Answer 1

3

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))

enter image description here

Sign up to request clarification or add additional context in comments.

3 Comments

Excellent. If this answer helped you, please accept it as correct :)
Edited original post with final product
In my case the id was a factor. It was useful to put y=id in the main aes. This handled the right vertical axis labels.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.