From 78abc4351add10be18999129590976884b4f658a Mon Sep 17 00:00:00 2001 From: HelenaLC Date: Sat, 5 Aug 2023 22:11:29 +0300 Subject: [PATCH 1/7] revise unit tests --- R/dplyr_methods.R | 16 +- data/pbmc_small.rda | Bin 33288 -> 41709 bytes tests/testthat/test-dplyr_methods.R | 391 +++++++++++++------------ tests/testthat/test-ggplotly_methods.R | 37 +++ tests/testthat/test-methods.R | 118 ++++---- tests/testthat/test-tidyr_methods.R | 125 ++++---- 6 files changed, 366 insertions(+), 321 deletions(-) create mode 100644 tests/testthat/test-ggplotly_methods.R diff --git a/R/dplyr_methods.R b/R/dplyr_methods.R index a57299f..01b3689 100755 --- a/R/dplyr_methods.R +++ b/R/dplyr_methods.R @@ -229,8 +229,7 @@ mutate.SingleCellExperiment <- function(.data, ...) { tst <- intersect( - cols %>% - names(), + cols, get_special_columns(.data) %>% c(get_needed_columns(.data)) ) %>% @@ -240,7 +239,7 @@ mutate.SingleCellExperiment <- function(.data, ...) { if (tst) { columns = get_special_columns(.data) %>% - c(get_needed_columns()) %>% + c(get_needed_columns(.data)) %>% paste(collapse=", ") stop( "tidySingleCellExperiment says: you are trying to rename a column that is view only", @@ -275,12 +274,13 @@ mutate.SingleCellExperiment <- function(.data, ...) { rename.SingleCellExperiment <- function(.data, ...) { # Check that we are not modifying a key column - cols <- tidyselect::eval_select(expr(c(...)), colData(.data) %>% as.data.frame()) - + df <- as_tibble(.data) + idx <- tidyselect::eval_rename(expr(c(...)), df) + cols <- names(df)[idx] + tst <- intersect( - cols %>% - names(), + cols, get_special_columns(.data) %>% c(get_needed_columns(.data)) ) %>% @@ -387,7 +387,7 @@ inner_join.SingleCellExperiment <- function(x, y, by=NULL, copy=FALSE, suffix=c( if(is_sample_feature_deprecated_used( x, when(by, !is.null(.) ~ by, ~ colnames(y)))){ x= ping_old_special_column_into_metadata(x) } - + x %>% as_tibble() %>% dplyr::inner_join(y, by=by, copy=copy, suffix=suffix, ...) %>% diff --git a/data/pbmc_small.rda b/data/pbmc_small.rda index aaf8f6574492580bcb4ed7ff9ee329da8ef32497..bba613d1f0a1651aeeaf2d746f24b4a1e1307491 100755 GIT binary patch literal 41709 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 Zcq}I%s@P~SUuh5iF64@Ep&)J52%;7EW#s?> literal 33288 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 diff --git a/tests/testthat/test-dplyr_methods.R b/tests/testthat/test-dplyr_methods.R index 6faee7c..cf6582b 100755 --- a/tests/testthat/test-dplyr_methods.R +++ b/tests/testthat/test-dplyr_methods.R @@ -1,191 +1,202 @@ -context("dplyr test") - -library(magrittr) - -test_that("arrange", { - - expect_warning( - tt_pca_aranged <- - pbmc_small %>% - arrange(groups) %>% - scater::logNormCounts() %>% - scater::runPCA()) - - expect_warning( - tt_pca <- - pbmc_small %>% - scater::logNormCounts() %>% - scater::runPCA()) - - expect_equal( - reducedDims(tt_pca_aranged)$PCA[sort(colnames(tt_pca_aranged)), 1:3] %>% abs() %>% head(), - reducedDims(tt_pca_aranged)$PCA[sort(colnames(tt_pca_aranged)), 1:3] %>% abs() %>% head(), - tollerance = 1e-3 - ) -}) - -test_that("bind_rows", { - expect_warning( - tt_bind <- pbmc_small %>% - bind_rows(pbmc_small)) - - tt_bind %>% - select(.cell) %>% - tidySingleCellExperiment:::to_tib() %>% - dplyr::count(.cell) %>% - dplyr::count(n, name="m") %>% - nrow() %>% - expect_equal(1) -}) - -test_that("bind_cols", { - tt_bind <- pbmc_small %>% select(groups) - - pbmc_small %>% - bind_cols(tt_bind) %>% - select(groups...7) %>% - ncol() %>% - expect_equal(1) -}) - -test_that("distinct", { - pbmc_small %>% - distinct(groups) %>% - ncol() %>% - expect_equal(1) -}) - -test_that("filter", { - pbmc_small %>% - filter(groups == "g1") %>% - ncol() %>% - expect_equal(44) -}) - -test_that("group_by", { - pbmc_small %>% - group_by(groups) %>% - nrow() %>% - expect_equal(80) -}) - -test_that("summarise", { - pbmc_small %>% - summarise(mean(nCount_RNA)) %>% - nrow() %>% - expect_equal(1) -}) - -test_that("mutate", { - pbmc_small %>% - mutate(groups = 1) %>% - distinct(groups) %>% - nrow() %>% - expect_equal(1) -}) - -test_that("rename", { - pbmc_small %>% - rename(s_score = groups) %>% - select(s_score) %>% - ncol() %>% - expect_equal(1) -}) - -test_that("left_join", { - pbmc_small %>% - left_join(pbmc_small %>% - distinct(groups) %>% - mutate(new_column = 1:2)) %>% - colData() %>% - ncol() %>% - expect_equal(10) -}) - -test_that("inner_join", { - pbmc_small %>% - inner_join(pbmc_small %>% - distinct(groups) %>% - mutate(new_column = 1:2) %>% - slice(1)) %>% - ncol() %>% - expect_equal(36) -}) - -test_that("right_join", { - pbmc_small %>% - right_join(pbmc_small %>% - distinct(groups) %>% - mutate(new_column = 1:2) %>% - slice(1)) %>% - ncol() %>% - expect_equal(36) -}) - -test_that("full_join", { - pbmc_small %>% - full_join(tibble::tibble(groups = "g1", other = 1:4)) %>% - nrow() %>% - expect_equal(212) -}) - -test_that("slice", { - pbmc_small %>% - slice(1) %>% - ncol() %>% - expect_equal(1) -}) - -test_that("select", { - pbmc_small %>% - select(.cell, orig.ident) %>% - class() %>% - as.character() %>% - expect_equal("SingleCellExperiment") - - pbmc_small %>% - select(orig.ident) %>% - class() %>% - as.character() %>% - .[1] %>% - expect_equal("tbl_df") -}) - -test_that("sample_n", { - pbmc_small %>% - sample_n(50) %>% - ncol() %>% - expect_equal(50) - - expect_equal( pbmc_small %>% sample_n(500, replace = TRUE) %>% ncol, 31 ) -}) - -test_that("sample_frac", { - pbmc_small %>% - sample_frac(0.1) %>% - ncol() %>% - expect_equal(8) - - expect_equal( pbmc_small %>% sample_frac(10, replace = TRUE) %>% ncol, 31 ) -}) - -test_that("count", { - pbmc_small %>% - count(groups) %>% - nrow() %>% - expect_equal(2) -}) - -test_that("add count", { - pbmc_small %>% - add_count(groups) %>% - nrow() %>% - expect_equal(230) -}) - -test_that("summarize alias", { - pbmc_small %>% - summarize(nCount_RNA = mean(nCount_RNA)) %>% - nrow() %>% - expect_equal(1) +df <- pbmc_small +df$number <- sample(seq(ncol(df))) +df$factor <- sample( + factor(1:3, labels=paste0("g", 1:3)), + ncol(df), TRUE, c(0.1, 0.3, 0.6)) + +test_that("arrange()", { + expect_identical( + arrange(df, number), + df[, order(df$number)]) + suppressWarnings({ + fd <- df %>% + scater::logNormCounts() %>% + scater::runPCA() + }) + expect_identical( + arrange(fd, PC1), + fd[, order(reducedDim(fd)[, 1])]) + fd <- df %>% + mutate(foo=seq(ncol(df))) %>% + arrange(foo) %>% select(-foo) + expect_identical(fd, df) +}) + +test_that("bind_rows()", { + # warn about duplicated cells names + expect_warning(fd <- bind_rows(df, df)) + # cell names should be unique after binding + expect_true(!any(duplicated(pull(fd, .cell)))) +}) + +test_that("bind_cols()", { + fd <- bind_cols(df, select(df, factor)) + i <- grep("^factor", names(colData(fd))) + expect_length(i, 2) + expect_identical(fd[[i[1]]], df$factor) + expect_identical(fd[[i[2]]], df$factor) + expect_identical( + select(fd, -starts_with("factor")), + select(df, -factor)) +}) + +test_that("distinct()", { + fd <- distinct(df, factor) + expect_equal(nrow(fd), nlevels(df$factor)) + expect_identical(fd[[1]], unique(df$factor)) +}) + +test_that("filter()", { + fd <- filter(df, factor %in% levels(df$factor)) + expect_identical(df, fd) + fd <- filter(df, factor == "g1") + expect_equal(ncol(fd), sum(df$factor == "g1")) + # missing cell names + fd <- df; colnames(fd) <- NULL + expect_silent(filter(df, number == 1)) + expect_message(fd <- filter(fd, number < 10)) + expect_type(pull(fd, .cell), "character") + expect_null(colnames(fd)) +}) + +test_that("group_by()", { + fd <- group_by(df, factor) + expect_equal(n_groups(fd), nlevels(df$factor)) + expect_equal(group_size(fd), tabulate(df$factor)) +}) + +test_that("summaris/ze()", { + fd <- mutate(df, n=runif(ncol(df))) + ne <- summarise(fd, a=mean(n)) + mo <- summarize(fd, b=mean(n)) + expect_identical(ne$a, mean(fd$n)) + expect_identical(ne$a, mo$b) +}) + +test_that("mutate()", { + fd <- mutate(df, peter="pan") + expect_true(all(fd$peter == "pan")) + fd <- mutate(df, number=paste(number)) + expect_identical(fd$number, paste(df$number)) + # special columns are blocked + expect_error(mutate(df, .cell=1)) + expect_error(mutate(df, PC_10=1)) +}) + +test_that("rename()", { + fd <- rename(df, num=number, fac=factor) + expect_identical(fd$num, df$number) + expect_identical(fd$fac, df$factor) + expect_error(rename(df, ne=mo)) + # special columns are blocked + expect_error(rename(df, a=.cell)) + expect_error(mutate(df, PC_10=1)) +}) + +test_that("left_join()", { + y <- df %>% + distinct(factor) %>% + mutate(string=letters[seq(nlevels(df$factor))]) + fd <- left_join(df, y, by="factor") + expect_s4_class(fd, "SingleCellExperiment") + expect_equal(n <- ncol(colData(fd)), ncol(colData(df))+1) + expect_identical(colData(fd)[-n], colData(df)) +}) + +test_that("inner_join()", { + string <- letters[seq(nlevels(df$factor))] + tbl <- df %>% distinct(factor) %>% mutate(string) %>% slice(1) + fd <- inner_join(df, tbl, by="factor") + expect_s4_class(fd, "SingleCellExperiment") + expect_equal(n <- ncol(colData(fd)), ncol(colData(df))+1) + expect_equal(ncol(fd), sum(df$factor == fd$factor[1])) +}) + +test_that("right_join()", { + y <- df %>% + distinct(factor) %>% + mutate(string=letters[seq(nlevels(df$factor))]) %>% + slice(1) + fd <- right_join(df, y, by="factor") + expect_s4_class(fd, "SingleCellExperiment") + expect_equal(n <- ncol(colData(fd)), ncol(colData(df))+1) + expect_equal(ncol(fd), sum(df$factor == fd$factor[1])) +}) + +test_that("full_join()", { + # w/ duplicated cell names + y <- tibble(factor="g2", other=1:3) + fd <- expect_message(full_join(df, y, by="factor", relationship="many-to-many")) + expect_s3_class(fd, "tbl_df") + expect_true(all(is.na(fd$other[fd$factor != "g2"]))) + expect_true(all(!is.na(fd$other[fd$factor == "g2"]))) + expect_equal(nrow(fd), ncol(df)+2*sum(df$factor == "g2")) + # w/o duplicates + y <- tibble(factor="g2", other=1) + fd <- expect_silent(full_join(df, y, by="factor")) + expect_s4_class(fd, "SingleCellExperiment") + expect_identical( + select(fd, -other), + mutate(df, factor=paste(factor))) +}) + +test_that("slice()", { + expect_identical(slice(df), df[, 0]) + expect_identical(slice(df, ncol(df)+1), df[, 0]) + expect_identical(slice(df, 1), df[, 1]) + expect_identical(slice(df, -1), df[, -1]) + i <- sample(ncol(df), 5) + expect_identical(slice(df, i), df[, i]) + expect_identical(slice(df, -i), df[, -i]) +}) + +test_that("select()", { + fd <- select(df, .cell, number) + expect_s4_class(fd, "SingleCellExperiment") + expect_equal(dim(fd), dim(df)) + fd <- select(df, number) + expect_s3_class(fd, "tbl_df") + expect_equal(nrow(fd), ncol(df)) +}) + +test_that("sample_n()", { + fd <- sample_n(df, n <- 50) + expect_s4_class(fd, "SingleCellExperiment") + expect_equal(nrow(fd), nrow(df)) + expect_equal(ncol(fd), n) + fd <- sample_n(df, 1e3, TRUE) + expect_s3_class(fd, "tbl_df") + expect_equal(nrow(fd), 1e3) +}) + +test_that("sample_frac()", { + fd <- sample_frac(df, 0.1) + expect_s4_class(fd, "SingleCellExperiment") + expect_equal(nrow(fd), nrow(df)) + expect_equal(ncol(fd), ncol(df)/10) + fd <- sample_frac(df, 10, TRUE) + expect_s3_class(fd, "tbl_df") + expect_equal(nrow(fd), ncol(df)*10) +}) + +test_that("count()", { + fd <- count(df, factor) + expect_s3_class(fd, "tbl_df") + expect_equal(nrow(fd), nlevels(df$factor)) + expect_identical(fd$n, tabulate(df$factor)) +}) + +test_that("add_count()", { + fd <- add_count(df, factor) + expect_identical(select(fd, -n), df) + expect_identical(fd$n, unname(c(table(df$factor)[df$factor]))) +}) + +test_that("rowwise()", { + expect_error(df %>% summarise(sum(lys))) + df$lys <- replicate(ncol(df), sample(10, 3), FALSE) + fd <- df %>% rowwise() %>% summarise(sum(lys)) + expect_s3_class(fd, "tbl_df") + expect_equal(dim(fd), c(ncol(df), 1)) + expect_identical(fd[[1]], sapply(df$lys, sum)) }) diff --git a/tests/testthat/test-ggplotly_methods.R b/tests/testthat/test-ggplotly_methods.R new file mode 100644 index 0000000..a41c2cd --- /dev/null +++ b/tests/testthat/test-ggplotly_methods.R @@ -0,0 +1,37 @@ +df <- pbmc_small +df$number <- rnorm(ncol(df)) +df$factor <- sample(gl(3, 1, ncol(df))) + +test_that("ggplot()", { + # cell metadata + p <- ggplot(df, aes(factor, number)) + expect_silent(show(p)) + expect_s3_class(p, "ggplot") + # assay data + g <- sample(rownames(df), 1) + fd <- join_features(df, g, shape="wide") + p <- ggplot(fd, aes(factor, .data[[g]])) + expect_silent(show(p)) + expect_s3_class(p, "ggplot") + # reduced dimensions + p <- ggplot(df, aes(PC_1, PC_2, col=factor)) + expect_silent(show(p)) + expect_s3_class(p, "ggplot") +}) + +test_that("plotly()", { + # cell metadata + p <- plot_ly(df, x=~factor, y=~number, type="violin") + expect_silent(show(p)) + expect_s3_class(p, "plotly") + # assay data + g <- sample(rownames(df), 1) + fd <- join_features(df, g, shape="wide") + p <- plot_ly(fd, x=~factor, y=g, type="violin") + expect_silent(show(p)) + expect_s3_class(p, "plotly") + # reduced dimensions + p <- plot_ly(fd, x=~PC_1, y=~PC_2, type="scatter", mode="markers") + expect_silent(show(p)) + expect_s3_class(p, "plotly") +}) diff --git a/tests/testthat/test-methods.R b/tests/testthat/test-methods.R index 20d142b..6411fde 100644 --- a/tests/testthat/test-methods.R +++ b/tests/testthat/test-methods.R @@ -1,61 +1,71 @@ -context('methods test') - -data("pbmc_small") -library(dplyr) -test_that("join_features",{ - - - pbmc_small %>% - join_features("CD3D") %>% - slice(1) %>% - pull(.abundance_counts) %>% - expect_equal(4, tolerance=0.1) - +df <- pbmc_small +test_that("show()", { + txt <- capture.output(show(df)) + expect_lt(length(txt), 20) + expect_equal(grep("SingleCellExperiment", txt), 1) + i <- grep(str <- ".*Features=([0-9]+).*", txt) + expect_equal(gsub(str, "\\1", txt[i]), paste(nrow(df))) + i <- grep(str <- ".*Cells=([0-9]+).*", txt) + expect_equal(gsub(str, "\\1", txt[i]), paste(ncol(df))) }) +test_that("join_features()", { + gs <- sample(rownames(df), 3) + # long + fd <- join_features(df, gs, shape="long") + expect_s3_class(fd, "tbl_df") + expect_setequal(unique(fd$.feature), gs) + expect_true(all(table(fd$.feature) == ncol(df))) + expect_identical( + matrix(fd$.abundance_counts, nrow=length(gs)), + as.matrix(unname(counts(df)[fd$.feature[seq_along(gs)], ]))) + # wide + fd <- join_features(df, gs, shape="wide", assay="counts") + expect_s4_class(fd, "SingleCellExperiment") + expect_null(fd$.feature) + expect_identical( + unname(t(as.matrix(as_tibble(fd)[, gs]))), + as.matrix(unname(counts(df)[gs, ]))) +}) -test_that("duplicated PCA matrices",{ - - pbmc_small@int_colData@listData$reducedDims$PCA2 = pbmc_small@int_colData@listData$reducedDims$PCA - - pbmc_small %>% - mutate(aa = 1) |> - as_tibble() |> - ncol() |> - expect_equal( - (pbmc_small |> as_tibble() |> ncol()) + 1 - ) - - +test_that("as_tibble()", { + fd <- as_tibble(df) + expect_s3_class(fd, "tbl_df") + expect_equal(nrow(fd), ncol(df)) + ncd <- ncol(colData(df)) + ndr <- vapply(reducedDims(df), ncol, integer(1)) + expect_equal(ncol(fd), sum(1, ncd, ndr)) + # duplicated PCs + reducedDim(df, "PCB") <- reducedDim(df, "PCA") + fd <- as_tibble(mutate(df, abc=1)) + expect_equal(ncol(fd), ncol(as_tibble(df))+1) }) -test_that("aggregate_cells() returns expected values", { - - # Create pseudo-bulk object for testing - pbmc_pseudo_bulk <- pbmc_small |> - tidySingleCellExperiment::aggregate_cells(c(groups, ident), assays = "counts") - - # Check row length is unchanged - pbmc_pseudo_bulk |> - nrow() |> - expect_equal(pbmc_small |> nrow()) - - # Check column length is correctly modified - pbmc_pseudo_bulk |> - ncol() |> - expect_equal(pbmc_small |> - as_tibble() |> - select(groups, ident) |> - unique() |> - nrow() - ) - - # Spot check for correctly aggregated count value of ACAP1 gene - assay(pbmc_pseudo_bulk, "counts")["ACAP1", "g1___0"] |> - expect_equal(assay(pbmc_small, "counts")["ACAP1", pbmc_small |> - as_tibble() |> - filter(groups == "g1", ident == 0) |> - pull(.cell)] |> - sum()) +test_that("aggregate_cells()", { + df$factor <- sample(gl(3, 1, ncol(df))) + df$string <- sample(c("a", "b"), ncol(df), TRUE) + tbl <- distinct(select(df, factor, string)) + fd <- aggregate_cells(df, c(factor, string)) + expect_identical(assayNames(fd), assayNames(df)) + # [HLC: aggregate_cells() currently + # reorders features alphabetically] + fd <- fd[rownames(df), ] + expect_s4_class(fd, "SummarizedExperiment") + expect_equal(dim(fd), c(nrow(df), nrow(tbl))) + foo <- mapply( + f=tbl$factor, + s=tbl$string, + \(f, s) { + expect_identical( + df %>% + filter(factor == f, string == s) %>% + assay() %>% rowSums() %>% as.vector(), + fd[, fd$factor == f & fd$string == s] %>% + assay() %>% as.vector()) + }) + # specified 'assays' are subsetted + expect_error(aggregate_cells(df, c(factor, string), assays="x")) + fd <- aggregate_cells(df, c(factor, string), assays="counts") + expect_identical(assayNames(fd), "counts") }) diff --git a/tests/testthat/test-tidyr_methods.R b/tests/testthat/test-tidyr_methods.R index 2006655..be0b9de 100755 --- a/tests/testthat/test-tidyr_methods.R +++ b/tests/testthat/test-tidyr_methods.R @@ -1,78 +1,65 @@ -context("tidyr test") - -tt <- pbmc_small %>% mutate(col2 = "other_col") - -test_that("nest_unnest", { - col_names <- tt %>% colData %>% colnames() %>% c("cell") - - expect_warning( - x <- tt %>% - nest(data = -groups) %>% - unnest(data) %>% - scater::logNormCounts() %>% - scater::runPCA()) - - expect_warning( - y <- tt %>% - scater::logNormCounts() %>% - scater::runPCA()) +df <- pbmc_small +df$number <- sample(seq(ncol(df))) +df$factor <- sample(gl(2, 1, ncol(df), c("g1", "g2"))) +test_that("un/nest()", { + fd <- nest(df, data=-factor) expect_equal( - reducedDims(x)$PCA %>% - as.data.frame() %>% - as_tibble(rownames = "cell") %>% - arrange(cell) %>% - pull(PC1) %>% - abs(), - reducedDims(x)$PCA %>% - as.data.frame() %>% - as_tibble(rownames = "cell") %>% - arrange(cell) %>% - pull(PC1) %>% - abs() - ) + nrow(fd), + nlevels(df$factor)) + expect_equal( + vapply(fd$data, ncol, integer(1)), + tabulate(df$factor)) + fd <- unnest(fd, data) + # [HLC: this is necessary because unnest() + # currently duplicates the 'int_metadata'] + int_metadata(fd) <- int_metadata(df) + expect_equal(fd, df[, colnames(fd)]) }) -test_that("unite separate", { - un <- tt %>% unite("new_col", c(groups, col2), sep = ":") - - un %>% - select(new_col) %>% - slice(1) %>% - pull(new_col) %>% - expect_equal("g2:other_col") - - se <- - un %>% - separate( - col = new_col, - into = c("orig.ident", "groups"), - sep = ":" - ) - - se %>% - select(orig.ident) %>% - ncol() %>% - expect_equal(1) +test_that("unite()/separate()", { + expect_error(unite(df, "x", c(number, x))) + expect_error(separate(df, x, c("a", "b"))) + + fd <- unite(df, "string", c(number, factor), sep=":") + expect_null(fd$number) + expect_null(fd$factor) + expect_identical(fd$string, paste(df$number, df$factor, sep=":")) + + fd <- separate(fd, string, c("a", "b"), sep=":") + expect_null(fd$string) + expect_identical(fd$a, paste(df$number)) + expect_identical(fd$b, paste(df$factor)) + + # special columns are blocked + expect_error(unite(df, ".cell", c(number, factor), sep=":")) + fd <- df; colnames(fd) <- paste(colnames(df), "x", sep="-") + expect_error(separate(fd, .cell, c("a", "b"), sep="-")) }) -test_that("extract", { - tt %>% - extract(groups, - into = "g", - regex = "g([0-9])", - convert = TRUE) %>% - pull(g) %>% - class() %>% - expect_equal("integer") +test_that("extract()", { + expect_error(extract(df, a, "b")) + expect_error(extract(df, factor, "x", "")) + + fd <- mutate(df, factor=paste(factor)) + expect_identical(extract(df, factor, "factor"), fd) + expect_identical(extract(df, factor, "factor", "(.*)"), fd) + + fd <- extract(df, factor, "g", "g([0-9])", convert=FALSE) + expect_identical(fd$g, gsub("^g", "", df$factor)) + expect_null(fd$factor) + + fd <- extract(df, factor, "g", "g([0-9])", convert=TRUE) + expect_identical(fd$g, as.integer(gsub("^g", "", df$factor))) + expect_null(fd$factor) }) -test_that("pivot_longer", { - tt %>% - pivot_longer(c(orig.ident, groups), - names_to = "name", - values_to = "value") %>% - class() %>% - .[1] %>% - expect_equal("tbl_df") +test_that("pivot_longer()", { + abc <- c("a", "b", "c") + df$string <- sample(abc, ncol(df), TRUE) + fd <- pivot_longer(df, c(factor, string)) + expect_s3_class(fd, "tbl_df") + expect_true(!any(c("factor", "string") %in% names(fd))) + expect_setequal(unique(fd$name), c("factor", "string")) + expect_setequal(unique(fd$value), c(levels(df$factor), abc)) }) From 07b8741538325f56cf8a2554f6f28255f1a42f69 Mon Sep 17 00:00:00 2001 From: HelenaLC Date: Sun, 6 Aug 2023 11:54:36 +0300 Subject: [PATCH 2/7] use base R pipe; bug fix: +make.names() when extracting features from tibble --- tests/testthat/test-dplyr_methods.R | 22 ++++++++++++---------- tests/testthat/test-ggplotly_methods.R | 2 +- tests/testthat/test-methods.R | 12 ++++++------ 3 files changed, 19 insertions(+), 17 deletions(-) diff --git a/tests/testthat/test-dplyr_methods.R b/tests/testthat/test-dplyr_methods.R index cf6582b..e3b96fd 100755 --- a/tests/testthat/test-dplyr_methods.R +++ b/tests/testthat/test-dplyr_methods.R @@ -94,8 +94,8 @@ test_that("rename()", { }) test_that("left_join()", { - y <- df %>% - distinct(factor) %>% + y <- df |> + distinct(factor) |> mutate(string=letters[seq(nlevels(df$factor))]) fd <- left_join(df, y, by="factor") expect_s4_class(fd, "SingleCellExperiment") @@ -104,18 +104,20 @@ test_that("left_join()", { }) test_that("inner_join()", { - string <- letters[seq(nlevels(df$factor))] - tbl <- df %>% distinct(factor) %>% mutate(string) %>% slice(1) - fd <- inner_join(df, tbl, by="factor") + y <- df |> + distinct(factor) |> + mutate(string=letters[seq(nlevels(df$factor))]) |> + slice(1) + fd <- inner_join(df, y, by="factor") expect_s4_class(fd, "SingleCellExperiment") expect_equal(n <- ncol(colData(fd)), ncol(colData(df))+1) expect_equal(ncol(fd), sum(df$factor == fd$factor[1])) }) test_that("right_join()", { - y <- df %>% - distinct(factor) %>% - mutate(string=letters[seq(nlevels(df$factor))]) %>% + y <- df |> + distinct(factor) |> + mutate(string=letters[seq(nlevels(df$factor))]) |> slice(1) fd <- right_join(df, y, by="factor") expect_s4_class(fd, "SingleCellExperiment") @@ -193,9 +195,9 @@ test_that("add_count()", { }) test_that("rowwise()", { - expect_error(df %>% summarise(sum(lys))) + expect_error(df |> summarise(sum(lys))) df$lys <- replicate(ncol(df), sample(10, 3), FALSE) - fd <- df %>% rowwise() %>% summarise(sum(lys)) + fd <- df |> rowwise() |> summarise(sum(lys)) expect_s3_class(fd, "tbl_df") expect_equal(dim(fd), c(ncol(df), 1)) expect_identical(fd[[1]], sapply(df$lys, sum)) diff --git a/tests/testthat/test-ggplotly_methods.R b/tests/testthat/test-ggplotly_methods.R index a41c2cd..6041ad2 100644 --- a/tests/testthat/test-ggplotly_methods.R +++ b/tests/testthat/test-ggplotly_methods.R @@ -10,7 +10,7 @@ test_that("ggplot()", { # assay data g <- sample(rownames(df), 1) fd <- join_features(df, g, shape="wide") - p <- ggplot(fd, aes(factor, .data[[g]])) + p <- ggplot(fd, aes(factor, .data[[make.names(g)]])) expect_silent(show(p)) expect_s3_class(p, "ggplot") # reduced dimensions diff --git a/tests/testthat/test-methods.R b/tests/testthat/test-methods.R index 6411fde..4cabdf5 100644 --- a/tests/testthat/test-methods.R +++ b/tests/testthat/test-methods.R @@ -25,7 +25,7 @@ test_that("join_features()", { expect_s4_class(fd, "SingleCellExperiment") expect_null(fd$.feature) expect_identical( - unname(t(as.matrix(as_tibble(fd)[, gs]))), + unname(t(as.matrix(as_tibble(fd)[, make.names(gs)]))), as.matrix(unname(counts(df)[gs, ]))) }) @@ -58,11 +58,11 @@ test_that("aggregate_cells()", { s=tbl$string, \(f, s) { expect_identical( - df %>% - filter(factor == f, string == s) %>% - assay() %>% rowSums() %>% as.vector(), - fd[, fd$factor == f & fd$string == s] %>% - assay() %>% as.vector()) + df |> + filter(factor == f, string == s) |> + assay() |> rowSums() |> as.vector(), + fd[, fd$factor == f & fd$string == s] |> + assay() |> as.vector()) }) # specified 'assays' are subsetted expect_error(aggregate_cells(df, c(factor, string), assays="x")) From de8dbb998079da7ff2f5263e93cc84d3d1bb14f0 Mon Sep 17 00:00:00 2001 From: HelenaLC Date: Mon, 14 Aug 2023 14:01:34 +0200 Subject: [PATCH 3/7] bug fix; rename() blocks special columns for both to & from --- R/dplyr_methods.R | 24 ++++++++++++------------ tests/testthat/test-dplyr_methods.R | 6 +++++- 2 files changed, 17 insertions(+), 13 deletions(-) diff --git a/R/dplyr_methods.R b/R/dplyr_methods.R index 01b3689..7eea148 100755 --- a/R/dplyr_methods.R +++ b/R/dplyr_methods.R @@ -274,18 +274,18 @@ mutate.SingleCellExperiment <- function(.data, ...) { rename.SingleCellExperiment <- function(.data, ...) { # Check that we are not modifying a key column - df <- as_tibble(.data) - idx <- tidyselect::eval_rename(expr(c(...)), df) - cols <- names(df)[idx] - - tst <- - intersect( - cols, - get_special_columns(.data) %>% - c(get_needed_columns(.data)) - ) %>% - length() %>% - gt(0) + .cols <- c( + get_needed_columns(.data), + get_special_columns(.data)) + names(.cols) <- .cols <- as.list(.cols) + df <- colData(.data) |> as.data.frame() |> data.frame(.cols) + + cols_to <- tryCatch( + error = function(e) e, + tidyselect::eval_rename(expr(c(...)), df) |> names()) + cols_from <- tidyselect::eval_select(expr(c(...)), df) |> names() + + tst <- any(cols_from %in% .cols) || inherits(cols_to, "error") if (tst) { columns = diff --git a/tests/testthat/test-dplyr_methods.R b/tests/testthat/test-dplyr_methods.R index e3b96fd..71a0f7d 100755 --- a/tests/testthat/test-dplyr_methods.R +++ b/tests/testthat/test-dplyr_methods.R @@ -89,8 +89,12 @@ test_that("rename()", { expect_identical(fd$fac, df$factor) expect_error(rename(df, ne=mo)) # special columns are blocked + # ...'to' cannot be special + expect_error(rename(df, a=PC_1)) expect_error(rename(df, a=.cell)) - expect_error(mutate(df, PC_10=1)) + # ...'from' cannot be special + expect_error(rename(df, PC_1=number)) + expect_error(rename(df, .cell=number)) }) test_that("left_join()", { From 61570adf42cfcc80c57ad4ff20b827ecdf7d079a Mon Sep 17 00:00:00 2001 From: Stefano Mangiola Date: Tue, 15 Aug 2023 14:11:12 +1000 Subject: [PATCH 4/7] update logics as the error we were getting was unexpected --- R/dplyr_methods.R | 53 +++++++++++++++++++++++++++-------------------- 1 file changed, 30 insertions(+), 23 deletions(-) diff --git a/R/dplyr_methods.R b/R/dplyr_methods.R index 7eea148..5b5bae1 100755 --- a/R/dplyr_methods.R +++ b/R/dplyr_methods.R @@ -274,31 +274,38 @@ mutate.SingleCellExperiment <- function(.data, ...) { rename.SingleCellExperiment <- function(.data, ...) { # Check that we are not modifying a key column - .cols <- c( + read_only_columns <- c( get_needed_columns(.data), - get_special_columns(.data)) - names(.cols) <- .cols <- as.list(.cols) - df <- colData(.data) |> as.data.frame() |> data.frame(.cols) - - cols_to <- tryCatch( - error = function(e) e, - tidyselect::eval_rename(expr(c(...)), df) |> names()) + get_special_columns(.data) + ) + + # Small df to be more efficient + df <- .data[1,1] |> as_tibble() + + # What columns we are going to create cols_from <- tidyselect::eval_select(expr(c(...)), df) |> names() - - tst <- any(cols_from %in% .cols) || inherits(cols_to, "error") - - if (tst) { - columns = - get_special_columns(.data) %>% - c(get_needed_columns(.data)) %>% - paste(collapse=", ") - stop( - "tidySingleCellExperiment says: you are trying to rename a column that is view only", - columns, " ", - "(it is not present in the colData). If you want to mutate a view-only column, make a copy and mutate that one." - ) - } - + + # What are the columns before renaming + original_columns = df |> colnames() + + # What the column after renaming would be + new_colums = df |> rename(...) |> colnames() + + # What column you are impacting + changed_columns = original_columns |> setdiff(new_colums) + + # Check that you are not impacting any read-only columns + if(changed_columns %in% read_only_columns) + stop( + "tidySingleCellExperiment says: you are trying to rename a column that is view only `", + changed_columns, + "` ", + "(it is not present in the colData). If you want to rename a view-only column, make a copy (e.g. mutate(", + cols_from[1], + " = ", + changed_columns[1], + "))." + ) colData(.data) <- dplyr::rename(colData(.data) %>% as.data.frame(), ...) %>% DataFrame() From a202e5f0c7a158ece02170ba692c7ea8550387dc Mon Sep 17 00:00:00 2001 From: Stefano Mangiola Date: Tue, 15 Aug 2023 14:16:35 +1000 Subject: [PATCH 5/7] fix mutate error message --- R/dplyr_methods.R | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/R/dplyr_methods.R b/R/dplyr_methods.R index 5b5bae1..a6db0d8 100755 --- a/R/dplyr_methods.R +++ b/R/dplyr_methods.R @@ -242,10 +242,14 @@ mutate.SingleCellExperiment <- function(.data, ...) { c(get_needed_columns(.data)) %>% paste(collapse=", ") stop( - "tidySingleCellExperiment says: you are trying to rename a column that is view only", - columns, " ", - "(it is not present in the colData). If you want to mutate a view-only column, make a copy and mutate that one." + "tidySingleCellExperiment says: you are trying to mutate a column that is view only `", + cols, + "` ", + "(it is not present in the colData). If you want to mutate a view-only column, make a copy (e.g. mutate(new_column = ", + cols[1], + ")) and mutate that one." ) + } colData(.data) <- From 619631375af4cd076f4d813a5e4c2c13d5a0f4c5 Mon Sep 17 00:00:00 2001 From: Stefano Mangiola Date: Tue, 15 Aug 2023 14:24:19 +1000 Subject: [PATCH 6/7] fix check --- R/dplyr_methods.R | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/R/dplyr_methods.R b/R/dplyr_methods.R index a6db0d8..e9f8512 100755 --- a/R/dplyr_methods.R +++ b/R/dplyr_methods.R @@ -299,7 +299,7 @@ rename.SingleCellExperiment <- function(.data, ...) { changed_columns = original_columns |> setdiff(new_colums) # Check that you are not impacting any read-only columns - if(changed_columns %in% read_only_columns) + if(any(changed_columns %in% read_only_columns)) stop( "tidySingleCellExperiment says: you are trying to rename a column that is view only `", changed_columns, From 02dcbf3815b3db7a7281960460ce34de0a86d23a Mon Sep 17 00:00:00 2001 From: Stefano Mangiola Date: Tue, 15 Aug 2023 14:24:31 +1000 Subject: [PATCH 7/7] test specify error messages --- tests/testthat/test-dplyr_methods.R | 41 +++++++++++++++++++++++------ 1 file changed, 33 insertions(+), 8 deletions(-) diff --git a/tests/testthat/test-dplyr_methods.R b/tests/testthat/test-dplyr_methods.R index 71a0f7d..50d5656 100755 --- a/tests/testthat/test-dplyr_methods.R +++ b/tests/testthat/test-dplyr_methods.R @@ -78,23 +78,45 @@ test_that("mutate()", { expect_true(all(fd$peter == "pan")) fd <- mutate(df, number=paste(number)) expect_identical(fd$number, paste(df$number)) + # special columns are blocked - expect_error(mutate(df, .cell=1)) - expect_error(mutate(df, PC_10=1)) + df |> + mutate(.cell=1) |> + expect_error(regexp = "you are trying to mutate a column that is view only") + + df |> + mutate(PC_10=1) |> + expect_error(regexp = "you are trying to mutate a column that is view only") }) test_that("rename()", { fd <- rename(df, num=number, fac=factor) expect_identical(fd$num, df$number) expect_identical(fd$fac, df$factor) - expect_error(rename(df, ne=mo)) + + df |> + rename(ne=mo) |> + expect_error(regexp = "Column `mo` doesn't exist") + # special columns are blocked # ...'to' cannot be special - expect_error(rename(df, a=PC_1)) - expect_error(rename(df, a=.cell)) + + df |> + rename(a=PC_1) |> + expect_error(regexp = "you are trying to rename a column that is view only") + + df |> + rename(a=.cell) |> + expect_error(regexp = "you are trying to rename a column that is view only") # ...'from' cannot be special - expect_error(rename(df, PC_1=number)) - expect_error(rename(df, .cell=number)) + + df |> + rename(PC_1=number) |> + expect_error(regexp = "These names are duplicated") + + df |> + rename(.cell=number) |> + expect_error(regexp = "These names are duplicated") }) test_that("left_join()", { @@ -199,7 +221,10 @@ test_that("add_count()", { }) test_that("rowwise()", { - expect_error(df |> summarise(sum(lys))) + df |> + summarise(sum(lys)) |> + expect_error(regexp = "object 'lys' not found") + df$lys <- replicate(ncol(df), sample(10, 3), FALSE) fd <- df |> rowwise() |> summarise(sum(lys)) expect_s3_class(fd, "tbl_df")