web-dev-qa-db-ja.com

ggplotプロットのテストの書き方

通常はggplot2を使用して、プロットを生成する関数がたくさんあります。現在、プロットを生成し、基になるデータをテストしています。しかし、プロットに期待するレイヤー/オプションが含まれていること、またはグラフィック要素が期待に一致することをテストする合理的な方法があるかどうかを知りたいです。

例えば:

library(ggplot2)
library(scales) # for percent()
library(testthat)

df <- data.frame(
  Response = LETTERS[1:5],
  Proportion = c(0.1,0.2,0.1,0.2,0.4)
)

#' @export plot_fun
plot_fun <- function(df) {
  p1 <- ggplot(df, aes(Response, Proportion)) +
    geom_bar(stat='identity') + 
    scale_y_continuous(labels = percent)
return(p1)
}

test_that("Plot returns ggplot object",{
  p <- plot_fun(df)
  expect_is(p,"ggplot")
})

test_that("Plot uses correct data", {
  p <- plot_fun(df)
  expect_that(df, equals(p$data))

})

これは私が立ち往生しているところです

test_that("Plot layers match expectations",{
  p <- plot_fun(df)
  expect_that(...,...)
})

test_that("Scale is labelled percent",{
  p <- plot_fun(df)
  expect_that(...,...)
})

おそらくもっと直接的なアプローチがありますか?

34

もちろん、パラメータとコンテンツをプロットするための特定の要件は異なりますが、これはあなたが目指しているもののようです。しかし、これらのテストの上でうまく作成した例では、すべて合格するはずです。

##  Load the proto library for accessing sub-components of the ggplot2
##    plot objects:
library(proto)

test_that("Plot layers match expectations",{
  p <- plot_fun(df)
  expect_is(p$layers[[1]], "proto")
  expect_identical(p$layers[[1]]$geom$objname, "bar")
  expect_identical(p$layers[[1]]$stat$objname, "identity")
})

test_that("Scale is labelled 'Proportion'",{
  p <- plot_fun(df)
  expect_identical(p$labels$y, "Proportion")
})

test_that("Scale range is NULL",{
  p <- plot_fun(df)
  expect_null(p$scales$scales[[1]]$range$range)
})

これ 質問とその回答 他にテストしたいことがある場合に備えて、ggplotオブジェクトを特徴付ける他の方法の良い出発点を提供します。

21

vdiffr パッケージは、プロットを比較するために設計されていることに注意してください。優れた機能は、testthatパッケージと統合されていることです(実際にはggplot2でのテストに使用されます)。また、テストスイートの管理に役立つRStudio用のアドインがあります。

9
Dylan

既存の回答に加えて私が役立つと思うのは、プロットが実際に印刷できるかどうかをテストすることです。

library(ggplot2)
library(scales) # for percent()
library(testthat)

# First, 'correct' data frame
df <- data.frame(
    Response   = LETTERS[1:5],
    Proportion = c(0.1,0.2,0.1,0.2,0.4)
)

# Second data frame where column has 'wrong' name that does not match aes()
df2 <- data.frame(
    x          = LETTERS[1:5],
    Proportion = c(0.1,0.2,0.1,0.2,0.4)
)

plot_fun <- function(df) {
    p1 <- ggplot(df, aes(Response, Proportion)) +
        geom_bar(stat='identity') + 
        scale_y_continuous(labels = percent)
    return(p1)
}

# All tests succeed
test_that("Scale is labelled 'Proportion'",{
    p <- plot_fun(df)
    expect_true(is.ggplot(p))
    expect_identical(p$labels$y, "Proportion")

    p <- plot_fun(df2)
    expect_true(is.ggplot(p))
    expect_identical(p$labels$y, "Proportion")
})

# Second test with data frame df2 fails
test_that("Printing ggplot object actually works",{
    p <- plot_fun(df)
    expect_error(print(p), NA)

    p <- plot_fun(df2)
    expect_error(print(p), NA)
})
#> Error: Test failed: 'Printing ggplot object actually works'
#> * `print(p)` threw an error.
#> Message: object 'Response' not found
#> Class:   simpleError/error/condition
3
hplieninger