R产生的PDF的MD5校验和不一致

时间:2019-07-18 23:42:39

标签: r pdf plot graphics metadata

我正在使用 testthat 测试R包。为S3方法plot.foo编写测试非常麻烦,因为它只返回NULL,所以我决定将图保存到文件中,并检查自上次运行以来是否已更改。 >

pdf(file='plot_foo.pdf')
plot.foo(bar)
dev.off()
tools::md5sum('plot_foo.pdf')

问题是每次使用相同的输入获得不同的结果时。输出看起来一样。

replicate(10, {
  pdf(file='plot.pdf')
  plot(1:10, 10:1)
  dev.off()
  Sys.sleep(1)
  tools::md5sum('plot.pdf')
})

请注意,每次迭代之间需要等待一段时间,否则文件将完全相同,这使我怀疑某些基于时间的元数据已更改。

                          plot.pdf                           plot.pdf
"5a0c096fe088342bc3c3d5960c5da1c9" "40d93c26b4901aef55a32b75473d05d2"
                          plot.pdf                           plot.pdf
"9815c6d9b2e94cda763a486fcd2ddf08" "a8e8db82d06b79f98416fa034b5aee46"
                          plot.pdf                           plot.pdf
"c2770250dbef3b60706559114c434851" "91c8cf124eb61ddebd3edbbb2d01677f"
                          plot.pdf                           plot.pdf
"d1594bd83b97fc890410a4c305366682" "f05197f165ec04df3dac4664494f4617"
                          plot.pdf                           plot.pdf
"64427124c6a6454e8f0e5944de20be95" "ff1abf2b31dfe688cf8f5994e409cc6d"

如何强制R生成一致的PDF?我出于测试目的暂时切换到PostScript,但是我更喜欢PDF,因为它得到了更好的支持(Windows似乎没有内置的PostScript查看器),因此也可以用作文档。

1 个答案:

答案 0 :(得分:1)

虽然我认为在某些方面有些粗略,但我认为vdiffr会让您做所需的事情。

  1. 首先,我将创建一个包;因为vdiffr仅在严格控制的环境中起作用:使用testthat的软件包。

    usethis::create_package("~/StackOverflow/nalzok")
    setwd("~/StackOverflow/nalzok")
    usethis::use_testthat()
    
  2. 创建一个test_something.R测试文件。

    context("basic plot tests")
    baseplot1 <- function() hist(1:10)
    vdiffr::expect_doppelganger("base 1", baseplot1)
    

    (我将假设hist(1:10)是相关且有趣的东西。基本图解必须是一个函数,ggplot2对象不是一个函数;有关更多信息,请参阅文档。)

  3. 我曾经以为我可以直接调用vdiffr::expect_doppelganger(因为大多数testthat::expect_*函数通常可以调用),但是首先需要对其进行“托管”(设置)。

    vdiffr::manage_cases(".")
    

    每个图像都需要(由人类进行)“验证”,因此这将打开一个闪亮的应用程序,该应用程序将遍历每个预期的doppelgangers:

    shiny app for image-validation

  4. 验证后,每次test软件包时,它将验证图像是否未更改:

    devtools::test()
    # Loading nalzok
    # Testing nalzok
    # v | OK F W S | Context
    # v |  1       | basic plot tests
    # == Results =====================================================================
    # OK:       1
    # Failed:   0
    # Warnings: 0
    # Skipped:  0
    
  5. 如果某些更改(例如将hist(1:10)更改为hist(2:11)),它将在下一个测试中失败:

    devtools::test()
    # Loading nalzok
    # Testing nalzok
    # v | OK F W S | Context
    # x |  0 1     | basic plot tests
    # --------------------------------------------------------------------------------
    # test_something.R:3: failure: (unknown)
    # Figures don't match: base-1.svg
    # --------------------------------------------------------------------------------
    # == Results =====================================================================
    # OK:       0
    # Failed:   1
    # Warnings: 0
    # Skipped:  0
    

    它通过创建一个./tests/testthat/figs/目录以及每个期望的目录和.svg文件来做到这一点,尽管您不需要与之交互,但对于{{1} }进行版本控制(您执行对您的程序包进行版本控制,对吧?)。

一些警告,我想:

  • 它正在保存到.../figs/个文件中;如果您的S3 .svg功能不能很好地与SVG配合使用(发生了吗?我不知道),那么我还不知道该如何处理;

  • 因为它使用的是基于文本的SVG格式,所以它将注意到一个点或一个框或某物是否发生了移动,但仅在某些基本公差范围内;例如,即使足够更改了一些元参数(限制),也会触发故障。一般而言,这很好,因为我认为测试应该可以抵抗较小的更改(上游库等)。

    plot.foo