ggplot: re-order categorical y-axis (Gantt chart)

Viewed 475

I am trying to produce a Gantt chart out of a table with different task (each having a start date and end date).

library(tidyverse)

# Sample data
df1 <- data.frame(from = c("2020-01-01", "2020-02-02", "2020-05-04", "2020-02-01", "2020-01-20", "2020-02-10"),
                  to =   c("2020-03-30", "2020-03-15", "2020-05-20", "2020-04-05", "2020-03-05", "2020-04-13"),
                  task= c("Task 1", "Task 2", "Task 3", "Task 4", "Task 5", "Task 6"),
                  group = c("Finance", "Finance", "Research", "Research", "Other", "Other")
)

# Plot gantt-chart
df1 %>% mutate(from = as.Date(from),
               to = as.Date(to)) %>% 
  pivot_longer(cols = c(from, to), values_to = "date") %>%
  ggplot(aes(x=date, y=task, colour = group)) + 
  geom_line(lwd=3) +
  geom_point(aes(color=group), alpha=.5, pch=18, size=5) +
  scale_x_date(position="bottom", date_breaks = "1 week", date_labels="%U") +
  theme_bw() +
  theme(plot.title = element_text(hjust = 0.5))+
  ggtitle("Milestones") +
  labs(y="", x = "", colour="Responsible")

So far so good, but now I have a major problem and a minor problem:

major problem:

  • How can I re-order the categories on the y-axis as they appear in the data (not alphabetically)? From top to bottom it should be: Finance, Research, Other. Additionally, within each category (finance, research, other) the lines should be ordered by starting date (i.e. the task starting first should be on top)

minor problem:

  • on the x-axis how can I plot a thicker line for each month and a thinner line for each week?

Thanks for help!

1 Answers

This could be achieved like so:

  1. As @RuiBarrades mentioned in his comments to get the right order you have to convert to a factor and set the levels in the right order. First, set the levels for the groups. Second, to get the tasks in the desired order I rearrange the dataset by group and start date and make use of forcats::fct_inorder to set the levels of the tasks in the desired order.

  2. If I got you right you want different grid lines for week and month? This could be achieved by setting date_breaks_minor="month" and styling of the grid lines via theme and panel.grid.minor/major.x. Here I opted for a "black" color but if you prefer different sizes you could do so via size.

library(tidyverse)
library(ggplot2)

# Sample data
df1 <- data.frame(from = c("2020-01-01", "2020-02-02", "2020-05-04", "2020-02-01", "2020-01-20", "2020-02-10"),
                  to =   c("2020-03-30", "2020-03-15", "2020-05-20", "2020-04-05", "2020-03-05", "2020-04-13"),
                  task= c("Task 1", "Task 2", "Task 3", "Task 4", "Task 5", "Task 6"),
                  group = c("Finance", "Finance", "Research", "Research", "Other", "Other")
)

# Plot gantt-chart
df1 %>% mutate(from = as.Date(from),
               to = as.Date(to),
               group = factor(group, levels = c("Finance", "Research", "Other"))) %>%
  arrange(desc(group), desc(from)) %>% 
  mutate(task = forcats::fct_inorder(task)) %>% 
  pivot_longer(cols = c(from, to), values_to = "date") %>%
  ggplot(aes(x=date, y=task, colour = group)) + 
  geom_line(lwd=3) +
  geom_point(aes(color=group), alpha=.5, pch=18, size=5) +
  scale_x_date(position="bottom", date_breaks = "1 week", date_minor_breaks = "1 month",
               date_labels="%U") +
  theme_bw() +
  theme(plot.title = element_text(hjust = 0.5), 
        panel.grid.minor.x = element_line(color = "black"))+
  ggtitle("Milestones") +
  labs(y="", x = "", colour="Responsible")

Related