Skip to content

Commit 8d5d3f6

Browse files
committed
draft stat_chain
1 parent 1bfb3c9 commit 8d5d3f6

File tree

1 file changed

+127
-0
lines changed

1 file changed

+127
-0
lines changed

R/stat-chain.R

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
stat_chain <- function(
2+
mapping = NULL,
3+
data = NULL,
4+
geom = "path",
5+
position = "identity",
6+
...,
7+
stats = "identity",
8+
stat.params = list(),
9+
redirect = list(),
10+
na.rm = FALSE,
11+
show.legend = NA,
12+
inherit.aes = TRUE) {
13+
14+
layer(
15+
data = data,
16+
mapping = mapping,
17+
stat = StatChain,
18+
geom = geom,
19+
position = position,
20+
show.legend = show.legend,
21+
inherit.aes = inherit.aes,
22+
params = list2(
23+
na.rm = na.rm,
24+
stats = stats,
25+
stat.params = stat.params,
26+
redirect = redirect,
27+
...
28+
)
29+
)
30+
}
31+
32+
StatChain <- ggproto(
33+
"StatChain", Stat,
34+
35+
extra_params = c("na.rm", "stats", "stat.params", "redirect"),
36+
37+
setup_params = function(data, params) {
38+
params$stats <- lapply(params$stats, validate_subclass, subclass = "Stat")
39+
n_stats <- length(params$stats)
40+
41+
params$stat.params <- force_length(
42+
params$stat.params, n_stats,
43+
warn_longer = TRUE, arg = "stat.params"
44+
)
45+
46+
params$redirect <- force_length(
47+
params$redirect, n_stats,
48+
warn_longer = TRUE, arg = "redirect"
49+
)
50+
51+
params
52+
},
53+
54+
compute_layer = function(self, data, params, layout) {
55+
56+
n_stats <- length(params$stats)
57+
58+
for (i in seq_len(n_stats)) {
59+
stat <- params$stats[[i]]
60+
param <- params$stat.params[[i]]
61+
62+
# We repeat the `layer()` duty of rejecting unknown parameters
63+
valid <- stat$parameters(TRUE)
64+
extra_param <- setdiff(names(param), valid)
65+
if (length(extra_param) > 0) {
66+
cli::cli_warn("Ignoring unknown parameters: {.arg {extra_param}}.")
67+
}
68+
param <- param[intersect(names(param), valid)]
69+
if (length(param) < 1) {
70+
param <- list()
71+
}
72+
73+
# Repeat `Layer$compute_statistic()` duty
74+
computed_param <- stat$setup_params(data, param)
75+
computed_param$na.rm <- computed_param$na.rm %||% params$na.rm
76+
data <- stat$setup_data(data, computed_param)
77+
data <- stat$compute_layer(data, computed_param, layout)
78+
if (nrow(data) < 1) {
79+
return(data)
80+
}
81+
82+
# Repeat `Layer$map_statistic()` duty, skipping backtransforms and such
83+
aes <- stat$default_aes[is_calculated_aes(stat$default_aes)]
84+
aes <- aes[setdiff(names(aes), names(data))]
85+
aes <- compact(defaults(params$redirect[[i]], aes))
86+
if (length(aes) == 0) {
87+
next
88+
}
89+
new <- eval_aesthetics(substitute_aes(aes), data)
90+
check_nondata_cols(
91+
new, aes,
92+
problem = "Aesthetics must be valid computed stats.",
93+
hint = "Did you specify the `redirect` argument correctly?"
94+
)
95+
data[names(new)] <- new
96+
}
97+
98+
data
99+
}
100+
)
101+
102+
force_length <- function(x, n = length(x), padding = list(NULL),
103+
warn_longer = FALSE, warn_shorter = FALSE,
104+
arg = caller_arg(x)) {
105+
force(arg)
106+
nx <- length(x)
107+
if (nx == n) {
108+
return(x)
109+
}
110+
n_pad <- n - nx
111+
if (n_pad > 0) {
112+
x <- c(x, rep(padding, length = n_pad))
113+
if (isTRUE(warn_shorter)) {
114+
cli::cli_warn(
115+
"Padded {.arg {arg}} with {n_pad} element{?s}."
116+
)
117+
}
118+
} else if (n_pad < 0) {
119+
x <- x[seq_len(n)]
120+
if (isTRUE(warn_longer)) {
121+
cli::cli_warn(
122+
"Dropped {abs(n_pad)} excess element{?s} from {.arg {arg}}."
123+
)
124+
}
125+
}
126+
x
127+
}

0 commit comments

Comments
 (0)