ggplot2 で図を並べる 話をしたblogdown で blogしてますassignInNamespace()
formals が対象なら便利なパッケージがある| 構成要素 | > identity | |
|---|---|---|
| formals | 引数のリスト | function (x) |
| body | 関数内のコード | x |
| environment | 関数を格納した変数の居場所 | <environment: namespace:base> |
formals() を弄ってassignInNamespace() せずにpackage:japanr2018namespace:japanr2018 に隔離f
# function(a) a + b
# <bytecode: 0x3e05f08>
# <environment: namespace:japanr2018>
f <- 1
f
# [1] 1
japanr2018::f
# function(a) a + b
# <bytecode: 0x3e3d700>
# <environment: namespace:japanr2018>japanr2018::f は上書きされない
formals() で関数の引数を確認するヘンなリストだけどリストのノリで弄れる。
`formals<-`## $a
## [1] 1
## [1] 2
alist() を使うと遅延評価できる## rnorm(1)
## [1] 3.439521
## [1] 0.649811
?formals にも載ってるアブナい技You can overwrite the formal arguments of a function (though this is advanced, dangerous coding).
f <- function(x) a + b
formals(f) <- alist(a = , b = 3)
f # function(a, b = 3) a + b
f(2) # result = 5
## function(a) a + b
## <bytecode: 0x4b4b6f8>
## <environment: namespace:japanr2018>
## [1] 1
b を a と同じ長さの乱数にしたい## [1] 1.438568 2.591437 3.015478
## [1] 1.994207 2.425113 3.596890 4.074767
## [1] 1

japanr2018::g は影響を受けない## [1] 2
assignInNamespace("b", 2, "japanr2018")
していたら
japanr2018::g(1) == 3
になっていた
ggproto で StatCI を定義StatCI <- ggproto(
"StatCI",
ggplot2::StatDensity,
compute_group = function(data, self, ci = 0.95, bw, adjust, kernel, n, trim, ...) {
# calculate density based on StatDensity
res <- self$super()$compute_group(
data = data,
bw = bw,
adjust = adjust,
kernel =kernel,
n = n,
trim = trim,
...
)
# quantile intervals to trim res
Q <- quantile(data$x, 0.5 + ci / c(-2, 2))
L <- Q[1] <= res$x
U <- res$x <= Q[2]
# return trimmed res
rbind(
find_boundary(res, !L, Q[1]),
res[L & U, ],
find_boundary(res, U, Q[2])
)
}
)
find_boundary <- function(data, bool, lim) {
if(any(data$x == lim)) return(NULL)
neighbors <- data[sum(bool) + c(0, 1), ]
colSums(neighbors * rev(abs((lim - neighbors$x) / diff(neighbors$x))))
}ggplot2::stat_density() を stat_ci() に改造## function (mapping = NULL, data = NULL, geom = "area", position = "stack",
## ..., bw = "nrd0", adjust = 1, kernel = "gaussian", n = 512,
## trim = FALSE, na.rm = FALSE, show.legend = NA, inherit.aes = TRUE)
## {
## layer(data = data, mapping = mapping, stat = StatDensity,
## geom = geom, position = position, show.legend = show.legend,
## inherit.aes = inherit.aes, params = list(bw = bw, adjust = adjust,
## kernel = kernel, n = n, trim = trim, na.rm = na.rm,
## ...))
## }
## <bytecode: 0x5fe15d0>
## <environment: namespace:ggplot2>
stat_density() が呼び出す StatDensity を、
ggplot2::StatDensity から、引数の StatDensity に摩り替え
library(ggplot2)
stat_ci <- stat_density
formals(stat_ci) <- c(
formals(stat_ci),
StatDensity = ggAtusy::StatCI
)
ggplot(data.frame(x = rnorm(1e5)), aes(x)) +
geom_density() + stat_ci()
遊び半分の実装です。
実用的には ggdistribute や bayseplot があります。
skimr::inline_hist() の skimr:::optioins を弄る## ▇▁▁▂▅▅▃▁
myopt <- rlang::env_clone(skimr:::options)
inline_hist <- skimr::inline_hist
myopt$formats$character$width <- 20
formals(inline_hist)$options = myopt
inline_hist(iris$Petal.Length)## ▁▇▂▁▁▁▁▁▁▁▃▃▃▅▂▃▂▁▁▁
optioins を弄るinline_hist <- skimr::inline_hist
.options <- function(n) {
options <- rlang::env_clone(skimr:::options)
options$formats$character$width <- n
options
}
formals(inline_hist)[c("n", "options")] <-
alist(n = 10, options = .options(n))
inline_hist(iris$Petal.Length)
# ▇▃▁▁▂▆▆▃▂▁
inline_hist(iris$Petal.Length, 20)
# ▁▇▂▁▁▁▁▁▁▁▃▃▃▅▂▃▂▁▁▁print.atusy <- function() {
cat("Printing atusy class object.\n")
NextMethod()
}
formals(print.atusy) <- formals(print)
structure(1, class = "atusy")## Printing atusy class object.
## [1] 1
## attr(,"class")
## [1] "atusy"
S3メソッドは最低でも、
総称関数と同じ引数を持たなければならない
`formals<-`() を使えば総称関数の引数を丸々引き継げる