Skip to content
Open
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
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -49,3 +49,8 @@ docs/*html
docker/testrun
scripts/._*
docs/._*
output/**
.gitignore
workflow/src/reports/._*
workflow/src/._*
.cwl_singularity_cache/
12 changes: 6 additions & 6 deletions workflow/Snakefile
Original file line number Diff line number Diff line change
Expand Up @@ -687,11 +687,11 @@ rule derive_kallisto_observed_whitelist:
import gzip

with open("{input.cb1}") as fh:
cb1 = {line.strip() for line in fh if line.strip()}
cb1 = {{line.strip() for line in fh if line.strip()}}
with open("{input.cb2}") as fh:
cb2 = {line.strip() for line in fh if line.strip()}
cb2 = {{line.strip() for line in fh if line.strip()}}
with open("{input.cb3}") as fh:
cb3 = {line.strip() for line in fh if line.strip()}
cb3 = {{line.strip() for line in fh if line.strip()}}

observed_valid_barcodes = set()
with gzip.open("{input.cb_umi_fq}", "rt") as fh:
Expand Down Expand Up @@ -1258,12 +1258,12 @@ ENDOFYML
sed -i "s|PLACEHOLDER_REF|$(realpath {params.ref_path})|" "$INPUT_YML"
sed -i "s|PLACEHOLDER_STV|{params.sample_tags_version}|" "$INPUT_YML"

CWL_SINGULARITY_CACHE=$(realpath .) \
SINGULARITY_PULLFOLDER=$(realpath .) \
mkdir -p .cwl_singularity_cache

CWL_SINGULARITY_CACHE="$(realpath .cwl_singularity_cache)" \
cwl-runner --singularity \
--outdir {params.outdir} \
{params.cwl} "$INPUT_YML" &> {log}

## cwl-runner places MEX outputs as zips in --outdir.
## Unzip both filtered and unfiltered into their respective subdirectories.
UNFILTERED_ZIP=$(ls {params.outdir}/*_RSEC_MolsPerCell_Unfiltered_MEX.zip 2>/dev/null | head -1)
Expand Down
1 change: 1 addition & 0 deletions workflow/envs/all_in_one.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ dependencies:
- conda-forge::r-matrixstats
- conda-forge::r-seurat
- conda-forge::r-seuratobject
- conda-forge::r-ggh4x
- bioconda::bioconductor-biocgenerics
- bioconda::bioconductor-biobase
Comment on lines +25 to 27

Copilot AI Apr 15, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

02_comparison.Rmd now loads/uses additional packages (e.g., pheatmap and scran::modelGeneVar). This conda env adds r-ggh4x but still doesn't include r-pheatmap or bioconductor-scran, so the report will fail at runtime. Please add the missing dependencies here (or remove the new imports if they aren't needed).

Suggested change
- conda-forge::r-ggh4x
- bioconda::bioconductor-biocgenerics
- bioconda::bioconductor-biobase
- conda-forge::r-ggh4x
- conda-forge::r-pheatmap
- bioconda::bioconductor-biocgenerics
- bioconda::bioconductor-biobase
- bioconda::bioconductor-scran

Copilot uses AI. Check for mistakes.
- bioconda::bioconductor-sparsematrixstats
Expand Down
113 changes: 113 additions & 0 deletions workflow/src/reports/02_comparison.Rmd
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@ suppressPackageStartupMessages({
library(UpSetR)
library(data.table)
library(patchwork)
library(pheatmap)
library(scran)
library(scater)
library(ggh4x)
})

wd <- params$working_dir
Expand Down Expand Up @@ -291,3 +295,112 @@ ggplot(umi_df, aes(x = log10(total_counts + 1),
x = "log10(total counts + 1)", y = "Density",
colour = NULL, linetype = NULL)
```

## Cell-level and gene-level pseudo-bulk comparison


```{r pb correlation, fig.width=12, fig.height=10}

Copilot AI Apr 15, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This chunk header uses {r pb correlation, ...} which knitr will parse as label pb plus an (unknown) option correlation. If the intent is a single label, please rename to something without spaces (e.g., pb_correlation) to avoid knitr warnings and make chunk references unambiguous.

Suggested change
```{r pb correlation, fig.width=12, fig.height=10}
```{r pb_correlation, fig.width=12, fig.height=10}

Copilot uses AI. Check for mistakes.

## cell-level pseudo-bulk
cb <- Reduce(intersect, lapply(sces, colnames))
if (length(cb) == 0) stop("No shared cell barcodes across sces.")

dt_cell <- data.table(feature = cb)
dt_cell[, (names(sces)) := lapply(sces, function(sce) {
vals <- colSums(assay(sce, "counts"))
vals[cb]
})]
dt_cell[, type := "Cell level"]

## gene-level pseudo-bulk
genes <- Reduce(intersect, lapply(sces, rownames))
if (length(genes) == 0) stop("No shared genes across sces.")

dt_gene <- data.table(feature = genes)
dt_gene[, (names(sces)) := lapply(sces, function(sce) {
vals <- rowSums(assay(sce, "counts"))
vals[genes]
})]
dt_gene[, type := "Gene level"]

## combine
dt_all <- rbindlist(list(dt_cell, dt_gene), fill = TRUE)

## pairwise comparisons
method_names <- names(sces)
pairs <- as.data.table(t(combn(method_names, 2)))
setnames(pairs, c("sample1", "sample2"))

plot_dt <- rbindlist(lapply(seq_len(nrow(pairs)), function(i) {
s1 <- pairs$sample1[i]
s2 <- pairs$sample2[i]

dt_all[, .(
feature,
type,
sample1 = s1,
sample2 = s2,
x = get(s1),
y = get(s2)
)]
}), fill = TRUE)

plot_dt <- plot_dt[!is.na(x) & !is.na(y)]
plot_dt[, pair := paste(sample1, "vs", sample2)]

## spearman labels
cor_lab <- plot_dt[, .(
cor = suppressWarnings(cor(x, y, method = "spearman"))
), by = .(type, sample1, sample2, pair)]
cor_lab[, label := sprintf("\u03C1 = %.2f", cor)]

## plot
ggplot(plot_dt, aes(x = x + 1, y = y + 1)) +
geom_point(alpha = 0.12, size = 0.35) +
geom_density_2d(linewidth = 0.3) +
geom_text(
data = cor_lab,
aes(label = label),
x = Inf, y = -Inf,
hjust = 1.1, vjust = -0.4,
inherit.aes = FALSE,
size = 3
) +
scale_x_log10() +
scale_y_log10() +
facet_grid2(type ~ pair, scales = "free", independent = "all") +
theme_classic() +
labs(
x = "Pseudo-bulk count + 1",
y = "Pseudo-bulk count + 1"
) +
theme(
strip.background = element_blank(),
axis.ticks = element_line(),
panel.spacing = unit(0.8, "lines"),
aspect.ratio = 1,
panel.border = element_rect(color = "black", fill = NA),
Comment on lines +380 to +382

Copilot AI Apr 15, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In this theme() call there are two issues that will break knitting: (1) panel.spacing = unit(...) will error unless unit is in scope (use grid::unit(...) or attach grid), and (2) there is a trailing comma after panel.border = ... which is a syntax error in R. Please fix both so the chunk runs.

Suggested change
panel.spacing = unit(0.8, "lines"),
aspect.ratio = 1,
panel.border = element_rect(color = "black", fill = NA),
panel.spacing = grid::unit(0.8, "lines"),
aspect.ratio = 1,
panel.border = element_rect(color = "black", fill = NA)

Copilot uses AI. Check for mistakes.
)

```

## Low dimensional space: PCA
```{r pca}
sces <- lapply(sces, \(sce) {
sce <- logNormCounts(sce)
tbl <- modelGeneVar(sce)
idx <- tbl$bio > 0
rowData(sce)$hvg <- FALSE
rowData(sce)$hvg[idx] <- TRUE
rowData(sce)$bio <- tbl$bio
sce <- runPCA(sce, subset_row = idx, ncomponents = 20)
})
lapply(names(sces), \(x) {
sce <- sces[[x]]
plotPCA(sce) +
ggtitle(x) +
theme_classic() +
coord_equal()}) |> wrap_plots(guides = "collect", ncol=4)
```