Rfanatic
Rfanatic

Reputation: 2290

Set the origin to start at 0 in ggplot

How can I set the origin / interception of the y-axis and x-axis in ggplot2?

I have a dataset like below (data structure at the end of question):

   Var1          Var2 value
1 04:00 Personal care     2
2 04:10 Personal care     2
3 04:20 Personal care     2
4 04:30 Personal care     2
5 04:40 Personal care     2

I am using the following code to plot my data

plot <- ggplot(melted_Activities, aes(x = Var1,y = value,fill = Var2)) +
         geom_col(position = "fill")  + 
         labs(x="Time", y="Probabilities", colour="Activties", fill="Activites") + 
         theme(legend.position="right", axis.text.x = element_text(angle = 0, hjust = 0)) + 
         annotate("rect", fill = "black", alpha = 0.3,
                  xmin = c(73), xmax = c(97), ymin = -Inf, ymax = Inf)

plot + scale_x_discrete(breaks = c("04:00","05:00", "06:00", "07:00","08:00", "09:00", 
                                   "10:00", "11:00", "12:00","13:00", "14:00", "15:00", 
                                   "16:00", "17:00", "18:00", "19:00", "20:00", "21:00",
                                    "22:00", "23:00", "00:00", "01:00", "02:00", "03:00"), 
                        expand = c(0,0)) + scale_y_continuous(expand = c(-0,0))

enter image description here

Data:

melted_Activities <- structure(list(Var1 = structure(1:5, .Label = c("04:00", "04:10", 
"04:20", "04:30", "04:40", "04:50", "05:00", "05:10", "05:20", 
"05:30", "05:40", "05:50", "06:00", "06:10", "06:20", "06:30", 
"06:40", "06:50", "07:00", "07:10", "07:20", "07:30", "07:40", 
"07:50", "08:00", "08:10", "08:20", "08:30", "08:40", "08:50", 
"09:00", "09:10", "09:20", "09:30", "09:40", "09:50", "10:00", 
"10:10", "10:20", "10:30", "10:40", "10:50", "11:00", "11:10", 
"11:20", "11:30", "11:40", "11:50", "12:00", "12:10", "12:20", 
"12:30", "12:40", "12:50", "13:00", "13:10", "13:20", "13:30", 
"13:40", "13:50", "14:00", "14:10", "14:20", "14:30", "14:40", 
"14:50", "15:00", "15:10", "15:20", "15:30", "15:40", "15:50", 
"16:00", "16:10", "16:20", "16:30", "16:40", "16:50", "17:00", 
"17:10", "17:20", "17:30", "17:40", "17:50", "18:00", "18:10", 
"18:20", "18:30", "18:40", "18:50", "19:00", "19:10", "19:20", 
"19:30", "19:40", "19:50", "20:00", "20:10", "20:20", "20:30", 
"20:40", "20:50", "21:00", "21:10", "21:20", "21:30", "21:40", 
"21:50", "22:00", "22:10", "22:20", "22:30", "22:40", "22:50", 
"23:00", "23:10", "23:20", "23:30", "23:40", "23:50", "00:00", 
"00:10", "00:20", "00:30", "00:40", "00:50", "01:00", "01:10", 
"01:20", "01:30", "01:40", "01:50", "02:00", "02:10", "02:20", 
"02:30", "02:40", "02:50", "03:00", "03:10", "03:20", "03:30", 
"03:40", "03:50"), class = "factor"), Var2 = structure(c(1L, 
1L, 1L, 1L, 1L), .Label = c("Personal care", "Sleep", "Eating", 
"Other personal care", "Employment", "Main job", "Second job", 
"Activites related to employment", "Study", "School or University", 
"Free time study", "House and family care", "Food management", 
"Household maintenance", "Making care for textiles", "Gardening and pet care", 
"Construction and repairs", "Shopping and services", "Household management", 
"Childcare of own household member", "Help to an adult household member", 
"Volunteer work and meeting", "Organisational work", "Informal help to others", 
"Participatory activties", "Social care", "Social life", "Entertainment and culture", 
"Resting", "Sport and outdoor activities", "Physical exercise", 
"Productive exercise", "Sportsrelated activities", "Hobbies, games and computing", 
"Arts and hobbies", "Computing", "PC Games", "Mass media", "Reading", 
"Tv and video", "Radio and music", "Travel and unspecified time use", 
"Travel by purpose", "Punctuating activity"), class = "factor"), 
 value = c(2, 2, 2, 2, 2)), row.names = c(NA, 5L), class = "data.frame")

Upvotes: 1

Views: 1079

Answers (1)

M--
M--

Reputation: 29202

Looking at the data and how it's been illustrated it seems that hours between midnight and before 4 are from the next day. That complicates the conversion of characters to datetime format just a bit. That's the reason behind if_else in the dplyr piping. Make sure that you are using dplyr::if_else since base::ifelse messes up the time format.

In the annotate you need to now insert the time that you want your "shadow box" appear instead of arbitrary numbers.

These said, expand_limits suggested in the comments work. Just note that R by default considers the current Sys.Date() when you are converting time-only strings to datetime. That's why in the expand_limits I use the converted datetime from the dataframe itself to account for that.

library(lubridate)
library(dplyr)
library(ggplot2)

melted_ActivitiesC <- melted_Activities %>% 
                       mutate(time = as.POSIXct(strptime(Var1, format="%H:%M"))) %>% 
                       mutate(time = if_else(hour(time) >= 4, time, 
                                                              time + as.difftime(1, unit="days")))



ggplot(melted_Activities, aes(x = time,y = value,fill = Var2)) +
  geom_col(position = "fill")  + 
  labs(x="Time", y="Probabilities", colour="Activties", fill="Activites") + 
  theme(legend.position="right", axis.text.x = element_text(angle = 0, hjust = 0)) + 
  annotate("rect", fill = "black", alpha = 0.3,
           xmin = as.POSIXct(strptime("16:00", format="%H:%M")), 
           xmax = as.POSIXct(strptime("24:00", format="%H:%M")), 
           ymin = -Inf, ymax = Inf) + scale_x_datetime(date_labels = "%H") + 
           expand_limits(x =floor_date(min(melted_Activities$time), "day"), y = 0)
                

Upvotes: 2

Related Questions