This tutorial builds one cluster-level single-cell RNA-seq analysis through four cumulative configurations:
Each configuration reuses the objects prepared in the previous sections, so the effect of each added source of information can be compared directly.
By the end, you will have:
mpaqt_index object for the reference
transcriptome;mpaqt_quant_result objects;
andThe four result lists are named sr_results,
sr_lr_results, sr_lr_bias_results, and
sr_lr_bias_prior_results.
The short-read configuration requires:
kallisto and bustools available on your
system.The cluster file must have barcodes in its first column and cluster labels in its second column. Additional columns are ignored. For example:
barcode,cluster
AAACCCAAGAAACACT-1,Astrocyte
AAACCCAAGAAACCAT-1,Neuron
AAACCCAAGAAACCCG-1,Neuron
The long-read configuration additionally requires a transcript-by-cell count matrix. Its first column contains transcript IDs, and its remaining column names are cell barcodes:
transcript_id,AAACCCAAGAAACACT-1,AAACCCAAGAAACCAT-1
ENST00000456328.2,2,0
ENST00000450305.2,0,3
The final configuration also uses the GTEx PCA table downloaded in Add the GTEx Prior.
Load MPAQT and create the index once for a reference:
library(mpaqt)
index <- mpaqt_index(
annotation = "reference/gencode.annotation.gtf",
transcriptome = "reference/gencode.transcripts.fa",
output_file = "reference/mpaqt.index.rds",
read_length = 91L,
threads = 8L
)Set read_length to the length of the cDNA sequence
represented by R2. Reuse the saved index in later runs:
index <- mpaqt_read_index("reference/mpaqt.index.rds")See the index reference for other supported reference inputs.
Prepare cluster-level equivalence-class counts from the 10x FASTQ files and cluster assignments:
sr_list <- mpaqt_prepare_short_reads_sc(
index = index,
fastq_1 = "data/sample_R1.fastq.gz",
fastq_2 = "data/sample_R2.fastq.gz",
clusters_file = "data/clusters.csv",
do_umi_dedup = TRUE,
umi_dedup_mode = "fractional_proportional",
output_dir = "results/short-read",
technology = "10xv3",
threads = 8L
)sr_list contains one mpaqt_counts_sr object
per cluster and an "all_clusters" object that pools their
counts. With the settings above, each barcode-UMI molecule contributes a
total count of one while its evidence can be distributed across
equivalence classes.
UMI handling occurs at two separate stages.
do_umi_dedup = TRUE collapses read records to
molecule-level counts during preparation. Later,
mpaqt_quant_sc() uses do_umi_correction = TRUE
by default to normalize the short-read probability matrices during
quantification.
Run the first configuration for every entry in
sr_list:
sr_results <- mpaqt_quant_sc(
index = index,
sr_counts_list = sr_list
)The returned list uses the same cluster names as sr_list
and also includes the pooled "all_clusters" result.
Aggregate the transcript-by-cell long-read matrix using the same cluster file:
lr_list <- mpaqt_prepare_long_reads_sc(
index = index,
count_file = "data/long_read_counts.csv",
clusters_file = "data/clusters.csv",
output_dir = "results/long-read"
)lr_list contains one mpaqt_counts_lr object
per cluster plus an "all_clusters" object. The short- and
long-read lists must use the same cluster names. Cell barcodes in the
count-matrix columns must match those in the cluster file exactly.
Add the long-read counts to obtain the second configuration:
sr_lr_results <- mpaqt_quant_sc(
index = index,
sr_counts_list = sr_list,
lr_counts_list = lr_list
)This call reuses the same cluster-level short-read evidence and adds transcript-level long-read evidence for each cluster.
For a 3’-biased protocol or observed 3’ enrichment, add 3’ positional-bias correction to obtain the third configuration:
sr_lr_bias_results <- mpaqt_quant_sc(
index = index,
sr_counts_list = sr_list,
lr_counts_list = lr_list,
positional_bias = "3p"
)MPAQT estimates one set of positional weights from the pooled
sr_list[["all_clusters"]] counts and applies those weights
to each cluster. For a 5’-biased protocol or observed 5’ enrichment, use
positional_bias = "5p" instead.
The GTEx prior table contains transcript expression embeddings
derived from principal component analysis of GTEx v8 multi-tissue bulk
RNA-seq data. Each row represents one transcript; the
transcript_id column is followed by 200 features named
PC1 through PC200. MPAQT uses these scores as
predictive features when fitting its abundance prior.
Download gtex_PCA_output.csv.gz
from the Zenodo record
and decompress it:
wget -O gtex_PCA_output.csv.gz "https://zenodo.org/records/21478011/files/gtex_PCA_output.csv.gz?download=1"
gunzip gtex_PCA_output.csv.gzRead the decompressed table, then pass it directly to
prior_model in the fourth configuration:
gtex_prior_path <- "gtex_PCA_output.csv"
prior_data <- data.table::fread(gtex_prior_path)
sr_lr_bias_prior_results <- mpaqt_quant_sc(
index = index,
sr_counts_list = sr_list,
lr_counts_list = lr_list,
positional_bias = "3p",
prior_model = prior_data,
prior_start = 25L,
convergence_start = 50L
)MPAQT matches prior_data$transcript_id to the index
after removing version suffixes. With these iteration settings, prior
fitting begins at iteration 25 and convergence is not checked until
iteration 50, allowing the fitted prior to affect the abundance
estimates before the run can stop.
These four configurations are cumulative to make their comparison clear. The R API does not make long reads, positional-bias correction, and the prior intrinsically dependent: arguments can be omitted when a study calls for a different combination.
Choose the result list for the configuration you want to take
forward. Here we use the fourth configuration and exclude the pooled
"all_clusters" result from the cluster-by-cluster
output:
final_results <- sr_lr_bias_prior_results
cluster_ids <- setdiff(names(final_results), "all_clusters")
cluster_results <- final_results[cluster_ids]
head(tpm(cluster_results[[1]]))
combined_tpm <- do.call(
combine_quant_results,
c(
unname(cluster_results),
list(sample_names = cluster_ids)
)
)
head(combined_tpm)combined_tpm has one transcript_id column
followed by one TPM column per cluster. Save the per-cluster result
objects, per-cluster TPM tables, and the combined table together:
mpaqt_save_result_sc(
cluster_results,
output_dir = "results/quantification",
prefix = "sample"
)Use sr_results, sr_lr_results, or
sr_lr_bias_results in the same way when you want to inspect
or save an earlier configuration.
If kallisto has already produced matching BUS and equivalence-class files, prepare the single-cell short-read list without rerunning pseudoalignment:
sr_list <- mpaqt_prepare_short_reads_sc(
index = index,
clusters_file = "data/clusters.csv",
bus_file = "data/output.bus",
ec_file = "data/matrix.ec",
do_umi_dedup = TRUE,
umi_dedup_mode = "fractional_proportional",
output_dir = "results/short-read",
technology = "10xv3",
threads = 8L
)Previously prepared cluster objects can be reconstructed into named
lists from their stored sample_id values:
sr_files <- list.files(
"results/short-read",
pattern = "\\.short_read\\.rds$",
full.names = TRUE
)
sr_list <- lapply(sr_files, mpaqt_read_short_read_counts)
names(sr_list) <- vapply(sr_list, function(x) x$sample_id, character(1))
lr_files <- list.files(
"results/long-read",
pattern = "\\.long_read\\.rds$",
full.names = TRUE
)
lr_list <- lapply(lr_files, mpaqt_read_long_read_counts)
names(lr_list) <- vapply(lr_list, function(x) x$sample_id, character(1))See the single-cell short-read and single-cell long-read references for complete input details.
Cluster names differ between lists. Prepare short and long reads from the same cluster file, or rename list entries so every short-read cluster has the corresponding long-read entry.
No long-read barcodes match a cluster. Compare the
matrix column names with the first column of clusters.csv,
including any -1 suffixes.
Transcript IDs do not match. Use the same reference release for the index and long-read counts. The GTEx table can be matched with or without transcript version suffixes.
kallisto, bustools, or GPBoost is unavailable. Follow the dependency checks in the installation article, then restart R if your environment changed.
The final result contains all_clusters.
This pooled entry is useful for shared weight estimation. Remove it with
setdiff() as shown before combining or saving per-cluster
results.