shosaco / vistime

Pretty timelines in R.
https://shosaco.github.io/vistime
GNU General Public License v3.0
168 stars 11 forks source link

Entering BC Dates #6

Open Archaeolithics opened 5 years ago

Archaeolithics commented 5 years ago

Is there a possibility to enter BC (Before Christ) dates to create timelines only based on year-numbers? Particularly crossing the BC/AD border?

shosaco commented 4 years ago

It is possible, albeit very hacky to workaround POSIXct's limitations. I came across a function as_BC_date, from this repository. Then you need to split the AC and BC parts of your data frame and handle them separately. A user sent me a working example. I didn't workt through it, but a proper timeline with BC and AC dates is returned, so if you want to check that out:

library(vistime)
library(rcarbon)
library(lubridate)

# from https://rdrr.io/github/mvazquezs/romanddbb/src/R/00_romanddbb.stats.R
as_BC_date <- function(year, month = 1, day = 1){
  if(year < 0) year<-(-year)
  Y <- as.character(year)
  M <- as.character(month)
  D <- as.character(day)
  fwdY <- paste(Y, "1", "1", sep = "/")
  fwdYMD <- paste(Y, M, D, sep = "/")
  AD0 <- lubridate::as_date("0000/1/1") ##merry xmas!
  n_AD0 <- as.numeric(AD0)
  n_fwdY <- as.numeric(lubridate::as_date(fwdY))
  n_MD <- as.numeric(lubridate::as_date(fwdYMD)) -
    as.numeric(lubridate::as_date(fwdY))
  n_BC <- n_AD0 - (n_fwdY - n_AD0) + n_MD
  if(n_MD==0) n_BC <- n_BC + 1
  BC_date <- lubridate::as_date(n_BC)
  return(BC_date)
}

data <- read.csv(text = "event, group, start,  end,   color, fontcolor
Period 1,  Anthropo-Environmental Period,  6000, 3000, #676767, White
Period 2,  Anthropo-Environmental Period,  3000, 800, #a6a6a6, White
First TOC, Groundwater (Carbon),  6000, 6000, #3973ac, Black
Peak TOC, Groundwater (Carbon),  1600, 1600, #6699cc, Black")

data[3]<-as.data.frame(BPtoBCAD(as.vector(t(data[3])))) #uses function from rcarbon to convert from BP to BCE/AD
data[4]<-as.data.frame(BPtoBCAD(as.vector(t(data[4])))) 
data_AD<-data #have to split the dataframe into two sections and treat BCE separately from AD
data[3][data[3]>0] <- NA #Anything AD is set to NA
data[4][data[4]>0] <- NA 
data_AD[3][data_AD[3]<0] <- NA #Anything BCE is set to NA
data_AD[4][data_AD[4]<0] <- NA 
data[3]<-as.data.frame(as_BC_date(as.numeric(t(data[3])))) #converts numbers to date (BCE)

data_AD[3]<-as.data.frame(as.Date(ISOdate(t(data_AD[3]),1,1))) #converts numbers to date (AD)
data_AD[4]<-as.data.frame(as.Date(ISOdate(t(data_AD[4]),1,1)))
data$start[is.na(data$start)] <- data_AD$start[match(data$event,data_AD$event)][which(is.na(data$start))] #recombine datasets
data$end[is.na(data$end)] <- data_AD$end[match(data$event,data_AD$event)][which(is.na(data$end))]
rm(data_AD) #remove surplus dataset
data <- as.data.frame(unclass(data)) #reformat
vistime(data) #visualise

result

ciology commented 3 years ago

The above solution only work if time is before 1000BC, it doesn't work for date such as 200BC.

` as_BC_date <- function(year, month = 1, day = 1){ if(year < 0) year<-(-year) Y <- as.character(str_pad(year,4, pad = "0")) ##I modified here M <- as.character(month) D <- as.character(day) fwdY <- paste(Y, "1", "1", sep = "/") fwdYMD <- paste(Y, M, D, sep = "/") AD0 <- lubridate::as_date("0000/1/1") ##merry xmas! n_AD0 <- as.numeric(AD0) n_fwdY <- as.numeric(lubridate::as_date(fwdY)) n_MD <- as.numeric(lubridate::as_date(fwdYMD)) - as.numeric(lubridate::as_date(fwdY)) n_BC <- n_AD0 - (n_fwdY - n_AD0) + n_MD if(n_MD==0) n_BC <- n_BC + 1 BC_date <- lubridate::as_date(n_BC)

BC_date <- as.Date(n_BC)

return(BC_date)

return(n_BC)

}

BCDate.start1 <- as_BC_date(-320, 1, 1) BCDate.end1 <- as_BC_date(-20, 1, 1)

BCDate.start2 <- as_BC_date(-1320, 1, 1) BCDate.end2 <- as_BC_date(-1120, 1, 1)

timeline_data <- data.frame(event = c("Event 1", "Event 2"), start = c(BCDate.start1, BCDate.start2), end = c(BCDate.end1, BCDate.end2), group = "My Events")

vistime(timeline_data)`

you will see that only Event 2 is shown. Any work around?

jcutlerbiostats commented 10 months ago

The code above from April 12, 2020, showing that you can enter BC dates, does not actually work. First of all, the as_BC_date function won't take a vector of years (e.g., from a column in a data frame). It will only take one year at a time, so that part would need to be modified. Also, that function fails when an NA year is passed into it, so that needs modification. Those modifications are easy, however. The biggest problem is that at the end of it all, even with those fixes, that code makes it look like you can pass a dataframe into vistime that has been unclassed. The problem there is that if you unclass it, vistime can no longer find the start and end columns. If you rename (one of) the start column back to "start", the next problem you encounter is that 'end' needs an origin. If you supply an origin of, say, 1970-01-01, there are no more errors, and vistime is able to output something, but it is completely wrong. If you supply an origin of, say, 0000-01-01, then you see more things on the graph, but it too is completely wrong. So, if it sounds like a good idea, I would love to re-open the issue, since nothing I've tried is able to make it show anything like the graph above.

jcutlerbiostats commented 10 months ago

Also it appears the less-than-1000 BC (encompassing years in the first millennium BC, or 1 to 999) problem persists. ggplot2 is able to handle BC dates from 1 to 999, so hopefully this isn't too big of a fix.