Skip to content

Commit cbe79c1

Browse files
Add experimental functionality
1 parent 78a64a1 commit cbe79c1

10 files changed

+210
-1
lines changed

DESCRIPTION

+1
Original file line numberDiff line numberDiff line change
@@ -29,5 +29,6 @@ RoxygenNote: 7.2.3
2929
Imports:
3030
lifecycle,
3131
rlang,
32+
timechange,
3233
tsibble
3334
VignetteBuilder: knitr

NAMESPACE

+1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ S3method(autoplot,tbl_ts)
55
export(CoordCalendar)
66
export(autolayer)
77
export(autoplot)
8+
export(cal_gregorian)
89
export(coord_calendar)
910
import(rlang)
1011
import(tsibble)

R/cal_wrap.R

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
calendar_wrap <- function(x, wrap_points = cal_gregorian("week")) {
2+
time <- convert_time(x)
3+
4+
if(is.function(wrap_points)) {
5+
wrap_points <- wrap_points(range(time, na.rm = TRUE))
6+
}
7+
i <- as.integer(cut(time, wrap_points))
8+
x <- x - as.numeric(wrap_points)[i]
9+
x
10+
}

R/coord-calendar.R

+103
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
#' Calendar coordinates
2+
#'
3+
#' @export
4+
coord_calendar <- function(period = "week", xlim = NULL, ylim = NULL, expand = TRUE,
5+
default = FALSE, clip = "on") {
6+
ggplot2::ggproto(NULL, CoordCalendar,
7+
period = period,
8+
limits = list(x = xlim, y = ylim),
9+
expand = expand,
10+
default = default,
11+
clip = clip
12+
)
13+
}
14+
15+
#' @rdname ggplot2-ggproto
16+
#' @format NULL
17+
#' @usage NULL
18+
#' @export
19+
CoordCalendar <- ggplot2::ggproto("CoordCalendar", ggplot2::CoordCartesian,
20+
aspect = function(details) 1,
21+
22+
range = function(self, panel_params) {
23+
list(
24+
x = panel_params$x.range,
25+
y = panel_params$y.range
26+
)
27+
},
28+
29+
# Currently only works for x, should work for c("x", "xmin", "xmax", "xend", "xintercept")
30+
# transform_position is the appropriate helper for this, but this is incompatible with the group hack (as is xmin, xmax, xend)
31+
transform = function(self, data, panel_params) {
32+
# Not sure what to do with training panel guides yet
33+
if(any(is.infinite(data$x))) return(data)
34+
35+
# Convert x from numeric for handling time
36+
time <- if (data$x[[1]] > 1e7) {
37+
structure(data$x, class = c("POSIXct", "POSIXt"))
38+
} else if (max(data$x) < 1e5) {
39+
structure(data$x, class = "Date")
40+
} else {
41+
# Already done?
42+
# Need to figure this out so inputs to $transform are consistent
43+
return(data)
44+
}
45+
46+
wrap_points <- cal_gregorian(self$period)(range(time, na.rm = TRUE))
47+
# data$group <-
48+
grp <- as.integer(cut(time, wrap_points))
49+
data$x <- data$x - as.numeric(wrap_points)[grp] #[data$group]
50+
51+
data
52+
},
53+
54+
setup_panel_params = function(self, scale_x, scale_y, params = list()) {
55+
# environment(ggplot2::CoordCartesian$setup_panel_params)$setup_panel_params(self, scale_x, scale_y, params)
56+
57+
# Find reasonable limits for x
58+
lim_x <- c(0, max(diff(as.numeric(cal_gregorian(self$period)(self$limits$x %||% scale_x$range$range)))))
59+
60+
# calculate break information
61+
out_x <- scale_x$break_info(lim_x)
62+
63+
# range in coord space has already been calculated
64+
# needs to be in increasing order for transform_value() to work
65+
# out_x$range <- range(continuous_ranges$continuous_range_coord)
66+
out_x <- list(
67+
# Note that a ViewScale requires a limit and a range that are before the
68+
# Coord's transformation, so we pass `continuous_range`, not `continuous_range_coord`.
69+
ggplot2:::view_scale_primary(scale_x, lim_x, lim_x),
70+
sec = ggplot2:::view_scale_secondary(scale_x, lim_x, lim_x),
71+
range = out_x$range,
72+
labels = out_x$labels,
73+
major = out_x$major_source,
74+
minor = out_x$minor_source,
75+
sec.labels = out_x$sec.labels,
76+
sec.major = out_x$sec.major_source,
77+
sec.minor = out_x$sec.minor_source
78+
)
79+
names(out_x) <- c("x", paste("x", names(out_x)[-1], sep = "."))
80+
81+
out_x <- ggplot2:::view_scales_from_scale(scale_x, self$limits$x, self$expand)
82+
out_x$x.range <- lim_x
83+
c(
84+
out_x,
85+
ggplot2:::view_scales_from_scale(scale_y, self$limits$y, self$expand)
86+
)
87+
},
88+
89+
modify_scales = function(self, scales_x, scales_y) {
90+
# body(scales_x[[1L]]$trans$transform)[[2]] <- rlang::expr(browser())
91+
# body(scales_x[[1L]]$trans$transform)[[4]] <- rlang::expr(as.numeric(x) %% !!lubridate::period_to_seconds(lubridate::as.period(self$period)))
92+
93+
invisible()
94+
}
95+
96+
# setup_data = function(data, params = list()) {
97+
# data
98+
# },
99+
#
100+
# setup_layout = function(layout, params) {
101+
# layout
102+
# },
103+
)

R/seq-gen.R

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
#' @export
2+
cal_gregorian <- function(period = "week", week_start = 1) {
3+
function(x) {
4+
if(any(!is.finite(x))) return(x)
5+
6+
# Convert to date, should not needed later?
7+
out <- convert_time(x)
8+
9+
# out <- as.Date(x, origin = "1970-01-01")
10+
# Only designed to work for period = "week" for now.
11+
# wday <- 1 + (as.numeric(out) + (6 - week_start))%%7
12+
13+
out <- seq(
14+
from = timechange::time_floor(out[1], period, week_start),
15+
to = timechange::time_ceiling(out[2], period, week_start),
16+
by = period
17+
)
18+
out
19+
# vctrs::vec_cast(out, x)
20+
}
21+
}

R/utils.R

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
convert_time <- function(x) {
2+
if (max(x) > 1e5) {
3+
structure(x, class = c("POSIXct", "POSIXt"))
4+
} else {
5+
structure(x, class = "Date")
6+
}
7+
}

README.Rmd

+17
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,24 @@ remotes::install_github("tidyverts/ggtime")
3636
```{r example}
3737
library(ggtime)
3838
library(tsibble)
39+
library(ggplot2)
3940
tsibbledata::aus_production %>%
4041
autoplot(Bricks)
42+
43+
cal_trans_x <- function() {
44+
scales::trans_new(
45+
name = "calendar",
46+
transform = ggtime:::calendar_wrap,
47+
inverse = identity,
48+
breaks = scales::breaks_pretty(),
49+
domain = c(0, 60*60*24*7)
50+
)
51+
}
52+
53+
pedestrian[with(pedestrian, Sensor == "Southern Cross Station" & Date < "2015-03-01"),] |>
54+
autoplot(Count) +
55+
# coord_calendar(xlim = c(Sys.time(), Sys.Date() + lubridate::days(1)))
56+
ggplot2::coord_trans(x = cal_trans_x(), xlim = as.POSIXct(c("2024-03-25 00:00:00", "2024-03-31 23:59:59"))) +
57+
scale_x_datetime(date_breaks = "day", date_labels = "%a")
4158
```
4259

README.md

+32-1
Original file line numberDiff line numberDiff line change
@@ -29,15 +29,46 @@ remotes::install_github("tidyverts/ggtime")
2929

3030
``` r
3131
library(ggtime)
32+
#> Registered S3 method overwritten by 'tsibble':
33+
#> method from
34+
#> as_tibble.grouped_df dplyr
3235
library(tsibble)
3336
#>
3437
#> Attaching package: 'tsibble'
3538
#> The following objects are masked from 'package:base':
3639
#>
3740
#> intersect, setdiff, union
41+
library(ggplot2)
3842
tsibbledata::aus_production %>%
3943
autoplot(Bricks)
40-
#> Warning: Removed 20 rows containing missing values (`geom_line()`).
44+
#> Warning: Removed 20 rows containing missing values or values outside the scale range
45+
#> (`geom_line()`).
4146
```
4247

4348
<img src="man/figures/README-example-1.png" width="100%" />
49+
50+
``` r
51+
52+
cal_trans_x <- function() {
53+
scales::trans_new(
54+
name = "calendar",
55+
transform = ggtime:::calendar_wrap,
56+
inverse = identity,
57+
breaks = scales::breaks_pretty(),
58+
domain = c(0, 60*60*24*7)
59+
)
60+
}
61+
62+
pedestrian[with(pedestrian, Sensor == "Southern Cross Station" & Date < "2015-03-01"),] |>
63+
autoplot(Count) +
64+
# coord_calendar(xlim = c(Sys.time(), Sys.Date() + lubridate::days(1)))
65+
ggplot2::coord_trans(x = cal_trans_x(), xlim = as.POSIXct(c("2024-03-25 00:00:00", "2024-03-31 23:59:59"))) +
66+
scale_x_datetime(date_breaks = "day", date_labels = "%a")
67+
#> Warning in max(x): no non-missing arguments to max; returning -Inf
68+
#> Warning in min.default(structure(numeric(0), class = "Date"), na.rm = FALSE):
69+
#> no non-missing arguments to min; returning Inf
70+
#> Warning in max.default(structure(numeric(0), class = "Date"), na.rm = FALSE):
71+
#> no non-missing arguments to max; returning -Inf
72+
```
73+
74+
<img src="man/figures/README-example-2.png" width="100%" />

man/coord_calendar.Rd

+18
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

man/figures/README-example-2.png

44.4 KB
Loading

0 commit comments

Comments
 (0)