Skip to content

Commit aae1612

Browse files
committed
Merge pull request #291 from kohske/feature/summary-2D
2D/hex summary
2 parents faded39 + 0ad2df1 commit aae1612

11 files changed

+310
-202
lines changed

DESCRIPTION

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -151,8 +151,8 @@ Collate:
151151
'scale-size.r'
152152
'scales-.r'
153153
'stat-.r'
154-
'stat-aggr-2d.r'
155-
'stat-aggr-hex.r'
154+
'stat-summary-2d.r'
155+
'stat-summary-hex.r'
156156
'stat-bin.r'
157157
'stat-bin2d.r'
158158
'stat-binhex.r'

NAMESPACE

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -166,8 +166,6 @@ export(scale_y_reverse)
166166
export(scale_y_sqrt)
167167
export(should_stop)
168168
export(stat_abline)
169-
export(stat_aggr2d)
170-
export(stat_aggrhex)
171169
export(stat_bin)
172170
export(stat_bin2d)
173171
export(stat_binhex)
@@ -183,7 +181,9 @@ export(stat_quantile)
183181
export(stat_smooth)
184182
export(stat_spoke)
185183
export(stat_sum)
184+
export(stat_summary_hex)
186185
export(stat_summary)
186+
export(stat_summary2d)
187187
export(stat_unique)
188188
export(stat_vline)
189189
export(stat_ydensity)

NEWS

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,10 @@ NEW FEATURES
1919
* New fortify methods have been added for objects produced by the `multcomp`
2020
package.
2121

22+
* `stat_summary2d` / `stat_summary_hex`. These are arbitrary function version
23+
of stat_bin2d / stat_binhex. Any summarization (as stat-summary for 1D) can
24+
be done for 2D.
25+
2226
DEVELOPMENT
2327

2428
* ggplot2 has moved away from the two (!!) homegrown documentation systems

R/stat-aggr-2d.r

Lines changed: 0 additions & 84 deletions
This file was deleted.

R/stat-aggr-hex.r

Lines changed: 0 additions & 66 deletions
This file was deleted.

R/stat-summary-2d.r

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
##' Apply function for 2D rectangular bins.
2+
##'
3+
##' \code{stat_summary2d} is 2D version of \code{\link{stat_summary}}. The data are devided by \code{x} and \code{y}.
4+
##' \code{z} in each cell is passed to arbitral summary function.
5+
##'
6+
##' \code{stat_summary2d} requires the following aesthetics:
7+
##'
8+
##' \itemize{
9+
##' \item \code{x}: horizontal position
10+
##' \item \code{y}: vertical position
11+
##' \item \code{z}: value passed to the summary function
12+
##' }
13+
##'
14+
##' @seealso \code{\link{stat_summary_hex}} for hexagonal summarization. \code{\link{stat_bin2d}} for the binning options.
15+
##' @title Apply funciton for 2D rectangular bins.
16+
##' @param mapping
17+
##' @param data
18+
##' @param geom
19+
##' @param position
20+
##' @param bins see \code{\link{stat_bin2d}}
21+
##' @param drop drop if the output of \code{fun} is \code{NA}.
22+
##' @param fun function for summary.
23+
##' @param ... parameters passed to \code{fun}
24+
##' @export
25+
##' @examples
26+
##' d <- ggplot(diamonds, aes(carat, depth, z = price))
27+
##' d + stat_summary2d()
28+
##'
29+
##' # Specifying function
30+
##' d + stat_summary2d(fun = function(x) sum(x^2))
31+
##' d + stat_summary2d(fun = var)
32+
stat_summary2d <- function (mapping = NULL, data = NULL, geom = NULL, position = "identity",
33+
bins = 30, drop = TRUE, fun = mean, ...) {
34+
35+
StatSummary2d$new(mapping = mapping, data = data, geom = geom, position = position,
36+
bins = bins, drop = drop, fun = fun, ...)
37+
}
38+
39+
StatSummary2d <- proto(Stat, {
40+
objname <- "Summary2d"
41+
42+
default_aes <- function(.) aes(fill = ..value..)
43+
required_aes <- c("x", "y", "z")
44+
default_geom <- function(.) GeomRect
45+
46+
calculate <- function(., data, scales, binwidth = NULL, bins = 30, breaks = NULL, origin = NULL, drop = TRUE, fun = mean, ...) {
47+
48+
data <- remove_missing(data, FALSE, c("x", "y", "z"), name="stat_summary2d")
49+
50+
range <- list(
51+
x = scale_dimension(scales$x, c(0, 0)),
52+
y = scale_dimension(scales$y, c(0, 0))
53+
)
54+
55+
# Determine origin, if omitted
56+
if (is.null(origin)) {
57+
origin <- c(NA, NA)
58+
} else {
59+
stopifnot(is.numeric(origin))
60+
stopifnot(length(origin) == 2)
61+
}
62+
originf <- function(x) if (is.integer(x)) -0.5 else min(x)
63+
if (is.na(origin[1])) origin[1] <- originf(data$x)
64+
if (is.na(origin[2])) origin[2] <- originf(data$y)
65+
66+
# Determine binwidth, if omitted
67+
if (is.null(binwidth)) {
68+
binwidth <- c(NA, NA)
69+
if (is.integer(data$x)) {
70+
binwidth[1] <- 1
71+
} else {
72+
binwidth[1] <- diff(range$x) / bins
73+
}
74+
if (is.integer(data$y)) {
75+
binwidth[2] <- 1
76+
} else {
77+
binwidth[2] <- diff(range$y) / bins
78+
}
79+
}
80+
stopifnot(is.numeric(binwidth))
81+
stopifnot(length(binwidth) == 2)
82+
83+
# Determine breaks, if omitted
84+
if (is.null(breaks)) {
85+
breaks <- list(
86+
seq(origin[1], max(range$x) + binwidth[1], binwidth[1]),
87+
seq(origin[2], max(range$y) + binwidth[2], binwidth[2])
88+
)
89+
} else {
90+
stopifnot(is.list(breaks))
91+
stopifnot(length(breaks) == 2)
92+
stopifnot(all(sapply(breaks, is.numeric)))
93+
}
94+
names(breaks) <- c("x", "y")
95+
96+
xbin <- cut(data$x, sort(breaks$x), include.lowest=TRUE)
97+
ybin <- cut(data$y, sort(breaks$y), include.lowest=TRUE)
98+
99+
if (is.null(data$weight)) data$weight <- 1
100+
101+
ans <- ddply(data.frame(data, xbin, ybin), .(xbin, ybin), function(d) data.frame(value = fun(d$z, ...)))
102+
if (drop) ans <- na.omit(ans)
103+
104+
within(ans,{
105+
xint <- as.numeric(xbin)
106+
xmin <- breaks$x[xint]
107+
xmax <- breaks$x[xint + 1]
108+
109+
yint <- as.numeric(ybin)
110+
ymin <- breaks$y[yint]
111+
ymax <- breaks$y[yint + 1]
112+
})
113+
}
114+
})

R/stat-summary-hex.r

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
##' Apply function for 2D hexagonal bins.
2+
##'
3+
##' \code{stat_summary2d} is hexagonal version of \code{\link{stat_summary}}. The data are devided by \code{x} and \code{y}.
4+
##' \code{z} in each cell is passed to arbitral summary function.
5+
##'
6+
##' \code{stat_summary-hex} requires the following aesthetics:
7+
##'
8+
##' \itemize{
9+
##' \item \code{x}: horizontal position
10+
##' \item \code{y}: vertical position
11+
##' \item \code{z}: value passed to the summary function
12+
##' }
13+
##'
14+
##' @seealso \code{\link{stat_summary2d}} for rectangular summarization. \code{\link{stat_bin2d}} for the hexagon-ing options.
15+
##' @title Apply funciton for 2D hexagonal bins.
16+
##' @param bins see \code{\link{stat_binhex}}
17+
##' @param drop drop if the output of \code{fun} is \code{NA}.
18+
##' @param fun function for summary.
19+
##' @param ... parameters passed to \code{fun}
20+
##' @export
21+
##' @examples
22+
##' d <- ggplot(diamonds, aes(carat, depth, z = price))
23+
##' d + stat_summary_hex()
24+
##'
25+
##' # Specifying function
26+
##' d + stat_summary_hex(fun = function(x) sum(x^2))
27+
##' d + stat_summary_hex(fun = var, na.rm = T)
28+
stat_summary_hex <- function (mapping = NULL, data = NULL, geom = "hex", position = "identity",
29+
bins = 30, drop = TRUE, fun = mean, ...) {
30+
31+
StatSummaryhex$new(mapping = mapping, data = data, geom = geom, position = position,
32+
bins = bins, drop = drop, fun = fun, ...)
33+
}
34+
35+
StatSummaryhex <- proto(Stat, {
36+
objname <- "summaryhex"
37+
38+
default_aes <- function(.) aes(fill = ..value..)
39+
required_aes <- c("x", "y", "z")
40+
default_geom <- function(.) GeomHex
41+
42+
calculate <- function(., data, scales, binwidth = NULL, bins = 30, drop = TRUE, fun = mean, ...) {
43+
try_require("hexbin")
44+
data <- remove_missing(data, FALSE, c("x", "y", "z"), name="stat_summary_hex")
45+
46+
if (is.null(binwidth)) {
47+
binwidth <- c(
48+
diff(scale_dimension(scales$x, c(0, 0))) / bins,
49+
diff(scale_dimension(scales$y, c(0, 0))) / bins
50+
)
51+
}
52+
53+
try_require("hexbin")
54+
55+
# Convert binwidths into bounds + nbins
56+
x <- data$x
57+
y <- data$y
58+
59+
xbnds <- c(
60+
round_any(min(x), binwidth[1], floor) - 1e-6,
61+
round_any(max(x), binwidth[1], ceiling) + 1e-6
62+
)
63+
xbins <- diff(xbnds) / binwidth[1]
64+
65+
ybnds <- c(
66+
round_any(min(y), binwidth[1], floor) - 1e-6,
67+
round_any(max(y), binwidth[2], ceiling) + 1e-6
68+
)
69+
ybins <- diff(ybnds) / binwidth[2]
70+
71+
# Call hexbin
72+
hb <- hexbin(
73+
x, xbnds = xbnds, xbins = xbins,
74+
y, ybnds = ybnds, shape = ybins / xbins,
75+
IDs = TRUE
76+
)
77+
78+
value <- tapply(data$z, hb@cID, fun, ...)
79+
80+
# Convert to data frame
81+
ret <- data.frame(hcell2xy(hb), value)
82+
if (drop) ret <- na.omit(ret)
83+
ret
84+
}
85+
})

0 commit comments

Comments
 (0)