如何将 r ggplot 图存储为 html 代码片段

Posted

技术标签:

【中文标题】如何将 r ggplot 图存储为 html 代码片段【英文标题】:How to store r ggplot graph as html code snippet 【发布时间】:2021-12-17 08:31:39 【问题描述】:

我正在通过使用ggplotly()htmltools 函数(如h3()html())创建各种对象来创建一个html 文档。然后我将它们作为列表提交给 htmltools::save_html() 以创建一个 html 文件。

我想直接将 ggplot 图表添加为图像,而不是附加所有的花里胡哨的情节。最后,我将创建一个自包含的 html 文件(无依赖关系),而情节复杂的东西会使该文件过大。

是否有一些函数可以将 ggplot 对象转换为 html 类型的对象?还是我必须将 ggplot 保存为 .png 文件,然后将 .png 文件读入我在 save_html() 函数中添加到列表中的某个对象?

我的 R 代码如下所示:

library("tidyverse")
library("plotly")
library("htmltools")

HTMLOut <- "c:/Users/MrMagoo/My.html")
df <- data.frame(x=1:25, y=c(1:25*1:25))

g7 <- ggplot(df,aes(x=x, y=y)) + geom_point()
p7 <- ggplotly(g7)  # I would like to use something other than ggplotly here. Just capturing the ggplot as an image would be fine.

# create other objects to add to the html file
t7 <- h2(id="graph7", "Title for graph #7")
d7 <- p("description of graph 7")

save_html(list(t7, p7, d7), HTMLOut)
# of course, the real code has many more objects in that list – more graphs, text, tables, etc.

我想将 plotly 对象 (p7) 替换为仅以不导致 save_html 函数出错的方式呈现 g7 的东西。

我曾希望找到一个可以直接 Base64 编码 ggplot 对象的函数,但似乎我首先需要将“ggplot”对象输出为 .png 文件(或 SVG,根据Teng L,下),然后对其进行 base64 编码。我希望有一种更直接的方法,但我最终可能会这样做,就像在 https://***.com/a/33410766/3799203 中一样,以

结尾
g7img <- "<img src=\"data:image/png;base64,(base64encode string)\""
g7img <- htmltools::html(g7img)

【问题讨论】:

你看过这个post 谢谢,我确实看到了那个帖子。我想避免阴谋,因为它创建的自包含 html 文件很大(超过 2 兆字节),以支持它提供的所有交互功能。 【参考方案1】:

如果要将绘图保存为动态 plotly 图形,可以使用 htmlwidgets::saveWidget。这将生成一个独立的 html 文件。

这是一个最小的例子:

library(tidyverse);
library(plotly);
library(htmlwidgets);

df <- data.frame(x = 1:25, y = c(1:25 * 1:25))
gg <- ggplot(df,aes(x = x, y = y)) + geom_point()

# Save ggplotly as widget in file test.html
saveWidget(ggplotly(gg), file = "test.html");

【讨论】:

【参考方案2】:

我最终生成了一个临时图像文件,然后在我称为 encodeGraphic() 的函数中对其进行 base64 编码(借用 LukeA's post 的代码):

library(ggplot2)
library(RCurl)
library(htmltools)
encodeGraphic <- function(g) 
  png(tf1 <- tempfile(fileext = ".png"))  # Get an unused filename in the session's temporary directory, and open that file for .png structured output.
  print(g)  # Output a graphic to the file
  dev.off()  # Close the file.
  txt <- RCurl::base64Encode(readBin(tf1, "raw", file.info(tf1)[1, "size"]), "txt")  # Convert the graphic image to a base 64 encoded string.
  myImage <- htmltools::HTML(sprintf('<img src="data:image/png;base64,%s">', txt))  # Save the image as a markdown-friendly html object.
  return(myImage)


HTMLOut <- "~/TEST.html"   # Say where to save the html file.
g <- ggplot(mtcars, aes(x=gear,y=mpg,group=factor(am),color=factor(am))) + geom_line()  # Create some ggplot graph object
hg <- encodeGraphic(g)  # run the function that base64 encodes the graph
forHTML <- list(h1("My header"), p("Lead-in text about the graph"), hg)
save_html(forHTML, HTMLOut)  # output it to the html file.

【讨论】:

有没有办法控制图片的宽度。 有没有办法使用 htm 代码 'forHTML' 并且仍然像真正的情节一样进行交互?我想知道因为我很难在 Wordpress 帖子或页面中添加一个情节图作为 html 输出......但是使用 html 代码“forHTML”是有效的......虽然它不再是交互式的......【参考方案3】:

我认为您想要的可能接近以下之一:

    您似乎正在创建 HTML 报告,但尚未签出 RMarkdown。它带有 Base64 编码。当您创建 RMarkdown 报告时,pandoc 会自动将任何图表转换为文档中的 HTML 元素,因此报告是独立的。

    SVG 绘图。这不太可能是您想要的,但 SVG 绘图是基于标记语言的,并且可能很容易移植。使用 ggsave() 时指定 .svg 扩展名,您应该会获得 SVG 图像。请注意,SVG 是绘图的原样实现,因此如果您有数千个形状和线条,则文件大小可能会很大。

【讨论】:

SVG 可能是一个不错的解决方案。我在原始帖子中添加了更多关于将 ggplot 保存到文件的内容。【参考方案4】:

这是the Maurits Evers post 的扩展。在这个答案中,我展示了如何以有组织的方式在同一个 html 文件中组合多个绘图:

library("plotly")
library("htmltools")

# a small helper function to avoid repetition
my_func <- function(..., title)
    ## Description:
    ##   A function to add title to put multiple gg plotly objects under a html heading
    ##
    ## Arguments:
    ##   ...: a list of gg objects
    ##   title: a character vector to specify the heading text
    
    # get the ... in list format
    lst <- list(...)
    
    # create the heading
    tmp_title <- htmltools::h1(title)
    
    # convert each ggplot to ggplotly and put them under the same div html tag
    tmp_plot <- lapply(lst, ggplotly) |>
        htmltools::div()
    
    # return the final object as list
    return(list(tmp_title, tmp_plot))


# a toy data
df <- data.frame(x = 1:25, y = c(1:25 * 1:25))

# the ggplot object using the toy data
gg <- ggplot(df,aes(x = x, y = y)) + geom_point()

# put everything in order
final_list <- list(my_func(obj = list(gg, gg, gg), title = "The first heading"),
                   my_func(obj = list(gg, gg), title = "The second heading"))

# write to disk as a unified HTML file
htmltools::save_html(html = final_list,
                     file = "index.html"))

免责声明:我专门这样做是为了避免使用 widgetframe R 包并完全与the documentation of plotly-r 相提并论。如果您对添加额外的依赖项和额外的抽象层感到满意,您可以阅读该链接。当且仅在必要时,我更喜欢使用包。 :)

【讨论】:

以上是关于如何将 r ggplot 图存储为 html 代码片段的主要内容,如果未能解决你的问题,请参考以下文章

如何将 2 个图(ggplot)合并为一个图?

使用ggplot将直方图转换为r中的小提琴图

R - ggplot2 - 限制分类数据的条形图输出

R闪亮:如何将滑块和单选按钮链接到ggplot

堆叠条形图将变量转换为ggplot2 R中不相关变量的基于存在缺失的百分比

如何使用 R ggplot 按值对条形图进行排序? [复制]