为啥 ggplotly 在 rmarkdown 中不能像 ggplot 一样工作
Posted
技术标签:
【中文标题】为啥 ggplotly 在 rmarkdown 中不能像 ggplot 一样工作【英文标题】:Why does ggplotly does not work in rmarkdown the same way ggplot does为什么 ggplotly 在 rmarkdown 中不能像 ggplot 一样工作 【发布时间】:2020-03-27 09:58:22 【问题描述】:我想使用ggplotly
,因为它的副作用与ggplot
甚至graphics
一样。我的意思是当我 knitr::knit
或 rmarkdown::render
一个 Rmd 文档时,我希望 print(obj)
其中 obj
是一个 ggplotly
对象,但事实并非如此。
question.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")
输出
【问题讨论】:
我认为这与情节输出是htmlwidgets有关。您可能需要使用 `htmltools::taglist()'。看看here 和here。 @joshpk 所以没有一致的API? @joshpk 我把那些页面变红了,但是很乱,我不知道该怎么做 你在渲染什么,HTML? 是的,我渲染到 html 【参考方案1】:编辑评论:作为一种风格,将计算和绘图分离成不同的函数通常是一个好主意,因为它增加了模块化,使代码更易于维护,并允许在没有参数蠕变。然后可以轻松地将各个函数的输出映射到单独的 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”。它将诸如 plotly 对象之类的 htmlwidgets 渲染到临时 .html 文件中,然后将这些临时文件组合起来以生成最终文档。它在函数内失败的原因是当执行离开函数范围时临时文件被删除。 (您可以通过使用tempfile()
而不是持久的"temp.html"
自己复制此内容;iframe
对象将在最终文档中显示“找不到文件”错误。)可能有一种方法可以修改 knitr 钩子以保留临时文件,但这超出了我的知识范围。最后,基本的ggplot
对象没有这个问题的原因是它们的输出进入了绘图设备,该设备在调用帧中持续存在。
【讨论】:
正如我在问题中所说的,我想在函数中绘图而不返回绘图对象 @statquant:生成与print()
内联的绘图而不是在结果旁边返回绘图对象有什么好处?我扩展了帖子以显示一些替代方案,但 return(list( results, plot ))
是一个更清洁的选择,恕我直言。
你好,我明白你的意思,但我觉得这是一种浪费,因为 plot 对象已经包含数据,对于 ggplot 你可以获得 plot$data,但是对于 ggplotly,API 是不同的,我没有知道为什么。不管怎样,谢谢你的回答,我会关闭这个以上是关于为啥 ggplotly 在 rmarkdown 中不能像 ggplot 一样工作的主要内容,如果未能解决你的问题,请参考以下文章
在 RMarkdown 中的 HTML 模板中渲染 ggplot2 绘图
在 Rmarkdown 中动态创建选项卡不适用于 ggplot,而它适用于 plotly
为啥我不需要 results = "asis" 在 Rmarkdown 中逐字嵌入块输出?
为啥 RMarkdown 中的“Knit to pdf”会引发错误?