Skip to content

Commit c00a154

Browse files
authored
Manual stat (#6103)
* write `stat_manual()` * document * add test * add news bullet * fix examples with double point layers * add to pkgdown index * document `geom` slot
1 parent e57d6b8 commit c00a154

File tree

8 files changed

+362
-7
lines changed

8 files changed

+362
-7
lines changed

DESCRIPTION

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -254,6 +254,7 @@ Collate:
254254
'stat-ellipse.R'
255255
'stat-function.R'
256256
'stat-identity.R'
257+
'stat-manual.R'
257258
'stat-qq-line.R'
258259
'stat-qq.R'
259260
'stat-quantilemethods.R'

NAMESPACE

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -265,6 +265,7 @@ export(StatEcdf)
265265
export(StatEllipse)
266266
export(StatFunction)
267267
export(StatIdentity)
268+
export(StatManual)
268269
export(StatQq)
269270
export(StatQqLine)
270271
export(StatQuantile)
@@ -691,6 +692,7 @@ export(stat_ecdf)
691692
export(stat_ellipse)
692693
export(stat_function)
693694
export(stat_identity)
695+
export(stat_manual)
694696
export(stat_qq)
695697
export(stat_qq_line)
696698
export(stat_quantile)

NEWS.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
# ggplot2 (development version)
22

3+
* New stat: `stat_manual()` for arbitrary computations (@teunbrand, #3501)
34
* Reversal of a dimension, typically 'x' or 'y', is now controlled by the
45
`reverse` argument in `coord_cartesian()`, `coord_fixed()`, `coord_radial()`
56
and `coord_sf()`. In `coord_radial()`, this replaces the older `direction`

R/stat-manual.R

Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
2+
#' Manually compute transformations
3+
#'
4+
#' `stat_manual()` takes a function that computes a data transformation for
5+
#' every group.
6+
#'
7+
#' @inheritParams layer
8+
#' @inheritParams geom_point
9+
#' @param fun Function that takes a data frame as input and returns a data
10+
#' frame or data frame-like list as output. The default (`identity()`) returns
11+
#' the data unchanged.
12+
#' @param args A list of arguments to pass to the function given in `fun`.
13+
#'
14+
#' @eval rd_aesthetics("stat", "manual")
15+
#' @section Aesthetics:
16+
#' Input aesthetics are determined by the `fun` argument. Output aesthetics must
17+
#' include those required by `geom`. Any aesthetic that is constant within a
18+
#' group will be preserved even if dropped by `fun`.
19+
#'
20+
#' @export
21+
#'
22+
#' @examples
23+
#' # A standard scatterplot
24+
#' p <- ggplot(mtcars, aes(disp, mpg, colour = factor(cyl))) +
25+
#' geom_point()
26+
#'
27+
#' # The default just displays points as-is
28+
#' p + stat_manual()
29+
#'
30+
#' # Using a custom function
31+
#' make_hull <- function(data) {
32+
#' hull <- chull(x = data$x, y = data$y)
33+
#' data.frame(x = data$x[hull], y = data$y[hull])
34+
#' }
35+
#'
36+
#' p + stat_manual(
37+
#' geom = "polygon",
38+
#' fun = make_hull,
39+
#' fill = NA
40+
#' )
41+
#'
42+
#' # Using the `with` function with quoting
43+
#' p + stat_manual(
44+
#' fun = with,
45+
#' args = list(expr = quote({
46+
#' hull <- chull(x, y)
47+
#' list(x = x[hull], y = y[hull])
48+
#' })),
49+
#' geom = "polygon", fill = NA
50+
#' )
51+
#'
52+
#' # Using the `transform` function with quoting
53+
#' p + stat_manual(
54+
#' geom = "segment",
55+
#' fun = transform,
56+
#' args = list(
57+
#' xend = quote(mean(x)),
58+
#' yend = quote(mean(y))
59+
#' )
60+
#' )
61+
#'
62+
#' # Using dplyr verbs with `vars()`
63+
#' if (requireNamespace("dplyr", quietly = TRUE)) {
64+
#'
65+
#' # Get centroids with `summarise()`
66+
#' p + stat_manual(
67+
#' size = 10, shape = 21,
68+
#' fun = dplyr::summarise,
69+
#' args = vars(x = mean(x), y = mean(y))
70+
#' )
71+
#'
72+
#' # Connect to centroid with `mutate`
73+
#' p + stat_manual(
74+
#' geom = "segment",
75+
#' fun = dplyr::mutate,
76+
#' args = vars(xend = mean(x), yend = mean(y))
77+
#' )
78+
#'
79+
#' # Computing hull with `reframe()`
80+
#' p + stat_manual(
81+
#' geom = "polygon", fill = NA,
82+
#' fun = dplyr::reframe,
83+
#' args = vars(hull = chull(x, y), x = x[hull], y = y[hull])
84+
#' )
85+
#' }
86+
stat_manual <- function(
87+
mapping = NULL,
88+
data = NULL,
89+
geom = "point",
90+
position = "identity",
91+
...,
92+
fun = identity,
93+
args = list(),
94+
na.rm = FALSE,
95+
show.legend = NA,
96+
inherit.aes = TRUE) {
97+
98+
layer(
99+
data = data,
100+
mapping = mapping,
101+
stat = StatManual,
102+
geom = geom,
103+
position = position,
104+
show.legend = show.legend,
105+
inherit.aes = inherit.aes,
106+
params = list2(
107+
na.rm = na.rm,
108+
fun = fun,
109+
args = args,
110+
...
111+
)
112+
)
113+
}
114+
115+
#' @rdname ggplot2-ggproto
116+
#' @format NULL
117+
#' @usage NULL
118+
#' @export
119+
StatManual <- ggproto(
120+
"StatManual", Stat,
121+
122+
setup_params = function(data, params) {
123+
params$fun <- allow_lambda(params$fun)
124+
check_function(params$fun, arg = "fun")
125+
params
126+
},
127+
128+
compute_group = function(data, scales, fun = identity, args = list()) {
129+
as_gg_data_frame(inject(fun(data, !!!args)))
130+
}
131+
)

_pkgdown.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ reference:
6868
- stat_summary_bin
6969
- stat_unique
7070
- stat_sf_coordinates
71+
- stat_manual
7172
- after_stat
7273

7374
- subtitle: Position adjustment

man/ggplot2-ggproto.Rd

Lines changed: 9 additions & 7 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)