4 Donor Assignment
Each multiplexed sample contains cells from two donors pooled together. Donor identity was assigned computationally using SNP-based demultiplexing (scSNPdemux), which leverages naturally occurring genetic variants in the scRNA-seq reads. To independently validate these assignments, HLA allele-specific expression is used as an orthogonal confirmation strategy. Each donor carries a unique combination of HLA alleles. If the SNP-based assignment is correct, HLA marker expression should segregate cleanly between the two assigned donors, PASC and Healty.
Two complementary HLA-based approaches are used: (1) expression of donor-specific HLA genes from a targeted HLA feature-barcode matrix (cellranger HLA output), and (2) HLA allele counts from scHLAcount, which quantifies allele-level HLA expression directly from the multiome reads.
4.1 Sample B
4.1.1 HLA gene expression
Load the HLA-typed feature-barcode matrix for Sample B. Donor-specific HLA marker genes are identified by matching gene names to the sample label. Expression of these markers is visualised per assigned donor — clean separation between donors confirms the demultiplexing is correct.
hla_h5 <- Read10X_h5("~/data/tasks/liam.kealy/processing/cellranger_sample_B_HLA/outs/filtered_feature_bc_matrix.h5")
hla_count <- CreateSeuratObject(counts = hla_h5,
assay = "RNA",
project = "SampleB",
names.delim = "-", names.field = 2)
demux <- read.table("~/data/tasks/liam.kealy/processing/scSNPdemux/cellranger_SC_ATAC_covid_B.demux/results/donor_ids.tsv",
header = T)
rownames(demux) <- demux$cell
hla_count <- AddMetaData(object = hla_count, metadata = demux)
marker_donor <- rownames(hla_count)[grepl('Sample-B', rownames(hla_count))]
VlnPlot(hla_count, features = marker_donor, pt.size = 0.1,
group.by = 'donor_id', ncol = 1) + NoLegend()
4.1.2 scHLAcount allele counts
HLA allele counts from the scHLAcount matrix are added to the Seurat object metadata. Each column corresponds to one HLA allele — the violin plots show allele count distributions per donor, providing a second orthogonal confirmation of donor assignment.
matrix_dir <- '~/data/tasks/liam.kealy/processing/scSNPdemux/scHLAcount/hla_B/'
mat <- readMM(file = paste0(matrix_dir, "count_matrix.mtx"))
feature.names <- read.delim(paste0(matrix_dir, "labels.tsv"),
header = FALSE, stringsAsFactors = FALSE)
barcode.names <- read.delim('~/data/tasks/liam.kealy/processing/scSNPdemux/scHLAcount/modify_cellranger/cellranger_SC_ATAC_covid_B_barcodes.tsv.gz',
header = FALSE, stringsAsFactors = FALSE)
colnames(mat) <- barcode.names$V1
rownames(mat) <- feature.names$V1
HLA <- data.frame(t(mat))
cntsB <- AddMetaData(cntsB, HLA)
VlnPlot(cntsB, features = colnames(HLA), group.by = 'donor_id', ncol = 2)
4.1.3 Cell counts per donor
table(cntsB$donor_id)
#>
#> donor0 donor1 doublet unassigned
#> 641 798 30 274.2 Sample C
4.2.1 HLA gene expression
hla_h5 <- Read10X_h5("~/data/tasks/liam.kealy/processing/cellranger_sample_C_HLA/outs/filtered_feature_bc_matrix.h5")
hla_count <- CreateSeuratObject(counts = hla_h5,
assay = "RNA",
project = "SampleC",
names.delim = "-", names.field = 2)
demux <- read.table("~/data/tasks/liam.kealy/processing/scSNPdemux/cellranger_SC_ATAC_covid_C.demux/results/donor_ids.tsv",
header = T)
rownames(demux) <- demux$cell
hla_count <- AddMetaData(object = hla_count, metadata = demux)
marker_donor <- rownames(hla_count)[grepl('Sample-C', rownames(hla_count))]
VlnPlot(hla_count, features = marker_donor, pt.size = 0.1,
group.by = 'donor_id', ncol = 1) + NoLegend()
4.2.2 scHLAcount allele counts
matrix_dir <- '~/data/tasks/liam.kealy/processing/scSNPdemux/scHLAcount/hla_C/'
mat <- readMM(file = paste0(matrix_dir, "count_matrix.mtx"))
feature.names <- read.delim(paste0(matrix_dir, "labels.tsv"),
header = FALSE, stringsAsFactors = FALSE)
barcode.names <- read.delim('~/data/tasks/liam.kealy/processing/scSNPdemux/scHLAcount/modify_cellranger/cellranger_SC_ATAC_covid_C_barcodes.tsv.gz',
header = FALSE, stringsAsFactors = FALSE)
colnames(mat) <- barcode.names$V1
rownames(mat) <- feature.names$V1
HLA <- data.frame(t(mat))
cntsC <- AddMetaData(cntsC, HLA)
VlnPlot(cntsC, features = colnames(HLA), group.by = 'donor_id', ncol = 2)
4.2.3 Cell counts per donor
table(cntsC$donor_id)
#>
#> donor0 donor1 doublet unassigned
#> 1573 428 38 324.3 Sample D
4.3.1 HLA gene expression
The donor-specific HLA alleles identified for Sample D are annotated in the comments below as a reference for interpreting the plots.
hla_h5 <- Read10X_h5("~/data/tasks/liam.kealy/processing/cellranger_sample_D_HLA/outs/filtered_feature_bc_matrix.h5")
hla_count <- CreateSeuratObject(counts = hla_h5,
assay = "RNA",
project = "SampleD",
names.delim = "-", names.field = 2)
demux <- read.table("~/data/tasks/liam.kealy/processing/scSNPdemux/cellranger_SC_ATAC_covid_D.demux/results/donor_ids.tsv",
header = T)
rownames(demux) <- demux$cell
hla_count <- AddMetaData(object = hla_count, metadata = demux)
marker_donor <- rownames(hla_count)[grepl('Sample-D', rownames(hla_count))]
VlnPlot(hla_count, features = marker_donor, pt.size = 0.1,
group.by = 'donor_id', ncol = 1) + NoLegend()
4.3.2 scHLAcount allele counts
matrix_dir <- '~/data/tasks/liam.kealy/processing/scSNPdemux/scHLAcount/hla_D/'
mat <- readMM(file = paste0(matrix_dir, "count_matrix.mtx"))
feature.names <- read.delim(paste0(matrix_dir, "labels.tsv"),
header = FALSE, stringsAsFactors = FALSE)
barcode.names <- read.delim('~/data/tasks/liam.kealy/processing/scSNPdemux/scHLAcount/modify_cellranger/cellranger_SC_ATAC_covid_D_barcodes.tsv.gz',
header = FALSE, stringsAsFactors = FALSE)
colnames(mat) <- barcode.names$V1
rownames(mat) <- feature.names$V1
HLA <- data.frame(t(mat))
cntsD <- AddMetaData(cntsD, HLA)
VlnPlot(cntsD, features = colnames(HLA), group.by = 'donor_id', ncol = 2)
4.3.3 Cell counts per donor
table(cntsD$donor_id)
#>
#> donor0 donor1 doublet unassigned
#> 566 1051 77 194.4 Condition Labelling
4.4.1 Assigning PASC and Healthy labels
Each multiplexed sample contains one PASC (Post-Acute Sequelae of COVID-19) donor and one healthy control donor. Donor identity was confirmed via HLA allele-specific expression in the Donor Assignment chapter. Based on those results, the PASC and Healthy labels are assigned to each sample–donor combination as follows:
| Sample | Donor | Condition |
|---|---|---|
| B | donor1 | PASC |
| B | donor0 | Healthy |
| C | donor0 | PASC |
| C | donor1 | Healthy |
| D | donor0 | PASC |
| D | donor1 | Healthy |
cntsB$sample <- 'Sample_B'
cntsC$sample <- 'Sample_C'
cntsD$sample <- 'Sample_D'
cntsB$sample_donor <- paste0(cntsB$sample, '_', cntsB$donor_id)
cntsC$sample_donor <- paste0(cntsC$sample, '_', cntsC$donor_id)
cntsD$sample_donor <- paste0(cntsD$sample, '_', cntsD$donor_id)
cntsB@meta.data$individual_condition <- NA
cntsC@meta.data$individual_condition <- NA
cntsD@meta.data$individual_condition <- NA
cntsB@meta.data$individual_condition[cntsB@meta.data$sample_donor == "Sample_B_donor1"] <- 'PASC'
cntsC@meta.data$individual_condition[cntsC@meta.data$sample_donor == "Sample_C_donor0"] <- 'PASC'
cntsD@meta.data$individual_condition[cntsD@meta.data$sample_donor == "Sample_D_donor0"] <- 'PASC'
cntsB@meta.data$individual_condition[cntsB@meta.data$sample_donor == "Sample_B_donor0"] <- 'Healthy'
cntsC@meta.data$individual_condition[cntsC@meta.data$sample_donor == "Sample_C_donor1"] <- 'Healthy'
cntsD@meta.data$individual_condition[cntsD@meta.data$sample_donor == "Sample_D_donor1"] <- 'Healthy'