Reputation: 67
I'm working with bedtime and waketime, so I would like to create a graph with a 24h x axis, starting at 12pm on day 1 and ending at 12pm on day 2. Meaning that after 11:59pm, it should start at 0 again.
Same question with number only, I'd like to create a scale from 10 to 20 and after 20 start at 1 again until 10.
This is the code that I have for now:
ggplot(SLEEP2, aes(x=as.POSIXct(bedT, format="%H:%M"), y=Jour))+
geom_rect(aes(xmin=as.POSIXct(sleepT, format="%H:%M"), xmax=as.POSIXct(wakeT,
format="%H:%M"),ymin=(Jour-0.4), ymax=(Jour+0.4)),fill="orange",
color="black")+ scale_x_datetime()
I'd like to represent their sleep time with bars...
How can I do that? I tried several option but nothing is working. Thank you.
Upvotes: 4
Views: 1542
Reputation: 23807
To turn my comment into an answer - I think this is one of the few moments when a circular / polar coordinate system may be appropriate.
I shamelessly used the data and good deal of the plotting code from user keithbjolley's answer - thanks and + 1.
The main change is the call to coord_polar().
library(tidyverse)
library(lubridate)
start <- ymd_hm("20210101-0000")
secsday <- 60 * 60 * 12
df <- tibble(date_time = seq(start, start %m+% weeks(2), by = 200)) %>%
mutate(
time = hms::as_hms(date_time),
date = factor(date(date_time)),
values = jitter(cos(day(date_time) / 30 + pi * as.numeric(time) / secsday), amount = 1 / 40),
values = ifelse(values > 0, values, 0)
)
reds <- grDevices::hcl.colors(length(unique(df$date)), "Reds")
ggplot(df, aes(x = time, y = values, color = date)) +
geom_line() +
coord_polar(start = 0) +
scale_color_manual(values = reds) +
theme_minimal()
Created on 2021-01-19 by the reprex package (v0.3.0)
Upvotes: 0
Reputation: 2273
Edit at bottom to include given data.
If there's a way to get the graph's axis transformed like maybe is more intuitive I don't know. I couldn't figure that out.
As other's mentioned having some sample data in your code would be helpful so that solutions could use it instead of having to guess and/or make up our own. Including a picture of what you have and/or want is also good.
Something like:
R> head(SLEEP2)
...
Anyways, here's one way of doing it. It's not at all elegant but it works.
First, make some "untransformed" data that peaks at midnight and plot it. I'm guessing this looks something like what you have already.
library(tidyverse)
library(lubridate)
start <- ymd_hm("20210101-0000")
# Make some pretend data. It's value is zero during the "day" and peaks around midnight.
secsday <- 60*60*12
df <- tibble(date_time = seq(start, start %m+% weeks(2), by=200)) %>%
mutate(time = hms::as_hms(date_time),
date = factor(date(date_time)),
values = jitter(cos(day(date_time)/30+pi*as.numeric(time)/secsday), amount=1/40),
values = ifelse(values>0, values, 0)
)
# Plot original data.
ggplot(df, aes(time, values, colour=date)) +
geom_line() +
scale_x_time(breaks=hours(seq(0,24,6)), labels=c("midnight","6AM","noon","6pm","midnight")) +
ggtitle('pre-transform')
Next, translate AM to PM and PM to AM.
# Transform times so AM is PM and PM is AM (swap around noon).
dt <- df %>% mutate(time=
ifelse(time>hm("12:00"), hms::as_hms(time)-secsday, hms::as_hms(time)+secsday)
)
ggplot(dt, aes(time, values, colour=date)) +
geom_line() +
scale_x_time(breaks=hours(seq(0,24,6)), labels=c("noon", "6PM", "midnight", "6AM", "noon")) +
ggtitle('post-transform')
I'd like to know if there's a way of doing this by only adjusting the axis instead of the data.
With the data you provided and using bars:
dat <- data.frame(Jour=1:5,
date=seq.Date(as.Date("2020-10-01"), as.Date("2020-10-05"), "day"),
sleeptime=c("22:30","21:10","23:00","23:00", "23:20"),
waketime= c("6:30", "7:00", "7:30", "6:25","7:10"))
# make fake dates for sleep and wake
dat <- dat %>% mutate(
sleep = ymd_hm(paste(dat[1,]$date, sleeptime)),
wake = ymd_hm(paste(dat[1,]$date, waketime)),
wake = wake + ddays(ifelse(lubridate::hm(waketime)<lubridate::hm(sleeptime), 1, 0))
)
ggplot(dat, aes(xmin=sleep, xmax=wake)) +
scale_x_datetime(breaks=ymd(dat[1,]$date) + hours(seq(12,36,length.out=5)),
labels=c("noon", "6PM", "midnight", "6AM", "noon"),
limits=ymd(dat[1,]$date) + hours(seq(12,36,length.out=2))
) +
geom_rect(ymin=0.25, ymax=0.75, fill='darkgreen') +
ylim(0,1) +
facet_grid(rows = vars(date)) +
theme(axis.title = element_blank()) +
theme(axis.text.y = element_blank(),
axis.ticks = element_blank()
)
Upvotes: 2
Reputation: 4497
You can use scales_x_...
function with custom label functions to achieved what you want. Here is the example, as you didn't provide a reproducible example I just create my own version which may not perfect, please check and adjust as you go.
library(dplyr)
library(lubridate)
library(ggplot2)
df <- tibble(time = seq(from = as.POSIXct("2020-01-01 00:00:00"),
by = "1 hour", length.out = 48),
number = seq(1, by = 1, length.out = 48),
y_value = runif(48, min = 0, max = 60))
format_time_label <- function(x) {
hour(x)
}
df[["hour"]] <- day(df[["time"]]) * hour(df[["time"]])
ggplot(data = df) +
geom_bar(aes(x = time, y = y_value), stat = "identity") +
scale_x_datetime(date_breaks = "1 hour", labels = format_time_label)
For the number, I am not sure what you want so I restart back to 1 after every 20.
format_number_label <- function(x) {
x[x %% 20 == 0] <- 20
x[x > 20] <- x[x > 20] - (x[x > 20] %/% 20) * 20
x
}
ggplot(data = df) +
geom_bar(aes(x = number, y = y_value), stat = "identity") +
scale_x_continuous(breaks = seq(1, by = 1, length.out = 48),
labels = format_number_label)
Upvotes: 1