代码之家  ›  专栏  ›  技术社区  ›  statquant

为什么ggplotly不能像ggplot那样在rmarkdown中工作

  •  -1
  • statquant  · 技术社区  · 5 年前

    我想用 ggplotly 因为同样的副作用 ggplot graphics 做。我是说当我 knitr::knit rmarkdown::render 我想是Rmd文件 print(obj) 哪里 obj 是一个 目标在报告中,事实并非如此。

    • 有人能解释一下发生了什么事吗?
    • 有谁能告诉我怎样才能实现我想做的。我希望能够在不返回对象的情况下将ggplotly图形绘制到函数中(我希望返回图形的底层数据),并且希望代码对ggplot和ggplotly都有效(即对ggplot或ggplotly使用相同的代码)

    问题.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")
    

    输出

    output

    0 回复  |  直到 5 年前
        1
  •  1
  •   Artem Sokolov    5 年前

    编辑评论: 作为一种风格,将计算和绘图分离成不同的函数通常是一个好主意,因为它增加了模块性,使代码更易于维护,并且允许更精细的控制,而无需参数爬行。然后,各个函数的输出可以很容易地映射到单独的knitr块。

    我知道您特别要求不要返回plot对象,但我只想指出,在返回结果的同时返回它提供了最干净和最优雅的解决方案:

    ---
    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: 将绘图呈现为temporary.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”。它将htmlwidget(如plotly对象)呈现为临时的.html文件,然后将这些临时文件组合起来生成最终文档。它在函数内部失败的原因是,当执行离开函数作用域时,临时文件会被删除。(您可以通过使用 tempfile() "temp.html" ;的 iframe 对象将在最终文档中显示“找不到文件”错误。)可能有方法修改knitr挂钩以保留临时文件,但这超出了我的知识范围。最后,你没有这个问题的原因是 ggplot