Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

Splicing QC and Normalization

Quality control and normalisation of alternative-splicing quantifications from leafcutter.

Overview

Quality control and normalization of alternative-splicing quantifications produced by the leafcutter tool. Raw outputs are converted to BED format, features with high per-sample missingness (default 40%) are dropped, low-variance introns (default min variance 0.001) are removed, values are quantile-normalized, and remaining missing values are mean-imputed. The normalized tables are ready to use as molecular phenotypes for tensorQTL.

Intron excision ratios are not comparable across samples as they come out of the caller. They are compositional - each intron is a fraction of its cluster - and sparse, because an intron unused in a sample has no reads rather than a zero. Left alone, both properties show up in association testing as signal that tracks sequencing depth and sample handling rather than genotype. The steps here filter clusters, impute the missing entries and quantile normalise, which is what makes the phenotype usable downstream.

leafcutter_norm runs the whole route; leafcutter_qqnorm is the normalisation half on its own, for when QC and imputation happened elsewhere.

When to run it. After splicing calling, before phenotype preprocessing and association testing.

Input

  • --ratios: the splicing ratio matrix to normalise, and the main input to both workflows. Which form it takes depends on the workflow: leafcutter_norm expects the leafcutter per-cluster intron usage counts, protocol_example.leafcutter.intron_usage_perind.counts.gz (counts, count/total per sample), and leafcutter_qqnorm an already-QCed numeric intron-ratio table, ..._raw_data.txt.

  • --qced-data: where step 3 looks for its input. A directory, the default ., is scanned for files ending _raw_data.txt. A single file is used directly, and that case also forces --mean_impute on to fill any remaining NAs.

  • --no_norm: stop leafcutter_norm before step 3, leaving the QCed table un-normalised. This is how the three-step route gets a QC-only result to hand to the imputer.

  • --mean_impute: off by default. Fills missing ratios by the mean; step 3 turns it on by itself when --qced-data names a file.

  • --cwd: the directory outputs are written to.

  • --container: the Apptainer or Docker image to run in, for example oras://ghcr.io/cumc/leafcutter_apptainer:latest.

  • --numThreads, --mem and --walltime: job resources.

  • --junc-path: the directory Junc_list globs for per-sample *.junc files. Required; it has no default.

  • --file-suffix: the extension Junc_list looks for, junc by default.

  • --dataset: names the junction list Junc_list writes, ROSMAP_DLPFC by default.

  • --sample-table: the sample lookup table Jointcall_samples reads, previewed above.

  • --junc-list: the junction list Jointcall_samples reads, normally the file Junc_list wrote.

  • --leafcutter-version: the subdirectory both steps write into, leafcutter2 by default.

Route B step 2 calls phenotype_imputation.ipynb, not this notebook, so the flags in that command (--phenoFile for the QCed table from step 1, and --prior and --varType for the EBMF model) are that module’s options and are documented there. They are not parameters of this notebook.

Output

  • {cwd}/{leafcutter_version}/{dataset}_intron_usage_perind.junc - the per-cluster junction file assembled by Junc_list.

  • {cwd}/{leafcutter_version}/{sample_table}.rnaseq - the joint-called sample table from Jointcall_samples.

  • {ratios}_phenotype_file_list.txt - the phenotype file list written by the first leafcutter_norm step. Example input/rnaseq/protocol_example.leafcutter.intron_usage_perind.counts.gz_phenotype_file_list.stdout sits beside it.

  • {input}_raw_data.txt - the QC’d numeric intron-ratio table from the second leafcutter_norm step, which is also what leafcutter_qqnorm takes as its starting point.

  • {input}.qqnorm.txt - the quantile-normalised phenotype table, from either leafcutter_norm or the standalone leafcutter_qqnorm. Example input/rnaseq/protocol_example.leafcutter.intron_usage_perind.counts.gz_raw_data.qqnorm.txt, with a bgzipped and tabix-indexed .qqnorm.bed.gz beside it. Example input/rnaseq/protocol_example.leafcutter.intron_usage_perind.counts.gz_raw_data.qqnorm.txt, 24 columns and 112 rows, first 5 columns:

    #Chr  start  end  ID  SAMPLE_001
    chr22  16671178  16671518  chr22:16671178:1667151  -0.25101591868327155
    chr22  16671588  16673600  chr22:16671588:1667360  -1.261282157758418

Example output/splicing/leafcutter2/protocol_example_intron_usage_perind.junc from Junc_list, 2 lines, one path per sample:

output/splicing/junc/SAMPLE_001.junc
output/splicing/junc/SAMPLE_002.junc

Example output/splicing/leafcutter2/protocol_example.rnaseq.sample_participant_lookup.txt.rnaseq from Jointcall_samples, 3 lines:

sample_id	participant_id
SAMPLE_001	SAMPLE_001
SAMPLE_002	SAMPLE_002

Each workflow ends in a quantile-normalised phenotype table in BED-like form, #Chr start end ID plus one column per sample, ready to use directly as a molecular phenotype input to TensorQTL.

Minimal Working Example

Build the junction list

RNA-seq sample IDs differ from the WGS sample IDs, so the joint-call sample lookup table is first subset to the RNA-seq samples used in the sQTL analysis, matching the sample set used elsewhere in the protocol. The table pairs each sample ID with its participant ID. Example tests/fixtures/bulk_expression_normalization/protocol_example.rnaseq.sample_participant_lookup.txt, 2 columns and 61 rows:

Junc_list globs --junc-path for per-sample *.junc files, resolves them to absolute paths and drops the all entry, leaving one list file. No directory of .junc files ships here, so --junc-path is a placeholder.

Timing: TBD (on toy dataset)

Joint-call the samples

Jointcall_samples takes the junction list from the previous step together with the sample lookup table and writes the .rnaseq table that the leafcutter routes consume. The two chain by hand: --junc-list is the file Junc_list wrote.

Timing: TBD (on toy dataset)

Leafcutter

This workflow runs the full leafcutter chain in one command: it builds the phenotype table, applies an autosome filter and QC, and quantile-normalizes the intron-usage ratios. The --mean_impute option fills missing ratios with the per-intron (row) mean. See the leafcutter documentation; the choice of regtool parameters is discussed here.

Parameters. chr_blacklist is a file of blacklisted chromosomes to exclude from analysis, one per line; if none is provided, no chromosomes are excluded.

Timing: TBD (on toy dataset)

Leafcutter with EBMF imputation

This is the leafcutter route split into three commands so that EBMF imputation can be used instead of the default mean imputation. Run it instead of, not after, the single leafcutter_norm command above.

The steps are chained by hand rather than by SoS, so the placeholders in the commands below must be filled in with real paths:

  1. QC - leafcutter_norm --no_norm stops after the raw-data table, writing {ratios}_raw_data.txt.

  2. Imputation - phenotype_imputation.ipynb EBMF takes that table through --phenoFile (<output_from_step1>). This step runs a different module.

  3. Normalization - leafcutter_qqnorm takes the imputed matrix through --qced-data (<output_from_step2>). Because that argument names a file rather than a directory, this step also switches on mean imputation for any NAs EBMF left behind.

To perform leafcutter analysis with QC (setting cluster counts of 0 as NA), imputation (flashR), and normalization, use the following commands (RECOMMENDED):

Step 1. QC

Timing: TBD (on toy dataset)

Step 2. Imputation

Timing: TBD (on toy dataset)

Step 3. Normalization

Timing: TBD (on toy dataset)

Or if you are going to use the default mean imputation method, you can run it with one-step command (remove --no_norm in the first step):

Timing: TBD (on toy dataset)

Command Interface

usage: sos run pipeline/splicing_normalization.ipynb
               [workflow_name | -t targets] [options] [workflow_options]
  workflow_name:        Single or combined workflows defined in this script
  targets:              One or more targets to generate
  options:              Single-hyphen sos parameters (see "sos run -h" for details)
  workflow_options:     Double-hyphen workflow-specific parameters

Workflows:
  Junc_list
  Jointcall_samples
  leafcutter_norm
  leafcutter_qqnorm

Global Workflow Options:
  --modular-script-dir code/script (as path)
  --cwd output (as path)
                        The output directory for generated files.
  --chr-blacklist . (as path)
                        intron usage ratio file wiht samples after QC optional
                        parameter black list if user want to blacklist some
                        chromosomes and not to analyze
  --job-size 1 (as int)
                        For cluster jobs, number commands to run per job
  --walltime 5h
                        Wall clock time expected
  --mem 16G
                        Memory expected
  --numThreads 8 (as int)
                        Number of threads
  --container ''
                        Software container option

Sections
  Junc_list:
    Workflow Options:
      --junc-path VAL (as path, required)
      --file-suffix junc
      --leafcutter-version leafcutter2
      --dataset 'ROSMAP_DLPFC'
  Jointcall_samples:
    Workflow Options:
      --sample-table VAL (as path, required)
      --junc-list VAL (as path, required)
      --leafcutter-version leafcutter2
  leafcutter_norm_1:
    Workflow Options:
      --ratios VAL (as path, required)
      --[no-]pseudo-ratio (default to False)
  leafcutter_norm_2:
    Workflow Options:
      --[no-]autosomes (default to True)
  leafcutter_norm_3, leafcutter_qqnorm:
    Workflow Options:
      --[no-]no-norm (default to False)
      --[no-]mean-impute (default to False)
      --na-rate 0.4 (as float)
                        minimal NA rate within sample values for an event to be
                        kept (default 0.4, leafcutter default)
      --min-variance 0.001 (as float)
                        minimal variance across samples for an event to be kept
                        (default 0.001)
      --qced-data . (as path)
      --[no-]bgzip (default to False)

Workflow implementation