2

My current chart looks like this:

Sorry, not enough rep for embedding

What I want to achieve in the scale is something like this:

Sorry, not enough rep for embedding

So basically show the date and day in the middle of the interval and all single hours on those minor breaks.

Here is a reproducible example of the plot:

# Input load. Please do not change #
`dataset` = structure(list(JobName = structure(c(1L, 1L, 1L, 1L, 1L, 1L), .Label = "Job 1", class = "factor"),
    RunDateTime = structure(c(1479195000, 1479196617, 1479281400,
    1479281851, 1479367800, 1479368235), class = c("POSIXct",
    "POSIXt"), tzone = ""), EndRunDateTime = structure(c(1479195855,
    1479197916, 1479283032, 1479283032, 1479369407, 1479369407
    ), class = c("POSIXct", "POSIXt"), tzone = ""), Status = structure(c(1L,
    2L, 2L, 2L, 2L, 2L), .Label = c("failed", "successfull"), class = "factor"),
    GraphicColor = structure(c(2L, 1L, 1L, 1L, 1L, 1L), .Label = c("green",
    "red"), class = "factor")), .Names = c("JobName", "RunDateTime",
"EndRunDateTime", "Status", "GraphicColor"), row.names = c(NA,
6L), class = "data.frame")

# Original Script. Please update your script content here and once completed copy below section back to the original editing window #
vars <- c("RunDateTime", "EndRunDateTime")
dataset[vars] <- lapply(dataset[vars], as.POSIXct, format = "%Y-%m-%dT%H:%M:%S")
df <- with(dataset, data.frame(Name = JobName, Start = RunDateTime, End = EndRunDateTime, Status = Status))
library(ggplot2)
lims <- with(df, c(min(Start), max(End)))
ggplot(df, aes(color = Status)) +
geom_segment(aes(x = Start, xend = End, y = Name, yend = Name), size = 3) +
scale_x_datetime(date_breaks = "1 day", date_minor_breaks = "1 hour", limits = lims, labels = function(x) paste(format(x, "%a \n %d.%m.%y"))) +
xlab(NULL) +
ylab(NULL) +
scale_colour_manual(values = c("successfull" = "#a1d99b", "failed" = "red", "repeated" = "yellow", "canceled" = "grey")) +
theme_bw()

Would love to hear suggestions on how to get a scale like this!

SOLUTION:

I've chosen @Marijn Stevering solution and rearanged the code a bit:

vars <- c("RunDateTime", "EndRunDateTime")
dataset[vars] <- lapply(dataset[vars], as.POSIXct, format = "%Y-%m-%dT%H:%M:%S")
df <- with(dataset, data.frame(Name = JobName, Start = RunDateTime, End = EndRunDateTime, Status = Status))
library(ggplot2)
lims <- with(df, c(min(Start), max(End)))
library(dplyr)
library(lubridate)
dates <- data.frame(Date = df$Start)
minute(dates$Date) <- 0
second(dates$Date) <- 0
hour(dates$Date) <- 12
dates <- distinct(dates) %>%
  mutate(Label = paste(format(Date, "%a - %d.%m.%y")),
         DateRound = Date)
hour(dates$DateRound) <- 0

ggplot(df) +
  geom_segment(aes(x = Start, xend = End, y = Name, yend = Name, color = Status), size = 3) +
  # Add the major labels as a geom, this does limit to the plot area so have to put them above axis
geom_text(data = dates, aes(x = dates$Date, label = dates$Label, y = 0, vjust = -0.5),check_overlap = TRUE, size = 3.5) +
  # Add vertical lines to separate the days visually
geom_vline(data = dates, aes(xintercept = as.numeric(dates$DateRound)),linetype = "longdash") +
  scale_x_datetime(date_breaks = "2 hour", date_minor_breaks = "1 hour", limits = lims, labels = function(x) paste(format(x, "%H"))) +
  xlab(NULL) +
  ylab(NULL) +
  scale_colour_manual(values = c("successfull" = "#a1d99b", "failed" = "red", "repeated" = "yellow", "canceled" = "grey")) +
theme_bw() +
theme(axis.text.x = element_text(size = 7))

So now my scale looks like this, with which I can live very well.

enter image description here

Talvien
  • 47
  • 7
  • Here is a comment from Hadley, but it is a few years old... http://stackoverflow.com/questions/1554942/placement-of-axis-labels-at-minor-breaks-with-ggplot2 – drmariod Nov 23 '16 at 09:54
  • Yes, I know that answer, but actually it doesn't help. Moving the major breaks won't solve the problem. – Talvien Nov 23 '16 at 09:57
  • 1
    Related: [Multi-row x-axis labels in ggplot line chart](http://stackoverflow.com/questions/20571306/multi-row-x-axis-labels-in-ggplot-line-chart). – Henrik Nov 23 '16 at 10:49
  • Looks nice but unfortunately doesn't show jobs that run from one day into the next. – Talvien Nov 23 '16 at 12:43

2 Answers2

0

I think facets might help you achieve what you want.

    # Original Script. Please update your script content here and once completed             copy below section back to the original editing window #
vars <- c("RunDateTime", "EndRunDateTime")
dataset[vars] <- lapply(dataset[vars], as.POSIXct, format = "%Y-%m-%dT%H:%M:%S")
df <- with(dataset, data.frame(Name = JobName, Start = RunDateTime, End = EndRunDateTime, Status = Status))
library(ggplot2)
library(lubridate)
df <- transform(df,
                Date = as.Date(Start),
                DateStart = as.Date(Start),
                DateEnd = as.Date(End),
                HourStart = hour(Start),
                HourEnd = hour(End)) 

if(sum(df$DateStart != df$DateEnd) != 0){
  stop("At least one job runs in two different days.")
}

ggplot(df, aes(color = Status)) +
  geom_segment(aes(x = HourStart, xend = HourEnd, y = Name, yend = Name), size = 3) +
  xlab(NULL) +
  ylab(NULL) +
  scale_x_continuous(breaks = 0:24, limits = c(0,24)) +
  scale_colour_manual(values = c("successfull" = "#a1d99b",
  "failed" = "red", "repeated" = "yellow", "canceled" = "grey")) +
  theme_bw()+
  facet_grid(~Date)

This lets you group every day in one column and then you have the hours as labels on the axis. I know that it is not exactly how you drew it but it is how I would display it.

Watch out for the treatment of jobs that start in one day and finish in another.

I hope this helps.

Marc Flury
  • 341
  • 1
  • 7
  • Nice solution but yes you're right, jobs that run from one day to another are definitely a problem in this solution. :/ – Talvien Nov 23 '16 at 12:43
0

I tried solving it by making the axis labels the hours and then manually adding in the date labels. I did this using a geom_text but that is limited to the plot area, so it appears above the axis. Also the way I create the data for the geom_text is probably sub-optimal. The plot then looks like this: Plot

Generated with this code:

# Fiddling with dates, there is probably a better way to do this
library(dplyr)
library(lubridate)
dates <- data.frame(Date = df$Start)
minute(dates$Date) <- 0
second(dates$Date) <- 0
hour(dates$Date) <- 12
dates <- distinct(dates) %>% 
  mutate(Label = paste(format(Date, "%a \n %d.%m.%y")),
         DateRound = Date)
hour(dates$DateRound) <- 0


ggplot(df) +
  geom_segment(aes(x = Start, xend = End, y = Name, yend = Name, color = Status), size = 3) +
  # Add the major labels as a geom, this does limit to the plot area so have to put them above axis
  geom_text(data = dates, aes(x = Date, label = Label, y = 0, vjust = -0.2)) +
  # Add vertical lines to separate the days visually
  geom_vline(data = dates, aes(xintercept = as.numeric(DateRound))) +
  scale_x_datetime(date_breaks = "1 hour", date_minor_breaks = "1 hour", limits = lims, labels = function(x) paste(format(x, "%H"))) +
  xlab(NULL) +
  ylab(NULL) +
  scale_colour_manual(values = c("successfull" = "#a1d99b", "failed" = "red", "repeated" = "yellow", "canceled" = "grey")) +
  theme_bw()
Marijn Stevering
  • 1,204
  • 10
  • 24
  • Shouldn't it be able to move the dates out of the plot when switching of clipping with something like: df$layout$clip[df$layout$name=="panel"] <- "off" ? – Talvien Nov 23 '16 at 12:34
  • I've never done much with clipping, but if you can turn it off you can just place the labels underneath the axis by changing the `vjust` to a positive value. – Marijn Stevering Nov 23 '16 at 13:52
  • I tried it. It generally works, but it pushes the text out of the visible window, so not a solution. – Talvien Nov 23 '16 at 14:29