From 89470f85dc00a73f873b7f4e5fd43a421c8e4918 Mon Sep 17 00:00:00 2001 From: ArthurDondi Date: Mon, 14 Oct 2024 02:41:00 +0200 Subject: [PATCH] Release v1.0 --- config/config.yaml | 6 +- profile/config.yaml | 2 +- run_LongSom.sh | 2 +- run_LongSom_slurm.sh | 2 +- workflow/rules/CellClustering.smk | 12 +- .../scripts/CellClustering/FormatInputBnpC.py | 19 +- .../libs/__pycache__/CRP.cpython-312.pyc | Bin 0 -> 45079 bytes .../CRP_learning_errors.cpython-312.pyc | Bin 0 -> 6073 bytes .../libs/__pycache__/MCMC.cpython-312.pyc | Bin 0 -> 21446 bytes .../libs/__pycache__/__init__.cpython-312.pyc | Bin 0 -> 216 bytes .../libs/__pycache__/dpmmIO.cpython-312.pyc | Bin 0 -> 29228 bytes .../libs/__pycache__/plotting.cpython-312.pyc | Bin 0 -> 21679 bytes .../libs/__pycache__/utils.cpython-312.pyc | Bin 0 -> 23993 bytes .../scripts/CellClustering/libs/dpmmIO.py | 6 +- .../scripts/CellClustering/libs/plotting.py | 6 +- workflow/scripts/CellClustering/run_BnpC.py | 2 +- .../HighConfidenceCancerVariants.py | 14 +- .../SNVCalling/BaseCellCalling.step3.py | 207 +++++++++++------- 18 files changed, 167 insertions(+), 111 deletions(-) create mode 100644 workflow/scripts/CellClustering/libs/__pycache__/CRP.cpython-312.pyc create mode 100644 workflow/scripts/CellClustering/libs/__pycache__/CRP_learning_errors.cpython-312.pyc create mode 100644 workflow/scripts/CellClustering/libs/__pycache__/MCMC.cpython-312.pyc create mode 100644 workflow/scripts/CellClustering/libs/__pycache__/__init__.cpython-312.pyc create mode 100644 workflow/scripts/CellClustering/libs/__pycache__/dpmmIO.cpython-312.pyc create mode 100644 workflow/scripts/CellClustering/libs/__pycache__/plotting.cpython-312.pyc create mode 100644 workflow/scripts/CellClustering/libs/__pycache__/utils.cpython-312.pyc diff --git a/config/config.yaml b/config/config.yaml index c4a9a01..17c4d44 100644 --- a/config/config.yaml +++ b/config/config.yaml @@ -6,7 +6,7 @@ User: output_dir: /path/to/output_dir sample_map: /path/to/sample_map.tsv cancer_cell_type: HGSOC - + # Change if you use a custom reference Reference: genome: /../ref/GRCh38_gencode_v44_CTAT_lib_Oct292023.plug-n-play/ctat_genome_lib_build_dir/ref_genome.fa @@ -78,7 +78,7 @@ SNVCalling: Min_cell_types: 2 min_distance: 0 max_gnomAD_VAF: 0.01 - deltaVAF: 0.1 + deltaVAF: 0.05 deltaMCF: 0.3 min_ac_reads: 3 min_ac_cells: 2 @@ -116,7 +116,7 @@ CellClust: FN: -1 estimator: 'posterior' pp: [1,1] - dpa: [1,1] + dpa: [0.001, 5.0] ### CNA Calling inferCNV: diff --git a/profile/config.yaml b/profile/config.yaml index 1924afa..b0be342 100644 --- a/profile/config.yaml +++ b/profile/config.yaml @@ -5,7 +5,7 @@ jobs: 500 cores: 500 default-resources: - mem_mb_per_cpu: max(2*input.size_mb, 4096) + mem_mb_per_cpu: max(2*input.size_mb, 8192) runtime: 240 slurm_account: "'es_beere'" #tmpdir: /cluster/scratch/ diff --git a/run_LongSom.sh b/run_LongSom.sh index 23da61a..a7ad97c 100755 --- a/run_LongSom.sh +++ b/run_LongSom.sh @@ -3,7 +3,7 @@ OUTPUT_DIR=/path/to/output_dir REF_DIR=path/to/LongSom/ref/GRCh38_gencode_v44_CTAT_lib_Oct292023.plug-n-play/ctat_genome_lib_build_dir snakemake \ - -s workflow/LongSom.smk \ + -s workflow/Snakefile \ --configfile config/config.yaml \ --use-conda \ --use-singularity \ diff --git a/run_LongSom_slurm.sh b/run_LongSom_slurm.sh index 0a49dfd..f5e0e61 100755 --- a/run_LongSom_slurm.sh +++ b/run_LongSom_slurm.sh @@ -10,7 +10,7 @@ sbatch \ -e logs/snakelog.err \ snakemake \ -s workflow/Snakefile \ - --configfile workflow/test.yaml \ + --configfile config/config.yaml \ --profile profile/ \ --use-conda \ --use-singularity \ diff --git a/workflow/rules/CellClustering.smk b/workflow/rules/CellClustering.smk index 8878404..97a33cd 100644 --- a/workflow/rules/CellClustering.smk +++ b/workflow/rules/CellClustering.smk @@ -57,7 +57,7 @@ else: tsv="SNVCalling/BaseCellCalling/{id}.calling.step3.tsv", bam=f"{INPUT}/bam/{{id}}.bam", barcodes="CellTypeReannotation/ReannotatedCellTypes/{id}.tsv", - fusions="FusionCalling/Somatic/{id}.Fusions.tsv" if CTATFUSION else [], + fusions="FusionCalling/Somatic/{id}.Fusions.SingleCellGenotype.tsv" if CTATFUSION else [], ref=str(workflow.basedir)+config['Reference']['genome'], output: tsv="CellClustering/SingleCellGenotype/{id}.SingleCellGenotype.tsv", @@ -106,11 +106,11 @@ rule FormatInputBnpC: input: bin="CellClustering/SingleCellGenotype/{id}.BinaryMatrix.tsv", vaf="CellClustering/SingleCellGenotype/{id}.VAFMatrix.tsv", - ctypes="CellTypeReannotation/ReannotatedCellTypes/{id}.tsv", + barcodes="CellTypeReannotation/ReannotatedCellTypes/{id}.tsv", output: bin="CellClustering/BnpC_input/{id}.BinaryMatrix.tsv", vaf="CellClustering/BnpC_input/{id}.VAFMatrix.tsv", - ctypes="CellClustering/BnpC_input/{id}.Barcodes.tsv", + barcodes="CellClustering/BnpC_input/{id}.Barcodes.tsv", params: script=str(workflow.basedir)+"/scripts/CellClustering/FormatInputBnpC.py", min_cells=config['CellClust']['FormatInput']['min_cells_per_mut'], @@ -126,7 +126,7 @@ rule FormatInputBnpC: python {params.script} \ --bin {input.bin} \ --vaf {input.vaf} \ - --ctypes {input.ctypes} \ + --barcodes {input.barcodes} \ --min_pos_cov {params.min_cov} \ --min_cells_per_mut {params.min_cells} \ --outfile CellClustering/BnpC_input//{wildcards.id} @@ -136,7 +136,7 @@ rule BnpC_clustering: input: bin="CellClustering/BnpC_input/{id}.BinaryMatrix.tsv", vaf="CellClustering/BnpC_input/{id}.VAFMatrix.tsv", - ctypes="CellClustering/BnpC_input/{id}.Barcodes.tsv", + barcodes="CellClustering/BnpC_input/{id}.Barcodes.tsv", output: pdf="CellClustering/BnpC_output/{id}/genoCluster_posterior_mean_raw.pdf" params: @@ -172,5 +172,5 @@ rule BnpC_clustering: -FN {params.FN} \ -pp {params.pp} \ -ap {params.dpa} \ - --ctypes {input.ctypes} + --barcodes {input.barcodes} """ diff --git a/workflow/scripts/CellClustering/FormatInputBnpC.py b/workflow/scripts/CellClustering/FormatInputBnpC.py index 8571228..9901e65 100644 --- a/workflow/scripts/CellClustering/FormatInputBnpC.py +++ b/workflow/scripts/CellClustering/FormatInputBnpC.py @@ -1,14 +1,12 @@ import timeit import argparse import pandas as pd -import matplotlib -import matplotlib.pyplot as plt import numpy as np -def filter_input(bin,vaf,ctypes,min_cells_per_mut,min_pos_cov,out_prefix): +def filter_input(bin,vaf,barcodes,min_cells_per_mut,min_pos_cov,out_prefix): bin = pd.read_csv(bin,sep='\t',index_col=0,na_values=[3,'.']) vaf = pd.read_csv(vaf,sep='\t',index_col=0,na_values=[3,'.']) - ctypes = pd.read_csv(ctypes,sep='\t') + barcodes = pd.read_csv(barcodes,sep='\t') #Save fusions: fusions = [i for i in bin.index if '--' in i] fusions_save = bin.loc[fusions,bin.columns] @@ -25,19 +23,22 @@ def filter_input(bin,vaf,ctypes,min_cells_per_mut,min_pos_cov,out_prefix): # Filter all input files: vaf = vaf.loc[idx,cols] - ctypes = ctypes[ctypes['Index'].isin(cols)] + barcodes = barcodes[barcodes['Index'].isin(cols)] bin = pd.concat([bin,fusions_save[cols]]) + + # Add reanno ctype colors + barcodes['Cell_Reanno_Colors'] = barcodes['Reannotated_cell_type'].apply(lambda x: '#94C773' if x=='Non-Cancer' else '#8F79A1') # Write bin.to_csv(out_prefix + '.BinaryMatrix.tsv', sep='\t') vaf.to_csv(out_prefix + '.VAFMatrix.tsv', sep='\t') - ctypes.to_csv(out_prefix + '.Barcodes.tsv', sep='\t', index = False) + barcodes.to_csv(out_prefix + '.Barcodes.tsv', sep='\t', index = False) def initialize_parser(): parser = argparse.ArgumentParser(description='Script to filter BnpC input matrix') parser.add_argument('--bin', type=str, default=1, help='SComatic binary matrix (obtained by SingleCellGenotype.py)', required = True) parser.add_argument('--vaf', type=str, default=1, help='SComatic VAF matrix (obtained by SingleCellGenotype.py)', required = True) - parser.add_argument('--ctypes', type=str, default=1, help='Barcode to celltypes (obtained by CellTypeReannotation.py)', required = True) + parser.add_argument('--barcodes', type=str, default=1, help='Barcode to celltypes (obtained by CellTypeReannotation.py)', required = True) parser.add_argument('--min_cells_per_mut', type=int, default=5, help='SComatic+CellTypeReannotation base calling file (obtained by BaseCellCalling.step3.py)', required = False) parser.add_argument('--min_pos_cov', type=int, default=3, help='SComatic+CellTypeReannotation base calling file (obtained by BaseCellCalling.step3.py)', required = False) parser.add_argument('--outfile', default = 'Matrix.tsv', help='Out file', required = False) @@ -51,7 +52,7 @@ def main(): bin = args.bin vaf = args.vaf - ctypes = args.ctypes + barcodes = args.barcodes min_cells_per_mut = args.min_cells_per_mut min_pos_cov = args.min_pos_cov out_prefix = args.outfile @@ -60,7 +61,7 @@ def main(): print("Outfile prefix: " , out_prefix , "\n") # 1. Create clinical annotation file - filter_input(bin,vaf,ctypes,min_cells_per_mut,min_pos_cov,out_prefix) + filter_input(bin,vaf,barcodes,min_cells_per_mut,min_pos_cov,out_prefix) if __name__ == '__main__': start = timeit.default_timer() diff --git a/workflow/scripts/CellClustering/libs/__pycache__/CRP.cpython-312.pyc b/workflow/scripts/CellClustering/libs/__pycache__/CRP.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b8fb63dc193068944acd1f3f26f18edc65a67c83 GIT binary patch literal 45079 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 Y{lrxISLW<_d*#o~URe8@x&6`q4-dvl^Z)<= literal 0 HcmV?d00001 diff --git a/workflow/scripts/CellClustering/libs/__pycache__/CRP_learning_errors.cpython-312.pyc b/workflow/scripts/CellClustering/libs/__pycache__/CRP_learning_errors.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..77221b2a3f2a22326d33b6bb53f25c3fd5ad9148 GIT binary patch literal 6073 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 q?bO8niOWm2z7h!u_OWf9-(+>wom}i2pxTavWL! literal 0 HcmV?d00001 diff --git a/workflow/scripts/CellClustering/libs/__pycache__/__init__.cpython-312.pyc b/workflow/scripts/CellClustering/libs/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..8e0b0377fd548a9a139c9df3baaae38174f76f33 GIT binary patch literal 216 zcmZ8byA8rX49yXc5KgJvmEDRZ2uUhLAgYIv=aMk#FMZMqvzd0u3O(AL+AJe3OfRWMj?AB zoGmDWn%xoe#)EdYl8jm5Wy6S|$igmY2WP(NQo9a(&Qu3;idv_?(_|~qq&!GTmKrJ7 ab$_34j4N7=Tb_kKL?}O!S1g3!IIs^}?>+PY literal 0 HcmV?d00001 diff --git a/workflow/scripts/CellClustering/libs/__pycache__/dpmmIO.cpython-312.pyc b/workflow/scripts/CellClustering/libs/__pycache__/dpmmIO.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..3a1ba53b05d809336d803a2cb1b10b597a2799b9 GIT binary patch literal 29228 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 E1t7MBdH?_b literal 0 HcmV?d00001 diff --git a/workflow/scripts/CellClustering/libs/dpmmIO.py b/workflow/scripts/CellClustering/libs/dpmmIO.py index 5a39c03..a594934 100644 --- a/workflow/scripts/CellClustering/libs/dpmmIO.py +++ b/workflow/scripts/CellClustering/libs/dpmmIO.py @@ -275,7 +275,7 @@ def save_similarity(args, inferred, results, out_dir): def save_geno_plots(args, data, data_raw, out_dir, names): - ctypes = pd.read_csv(args.ctypes, sep='\t') + barcodes = pd.read_csv(args.barcodes, sep='\t') row_cl = False if args.mut_order: row_cl = list(pd.read_csv(args.mut_order, sep='\t')['INDEX']) @@ -289,11 +289,11 @@ def save_geno_plots(args, data, data_raw, out_dir, names): df_obs = pd.DataFrame(data_raw, index=names[0], columns=names[1]).T pl.plot_raw_data( data_est['genotypes'], df_obs, assignment=data_est['assignment'], - ctypes=ctypes, out_file=out_file, row_cl=row_cl + barcodes=barcodes, out_file=out_file, row_cl=row_cl ) pl.plot_raw_data( df_obs, df_obs, assignment=data_est['assignment'], - ctypes=ctypes, out_file=out_file_raw, row_cl=row_cl + barcodes=barcodes, out_file=out_file_raw, row_cl=row_cl ) diff --git a/workflow/scripts/CellClustering/libs/plotting.py b/workflow/scripts/CellClustering/libs/plotting.py index fb2a958..888e72b 100644 --- a/workflow/scripts/CellClustering/libs/plotting.py +++ b/workflow/scripts/CellClustering/libs/plotting.py @@ -64,7 +64,7 @@ def _get_col_order(assignment): def plot_raw_data(data_in, data_raw_in=pd.DataFrame(), out_file=None, assignment=np.array([]), metric='correlation', row_cl=True, - ctypes=pd.Series()): + barcodes=pd.Series()): data = data_in.copy() data_raw = data_raw_in.copy() @@ -93,7 +93,7 @@ def plot_raw_data(data_in, data_raw_in=pd.DataFrame(), out_file=None, cluster_cols = pd.Series(col_dict, name='clusters', index=col_order) - ctypes = ctypes.reindex([ctypes.index[i] for i in col_order]) + barcodes = barcodes.reindex([barcodes.index[i] for i in col_order]) data.columns = np.arange(data_in.shape[1]) data = data[col_order] @@ -137,7 +137,7 @@ def plot_raw_data(data_in, data_raw_in=pd.DataFrame(), out_file=None, cmap.set_over('green') cmap.set_bad('grey') - col_colors=[ctypes['Cancer_Color'],cluster_cols] + col_colors=[barcodes['Cell_Reanno_Colors'],cluster_cols] cm = sns.clustermap( data, diff --git a/workflow/scripts/CellClustering/run_BnpC.py b/workflow/scripts/CellClustering/run_BnpC.py index be7df58..35bca1d 100644 --- a/workflow/scripts/CellClustering/run_BnpC.py +++ b/workflow/scripts/CellClustering/run_BnpC.py @@ -55,7 +55,7 @@ def check_PSRF_cutoff(val): help='Run single chain in main python thread for debugging with pdb.' ) parser.add_argument( - '--ctypes', type=str, + '--barcodes', type=str, help='Absolute or relative path(s) to input barcode-to-ctype file' ) parser.add_argument( diff --git a/workflow/scripts/CellTypeReannotation/HighConfidenceCancerVariants.py b/workflow/scripts/CellTypeReannotation/HighConfidenceCancerVariants.py index 4233580..95c283b 100644 --- a/workflow/scripts/CellTypeReannotation/HighConfidenceCancerVariants.py +++ b/workflow/scripts/CellTypeReannotation/HighConfidenceCancerVariants.py @@ -46,9 +46,9 @@ def HCCV_SNV(SNVs,outfile,min_dp,deltaVAF,deltaMCF,clust_dist): input_df['DP_FILTER'] = input_df.apply(lambda x: DP_filtering(x['Cancer'],x['Non-Cancer'],min_dp), axis=1) input_df = input_df[input_df['DP_FILTER']=='PASS'] + input_df.to_csv(outfile+'2', sep='\t', index=False, mode='a') #Special case for chrM due to contaminants: - # Save chrM candidate SNVs to apply specific filters chrm_df = input_df[input_df['#CHROM']=='chrM'].copy() input_df = input_df[input_df['#CHROM']!='chrM'] @@ -77,6 +77,7 @@ def HCCV_SNV(SNVs,outfile,min_dp,deltaVAF,deltaMCF,clust_dist): # Filter 7: PoN filterDelta VAF and MCF filtering input_df['HCCV_FILTER'] = input_df.apply(lambda x: MCF_filtering(x['Cell_types'],x['VAF'], x['MCF'],deltaVAF,deltaMCF), axis=1) + input_df.to_csv(outfile+'3', sep='\t', index=False, mode='a') input_df = input_df[input_df['HCCV_FILTER']=='PASS'] # Filter 8: Distance filter @@ -229,16 +230,19 @@ def MCF_filtering(CTYPES,VAF,MCF,deltaVAFmin,deltaMCFmin): VAFNonCancer = float(VAFs[0]) MCFCancer = float(MCFs[1]) MCFNonCancer = float(MCFs[0]) - - if VAFNonCancer>0.12: - return 'Heterozygous' if VAFCancer<0.05: return 'NonSig' - # deltaVAF = VAFCancer-VAFNonCancer + deltaVAF = VAFCancer-VAFNonCancer deltaMCF = MCFCancer-MCFNonCancer + if VAFNonCancer>0.1 and deltaVAF<2*deltaVAFmin: + return 'Heterozygous' + + if VAFNonCancer>0.2: + return 'Heterozygous' + # HCCV are variants with high VAF/MCF in cancer and low VAF/MCF in non-cancer cells # if deltaVAF < deltaVAFmin: # return 'LowDeltaVAF' diff --git a/workflow/scripts/SNVCalling/BaseCellCalling.step3.py b/workflow/scripts/SNVCalling/BaseCellCalling.step3.py index 6363220..505014a 100644 --- a/workflow/scripts/SNVCalling/BaseCellCalling.step3.py +++ b/workflow/scripts/SNVCalling/BaseCellCalling.step3.py @@ -30,23 +30,21 @@ def variant_calling_step3(file,out_prefix,deltaVAF,deltaMCF,chrM_conta,min_ac_re f3.write('##INFO=FINAL_FILTER,Description=Final ilter status, including chrM contaminants and clustered sites\n') f2.close() f3.close() - input_df = pd.read_csv(file, sep='\t',comment='#',names=output_column_names) - input_df['INDEX'] = input_df['#CHROM'].astype(str) + ':' + input_df['Start'].astype(str) + ':' + input_df['ALT'].str.split(',', n=1, expand=True)[0] - - # Only keeping sites with alternative reads in cancer + + # Only keeping sites called in cancer input_df = input_df[input_df['Cell_types']!='Non-Cancer'] # Filtering multiallelic sites, keeping only one allele if it's 50x larger than the other # Otherwise deleting the line (it messes with filters later on) # This is important as SComatic will often detect low expr secondary alt allele in very high expr. (e.g. in chrM) - input_df[['ALT', 'FILTER', 'Cell_types', 'Bc', 'Cc', 'VAF', 'MCF','MultiAllelic_filter']] = input_df.apply(lambda x: MultiAllelic_filtering(x['REF'], x['ALT'], x['FILTER'], x['Cell_types'],x['Dp'], x['Nc'], x['Bc'], x['Cc'], x['VAF'], x['MCF'], x['Cancer'], x['Non-Cancer']), axis=1, result_type="expand") - input_df = input_df[input_df['MultiAllelic_filter']=='KEEP'] - input_df = input_df[output_column_names + ['INDEX']] + input_df[['ALT', 'FILTER', 'Cell_types', 'Bc', 'Cc', 'VAF', 'MCF','STEP3FILTER']] = input_df.apply(lambda x: MultiAllelic_filtering(x['REF'], x['ALT'], x['FILTER'], x['Cell_types'],x['Dp'], x['Nc'], x['Bc'], x['Cc'], x['VAF'], x['MCF'], x['Cancer'], x['Non-Cancer']), axis=1, result_type="expand") + #input_df = input_df[input_df['MultiAllelic_filter']=='KEEP'] - #Special case for chrM due to contaminants: + input_df['INDEX'] = input_df['#CHROM'].astype(str) + ':' + input_df['Start'].astype(str) + ':' + input_df['ALT'].str.split(',', n=1, expand=True)[0] + #Special case for chrM due to contaminants: # Save chrM candidate SNVs to apply specific filters chrm_df = input_df[input_df['#CHROM']=='chrM'].copy() input_df = input_df[input_df['#CHROM']!='chrM'] @@ -55,27 +53,17 @@ def variant_calling_step3(file,out_prefix,deltaVAF,deltaMCF,chrM_conta,min_ac_re chrm_df = chrm_df[~chrm_df['FILTER'].str.contains('Min|LR|gnomAD|LC|RNA', regex=True)] if len(chrm_df)>0: # Applying deltaVAF and deltaMCF filters - chrm_df['FILTER'] = chrm_df.apply(lambda x: - chrM_filtering(x['Cell_types'],x['Dp'],x['VAF'], x['MCF'],deltaVAF,deltaMCF), axis=1) - + chrm_df['STEP3FILTER'] = chrm_df.apply(lambda x: + chrM_filtering(x['STEP3FILTER'],x['Cell_types'],x['Dp'],x['VAF'], x['MCF'],deltaVAF,deltaMCF), axis=1) # Filter 1: Non-cancer coverage filter input_df = input_df[~input_df['FILTER'].str.contains('Min_cell_types')] - - # Filter 2: Alt reads and cells in cancer filter - input_df['Bc'] = [i.split(',')[1] if ',' in i else i for i in input_df['Bc']] #only keeping cancer info - input_df['Cc'] = [i.split(',')[1] if ',' in i else i for i in input_df['Cc']] #only keeping cancer info - input_df = input_df.astype({'Bc':'int','Cc':'int'}) - input_df = input_df[input_df['Bc']>=min_ac_reads] - input_df = input_df[input_df['Cc']>=min_ac_cells] - - # Filter 3: Betabinomial filter in cancer cells - input_df = input_df[~input_df['Cell_type_Filter'].str.contains(',Non-Significant|,Low-Significant', regex = True)] - input_df = input_df[~input_df['Cell_type_Filter'].isin(['Non-Significant','Low-Significant'])] - - #Adding chrM SNVs detected above: - unfiltered_df = pd.concat([input_df,chrm_df]) - unfiltered_df.to_csv(out_prefix+ '.calling.step3.unfiltered.tsv', sep='\t', index=False, mode='a') + + #Filter 2: Min. alt reads and cells in cancer + input_df['STEP3FILTER'] = input_df.apply(lambda x: BC_CC_filtering(x['STEP3FILTER'],x['ALT'],x['Cancer'],min_ac_reads,min_ac_cells), axis=1) + + # Filter 3 and 8: Betabinomial filtering in cancer cells (Filter 3) and non-cancer cells (Filter 8) + input_df['STEP3FILTER'] = input_df.apply(lambda x: BetaBino_filtering(x['STEP3FILTER'],x['Cell_types'],x['Cell_type_Filter'],x['Start']), axis=1) # Filter 4: Noise filter: input_df = input_df[~input_df['FILTER'].str.contains('Noisy_site')] #multi allelic sites are filtered above @@ -90,26 +78,27 @@ def variant_calling_step3(file,out_prefix,deltaVAF,deltaMCF,chrM_conta,min_ac_re input_df = input_df[~input_df['FILTER'].str.contains('PoN', regex = True)] # Filter 8: Betabinomial filter in non-cancer cells - input_df = input_df[~input_df['Cell_type_Filter'].str.contains('Low-Significant,|PASS,', regex = True)] - input_df = input_df[~input_df['FILTER'].str.contains('Cell_type_noise|Multiple_cell_types|Noisy_site', regex = True)] + input_df = input_df[~input_df['FILTER'].str.contains('Cell_type_noise', regex = True)] # Filter 9: gnomAD filter input_df = input_df[~input_df['FILTER'].str.contains('gnomAD', regex = True)] - # Filter 10: Distance filter - input_df['FILTER'] = tag_clustered_SNVs(input_df, clust_dist) - input_df = input_df[~input_df['FILTER'].str.contains('dist', regex = True)] - #Adding chrM SNVs detected above: input_df = pd.concat([input_df,chrm_df]) + # Filter 10: Distance filter + input_df['STEP3FILTER'] = tag_clustered_SNVs(input_df, clust_dist) + input_df.to_csv(out_prefix+ '.calling.step3.unfiltered.tsv', sep='\t', index=False, mode='a') + input_df = input_df[~input_df['STEP3FILTER'].str.contains('dist', regex = True)] + #Filtering PASS SNVs (only left in chrM) - filtered_df = input_df[input_df['FILTER'] =='PASS'] + filtered_df = input_df[input_df['STEP3FILTER'] =='PASS'] # Write output filtered_df.to_csv(out_prefix+ '.calling.step3.tsv', sep='\t', index=False, mode='a') + -def chrM_filtering(CTYPES,DP,VAF,MCF,deltaVAFmin,deltaMCFmin): +def chrM_filtering(STEP3FILTER,CTYPES,DP,VAF,MCF,deltaVAFmin,deltaMCFmin): ctypes = CTYPES.split(',') if len(ctypes)>1: if ctypes[0]=='Cancer': @@ -121,7 +110,10 @@ def chrM_filtering(CTYPES,DP,VAF,MCF,deltaVAFmin,deltaMCFmin): DP1,DP2=DP.split(',') #Only look at higher depth loci if int(DP1)<100 or int(DP2)<100: - return 'LowDepth' + if STEP3FILTER == 'PASS': + return 'LowDepth' + else: + return STEP3FILTER+',LowDepth' else: VAFs = VAF.split(',') MCFs = MCF.split(',') @@ -135,24 +127,38 @@ def chrM_filtering(CTYPES,DP,VAF,MCF,deltaVAFmin,deltaMCFmin): # mtSNVs are variants with high VAF in cancer and low VAF in non-cancer cells if deltaVAF < deltaVAFmin: - return 'LowDeltaVAF' + if STEP3FILTER == 'PASS': + return 'LowDeltaVAF' + else: + return STEP3FILTER+',LowDeltaVAF' + elif deltaMCF < deltaMCFmin: - return 'LowDeltaMCF' + if STEP3FILTER == 'PASS': + return 'LowDeltaMCF' + else: + return STEP3FILTER+',LowDeltaMCF' else: - return 'PASS' + return STEP3FILTER elif len(ctypes)==1: - if ctypes[0]!="Cancer": - return 'Non-Cancer' - elif int(DP)<100: - return 'LowDepth' + if int(DP)<100: + if STEP3FILTER == 'PASS': + return 'LowDepth' + else: + return STEP3FILTER+',LowDepth' elif float(VAF)<0.05: - return 'LowVAF' + if STEP3FILTER == 'PASS': + return 'LowVAF' + else: + return STEP3FILTER+',LowVAF' elif float(MCF)<0.05: - return 'LowMCF' + if STEP3FILTER == 'PASS': + return 'LowMCF' + else: + return STEP3FILTER+',LowMCF' else: - return 'PASS' + return STEP3FILTER def MultiAllelic_filtering(REF, ALT, FILTER, CTYPES, DP, NC, BC, CC, VAF, MCF, CancerInfo, NonCancerInfo): ref_dict = {'A':0, 'C':1, 'T':2, 'G':3} @@ -174,8 +180,6 @@ def MultiAllelic_filtering(REF, ALT, FILTER, CTYPES, DP, NC, BC, CC, VAF, MCF, C index = np.argmax(BCS) BCS[index] = 0 # removing max to select next "max" MAX2 = max(BCS) - if not(MAX2/MAX<0.05): # one alt 20x larger than the other) - return ALT, FILTER, CTYPES, BC, CC, VAF, MCF,'DELETE' ALT_Cancer = 'ACTG'[index] BC_Cancer = int(CancerInfo.split('|')[3].split(':')[index]) @@ -195,42 +199,89 @@ def MultiAllelic_filtering(REF, ALT, FILTER, CTYPES, DP, NC, BC, CC, VAF, MCF, C VAF = ','.join([str(VAF_NonCancer),str(VAF_Cancer)]) MCF = ','.join([str(MCF_NonCancer),str(MCF_Cancer)]) + if not(MAX2/MAX<0.05): # one alt 20x larger than the other) + return ALT, FILTER, CTYPES, BC, CC, VAF, MCF,'Multi-Allelic' + + return ALT, FILTER, CTYPES, BC, CC, VAF, MCF,'PASS' + + elif len(ctypes)==1: + BCS = CancerInfo.split('|')[3].split(':')[:4] + BCS = [int(i) for i in BCS] + BCS[i_ref] = 0 # setting REF to 0 as we only consider ALT + MAX = max(BCS) + index = np.argmax(BCS) + BCS[index] = 0 # removing max to select next "max" + MAX2 = max(BCS) + + ALT = 'ACTG'[index] + BC = int(CancerInfo.split('|')[3].split(':')[index]) + CC = int(CancerInfo.split('|')[2].split(':')[index]) + VAF = round(BC/int(DP),4) + MCF= round(CC/int(NC),4) + FILTER = FILTER.replace('Multi-allelic,','') FILTER = FILTER.replace(',Multi-allelic','') FILTER = FILTER.replace('Multi-allelic','') - return ALT, FILTER, CTYPES, BC, CC, VAF, MCF,'KEEP' - - elif len(ctypes)==1: - if ctypes[0]=='Cancer': - BCS = CancerInfo.split('|')[3].split(':')[:4] - BCS = [int(i) for i in BCS] - BCS[i_ref] = 0 # setting REF to 0 as we only consider ALT - MAX = max(BCS) - index = np.argmax(BCS) - BCS[index] = 0 # removing max to select next "max" - MAX2 = max(BCS) - if not(MAX2/MAX<0.05): # one alt 20x larger than the other) - return ALT, FILTER, CTYPES, BC, CC, VAF, MCF,'DELETE' - - ALT = 'ACTG'[index] - BC = int(CancerInfo.split('|')[3].split(':')[index]) - CC = int(CancerInfo.split('|')[2].split(':')[index]) - VAF = round(BC/int(DP),4) - MCF= round(CC/int(NC),4) - - FILTER = FILTER.replace('Multi-allelic,','') - FILTER = FILTER.replace(',Multi-allelic','') - FILTER = FILTER.replace('Multi-allelic','') - - return ALT, FILTER, CTYPES, BC, CC, VAF, MCF,'KEEP' - else: - return ALT, FILTER, CTYPES, BC, CC, VAF, MCF,'DELETE' + if not(MAX2/MAX<0.05): # one alt 20x larger than the other) + return ALT, FILTER, CTYPES, BC, CC, VAF, MCF,'Multi-Allelic' + + return ALT, FILTER, CTYPES, BC, CC, VAF, MCF,'PASS' else: - return ALT, FILTER, CTYPES, BC, CC, VAF, MCF,'KEEP' + return ALT, FILTER, CTYPES, BC, CC, VAF, MCF,'PASS' +def BC_CC_filtering(STEP3FILTER,ALT,CancerInfo,min_ac_reads,min_ac_cells): + alt_dict = {'A':0, 'C':1, 'T':2, 'G':3} + i_alt = alt_dict[ALT[0]] + try: + CancerInfos = CancerInfo.split('|') + BC = CancerInfos[3].split(':')[i_alt] + CC = CancerInfos[2].split(':')[i_alt] + if int(BC) 1: + if ctypes[0] == 'Cancer': + i_cancer = 0 + i_noncancer = 1 + elif ctypes[1] == 'Cancer': + i_cancer = 1 + i_noncancer = 0 + if CTYPESFILTER.split(',')[i_cancer] in ['Non-Significant','Low-Significance']: + if STEP3FILTER == 'PASS': + return 'CancerNonSig' + else: + return STEP3FILTER + ',CancerNonSig' + if CTYPESFILTER.split(',')[i_noncancer] in ['PASS','Low-Significance']: + if STEP3FILTER == 'PASS': + return 'NonCancerSig' + else: + return STEP3FILTER + ',NonCancerSig' + return STEP3FILTER + + def tag_clustered_SNVs(df, clust_dist): - df2 = df[df['FILTER']=='PASS'] + df2 = df[df['STEP3FILTER']=='PASS'] idx = df2['INDEX'] a=[] for i in idx: @@ -249,13 +300,13 @@ def tag_clustered_SNVs(df, clust_dist): trash.append(':'.join([chr2,pos2,base2])) trash = set(trash) updated_filter= df.apply(lambda x : - modify_filter(x['INDEX'],x['FILTER'], clust_dist, trash), + modify_filter(x['INDEX'],x['STEP3FILTER'], clust_dist, trash), axis=1) print(updated_filter) return updated_filter def modify_filter(INDEX, FILTER, clust_dist, trash): - clustered = 'Clust_dist{}'.format(str(clust_dist)) + clustered = 'Clust_dist_{}'.format(str(clust_dist)) if INDEX in trash: if FILTER == 'PASS': return clustered