1

I've been trying to add appropriate dates on the x-axis of my graph, but can't figure out how to do it in a sane way. What I want is pretty simple: a date at every January 1st in between the minimum and maximum of my data set.

I don't want to include the month - just '2008' or '2009' or whatever is fine. A great example would be this graph:

example graph

Except I want the date on every year, rather than every other year.

I can't seem to figure this out. My dates are defined as days since 1/1/1970, and I've included a method dateEPOCH_formatter which converts the epoch format to a format using the chron package. I've figured out how to make a tick mark and date at the origin of the graph and every 365 days thereafter, but that's not quite the same thing.

Another minor problem is that, mysteriously, the line chron(floor(y), out.format="mon year",origin.=epoch) outputs a graph with axis markers like 'Mar 2008', but changing the line to chron(floor(y), out.format="year",origin.=epoch) doesn't give me a result like '2008' - it just results in the error:

Error in parse.format(format[1]) : unrecognized format year
Calls: print ... as.character.times -> format -> format.dates -> parse.format
Execution halted

Here's my code - thanks for the help.

library(ggplot2)
library(chron)
argv <- commandArgs(trailingOnly = TRUE)
mydata = read.csv(argv[1])
png(argv[2], height=300, width=470)


timeHMS_formatter <- function(x) {                  # Takes time in seconds from midnight, converts to HH:MM:SS
h <- floor(x/3600)
m <- floor(x %% 60)
s <- round(60*(x %% 1))                         # Round to nearest second
lab <- sprintf('%02d:%02d', h, m, s)        # Format the strings as HH:MM:SS
lab <- gsub('^00:', '', lab)                    # Remove leading 00: if present
lab <- gsub('^0', '', lab)                      # Remove leading 0 if present
}

dateEPOCH_formatter <- function (y){
epoch <- c(month=1,day=1,year=1970)
    chron(floor(y), out.format="mon year",origin.=epoch)
}

p=  ggplot() + 
coord_cartesian(xlim=c(min(mydata$day),max(mydata$day)), ylim=c(0,86400)) +         # displays data from first email through present
scale_color_hue() +
xlab("Date") +
ylab("Time of Day") +
scale_y_continuous(label=timeHMS_formatter, breaks=seq(0, 86400, 14400)) +              # adds tick marks every 4 hours
scale_x_continuous(label=dateEPOCH_formatter, breaks=seq(min(mydata$day), max(mydata$day), 365) ) +
ggtitle("Email Sending Times") +                                                        # adds graph title
theme( legend.position = "none", axis.title.x = element_text(vjust=-0.3)) +
theme_bw() +
layer(
    data=mydata, 
    mapping=aes(x=mydata$day, y=mydata$seconds), 
    stat="identity", 
    stat_params=list(), 
    geom="point", 
    geom_params=list(alpha=5/8, size=2, color="#A9203E"),
    position=position_identity(),
)   

print(p)
dev.off()
user1807967
  • 137
  • 1
  • 1
  • 6
  • 4
    This, and your previous question would improve if you included some example data (using `dput` or similar). I think it will be easier to use `scale_x_date` and `date_breaks` from the `scales` library that is associated with `ggplot2` – mnel Nov 08 '12 at 22:13

1 Answers1

4

I think it will be much easier to use the built in function scale_x_date with date_format and date_breaks from the scales package. These should work with most date classes in R, such as Date, chron etc

for example

library(ggplot2)
library(chron)
library(scales)

# some example data 
days <- seq(as.Date('01-01-2000', format = '%d-%m-%Y'),
            as.Date('01-01-2010', format = '%d-%m-%Y'), by = 1)

days_chron <- as.chron(days)
mydata <- data.frame(day = days_chron, y = rnorm(length(days)))

# the plot
ggplot(mydata, aes(x=days, y= y)) + geom_point() + 
 scale_x_date(breaks = date_breaks('year'), labels = date_format('%Y'))

enter image description here

To show how intuitive and easy these function are, if you wanted Montth-year labels every 6 months - note that this requires a very wide plot or very small axis labels

ggplot(mydata, aes(x=days, y= y)) + geom_point() +
   scale_x_date(breaks = date_breaks('6 months'), labels = date_format('%b-%Y'))

enter image description here

mnel
  • 113,303
  • 27
  • 265
  • 254