首页 > 解决方案 > 为什么 ggplotly 在 rmarkdown 中不能像 ggplot 一样工作

问题描述

我想以ggplotly同样的方式使用它的副作用,ggplot甚至graphics这样做。我的意思是当我knitr::knitrmarkdown::renderRmd 文档时,我希望报告中的对象print(obj)在哪里,但事实并非如此。objggplotly

问题.R文件

#+ libs, echo = FALSE                                                                                                                                                                                                                                        
suppressMessages({                                                                                                                                                                                                                             
    library(ggplot2)                                                                                                                                                                                                                           
    library(plotly)                                                                                                                                                                                                                            
    library(rmarkdown)                                                                                                                                                                                                                         
})                                                                                                                                                                                                                                             

#+ functions decl, echo = FALSE
df <- data.frame(x = 1:5, y = 1:5)                                                                                                                                                                                                                             
f_0 <- function(df) {                                                                                                                                                                                                                                                                                                                                                                                                                                     
    p <- ggplot(df, aes(x, y)) + geom_line()
    # p or plot(p) or print(p) works                                                                                                                                                                                                   
    print(p)                                                                                                                                                                                                                                   
    return(df)                                                                                                                                                                                                                                 
}                                                                                                                                                                                                                                              
f_1 <- function(df) {                                                                                                                                                                                                                                                                                                                                                                                                                                     
    p <- ggplot(df, aes(x, y)) + geom_line()                                                                                                                                                                                                   
    p <- ggplotly(p)    
    # plot(p) crashes                                                                                                                                                                                                                       
    # print p does not print in report                                                                                                                                                                                                         
    print(p)                                                                                                                                                                                                                                   
    # p standalone does not work either                                                                                                                                                                                                        
    p                                                                                                                                                                                                                                          
    return(df)                                                                                                                                                                                                                                 
}                                                                                                                                                                                                                                              

#' # plots                                                                                                                                                                                                                                     
#' plot 0                                                                                                                                                                                                                                      
#+ plot_0                                                                                                                                                                                                                                      
res_0 <- f_0(df)                                                                                                                                                                                                                                 
#' plot 1                                                                                                                                                                                                                                      
#+ plot_1                                                                                                                                                                                                                                      
res_1 <- f_1(df)     

渲染这个文件

rmarkdown::render("question.R")

输出

输出

标签: rggplot2r-markdownggplotly

解决方案


编辑评论:作为一种风格,将计算和绘图分离成不同的函数通常是一个好主意,因为它增加了模块化,使代码更易于维护,并允许在没有参数蠕变的情况下进行更精细的控制。然后可以轻松地将各个函数的输出映射到单独的 knitr 块。

最佳解决方案:我知道您特别询问不返回绘图对象,但我只想指出,将它与结果一起返回提供了最干净、最优雅的解决方案:

---
output: html_document
---

```{r include=FALSE}
library( tidyverse )
df <- data_frame( x=1:5, y=1:5 )
```

```{r}
f <- function(df) {
  gg <- ggplot(df, aes(x,y)) + geom_point()
  list( result=df, plot=plotly::ggplotly(gg) )
}
res <- f(df)
res$plot
```

但是,如果您绝对不能从函数返回一个 plotly 对象,您有一些选择。

选项 1:将 plotly 对象存储到父框架,提供从 knitr 块对其的访问。

```{r}
f1 <- function(df) {
  gg <- ggplot(df, aes(x,y)) + geom_point()
  assign("ggp", plotly::ggplotly(gg), envir=parent.frame())
  df    # NOT returning a plot
}
res1 <- f1(df)
ggp   # Let knitr handle the rendering naturally
```

选项 2:将绘图渲染为临时 .html,然后将其作为 iframe 导入

```{r, results='asis'}     # <-- note the "asis" chunk option
f2 <- function(df)
{
  gg <- ggplot(df, aes(x,y)) + geom_point()
  htmlwidgets::saveWidget( plotly::ggplotly(gg), "temp.html")
  print( htmltools::tags$iframe(src="temp.html", width=640, height=480) )
  df    # NOT returning a plot
}
res2 <- f2(df)
```

解释:如果我错了,易辉可以纠正我,但knitr基本上是在幕后做“选项2”。它将 htmlwidgets(例如 plotly 对象)渲染到临时 .html 文件中,然后组合这些临时文件以生成最终文档。它在函数内失败的原因是当执行离开函数范围时临时文件被删除。(您可以通过使用tempfile()而不是 persistent自己复制此内容"temp.html";该iframe对象将在最终文档中显示“找不到文件”错误。)可能有一种方法可以修改 knitr 挂钩以保留临时文件,但这超出了我的知识范围。最后,基本对象没有这个问题的原因ggplot是因为它们的输出到绘图设备,


推荐阅读