2015-06-24 1 views
24

У меня есть много функций, которые генерируют графики, обычно с ggplot2. Сейчас я создаю сюжет и тестирую основные данные. Но я хотел бы знать, есть ли разумный способ проверить, что сюжет содержит слои/варианты, которые я ожидаю, или что графические элементы соответствуют ожиданиям.Как написать тест для графика ggplot

Например:

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(...,...) 
}) 

Может быть, есть более прямой подход?

+0

ggplot2 [репо] (https://github.com/hadley/ggplot2/blob/master/tests/test-all.R) не имеет тестов, поэтому, возможно, это не реализовано? Было бы неплохо. – jeremycg

+1

Я знаю, следовательно, вопрос - и входящую награду. –

+3

[Это] (https://github.com/wch/ggplot2/wiki) может быть полезным, хотя я не уверен, насколько развит набор визуальных тестов с момента его внедрения. – joran

ответ

14

Это, кажется, то, на что вы нацеливаетесь, хотя конкретные требования к построению параметров и содержимого будут варьироваться, конечно. Но для примера вы красиво созданный выше этих тестов все должны пройти:

## 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) 
}) 

question and its answers Это предложение является хорошей отправной точкой на другие способы характеризовать ggplot объекты в случае, если у вас есть другие вещи, которые вы хотели бы проверить.

4

Следует отметить, что пакет vdiffr предназначен для сравнения участков. Хорошей особенностью является то, что он интегрируется с пакетом testthat - он фактически используется для тестирования в ggplot2 - и у него есть надстройка для RStudio, которая поможет управлять вашим testuite.

1

Что я также считаю полезным в дополнение к существующим ответам, это проверить, действительно ли можно распечатать сюжет.

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 
Смежные вопросы