APA Calling#

Aim#

The purpose of this notebook is to call APA-based information (PDUI) based on DAPARS2 method.

Methods#

Timing: Runtime varies by dataset size and compute resources. For the toy chr22 MWE dataset, most steps complete in under 10 minutes on a standard HPC node.

%preview ../../images/apa_calling.png

3’UTR Reference#

Call WIG data from transcriptome BAM files#

Using bedtools or rsem-bam2wig, for RSEM based alignment

Config files Generation#

  • Python 3 loops to read line by line the sum of reads coverage of all chromosome.

Dapars2 Main Function#

  • Dapars2_Multi_Sample.py: use the least sqaures methods to calculate the usage of long isoforms (3UTR/DaPars2)

    Note: this part of code have been modified from source to deal with some formatting discrepancy in wig file

Impute missing values in Dapars result#

KNN using impute R package.

Input#

  • A list of transcriptome level BAM files, eg generated by RSEM

  • The 3’UTR annotation reference file

If you do not have 3’UTR annotation file, please generate it first. Input to this step is the transcriptome level gene feature file in GTF format that we previously prepared.

Output#

  • Dapars config files

  • PUDI (Raw) information saved in txt

  • PDUI (Imputed) information saved in txt. This is recommended for further analysis.

Steps#

Step 1. Generate the 3’UTR reference regions from a GTF annotation:

sos run pipeline/apa_calling.ipynb UTR_reference \
    --cwd output/apa \
    --hg-gtf output/apa/chr22.gtf

Step 2. Convert the transcriptome BAM files into per-base coverage (wig) and read-depth (flagstat) files:

sos run pipeline/apa_calling.ipynb bam2tools \
    --cwd output/apa \
    --bam-dir output/rnaseq/bam

Step 3. Generate the DaPars2 sample configuration and mapping files:

sos run pipeline/apa_calling.ipynb APAconfig \
    --cwd output/apa \
    --bfile output/apa/wig \
    --annotation output/apa/chr22_3UTR.bed

Step 4. Run DaPars2 to calculate the PDUI matrix per chromosome:

sos run pipeline/apa_calling.ipynb APAmain \
    --cwd output/apa \
    --chrlist chr22 \
    --dapars-path code/molecular_phenotypes/calling/apa/Dapars2_Multi_Sample.py

Command interface#

sos run pipeline/apa_calling.ipynb -h

Workflow implementation#

[global]
parameter: walltime = '400h'
parameter: mem = '200G'
parameter: ncore = 16
# the output directory for generated files
parameter: cwd = path("output")
# Number of threads
parameter: numThreads = 8
parameter: job_size = 1
parameter: container = ''

Step 0. Generate 3’UTR regions based on GTF#

# Generate the 3UTR region according to the gtf file
[UTR_reference]
# gtf file
parameter: hg_gtf = path
input: hg_gtf
output: f'{cwd}/{_input:bn}.bed', 
        f'{cwd}/{_input:bn}.transcript_to_geneName.txt',
        f'{cwd}/{_input:bn}_3UTR.bed'
bash: expand = '${ }', container = container
    gtf2bed12.py --gtf ${_input} --out ${cwd}
    mv ${cwd}/gene_annotation.bed ${_output[0]}
    mv ${cwd}/transcript_to_geneName.txt ${_output[1]}
    DaPars_Extract_Anno.py -b ${_output[0]} -s ${_output[1]} -o ${_output[2]}

Step 1. Generate WIG coverage and flagstat files from BAM files#

[bam2tools]
parameter: n = 9
n  = [x for x in range(n)]
input: for_each = 'n'
task: trunk_workers = 1, trunk_size = job_size, walltime = walltime, mem = mem, cores = numThreads
python: expand = True, container = container
    import glob
    import os
    import subprocess
    path = "/mnt/mfs/ctcn/datasets/rosmap/rnaseq/dlpfcTissue/batch{_n}/STAR_aligned"
    name = glob.glob(path + "/**/*Aligned.sortedByCoord.out.bam", recursive = True)
    wigpath = "/home/ls3751/project/ls3751/wig/batch{_n}/"
    if not os.path.exists(wigpath):
        os.makedirs(os.path.dirname(wigpath))
    for i in name:
        id = i.split("/")[-2]
        filedir = path + "/" + id + "/" + id + ".bam"
        out = wigpath + id + ".wig"
        new_cmd = "bedtools genomecov -ibam " + filedir + " -bga -split -trackline" + " > " + out
        os.system(new_cmd)
        out_2 = wigpath + id + ".flagstat"
        new_cmd_2 = f"samtools flagstat --thread {numThreads} " + filedir + " > " + out_2
        os.system(new_cmd_2)
[bam2toolsv1]
parameter: sample = path
parameter: tissue = path
task: trunk_workers = 1, trunk_size = job_size, walltime = walltime, mem = mem, cores = numThreads, concurrent = True
python: expand = "${ }", container = container
    import os
    import multiprocessing
    import re
    sample_list = [line.strip('\n') for line in open("${sample}")]

    def call_wig_flagstat(subject):
        id = re.findall(r"\D(\d{8})\D",subject)[1]
        prefix = "/mnt/mfs/statgen/ls3751/aqtl_analysis/wig/" + "${tissue}" + "/"
        out = prefix + id + ".wig"
        out_2 = prefix + id + ".flagstat"
        new_cmd = "bedtools genomecov -ibam " + subject + " -bga -split -trackline" + " > " + out
        os.system(new_cmd)
        new_cmd_2 = f"samtools flagstat --thread {numThreads} " + subject + " > " + out_2
        os.system(new_cmd_2)
    
    for sample in sample_list:
        call_wig_flagstat(sample)
    ### process = multiprocessing.Process(target = call_wig_flagstat, args =(sample_list[i]))
    ### process.start()
    ### for p in processes:
    ###     p.join()
[bam2toolsv2]
parameter: sample = path
parameter: tissue = path
task: trunk_workers = 1, trunk_size = job_size, walltime = walltime, mem = mem, cores = numThreads
bash: expand = "${ }", container = container
    input="${sample}"
    while IFS=',' read -r col1 col2
    do
      bedtools genomecov -ibam $col1  -bga -split -trackline  > /mnt/mfs/statgen/ls3751/aqtl_analysis/wig/${tissue}/$col2.wig &
      samtools flagstat --thread ${numThreads} $col1  > /mnt/mfs/statgen/ls3751/aqtl_analysis/wig/${tissue}/$col2.flagstat &
    done < "$input"
[bam2toolstmp]
parameter: sample = path
parameter: tissue = path
task: trunk_workers = 1, trunk_size = job_size, walltime = walltime, mem = mem, cores = ncore
python: expand = "${ }", container = container
    import os
    import re
    sample_list = [line.strip('\n') for line in open("${sample}")]

    def copy_wigfile(subject):
        id = re.findall(r"\D(\d{8})\D",subject)[0]
        prefix = "/mnt/mfs/statgen/ls3751/aqtl_analysis/wig/" + "${tissue}" + "/"
        file1 = os.path.splitext(subject)[0] + ".flagstat"
        out = prefix + id + ".wig"
        out_2 = prefix + id + ".flagstat"
        new_cmd = "cp " + subject + " " + out
        os.system(new_cmd)
        new_cmd_2 = "cp " + file1 + " " + out_2
        os.system(new_cmd_2)
    
    for sample in sample_list:
        copy_wigfile(sample)

Step 2. Generate the DaPars2 configuration and sample mapping files#

# Generate configuration file
[APAconfig]
parameter: bfile = path
parameter: annotation = path
parameter: job_size = 1
# Default parameters for Dapars2:
parameter: least_pass_coverage_percentage = 0.3
parameter: coverage_threshold = 10
output: [f'{cwd}/sample_mapping_files.txt',f'{cwd}/sample_configuration_file.txt']
task: trunk_workers = 1, trunk_size = 1, walltime = walltime, mem = mem, cores = ncore
python3: expand = "${ }", container = container
    import re
    import os
    target_all_sample = os.listdir("${bfile}")
    target_all_sample = list(filter(lambda v: re.match('.*wig$', v), target_all_sample))
    target_all_sample = ["${bfile}" + "/" + w for w in target_all_sample]
    

    def extract_total_reads(input_flagstat_file):
        num_line = 0
        total_reads = '-1'
        #print input_flagstat_file
        for line in open(input_flagstat_file,'r'):
            num_line += 1
            if num_line == 5:
                total_reads = line.strip().split(' ')[0]
                break
        return total_reads

    #print(target_all_sample)
    print("INFO: Total",len(target_all_sample),"samples found in provided dirctory!")
    # Total depth file:
    mapping_file = open("${_output[0]}", "w")
    for current_sample in target_all_sample:
        flag = current_sample.split(".")[0] + ".flagstat"
        current_sample_total_depth = extract_total_reads(flag)
        field_out = [current_sample, str(current_sample_total_depth)]
        mapping_file.writelines('\t'.join(field_out) + '\n')

        print("Coverage of sample ", current_sample, ": ", current_sample_total_depth)
    mapping_file.close()

    # Configuration file:

    config_file = open(${_output[1]:r},"w")
    config_file.writelines(f"Annotated_3UTR=${annotation}\n")
    config_file.writelines( "Aligned_Wig_files=%s\n" % ",".join(target_all_sample))
    config_file.writelines(f"Output_directory=${cwd}/apa \n")
    config_file.writelines(f"Output_result_file=Dapars_result\n")
    config_file.writelines(f"Least_pass_coverage_percentage=${least_pass_coverage_percentage}\n")
    config_file.writelines( "Coverage_threshold=${coverage_threshold}\n")
    config_file.writelines( "Num_Threads=${numThreads}\n")
    config_file.writelines(f"sequencing_depth_file=${_output[0]}") 
    config_file.close()    

Step 3. Run DaPars2 main to calculate PDUIs#

Anticipated Results#

The pipeline produces output files in the output/ subdirectory named after the workflow step. Verify success by checking that output files exist and are non-empty. See the Output section above for the expected file names and formats.

# Call Dapars2 multi_chromosome
[APAmain]
parameter: chr_prefix = False
parameter: chrlist = list
input: for_each = 'chrlist'
output: [f'{cwd}/apa_{x}/Dapars_result_result_temp.{x}.txt' for x in chrlist], group_by = 1
task: trunk_workers = 1, trunk_size = job_size, walltime = walltime, mem = mem, cores = ncore
bash: expand = True, container = container
    python2 /mnt/mfs/statgen/ls3751/github/xqtl-protocol/code/Dapars2_Multi_Sample.py {cwd}/sample_configuration_file.txt {_chrlist} {"F" if chr_prefix else "T"}