如何临时更改R包中函数中的代码?

问题描述 投票:0回答:1

我在

gganimate
包中发现了一个错误,它破坏了我的一张图表 (https://github.com/thomasp85/gganimate/issues/502)。我知道如何修复它如果我在调试模式下逐步执行相关函数(https://github.com/thomasp85/gganimate/issues/502#issuecomment-2395009593)。我需要运行这行代码:

data <- lapply(data, function(el){
      el[order(el$x, decreasing = TRUE),]
    })

就在

gganimate:::ggplot_build.gganim
函数的第 76 行之后(https://github.com/thomasp85/gganimate/blob/b46d1ff9bfee89c33ca8d6c4fd3fa1074c649027/R/plot-build.R#L76)。当然,只有当我以交互方式运行代码时,使用
debug
才有效。我想做的是临时修补此函数,以便在我以非交互方式运行代码时(例如,使用
knitr
)正确显示我的图表。

我想在等待包中的错误修复时获得工作图表。

我在想这样的事情:

bdy = deparse(body(gganimate:::ggplot_build.gganim))
c(
  bdy[1:41],
  "data <- lapply(data, function(el){
      el[order(el$x, decreasing = TRUE),]
    })",
  bdy[42:length(bdy)]
  ) -> bdy 
f <- function(plot){}
body(f) <- as.expression(parse(text=paste0(bdy, collapse="\n")))

rlang::env_unlock(env = asNamespace('gganimate'))
rlang::env_binding_unlock(env = asNamespace('gganimate'))
assignInNamespace("ggplot_build.gganim", f, "gganimate")
rlang::env_binding_lock(env = asNamespace('gganimate'))
rlang::env_lock(asNamespace('gganimate'))

(来自拼凑答案https://stackoverflow.com/a/38732761/1129889https://stackoverflow.com/a/8502385/1129889)但它似乎不起作用,因为它然后不起作用看一下

gganimate
包函数:

library(ggplot2)
library(gganimate)
library(ragg)
library(gifski)

dplyr::tibble(
  x = seq(0,.5,length.out=256),
  y = 1-pnorm(qnorm(x)/5)
) -> df

res = 300
w = 7
h = 4
# If this is run in knitr, w and h are in inches, otherwise
# they are in pixels
anim_w = ifelse(interactive(),w*res,w)
anim_h = ifelse(interactive(),h*res,h)


ggplot(df,aes(x=x,y=y)) +
  geom_line() +
  geom_point() +
  coord_cartesian(
    xlim=c(0,.5),ylim=c(.5,1),expand = FALSE
  ) -> gg

anim = gg + transition_reveal(x, range = c(.5,0)) 

## Try to hack the function in place
bdy = deparse(body(gganimate:::ggplot_build.gganim))
c(
  bdy[1:41],
  "data <- lapply(data, function(el){
      el[order(el$x, decreasing = TRUE),]
    })",
  bdy[42:length(bdy)]
  ) -> bdy 
f <- function(plot){}
body(f) <- as.expression(parse(text=paste0(bdy, collapse="\n")))

rlang::env_unlock(env = asNamespace('gganimate'))
rlang::env_binding_unlock(env = asNamespace('gganimate'))
assignInNamespace("ggplot_build.gganim", f, "gganimate")
rlang::env_binding_lock(env = asNamespace('gganimate'))
rlang::env_lock(asNamespace('gganimate'))

anim

产生错误:

Error in plot_clone(plot) : could not find function "plot_clone"

(我想是因为

plot_clone
gganimate
的内部函数)

有没有办法做这样的事情(或以另一种方式完成同样的事情)?

注意:我不想分叉该包并插入此行,然后安装我的版本(因为我只需要对一个图形进行此临时修复,并且它将中断对该函数的其他调用)。

r rlang gganimate
1个回答
0
投票

理想情况下你会做叉子。

如果没有分叉,一种方法是通过

:::
:

在全局中复制非导出的 {gganimate} 对象
library(ggplot2)
library(gganimate)
library(ragg)
library(gifski)

# make global copies of unexported {gganimate} objects
plot_clone    <- gganimate:::plot_clone
create_scene  <- gganimate:::create_scene
is.waive      <- gganimate:::is.waive
by_layer      <- gganimate:::by_layer
create_layout <- gganimate:::create_layout

dplyr::tibble(
  x = seq(0,.5,length.out=256),
  y = 1-pnorm(qnorm(x)/5)
) -> df

res = 300
w = 7
h = 4
# If this is run in knitr, w and h are in inches, otherwise
# they are in pixels
anim_w = ifelse(interactive(),w*res,w)
anim_h = ifelse(interactive(),h*res,h)


ggplot(df,aes(x=x,y=y)) +
  geom_line() +
  geom_point() +
  coord_cartesian(
    xlim=c(0,.5),ylim=c(.5,1),expand = FALSE
  ) -> gg

anim = gg + transition_reveal(x, range = c(.5,0)) 

## Try to hack the function in place
bdy = deparse(body(gganimate:::ggplot_build.gganim))
c(
  bdy[1:41],
  "data <- lapply(data, function(el){
      el[order(el$x, decreasing = TRUE),]
    })",
  bdy[42:length(bdy)]
  ) -> bdy 
f <- function(plot){}
body(f) <- as.expression(parse(text=paste0(bdy, collapse="\n")))

rlang::env_unlock(env = asNamespace('gganimate'))
rlang::env_binding_unlock(env = asNamespace('gganimate'))
assignInNamespace("ggplot_build.gganim", f, "gganimate")
rlang::env_binding_lock(env = asNamespace('gganimate'))
rlang::env_lock(asNamespace('gganimate'))

anim

创建于 2024 年 10 月 5 日,使用 reprex v2.1.1

© www.soinside.com 2019 - 2024. All rights reserved.