1

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")
Community
  • 1
  • 1
Rfanatic
  • 2,224
  • 1
  • 5
  • 21
  • `expand` isn't a limit, it's the amount by which you would expand the scope of the scale. You want the `limits` argument. – camille May 14 '19 at 15:14
  • 1
    Possible duplicate of [Force the origin to start at 0](https://stackoverflow.com/questions/13701347/force-the-origin-to-start-at-0) – camille May 14 '19 at 15:15
  • 1
    @camille try the solution. At the end it works, but needs other steps taken before the point which that solution becomes valid. – M-- May 14 '19 at 15:25
  • 1
    @M-M that's fair, I didn't realize the times were encoded as characters. If you convert the times to an actual datetime object, this will be easier, and you can format it however you want. There are a lot of posts covering that as well. The crux of it is that the wrong argument was set in the scale. – camille May 14 '19 at 15:35
  • @camille There's a slight complication involved in conversion as well. All in all, I am hesitant to close the question. Cheers. – M-- May 14 '19 at 15:38

1 Answers1

2

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)
                
M--
  • 25,431
  • 8
  • 61
  • 93
  • 1
    @user10974052 you're welcome. A comment on the side. The point about *hours between midnight and 4 are from the next day*, that'd be better if you had it cleared in your question. It may not be obvious to folks trying to answer your question. It's the best to have all the information laid out. Cheers. – M-- May 14 '19 at 17:29
  • 1
    Here's why(?) `ifelse` is acting out: https://stackoverflow.com/questions/6668963/how-to-prevent-ifelse-from-turning-date-objects-into-numeric-objects – M-- May 14 '19 at 18:37