【问题标题】:knitr HTML output too largeknitr HTML 输出太大
【发布时间】:2016-08-07 15:41:30
【问题描述】:

我一直在使用rmarkdown/knitrknit to html 功能为一些博客生成html 代码。我发现它非常有用和方便,但最近在文件大小方面遇到了一些问题。

当我编写包含使用 shapefile 或 ggmap 图像的图形的脚本时,html 文件变得太大,博客主机无法理解它(我已尝试使用 blogger 和 wordpress)。我相信这与将 shapefiles/ggmap 放入 html 表单的相对较大的 data.frames/files 有关。我可以做些什么来获得可以由博客主机解析的较小的 html 文件?

作为参考,rmarkdown 脚本的 html 输出带有一个使用 ggmap 层的图形、一层 shapefile 和一些数据,大小为 1.90MB,对于博客或 wordpress 而言,在 html 输入中无法处理。感谢您的任何想法。

【问题讨论】:

    标签: r knitr r-markdown


    【解决方案1】:

    以下是 3 个不同的选项,可帮助您减少带有编码图像的 HTML 文件的文件大小。


    1。优化现有 HTML 文件

    您可以在现有 HTML 文件上运行 this Python script。该脚本将:

    • 解码 base64 编码图像
    • 运行pngquant 优化图像
    • 将优化后的图片重新编码为base64

    用法:

    python optimize_html.py infile.html
    

    它将输出写入infile-optimized.html


    2。使用内置的 knitr hook 优化 PNG 图片

    knitr 1.15 包含一个名为 hook_optipng 的钩子,它将在生成的 PNG 文件上运行 optipng 程序以减小文件大小。

    这是一个.Rmd 示例(取自:knitr-examples/035-optipng.Rmd):

    # 035-optipng.Rmd
    
    This demo shows you how to optimize PNG images with `optipng`.
    
    ```{r setup}
    library(knitr)
    knit_hooks$set(optipng = hook_optipng)
    ```
    
    Now we set the chunk option `optipng` to a non-`NULL` value,
    e.g. `optipng=''`, to activate the hook. This string is passed to
    `optipng`, so you can use `optipng='-o7'` to optimize more heavily.
    
    ```{r use-optipng, optipng=''}
    library(methods)
    library(ggplot2)
    set.seed(123)
    qplot(rnorm(1e3), rnorm(1e3))
    ```
    

    3。为任何图像优化器编写自己的 knitr hook

    Writing your own hook 也很简单,所以我写了一个调用pngquant 程序的钩子。我发现pngquant 运行得更快,输出文件更小,看起来更好。

    这是一个 .R 示例,它定义并使用了 hook_pngquant(取自 this gist)。

    #' ---
    #' title: "pngquant demo"
    #' author: "Kamil Slowikowski"
    #' date: "`r Sys.Date()`"
    #' output:
    #'   html_document:
    #'     self_contained: true
    #' ---
    
    #+ setup, include=FALSE
    library(knitr)
    
    # Functions taken from knitr/R/utils.R
    all_figs = function(options, ext = options$fig.ext, num = options$fig.num) {
      fig_path(ext, options, number = seq_len(num))
    }
    in_dir = function(dir, expr) {
      if (!is.null(dir)) {
        owd = setwd(dir); on.exit(setwd(owd))
      }
      wd1 = getwd()
      res = expr
      wd2 = getwd()
      if (wd1 != wd2) warning(
        'You changed the working directory to ', wd2, ' (probably via setwd()). ',
        'It will be restored to ', wd1, '. See the Note section in ?knitr::knit'
      )
      res
    }
    is_windows = function() .Platform$OS.type == 'windows'
    in_base_dir = function(expr) {
      d = opts_knit$get('base.dir')
      if (is.character(d) && !file_test('-d', d)) dir.create(d, recursive = TRUE)
      in_dir(d, expr)
    }
    
    # Here is the code you can modify to use any image optimizer.
    hook_pngquant <- function(before, options, envir) {
      if (before)
        return()
      ext = tolower(options$fig.ext)
      if (ext != "png") {
        warning("this hook only works with PNG")
        return()
      }
      if (!nzchar(Sys.which("pngquant"))) {
        warning("cannot find pngquant; please install and put it in PATH")
        return()
      }
      paths = all_figs(options, ext)
      in_base_dir(lapply(paths, function(x) {
        message("optimizing ", x)
        cmd = paste(
          "pngquant",
          if (is.character(options$pngquant)) options$pngquant,
          shQuote(x)
        )
        message(cmd)
        (if (is_windows())
          shell
          else system)(cmd)
        x_opt = sub("\\.png$", "-fs8.png", x)
        file.rename(x_opt, x)
      }))
      return()
    }
    
    # Enable this hook in this R script.
    knit_hooks$set(
      pngquant = hook_pngquant
    )
    
    #' Here we set the chunk option `pngquant='--speed=1 --quality=0-50'`,
    #' which activates the hook.
    
    #+ use-pngquant, pngquant='--speed=1 --quality=0-50'
    library(methods)
    library(ggplot2)
    set.seed(123)
    qplot(rnorm(1e3), rnorm(1e3))
    

    我更喜欢用 R 脚本 (.R) 而不是 R markdown 文档 (.Rmd) 来编写我的报告。有关如何执行此操作的更多信息,请参阅http://yihui.name/knitr/demo/stitch/

    【讨论】:

    • hook_pngquant 自版本 1.15.1 起在 knitr 中本机可用
    【解决方案2】:

    您可以做的一件事是不使用嵌入式图像和其他资源。为此,您可以将文档的 YAML 标头中的 self_contained 选项设置为 false,例如:

    ---
    output:
      html_document:
        self_contained: false
    ---
    

    更多信息在这里:http://rmarkdown.rstudio.com/html_document_format.html

    【讨论】:

    • 有没有办法嵌入图像而不是其余的东西(如所有数据点等)?不确定这些是否可以真正分开,但那将是理想的。感谢您指出这个方向。
    • 你说的数据点是什么意思?当您呈现 knitr/RMarkdown 文档时,进入 HTML 的唯一内容是文档中的文本/代码,以及任何打印或绘制的内容。因此,除非您将数据框显式打印到屏幕上,否则数据点本身只会间接出现在您的图中。如果您使用的是 SVG 或类似的东西,那么图像会很大,因为它们存储了每个数据点,但如果您只是使用默认值 (PNG),那么这应该不是问题。
    • 我认为每个数据帧的内容都以某种方式存储在编织的html中,就像html代码是运行计算的整个过程等等。我只是这么认为是因为html文件相当多比针织的word文档大。显然我对这些内部工作原理和 html 不是很熟悉,所以感谢您的帮助。
    • @moman822 Jupyter/Ipython 笔记本确实以 JSON 格式存储了一些中间数据结构,但 knitr 并非如此。文件大小的差异可能与 html/doc 输出的不同默认图像格式以及嵌入在独立 html 输出文件中的外部 javascript 和 CSS 文件有关。通过生成非独立版的HTML,也可以更方便的判断每张图片有多大,如果有特别大的,可以尝试改变图片尺寸、格式等来减少图片大小大小。
    猜你喜欢
    • 1970-01-01
    • 2020-10-09
    • 2014-03-18
    • 2023-03-20
    • 1970-01-01
    • 2017-06-24
    • 2013-02-07
    • 2016-06-16
    • 2015-03-08
    相关资源
    最近更新 更多