Difficulty ggplot'ing with lubridate periods or intervals

I have some data over time periods that I'm trying to plot. Unfortunately, neither lubridate periods and durations seem to be cooperating with ggplot2. In my real data, I have different subjects with measurements over time. Different subjects have different t0s, so I can't use the date. I need to use the elapsed time to measurement which I think is a lubridate duration.

Here were my attempts at the plotting with toy data:

library(tidyverse)
library(lubridate)
#> 
#> Attaching package: 'lubridate'
#> The following object is masked from 'package:base':
#> 
#>     date
library(ggplot2)

test <- tribble(
  ~y, ~days_num, ~hrs_num,
  1,    1,         2.5,
  2,    1,        10.3,
  3,    2,         5.1,
  4,    3,         15,
)

# convert to periods
test <- test %>%
  mutate(
    days=days(days_num),
    hours=hours(hrs_num),
    per = days + hours
    )
#> Error in validObject(.Object): invalid class "Period" object: periods must have integer values
# Really, why can't a period be fractional???


# try durations instead
test <- test %>% 
  mutate(
    days=ddays(days_num), 
    hours=dhours(hrs_num),
    dur = days + hours
    )
test %>% select(dur, everything())
#> # A tibble: 4 x 6
#>   dur                      y days_num hrs_num days             
#>   <Duration>           <dbl>    <dbl>   <dbl> <Duration>       
#> 1 95400s (~1.1 days)       1        1     2.5 86400s (~1 days) 
#> 2 123480s (~1.43 days)     2        1    10.3 86400s (~1 days) 
#> 3 191160s (~2.21 days)     3        2     5.1 172800s (~2 days)
#> 4 313200s (~3.62 days)     4        3    15   259200s (~3 days)
#> # … with 1 more variable: hours <Duration>

ggplot(test, aes(x=dur, y=y)) + geom_line()
#> Error: Incompatible duration classes (Duration, numeric). Please coerce with `as.duration`.

# This was supposedly fixed in 2018 here:
# https://github.com/tidyverse/ggplot2/issues/2414
# https://github.com/tidyverse/lubridate/pull/696

# try as periods
test <- test %>% mutate(per = as.period(dur))
test %>% select(per, everything())
#> # A tibble: 4 x 7
#>   per               y days_num hrs_num days              hours               
#>   <Period>      <dbl>    <dbl>   <dbl> <Duration>        <Duration>          
#> 1 1d 2H 30M 0S      1        1     2.5 86400s (~1 days)  9000s (~2.5 hours)  
#> 2 1d 10H 18M 0S     2        1    10.3 86400s (~1 days)  37080s (~10.3 hours)
#> 3 2d 5H 6M 0S       3        2     5.1 172800s (~2 days) 18360s (~5.1 hours) 
#> 4 3d 15H 0M 0S      4        3    15   259200s (~3 days) 54000s (~15 hours)  
#> # … with 1 more variable: dur <Duration>
ggplot(test, aes(x=per, y=y)) + geom_line()
#> Warning: Removed 4 row(s) containing missing values (geom_path).

# the period value is being thrown out?

# try as numeric
test <- test %>% mutate(num = as.numeric(dur))
test %>% select(num, per, everything())
#> # A tibble: 4 x 8
#>      num per               y days_num hrs_num days             
#>    <dbl> <Period>      <dbl>    <dbl>   <dbl> <Duration>       
#> 1  95400 1d 2H 30M 0S      1        1     2.5 86400s (~1 days) 
#> 2 123480 1d 10H 18M 0S     2        1    10.3 86400s (~1 days) 
#> 3 191160 2d 5H 6M 0S       3        2     5.1 172800s (~2 days)
#> 4 313200 3d 15H 0M 0S      4        3    15   259200s (~3 days)
#> # … with 2 more variables: hours <Duration>, dur <Duration>
ggplot(test, aes(x=num, y=y)) + geom_line()


# OK this works, but now I've totally lost my scale...
# do I need to mess with scales() now?

Created on 2020-03-19 by the reprex package (v0.3.0)

It looks like it works if you add scale_x_time(), but I'm not sure you can get days as part of the tick labels:

library(tidyverse)
library(lubridate)
#> 
#> Attaching package: 'lubridate'
#> The following object is masked from 'package:base':
#> 
#>     date

test <- tribble(
  ~y, ~days_num, ~hrs_num,
  1,    1,         2.5,
  2,    1,        10.3,
  3,    2,         5.1,
  4,    3,         15,
)

# convert fractions to durations
test <- 
  test %>% 
  mutate(
    days = duration(days_num, 'day'),
    hours = duration(hrs_num, 'hour'),
    per = hours + days
  )

test %>% select(per, everything())
#> # A tibble: 4 x 6
#>   per                      y days_num hrs_num days             
#>   <Duration>           <dbl>    <dbl>   <dbl> <Duration>       
#> 1 95400s (~1.1 days)       1        1     2.5 86400s (~1 days) 
#> 2 123480s (~1.43 days)     2        1    10.3 86400s (~1 days) 
#> 3 191160s (~2.21 days)     3        2     5.1 172800s (~2 days)
#> 4 313200s (~3.62 days)     4        3    15   259200s (~3 days)
#> # … with 1 more variable: hours <Duration>

# plot
test %>% 
  ggplot(aes(per, y)) +
  geom_point() +
  scale_x_time()

Created on 2020-03-19 by the reprex package (v0.3.0)

This topic was automatically closed 21 days after the last reply. New replies are no longer allowed.