Search code examples
rggplot2lubridate

Plotting time intervals in R and tiling for several years


I am currently trying to plot the effort in sampling for my masters thesis, which looks something similar to this:

Figure 1:

enter image description here

So i have data for 3 years, and i want to reflect the exact days of the month when each deployment started and finished. But in R, i only manage to plot the following:

Figure 2:

enter image description here

The thing is, i would like my plot to show only the 12 months in the x axis and overlap the years on the y axis, so that the figure is "slimmer". I am guessing i have to somehow take out the year of the POSIXct dates, but i do not manage to represent the intervals as precisely then.

I did a subset of my data for this question and my script looks like this:

library(ggplot2)      
library(scales)
library(tidyverse)
library(dplyr)
library(lubridate)

Deployment3 <- seq(from = as.Date("2021-12-15"), to = as.Date("2021-12-31"), by = "day"); 
deploy3 <- data.frame(count=1:length(Deployment3)); 
deploy3$day <- Deployment3; 
deploy3$year <- format(Deployment3, "%Y");  
deploy3$id <- "Deployment 3"
deploy3$start <- as.Date("2021-12-15"); deploy3$end <- as.Date("2021-12-31"); 

Deployment7 <- seq(from = as.Date("2022-12-17"), to = as.Date("2022-12-31"), by = "day"); 
deploy7 <- data.frame(count=1:length(Deployment7)); deploy7$day <- Deployment7; 
deploy7$year <- format(Deployment7, "%Y");  deploy7$id <- "Deployment 7";
deploy7$start <- as.Date("2022-12-17"); deploy7$end <- as.Date("2022-12-31");

Deployment7b <- seq(from = as.Date("2023-01-01"), to = as.Date("2023-01-31"), by = "day"); 
deploy7b <- data.frame(count=1:length(Deployment7b)); deploy7b$day <- Deployment7b; 
deploy7b$year <- format(Deployment7b, "%Y");  deploy7b$id <- "Deployment 7"
deploy7b$start <- as.Date("2023-01-01"); deploy7b$end <- as.Date("2023-01-31")

deployments <- bind_rows(deploy3,deploy7,deploy7b)
deployments$start <- as.Date(deployments$start)
deployments$end <- as.Date(deployments$end)

ggplot(deployments) + 
geom_tile(aes(x = start, y = as.factor(year), width = end - start), height = 0.4) +
scale_x_date(date_labels = "%b", date_breaks = "1 month", expand = c(0, 0)) +  
labs(x = "Month", y = "Year") +
theme_minimal() +
theme(axis.text.x = element_text(angle = 45, hjust = 1))

If somebody would have any idea or suggestion to make the fig.2 more similar to fig.1 would be great.

Thank you and cheers!


Solution

  • I've used line segments that I group by year and in this case, deployment, so they can span multiple years, my x axis is the day of the year, with months as labels:

    library(ggplot2)      
    library(scales)
    library(tidyverse)
    library(dplyr)
    library(lubridate)
    
    df <- tribble(
      ~start, ~end,
      "2021-09-25", "2021-11-08",  
      "2021-11-16", "2021-11-30",
      "2021-12-08", "2022-01-02",
      "2022-04-15", "2022-06-07",
      "2022-08-15", "2022-11-30",
      "2022-12-15", "2023-01-20",
      "2023-02-15", "2023-04-07",
      "2023-07-07", "2023-08-14",
      "2023-08-15", "2023-09-30",
      "2023-10-10", "2023-11-30"
      )  |> 
      mutate(deployment = paste0("D", row_number())) |>
      mutate(across(start:end, ymd)) |>  
      reframe(day = seq.Date(start, end, "day"), .by = c(deployment, start, end)) |>  
      mutate(year = year(day),
             yday = yday(day),
             group = paste(year, deployment, sep = "_")
             )
    
    tail(df)
    
    ggplot(data = df) +
      coord_cartesian(clip = 'off') +
      geom_line(aes(
        x = yday, 
        y = year, 
        group = group, 
        color = deployment
      ),
      alpha = .5,
      linewidth = 12)+
      scale_y_reverse(
        breaks = sort(unique(df$year)), 
        limits = rev(range(unique(df$year)) + c(-.8, .8))
      )+
      scale_x_continuous(
        breaks = yday(seq(from = as.Date("2021-01-15"), to = as.Date("2021-12-15"), by = "month")),
        labels = month.abb,
        position = "top"
      )+
      labs(x = "", y = "")+
      theme_void()+
      theme(aspect.ratio = 1/4,
            legend.position = "none",
            axis.text = element_text(size = 12),
            panel.grid.minor.y = element_line(color = "grey95", linewidth = .5),
      )