为什么 ggplotly 在 rmarkdown 中的工作方式与 ggplot 不同
Why does ggplotly does not work in rmarkdown the same way ggplot does
我想使用 ggplotly
因为它的副作用与 ggplot
甚至 graphics
相同。我的意思是,当我 knitr::knit
或 rmarkdown::render
一个 Rmd 文档时,我希望 print(obj)
其中 obj
是一个 ggplotly
objcet 在报告中,而不是案例.
- 谁能解释一下这是怎么回事?
- 谁能告诉我如何实现我想做的事情。我希望能够在不 returning 对象的情况下将 ggplotly 图绘制到函数中(我想 return 图的基础数据)并且我希望代码适用于 ggplot和 ggplotly(即对 ggplot 或 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")
输出
编辑评论:作为一种风格,将计算和绘图分离到不同的函数通常是个好主意,因为它增加了模块化,使代码更易于维护,并且允许在没有参数蠕变的情况下进行更精细的控制。然后可以轻松地将各个函数的输出映射到单独的 knitr 块。
最佳解决方案: 我知道您特别询问不 return 绘图对象,但我只想指出 return将其与结果一起使用可提供最干净、最优雅的解决方案:
---
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
```
但是,如果您绝对不能 return 从函数中绘制对象,您还有其他选择。
选项 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 基本上是在幕后"Option 2"。它将 html 小部件(例如 plotly 对象)呈现为临时 .html 文件,然后组合这些临时文件以生成最终文档。它在函数内部失败的原因是当执行离开函数范围时临时文件被删除。 (您可以通过使用 tempfile()
而不是持久的 "temp.html"
来自己复制它;iframe
对象将在最终文档中显示 "file not found" 错误。)可能有一种方法可以修改 knitr hooks 以保留临时文件,但这超出了我的知识范围。最后,基本 ggplot
对象没有这个问题的原因是它们的输出进入绘图设备,该设备在调用帧中持续存在。
我想使用 ggplotly
因为它的副作用与 ggplot
甚至 graphics
相同。我的意思是,当我 knitr::knit
或 rmarkdown::render
一个 Rmd 文档时,我希望 print(obj)
其中 obj
是一个 ggplotly
objcet 在报告中,而不是案例.
- 谁能解释一下这是怎么回事?
- 谁能告诉我如何实现我想做的事情。我希望能够在不 returning 对象的情况下将 ggplotly 图绘制到函数中(我想 return 图的基础数据)并且我希望代码适用于 ggplot和 ggplotly(即对 ggplot 或 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")
输出
编辑评论:作为一种风格,将计算和绘图分离到不同的函数通常是个好主意,因为它增加了模块化,使代码更易于维护,并且允许在没有参数蠕变的情况下进行更精细的控制。然后可以轻松地将各个函数的输出映射到单独的 knitr 块。
最佳解决方案: 我知道您特别询问不 return 绘图对象,但我只想指出 return将其与结果一起使用可提供最干净、最优雅的解决方案:
---
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
```
但是,如果您绝对不能 return 从函数中绘制对象,您还有其他选择。
选项 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 基本上是在幕后"Option 2"。它将 html 小部件(例如 plotly 对象)呈现为临时 .html 文件,然后组合这些临时文件以生成最终文档。它在函数内部失败的原因是当执行离开函数范围时临时文件被删除。 (您可以通过使用 tempfile()
而不是持久的 "temp.html"
来自己复制它;iframe
对象将在最终文档中显示 "file not found" 错误。)可能有一种方法可以修改 knitr hooks 以保留临时文件,但这超出了我的知识范围。最后,基本 ggplot
对象没有这个问题的原因是它们的输出进入绘图设备,该设备在调用帧中持续存在。