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
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
# task_spatial_simulators dev

Bug fixes:
- `generate_cosine()`: filter the Moran's I values rather than the objects
holding them, so that a single NaN no longer takes the whole metric with
it. `crosscor_cosine` was NA for 32 of 99 runs.
- `calculate_precision()`: report 0 rather than NA when a simulation has no
spatially variable genes at all. Both negative controls were left without a
score on any dataset, so nothing anchored the bottom of the scale.
- `ks_statistic_gene_cell` and `ks_statistic_sc_features`: the metric
descriptions said Kolmogorov-Smirnov, but both call `ks::kde.test()`, which
is a kernel density based two-sample test.
Expand Down
25 changes: 21 additions & 4 deletions src/helpers/utils.R
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,20 @@ generate_moransI <- function(adata) {

generate_cosine <- function(real, sim) {
requireNamespace("lsa", quietly = TRUE)
real_new <- real[!is.na(real) & !is.na(sim)]
sim_new <- sim[!is.na(real) & !is.na(sim)]
similarity <- lsa::cosine(lsa::as.textmatrix(cbind(as.vector(real_new$Morans.I), as.vector(sim_new$Morans.I))))

real_i <- as.vector(real$Morans.I)
sim_i <- as.vector(sim$Morans.I)

# drop the pairs where either side is missing. This used to filter `real` and
# `sim` themselves, which are lists, so it never dropped anything and a single
# NaN took the whole metric with it -- 32 of 99 runs came out NA, while
# generate_mantel() passes na.rm and lost none.
keep <- is.finite(real_i) & is.finite(sim_i)
if (sum(keep) < 2) {
return(NA_real_)
}

similarity <- lsa::cosine(lsa::as.textmatrix(cbind(real_i[keep], sim_i[keep])))
return(mean(similarity))
}

Expand Down Expand Up @@ -57,7 +68,10 @@ calculate_precision <- function(real_svg, sim_svg) {
filtered_compared_data <- dplyr::filter(sim_svg$res_mtest, adjustedPval < 0.05)
tp <- length(intersect(row.names(filtered_real_data), row.names(filtered_compared_data)))
fp <- length(setdiff(row.names(filtered_compared_data), row.names(filtered_real_data)))
precision <- ifelse((tp + fp) > 0, tp / (tp + fp), NA)
# a simulation that produces no spatially variable genes at all is a bad
# simulation, not a missing result. Reporting NA meant both negative controls
# had no score on any dataset, so nothing anchored the bottom of the scale.
precision <- ifelse((tp + fp) > 0, tp / (tp + fp), 0)
return(precision)
}

Expand All @@ -66,6 +80,9 @@ calculate_recall <- function(real_svg, sim_svg) {
filtered_compared_data <- dplyr::filter(sim_svg$res_mtest, adjustedPval < 0.05)
tp <- length(intersect(row.names(filtered_real_data), row.names(filtered_compared_data)))
fn <- length(setdiff(row.names(filtered_real_data), row.names(filtered_compared_data)))
# unlike precision, an empty denominator here says something about the real
# dataset rather than about the simulation: there are no spatially variable
# genes to recover, so no simulator can be scored on it. NA is right.
recall <- ifelse((tp + fn) > 0, tp / (tp + fn), NA)
return(recall)
}
Expand Down
Loading