Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion DESCRIPTION
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Package: AzimuthAPI
Title: Pan-Azimuth Web API Interface
Version: 1.0.0
Version: 1.0.1
Authors@R:
person("Satija", "Lab", email = "satijalabnygc@gmail.com", role = c("aut", "cre"))
Description: An R package providing an interface to the Pan-Azimuth Web API for single-cell RNA sequencing analysis.
Expand Down
17 changes: 17 additions & 0 deletions R/make_qc_heatmaps.R
Original file line number Diff line number Diff line change
Expand Up @@ -50,11 +50,22 @@ make_QC_heatmap <- function(
seurat_obj <- subset(seurat_obj,idents = names(which(table(Idents(seurat_obj))<=max.size)))
}
if (!is.null(n_downsample)) seurat_obj <- subset(seurat_obj, downsample=n_downsample)

ident_groups <- table(Idents(seurat_obj))
ident_groups <- ident_groups[ident_groups > 0]
if (length(ident_groups) < 2) {
stop("QC heatmaps require at least two identity groups with cells after filtering.")
}

mark_all <- FindAllMarkers(seurat_obj,only.pos = TRUE,min.pct = min.pct)
mark_all %>% group_by(.data$cluster) %>%
dplyr::filter(.data$avg_log2FC > logfc_cutoff) %>%
slice_head(n = n_markers) %>%
ungroup() -> top_markers

if (nrow(top_markers) == 0) {
stop("No marker genes were identified for the requested identity groups.")
}

if (!is.null(switch_id)) {
Idents(seurat_obj) <- switch_id
Expand Down Expand Up @@ -187,6 +198,12 @@ make_azimuth_QC_heatmaps <- function(
for (level1 in names(result_list)) {
lobj <- subset(object,cells = rownames(result_list[[level1]]))
Idents(lobj) <- final_name
ident_groups <- table(Idents(lobj))
ident_groups <- ident_groups[ident_groups > 0]
if (length(ident_groups) < 2) {
cli::cli_warn("Skipping {level1}; QC heatmaps require at least two final annotation groups with cells.")
next
}
tryCatch({
plot_list[[level1]] <- make_QC_heatmap(lobj, min.size = min.final.group, identity = as.character(level1), ...)
}, error = function(e) {
Expand Down
84 changes: 84 additions & 0 deletions tests/testthat/test_visualization.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@

make_viz_test_object <- function(cells = NULL) {
query <- readRDS(test_path("test_obj.rds"))
query <- Seurat::NormalizeData(query, verbose = FALSE)
if (!is.null(cells)) {
query <- subset(query, cells = colnames(query)[seq_len(cells)])
}
return(query)
}

set_azimuth_metadata <- function(query, fine, broad, full) {
query@meta.data$azimuth_fine <- fine
query@meta.data$azimuth_broad <- broad
query@meta.data$full_hierarchical_labels <- full
query@meta.data$full_consistent_hierarchy <- TRUE
return(query)
}

test_that("make_QC_heatmap rejects single-label inputs before marker detection", {
query <- make_viz_test_object()
query@meta.data$final_level_labels <- "Unassigned"

expect_error(
make_QC_heatmap(query, group.by = "final_level_labels"),
"at least two identity groups",
fixed = TRUE
)
})

test_that("make_azimuth_QC_heatmaps skips single-label final annotation groups", {
query <- make_viz_test_object()
query <- set_azimuth_metadata(
query,
fine = "Unassigned",
broad = "Unassigned",
full = "Unassigned"
)

expect_warning(
plots <- make_azimuth_QC_heatmaps(query, min.final.group = 10),
"Skipping Unassigned_1",
fixed = TRUE
)
expect_false("Unassigned_1" %in% names(plots))
})

test_that("make_azimuth_QC_heatmaps returns valid plots even when one group errors", {
query <- make_viz_test_object(cells = 70)
query <- set_azimuth_metadata(
query,
fine = c(
rep("Unassigned", 10),
rep("T cell", 10),
rep("B cell", 10),
rep("Fibroblast", 25),
rep("Rare stromal", 15)
),
broad = c(
rep("Immune cell", 30),
rep("Stromal cell", 40)
),
full = c(
rep("Immune cell|Lymphoid cell", 30),
rep("Stromal cell", 40)
)
)

# after the filtering, the stromal cell group has only "Rare stromal" left, but this is a single-label group, so it will error out in make_QC_heatmap
# the valid plot for "Immune cell" should still be returned, and the error for "Stromal cell" should be caught and reported as a warning
expect_warning(
plots <- make_azimuth_QC_heatmaps(
query,
min.final.group = 9,
n_markers = 1,
max.size = 20
),
"Error in processing Stromal cell_1",
fixed = TRUE
)

expect_named(plots, "Immune_Lymphoid cell_1")
expect_s3_class(plots[["Immune_Lymphoid cell_1"]], "ggplot")
expect_false("Stromal cell_1" %in% names(plots))
})
Loading