From f0b585d76b4dd5bb237509d0ba5c1bf19fc7d7d6 Mon Sep 17 00:00:00 2001 From: Wei Cheng <36087657+Colin-Cheng@users.noreply.github.com> Date: Thu, 5 Jul 2018 14:12:12 -0400 Subject: [PATCH 01/46] Add files via upload --- scripts/generate_index_files.py | 199 ++++++++++++++++++++++++++++++++ 1 file changed, 199 insertions(+) create mode 100644 scripts/generate_index_files.py diff --git a/scripts/generate_index_files.py b/scripts/generate_index_files.py new file mode 100644 index 0000000..4368cd1 --- /dev/null +++ b/scripts/generate_index_files.py @@ -0,0 +1,199 @@ +""" +2016 Gregory Way +scripts/generate_index_files.py + +Description: +Generates index files mapping genomic content to TADs enabling quick lookup + +1) SNPs +2) Genes +3) Repetitive Elements + +Usage: +Is called by 'scripts/run_pipeline.sh': + + python scripts/generate_index_files.py --TAD-Boundary 'hESC' + +Output: +3 gzipped tsv index files and a tsv file of all genes that span TAD boundaries +""" + +import os +import argparse +import pandas as pd +from tad_util.util import load_tad, parse_gene_gtf + +pd.options.mode.chained_assignment = None + +parser = argparse.ArgumentParser() +parser.add_argument('-t', '--TAD-Boundary', help='boundary cell type') +parser.add_argument('-f', '--TAD-File', help='path to 3-column-tab-separated TAD domain bed file') +args = parser.parse_args() + +TAD_CELL = args.TAD_Boundary + +BASE_DIR = 'data/' +GENOME = 'hg19' +REF_GENE_GTF = BASE_DIR + 'gencode.v19.annotation.gtf.gz' +TAD_LOC = args.TAD_File +REF_SNPS = BASE_DIR + 'hg_common-snps.tsv' + +REPEAT_FH = BASE_DIR + GENOME + '.fa.out.tsv' +bmd_ld_windows = os.path.join('data', 'BMD_ldwindows.tsv') + +SNP_INDEX = 'index/SNP_index_' + GENOME + '_' + TAD_CELL + '.tsv.bz2' +GENE_INDEX = 'index/GENE_index_' + GENOME + '_' + TAD_CELL + '.tsv.bz2' +REPEAT_INDEX = 'index/REPEATS_index_' + GENOME + '_' + TAD_CELL + '.tsv.bz2' +SPANNED_GENES_FH = 'tables/SpannedGenesAcross_' + TAD_CELL + '_TADs.tsv' +bmd_window_genes_file = os.path.join('data', 'BMD_LDwindow_genes.tsv') + + +def curate_tad_elements(tad_df, input_df, gen_class): + """ + Loop through TAD boundaries to assign genomic elements to TADs + + Arguments: + :param tad_df: pandas dataframe, TAD boundary locations + :param input_df: pandas dataframe, the genomic content to subset + :param gen_class: str, either 'snp', 'gene', or 'repeat' + + Output: + Large summary dataframes of the TAD assignment for input genomic element + """ + + big_out_df = pd.DataFrame() + bnd_df = pd.DataFrame() + + if gen_class in ['gene', 'repeat']: + input_df['chromosome'] = input_df['chromosome'].map(lambda x: x[3:]) + + for tad in tad_df.itertuples(): + tad_id, chrom, start, end = list(tad) + start, end = int(start), int(end) + + if gen_class == 'snp' and chrom != 'X' and chrom !='Y': + chrom = int(chrom) + + if gen_class == 'LD': + chrom = 'chr{}'.format(chrom) + + chm_sub_df = input_df[input_df['chromosome'] == chrom] + + if gen_class == 'snp': + elem_sub_df = chm_sub_df[(chm_sub_df['position'] >= start) & + (chm_sub_df['position'] < end)] + + else: + elem_sub_df = chm_sub_df[(chm_sub_df['start'] >= start) & + (chm_sub_df['stop'] <= end)] + + # Get the overlapping genomic elements + o_df = chm_sub_df[((chm_sub_df['start'] >= start) & + (chm_sub_df['start'] < end) & + (chm_sub_df['stop'] > end)) | + ((chm_sub_df['stop'] >= start) & + (chm_sub_df['stop'] < end) & + (chm_sub_df['start'] < start))] + + elem_sub_df = pd.concat([elem_sub_df, o_df], axis=0, + ignore_index=True) + bnd_df = bnd_df.append(o_df, ignore_index=True) + + if gen_class == 'LD': + # Assign LD information + elem_sub_df['rs_id'] = tad_id + elem_sub_df['LD_window_start'] = start + elem_sub_df['LD_window_end'] = end + else: + # Assign TAD information + elem_sub_df['TAD_id'] = tad_id + elem_sub_df['TAD_start'] = start + elem_sub_df['TAD_end'] = end + + big_out_df = big_out_df.append(elem_sub_df, ignore_index=True) + + if gen_class in ['gene', 'repeat']: + bnd_df = bnd_df.drop_duplicates() + + return big_out_df, bnd_df + + +# For parsing messy repeat info data +def rm_paren(x): return x.strip('(').strip(')') + +# Create index path +if not os.path.exists('index'): + os.makedirs('index') + +# Read in TAD boundary file +tad_df = load_tad(TAD_LOC) + +#################################### +# PART 1 - SNPs +#################################### +snp_df = pd.read_table(REF_SNPS) + +big_snp_df, _ = curate_tad_elements(tad_df, snp_df, gen_class='snp') + +# Every SNP that did not map is in a boundary region +boundary_snp_df = snp_df.query("rsid not in @big_snp_df.rsid") +boundary_snp_df['TAD_id'] = "Boundary" +boundary_snp_df['TAD_start'] = 0 +boundary_snp_df['TAD_end'] = 0 + +all_snp_df = big_snp_df.append(boundary_snp_df) +all_snp_df.to_csv(SNP_INDEX, sep='\t', compression='bz2') + +#################################### +# PART 2 - Genes +#################################### +# Process data +refGene_df = pd.read_table(REF_GENE_GTF, skiprows=5, header=None) +refGene_df = refGene_df.drop(refGene_df.columns[[5, 7]], axis=1) +refGene_df.columns = ['chromosome', 'db', 'type', 'start', 'stop', 'strand', + 'info'] +parsed_info_df = refGene_df.apply(parse_gene_gtf, axis=1) +parsed_info_df.columns = ['gene_type', 'gene_name'] +refGene_df = pd.concat([refGene_df, parsed_info_df], axis=1) +refGene_df = refGene_df[refGene_df['type'] == 'gene'].drop('info', axis=1) + +big_gene_df, bound_gene_df = curate_tad_elements(tad_df, refGene_df, + gen_class='gene') + +# Which genes belong entirely in the boundary? +only_bound_gene_df = refGene_df.ix[~refGene_df['gene_name'] + .isin(big_gene_df['gene_name'])] +only_bound_gene_df = only_bound_gene_df.ix[~only_bound_gene_df['chromosome'] + .isin(['X', 'Y', 'M'])] +only_bound_gene_df['TAD_id'] = "Boundary" +only_bound_gene_df['TAD_start'] = 0 +only_bound_gene_df['TAD_end'] = 0 + +big_gene_tad_df = big_gene_df.append(only_bound_gene_df) +big_gene_tad_df.to_csv(GENE_INDEX, sep='\t', compression='bz2') +bound_gene_df.to_csv(SPANNED_GENES_FH, sep='\t') + +#################################### +# PART 3 - Repeat Elements ######### +#################################### +repeats_df = pd.read_csv(REPEAT_FH, delimiter='\t', + skiprows=[0, 1, 2], header=None, + names=['div', 'chromosome', 'start', 'stop', + 'repeat'], + index_col=False, usecols=[2, 5, 6, 7, 11], + converters={'start': rm_paren, 'stop': rm_paren}) +repeats_df['start'] = repeats_df['start'].astype(int) +repeats_df['stop'] = repeats_df['stop'].astype(int) + +big_rep_tad_df, boundary_rep_df = curate_tad_elements(tad_df, repeats_df, + gen_class='repeat') + +big_rep_tad_df = big_rep_tad_df.append(boundary_rep_df, ignore_index=True) +big_rep_tad_df.to_csv(REPEAT_INDEX, sep='\t', compression='bz2') + +#################################### +# PART 4 - BMD genes in LD Windows # +#################################### +bmd_ld_df = pd.read_table(bmd_ld_windows, index_col=0) +bmd_ld_genes_df, _ = curate_tad_elements(bmd_ld_df, refGene_df, gen_class='LD') +bmd_ld_genes_df.to_csv(bmd_window_genes_file, sep='\t', index_col=0) From a28cf0d060e124516a692fd3b36edb11507f92c1 Mon Sep 17 00:00:00 2001 From: Wei Cheng <36087657+Colin-Cheng@users.noreply.github.com> Date: Thu, 5 Jul 2018 14:58:22 -0400 Subject: [PATCH 02/46] Delete generate_index_files.py --- scripts/generate_index_files.py | 199 -------------------------------- 1 file changed, 199 deletions(-) delete mode 100644 scripts/generate_index_files.py diff --git a/scripts/generate_index_files.py b/scripts/generate_index_files.py deleted file mode 100644 index 4368cd1..0000000 --- a/scripts/generate_index_files.py +++ /dev/null @@ -1,199 +0,0 @@ -""" -2016 Gregory Way -scripts/generate_index_files.py - -Description: -Generates index files mapping genomic content to TADs enabling quick lookup - -1) SNPs -2) Genes -3) Repetitive Elements - -Usage: -Is called by 'scripts/run_pipeline.sh': - - python scripts/generate_index_files.py --TAD-Boundary 'hESC' - -Output: -3 gzipped tsv index files and a tsv file of all genes that span TAD boundaries -""" - -import os -import argparse -import pandas as pd -from tad_util.util import load_tad, parse_gene_gtf - -pd.options.mode.chained_assignment = None - -parser = argparse.ArgumentParser() -parser.add_argument('-t', '--TAD-Boundary', help='boundary cell type') -parser.add_argument('-f', '--TAD-File', help='path to 3-column-tab-separated TAD domain bed file') -args = parser.parse_args() - -TAD_CELL = args.TAD_Boundary - -BASE_DIR = 'data/' -GENOME = 'hg19' -REF_GENE_GTF = BASE_DIR + 'gencode.v19.annotation.gtf.gz' -TAD_LOC = args.TAD_File -REF_SNPS = BASE_DIR + 'hg_common-snps.tsv' - -REPEAT_FH = BASE_DIR + GENOME + '.fa.out.tsv' -bmd_ld_windows = os.path.join('data', 'BMD_ldwindows.tsv') - -SNP_INDEX = 'index/SNP_index_' + GENOME + '_' + TAD_CELL + '.tsv.bz2' -GENE_INDEX = 'index/GENE_index_' + GENOME + '_' + TAD_CELL + '.tsv.bz2' -REPEAT_INDEX = 'index/REPEATS_index_' + GENOME + '_' + TAD_CELL + '.tsv.bz2' -SPANNED_GENES_FH = 'tables/SpannedGenesAcross_' + TAD_CELL + '_TADs.tsv' -bmd_window_genes_file = os.path.join('data', 'BMD_LDwindow_genes.tsv') - - -def curate_tad_elements(tad_df, input_df, gen_class): - """ - Loop through TAD boundaries to assign genomic elements to TADs - - Arguments: - :param tad_df: pandas dataframe, TAD boundary locations - :param input_df: pandas dataframe, the genomic content to subset - :param gen_class: str, either 'snp', 'gene', or 'repeat' - - Output: - Large summary dataframes of the TAD assignment for input genomic element - """ - - big_out_df = pd.DataFrame() - bnd_df = pd.DataFrame() - - if gen_class in ['gene', 'repeat']: - input_df['chromosome'] = input_df['chromosome'].map(lambda x: x[3:]) - - for tad in tad_df.itertuples(): - tad_id, chrom, start, end = list(tad) - start, end = int(start), int(end) - - if gen_class == 'snp' and chrom != 'X' and chrom !='Y': - chrom = int(chrom) - - if gen_class == 'LD': - chrom = 'chr{}'.format(chrom) - - chm_sub_df = input_df[input_df['chromosome'] == chrom] - - if gen_class == 'snp': - elem_sub_df = chm_sub_df[(chm_sub_df['position'] >= start) & - (chm_sub_df['position'] < end)] - - else: - elem_sub_df = chm_sub_df[(chm_sub_df['start'] >= start) & - (chm_sub_df['stop'] <= end)] - - # Get the overlapping genomic elements - o_df = chm_sub_df[((chm_sub_df['start'] >= start) & - (chm_sub_df['start'] < end) & - (chm_sub_df['stop'] > end)) | - ((chm_sub_df['stop'] >= start) & - (chm_sub_df['stop'] < end) & - (chm_sub_df['start'] < start))] - - elem_sub_df = pd.concat([elem_sub_df, o_df], axis=0, - ignore_index=True) - bnd_df = bnd_df.append(o_df, ignore_index=True) - - if gen_class == 'LD': - # Assign LD information - elem_sub_df['rs_id'] = tad_id - elem_sub_df['LD_window_start'] = start - elem_sub_df['LD_window_end'] = end - else: - # Assign TAD information - elem_sub_df['TAD_id'] = tad_id - elem_sub_df['TAD_start'] = start - elem_sub_df['TAD_end'] = end - - big_out_df = big_out_df.append(elem_sub_df, ignore_index=True) - - if gen_class in ['gene', 'repeat']: - bnd_df = bnd_df.drop_duplicates() - - return big_out_df, bnd_df - - -# For parsing messy repeat info data -def rm_paren(x): return x.strip('(').strip(')') - -# Create index path -if not os.path.exists('index'): - os.makedirs('index') - -# Read in TAD boundary file -tad_df = load_tad(TAD_LOC) - -#################################### -# PART 1 - SNPs -#################################### -snp_df = pd.read_table(REF_SNPS) - -big_snp_df, _ = curate_tad_elements(tad_df, snp_df, gen_class='snp') - -# Every SNP that did not map is in a boundary region -boundary_snp_df = snp_df.query("rsid not in @big_snp_df.rsid") -boundary_snp_df['TAD_id'] = "Boundary" -boundary_snp_df['TAD_start'] = 0 -boundary_snp_df['TAD_end'] = 0 - -all_snp_df = big_snp_df.append(boundary_snp_df) -all_snp_df.to_csv(SNP_INDEX, sep='\t', compression='bz2') - -#################################### -# PART 2 - Genes -#################################### -# Process data -refGene_df = pd.read_table(REF_GENE_GTF, skiprows=5, header=None) -refGene_df = refGene_df.drop(refGene_df.columns[[5, 7]], axis=1) -refGene_df.columns = ['chromosome', 'db', 'type', 'start', 'stop', 'strand', - 'info'] -parsed_info_df = refGene_df.apply(parse_gene_gtf, axis=1) -parsed_info_df.columns = ['gene_type', 'gene_name'] -refGene_df = pd.concat([refGene_df, parsed_info_df], axis=1) -refGene_df = refGene_df[refGene_df['type'] == 'gene'].drop('info', axis=1) - -big_gene_df, bound_gene_df = curate_tad_elements(tad_df, refGene_df, - gen_class='gene') - -# Which genes belong entirely in the boundary? -only_bound_gene_df = refGene_df.ix[~refGene_df['gene_name'] - .isin(big_gene_df['gene_name'])] -only_bound_gene_df = only_bound_gene_df.ix[~only_bound_gene_df['chromosome'] - .isin(['X', 'Y', 'M'])] -only_bound_gene_df['TAD_id'] = "Boundary" -only_bound_gene_df['TAD_start'] = 0 -only_bound_gene_df['TAD_end'] = 0 - -big_gene_tad_df = big_gene_df.append(only_bound_gene_df) -big_gene_tad_df.to_csv(GENE_INDEX, sep='\t', compression='bz2') -bound_gene_df.to_csv(SPANNED_GENES_FH, sep='\t') - -#################################### -# PART 3 - Repeat Elements ######### -#################################### -repeats_df = pd.read_csv(REPEAT_FH, delimiter='\t', - skiprows=[0, 1, 2], header=None, - names=['div', 'chromosome', 'start', 'stop', - 'repeat'], - index_col=False, usecols=[2, 5, 6, 7, 11], - converters={'start': rm_paren, 'stop': rm_paren}) -repeats_df['start'] = repeats_df['start'].astype(int) -repeats_df['stop'] = repeats_df['stop'].astype(int) - -big_rep_tad_df, boundary_rep_df = curate_tad_elements(tad_df, repeats_df, - gen_class='repeat') - -big_rep_tad_df = big_rep_tad_df.append(boundary_rep_df, ignore_index=True) -big_rep_tad_df.to_csv(REPEAT_INDEX, sep='\t', compression='bz2') - -#################################### -# PART 4 - BMD genes in LD Windows # -#################################### -bmd_ld_df = pd.read_table(bmd_ld_windows, index_col=0) -bmd_ld_genes_df, _ = curate_tad_elements(bmd_ld_df, refGene_df, gen_class='LD') -bmd_ld_genes_df.to_csv(bmd_window_genes_file, sep='\t', index_col=0) From 400704846467d20820e6f977f7d5f32707bf87fc Mon Sep 17 00:00:00 2001 From: Wei Cheng <36087657+Colin-Cheng@users.noreply.github.com> Date: Thu, 5 Jul 2018 15:52:46 -0400 Subject: [PATCH 03/46] Add files via upload --- scripts/generate_index_files.py | 199 ++++++++++++++++++++++++++++++++ 1 file changed, 199 insertions(+) create mode 100644 scripts/generate_index_files.py diff --git a/scripts/generate_index_files.py b/scripts/generate_index_files.py new file mode 100644 index 0000000..38ccb72 --- /dev/null +++ b/scripts/generate_index_files.py @@ -0,0 +1,199 @@ +""" +2016 Gregory Way +scripts/generate_index_files.py + +Description: +Generates index files mapping genomic content to TADs enabling quick lookup + +1) SNPs +2) Genes +3) Repetitive Elements + +Usage: +Is called by 'scripts/run_pipeline.sh': + + python scripts/generate_index_files.py --TAD-Boundary 'hESC' + +Output: +3 gzipped tsv index files and a tsv file of all genes that span TAD boundaries +""" + +import os +import argparse +import pandas as pd +from tad_util.util import load_tad, parse_gene_gtf + +pd.options.mode.chained_assignment = None + +parser = argparse.ArgumentParser() +parser.add_argument('-t', '--TAD-Boundary', help='boundary cell type') +parser.add_argument('-f', '--TAD-File', help='path to 3-column Tab-separated TAD domain bed file') +args = parser.parse_args() + +TAD_CELL = args.TAD_Boundary + +BASE_DIR = 'data/' +GENOME = 'hg19' +REF_GENE_GTF = BASE_DIR + 'gencode.v19.annotation.gtf.gz' +TAD_LOC = args.TAD_File +REF_SNPS = BASE_DIR + 'hg_common-snps.tsv' + +REPEAT_FH = BASE_DIR + GENOME + '.fa.out.tsv' +bmd_ld_windows = os.path.join('data', 'BMD_ldwindows.tsv') + +SNP_INDEX = 'index/SNP_index_' + GENOME + '_' + TAD_CELL + '.tsv.bz2' +GENE_INDEX = 'index/GENE_index_' + GENOME + '_' + TAD_CELL + '.tsv.bz2' +REPEAT_INDEX = 'index/REPEATS_index_' + GENOME + '_' + TAD_CELL + '.tsv.bz2' +SPANNED_GENES_FH = 'tables/SpannedGenesAcross_' + TAD_CELL + '_TADs.tsv' +bmd_window_genes_file = os.path.join('data', 'BMD_LDwindow_genes.tsv') + + +def curate_tad_elements(tad_df, input_df, gen_class): + """ + Loop through TAD boundaries to assign genomic elements to TADs + + Arguments: + :param tad_df: pandas dataframe, TAD boundary locations + :param input_df: pandas dataframe, the genomic content to subset + :param gen_class: str, either 'snp', 'gene', or 'repeat' + + Output: + Large summary dataframes of the TAD assignment for input genomic element + """ + + big_out_df = pd.DataFrame() + bnd_df = pd.DataFrame() + + if gen_class in ['gene', 'repeat']: + input_df['chromosome'] = input_df['chromosome'].map(lambda x: x[3:]) + + for tad in tad_df.itertuples(): + tad_id, chrom, start, end = list(tad) + start, end = int(start), int(end) + + if gen_class == 'snp' and chrom != 'X' and chrom !='Y': + chrom = int(chrom) + + if gen_class == 'LD': + chrom = 'chr{}'.format(chrom) + + chm_sub_df = input_df[input_df['chromosome'] == chrom] + + if gen_class == 'snp': + elem_sub_df = chm_sub_df[(chm_sub_df['position'] >= start) & + (chm_sub_df['position'] < end)] + + else: + elem_sub_df = chm_sub_df[(chm_sub_df['start'] >= start) & + (chm_sub_df['stop'] <= end)] + + # Get the overlapping genomic elements + o_df = chm_sub_df[((chm_sub_df['start'] >= start) & + (chm_sub_df['start'] < end) & + (chm_sub_df['stop'] > end)) | + ((chm_sub_df['stop'] >= start) & + (chm_sub_df['stop'] < end) & + (chm_sub_df['start'] < start))] + + elem_sub_df = pd.concat([elem_sub_df, o_df], axis=0, + ignore_index=True) + bnd_df = bnd_df.append(o_df, ignore_index=True) + + if gen_class == 'LD': + # Assign LD information + elem_sub_df['rs_id'] = tad_id + elem_sub_df['LD_window_start'] = start + elem_sub_df['LD_window_end'] = end + else: + # Assign TAD information + elem_sub_df['TAD_id'] = tad_id + elem_sub_df['TAD_start'] = start + elem_sub_df['TAD_end'] = end + + big_out_df = big_out_df.append(elem_sub_df, ignore_index=True) + + if gen_class in ['gene', 'repeat']: + bnd_df = bnd_df.drop_duplicates() + + return big_out_df, bnd_df + + +# For parsing messy repeat info data +def rm_paren(x): return x.strip('(').strip(')') + +# Create index path +if not os.path.exists('index'): + os.makedirs('index') + +# Read in TAD boundary file +tad_df = load_tad(TAD_LOC) + +#################################### +# PART 1 - SNPs +#################################### +snp_df = pd.read_table(REF_SNPS) + +big_snp_df, _ = curate_tad_elements(tad_df, snp_df, gen_class='snp') + +# Every SNP that did not map is in a boundary region +boundary_snp_df = snp_df.query("rsid not in @big_snp_df.rsid") +boundary_snp_df['TAD_id'] = "Boundary" +boundary_snp_df['TAD_start'] = 0 +boundary_snp_df['TAD_end'] = 0 + +all_snp_df = big_snp_df.append(boundary_snp_df) +all_snp_df.to_csv(SNP_INDEX, sep='\t', compression='bz2') + +#################################### +# PART 2 - Genes +#################################### +# Process data +refGene_df = pd.read_table(REF_GENE_GTF, skiprows=5, header=None) +refGene_df = refGene_df.drop(refGene_df.columns[[5, 7]], axis=1) +refGene_df.columns = ['chromosome', 'db', 'type', 'start', 'stop', 'strand', + 'info'] +parsed_info_df = refGene_df.apply(parse_gene_gtf, axis=1) +parsed_info_df.columns = ['gene_type', 'gene_name'] +refGene_df = pd.concat([refGene_df, parsed_info_df], axis=1) +refGene_df = refGene_df[refGene_df['type'] == 'gene'].drop('info', axis=1) + +big_gene_df, bound_gene_df = curate_tad_elements(tad_df, refGene_df, + gen_class='gene') + +# Which genes belong entirely in the boundary? +only_bound_gene_df = refGene_df.ix[~refGene_df['gene_name'] + .isin(big_gene_df['gene_name'])] +only_bound_gene_df = only_bound_gene_df.ix[~only_bound_gene_df['chromosome'] + .isin(['X', 'Y', 'M'])] +only_bound_gene_df['TAD_id'] = "Boundary" +only_bound_gene_df['TAD_start'] = 0 +only_bound_gene_df['TAD_end'] = 0 + +big_gene_tad_df = big_gene_df.append(only_bound_gene_df) +big_gene_tad_df.to_csv(GENE_INDEX, sep='\t', compression='bz2') +bound_gene_df.to_csv(SPANNED_GENES_FH, sep='\t') + +#################################### +# PART 3 - Repeat Elements ######### +#################################### +repeats_df = pd.read_csv(REPEAT_FH, delimiter='\t', + skiprows=[0, 1, 2], header=None, + names=['div', 'chromosome', 'start', 'stop', + 'repeat'], + index_col=False, usecols=[2, 5, 6, 7, 11], + converters={'start': rm_paren, 'stop': rm_paren}) +repeats_df['start'] = repeats_df['start'].astype(int) +repeats_df['stop'] = repeats_df['stop'].astype(int) + +big_rep_tad_df, boundary_rep_df = curate_tad_elements(tad_df, repeats_df, + gen_class='repeat') + +big_rep_tad_df = big_rep_tad_df.append(boundary_rep_df, ignore_index=True) +big_rep_tad_df.to_csv(REPEAT_INDEX, sep='\t', compression='bz2') + +#################################### +# PART 4 - BMD genes in LD Windows # +#################################### +bmd_ld_df = pd.read_table(bmd_ld_windows, index_col=0) +bmd_ld_genes_df, _ = curate_tad_elements(bmd_ld_df, refGene_df, gen_class='LD') +bmd_ld_genes_df.to_csv(bmd_window_genes_file, sep='\t', index_col=0) From 624cea3a1483c13acef83a2e3e7305fc7c9326a0 Mon Sep 17 00:00:00 2001 From: Wei Cheng <36087657+Colin-Cheng@users.noreply.github.com> Date: Fri, 6 Jul 2018 14:50:32 -0400 Subject: [PATCH 04/46] Add files via upload --- scripts/tad_util/Identify_TAD_signal.py | 99 +++ .../__pycache__/__init__.cpython-35.pyc | Bin 0 -> 149 bytes .../__pycache__/__init__.cpython-36.pyc | Bin 0 -> 151 bytes .../tad_util/__pycache__/util.cpython-35.pyc | Bin 0 -> 3943 bytes .../tad_util/__pycache__/util.cpython-36.pyc | Bin 0 -> 3737 bytes scripts/tad_util/build_snp_list.R | 66 ++ scripts/tad_util/convert_GWAS_catalog_hg19.py | 56 ++ scripts/tad_util/grab_TAD_genes.py | 46 ++ scripts/tad_util/util.py | 152 ++++ .../tad_util/viz/gc_content_distribution.py | 450 ++++++++++++ scripts/tad_util/viz/visualize.sh | 10 + .../tad_util/viz/visualize_TAD_locations.py | 677 ++++++++++++++++++ 12 files changed, 1556 insertions(+) create mode 100644 scripts/tad_util/Identify_TAD_signal.py create mode 100644 scripts/tad_util/__pycache__/__init__.cpython-35.pyc create mode 100644 scripts/tad_util/__pycache__/__init__.cpython-36.pyc create mode 100644 scripts/tad_util/__pycache__/util.cpython-35.pyc create mode 100644 scripts/tad_util/__pycache__/util.cpython-36.pyc create mode 100644 scripts/tad_util/build_snp_list.R create mode 100644 scripts/tad_util/convert_GWAS_catalog_hg19.py create mode 100644 scripts/tad_util/grab_TAD_genes.py create mode 100644 scripts/tad_util/util.py create mode 100644 scripts/tad_util/viz/gc_content_distribution.py create mode 100644 scripts/tad_util/viz/visualize.sh create mode 100644 scripts/tad_util/viz/visualize_TAD_locations.py diff --git a/scripts/tad_util/Identify_TAD_signal.py b/scripts/tad_util/Identify_TAD_signal.py new file mode 100644 index 0000000..70674b7 --- /dev/null +++ b/scripts/tad_util/Identify_TAD_signal.py @@ -0,0 +1,99 @@ +""" +2016 Gregory Way +TAD Pathways +scripts/tad_util/Identify_TAD_signal.py + +Description: +Uses TAD boundaries and trait specific GWAS files that were generated by +'scripts/NHGRI-EBI_GWAS_summary.R' to output an intermediate file of TAD +coordinates for each significant SNP + +Usage: +Is called by 'scripts/build_TAD_genelists.py' + +Output: +Intermediate files 'data/gwas_TAD_location/', which are summaries of each SNP +and which TAD they fall in. The format of the output files by row is: +[rs, Chromosome, SNP Coordinate, TAD Start, TAD End, TAD ID, nearest gene] +""" + +import argparse +from collections import OrderedDict +import pandas as pd + + +def assign_tad(snp_signal, tad_boundary): + """ + Take an input snp signal and TAD boundary coordinates to output the + coordinates of TAD where the SNP signal resides. + + Arguments: + :param snp_signal: Pandas Series with SNP descriptive attributes + :param tad_boundary: a Pandas DataFrame of all TADs and genomic locations + + Output: + an OrderedDict object storing SNP and TAD specific info + """ + chrom = ('chrom', snp_signal.chrom) + snp_loc = ('snploc', snp_signal.position) + snp = ('rs', snp_signal.snp) + + mapped_gene = snp_signal.mapped_gene + + mapped_gene = mapped_gene.replace(' - ', ',') + mapped_gene = mapped_gene.replace(' ', '') + mapped_gene = ('gene', mapped_gene) + + if snp_loc[1] == 'Not Mapped': + tad_start = ('TADStart', '') + tad_end = ('TADEnd', '') + tad_idx = ('TADidx', '') + + return OrderedDict([snp, chrom, snp_loc, tad_start, tad_end, tad_idx, + mapped_gene]) + else: + snp_loc = ('snploc', int(snp_loc[1])) + + tad = tad_boundary.ix[ + (tad_boundary.chrom == chrom[1]) & + (tad_boundary.start <= snp_loc[1]) & + (tad_boundary.stop > snp_loc[1]) + ] + + if tad.shape[0] == 0: + tad_start = ('TADStart', '') + tad_end = ('TADEnd', '') + tad_idx = ('TADidx', '') + else: + tad_start = ('TADStart', int(tad.start)) + tad_end = ('TADEnd', int(tad.stop)) + tad_idx = ('TADidx', int(tad.index.tolist()[0])) + + return OrderedDict([snp, chrom, snp_loc, tad_start, tad_end, tad_idx, + mapped_gene]) + +# Load Command Arguments +parser = argparse.ArgumentParser() +parser.add_argument("-t", "--tad_data", help="Location of TAD data") +parser.add_argument("-g", "--gwas_data", help="Location of GWAS data") +parser.add_argument("-o", "--output_file", help="Name of the output file") +args = parser.parse_args() + +# Load Constants +tad_data = args.tad_data +gwas_data = args.gwas_data +output_file = args.output_file + +# Load and process data +tad_boundary_df = pd.read_table(tad_data, names=['chrom', 'start', 'stop']) +gwas_df = pd.read_table(gwas_data, names=['snp', 'chrom', 'position', + 'trait', 'reported_gene', + 'mapped_gene', 'pubmed_id'], + skiprows=1) +gwas_df = gwas_df[~gwas_df['mapped_gene'].isnull()] + +# Output results +snp_tad_df = gwas_df.apply(lambda x: assign_tad(x, tad_boundary_df), axis=1) +result_col = ('rs', 'chrom', 'snploc', 'TADStart', 'TADEnd', 'TADidx', 'gene') +snp_tad_df = pd.DataFrame.from_records(snp_tad_df, columns=result_col) +snp_tad_df.to_csv(output_file, index=False, header=True, sep='\t') diff --git a/scripts/tad_util/__pycache__/__init__.cpython-35.pyc b/scripts/tad_util/__pycache__/__init__.cpython-35.pyc new file mode 100644 index 0000000000000000000000000000000000000000..50962b3c0a4712c2bbf37f0fe29718daca14dc9f GIT binary patch literal 149 zcmWgR<>hh+>IacWVqesV@? zUV6EqzDs^`X>Mv>NwI!OVoH2LVo64MVr8*@adJ^+0aUQGBr``pK0Y%qvm`!Vub}c4 ThfQvNN@-529mworAZ7pnk$@!i literal 0 HcmV?d00001 diff --git a/scripts/tad_util/__pycache__/__init__.cpython-36.pyc b/scripts/tad_util/__pycache__/__init__.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..13c984a60607199ad3541609bb6ce018918b7d0f GIT binary patch literal 151 zcmXr!<>hh+&=ek&P@K*9*(my3RAacWVqesV@? zUV6Eqer8^ANn%cpzF%s2d`V(Td_iJKMtNdov3_xKQD#9&u|7z!v?Mb}KR!M)FS8^* YUaz3?7Kcr4eoARhsvXGmVjyM!0QS8l;s5{u literal 0 HcmV?d00001 diff --git a/scripts/tad_util/__pycache__/util.cpython-35.pyc b/scripts/tad_util/__pycache__/util.cpython-35.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b2d35c2618d9ee8149517c2073aae6154ce03ffc GIT binary patch literal 3943 zcmcIn&vV+gq-k>7UR;FZmnNnf?Vm;M$Y^1zpnbJphy}+0#=<0o+}@#qPfMecyZf z&hoPN!N={V4_AcvuekED(f$CJ`2%i|5CQI%h-~p^w9#-x)Zn%)qNa#kZey?|qBgf1 zBI=09<2DSIMAYTBE23o)t#BL0t772yPX6PWk&d(6Y~^7zoaga$i*B3Qv3Gx-AEdf3 zKh$a>KMjvPZ%38JahmkKkJ3??qb0|wmUE-V^QoLEOoB9G$yKt8#@ zW3~o+kImMHDpAJsJ~81$^}XF$mg-!>K9$)qUXaLYPx7veQkkT=RLK|Vp^{Oo)hM50 zE05-RHqZOsKq+Z5HHydaNRH@guxYiNtpTpa=ho8fUN4N1a@H;2}@+3ZwLmk2aN}E3Sao*ua zj~?`8exT&E_EtLPJ|4>bbe=?^K9-|2)lr;;xsu~}syv=vpO9W1CQ{9^{1^`41Jb10 zr*Ir1Fe_sb8hNOW&8B>)j-|=Qyd(As zZ*-v3S!&XmDw=FoI4~-j2~KAgjwJ^>xCXckFwA~~ONIE0E!GFVy?0KJ{~>&-3H1AM0(6=0y96VCt=zzARSXX$r)eC@s-duj1DVlt_jQoj$PT`ds zP^pbOa)ah?NXXlUR+$R(4gV%JpWvKfmgzLpF%g)~T9;g-A84lFd8oqvOmZ(s1^i|Vm& z>o>{ZExN7OH?Y%z^7`$@t&})R1!OLXFV|k!Z-_A=YwGX+1{^EI|vFRi~sJB!A#HPyWu(xDH9mg(P=KK%q3q zU{lIH3+aW#mhxK)?<;lnCR#!{1xCxs1PwsnsED`$94=&>_jF{#M3MF#@ zZ)kEhjdT4r9{CQ3iMJZ8)|-aHQ;>o#4b)J%9-tLoc}U2kgZ_@ZOqwOyU2D}^v-FS9 zUIc^0Z=q)YMCWQ2rG!Zt65elA-j9)99q}w8mm|IANTZZbseSvoEp|TJWywQu5E+{2 z@K#>uvTftk8uNQ=kYY+V+YMJ&-H%L;-8@jys|;71f4`34a?_CTA_?chJ@W$ z0Est>BmW*tm|M7sPS;+uTuTB>^j)!T+4`p#Ux2EvAeiA)LA;P6Q9+!1`O>ISntmZ@ zR0%8 zNk1!S*PFTSme)&uVeW#0DUN6;tfH-dhWo-1E;E%~dt_}-vM?Nk2 zaanubLHUXjb%;!-O0pCUvMHKuQ@DU4>beW--7@cyJk@b=^?T?A%?VA=zu-2^lZZ_V zH|2jGu7_;34B5g5Czxlbs1t3^qA#Vb9@J6)5@U<#(ZY-9y^GHOiC!5Fhr%)N8z+B# zX&}ms{vynQ;&K>Sg9_S9fZxP%WysX8{xx`&hbtwzjh(ZrisrtW#0h)HZv@~zl|H3j z)SZQ2OW!Yw`?5-Yt#ss-iC^O7ReC91so%%Q9;%Mka2Tbd;gG9mt^hdmuu?Ef*x77; kC0@K>S&?tg(r7+a_m*i1QW4kbu5~xME8XvQm%3~J16?faJ^%m! literal 0 HcmV?d00001 diff --git a/scripts/tad_util/__pycache__/util.cpython-36.pyc b/scripts/tad_util/__pycache__/util.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..81e06eff33a16a51fce9631319b0771e449d5c96 GIT binary patch literal 3737 zcmcInU2ojR73KGGsg>k3ZeyiDF-Qt*7O}Mr0<`E>5bRoLs@jm<%0U7e!GhYEUD4u_ z>h@z$!+f7X>pf(c-p+heLNlB<^i5AU*R1* zJ-*7<@NDt*eWQ10{_jAIWSkeOUqpO3E8?V2)n`wDc77X?o%TMrulr8qe9x$G*g#o~2kXOI0v30T2D0MR|;;8lWP)65~|k#odX0YL(_IvouPJdvB~$yR^BzVZ5?x z{LW13ZyBWxwA%B31q{FEk&JLsA=NSRE^TRdXF!k_kt`mdAyVGm)CT8(!Pu*U(V@(ynaZZ3aDIgZi@4%21CNq zM%hPE9aJTuX#CmQz);WHJExcbFfh@4En8^o>f&MlO9hPjqeGESjz87< z64~;oI6RI{RR1;xR{mBJO%Hgq{S#Ul#h8DXWSENSn_Gl*qPEefje2(FG^j^Qx3upWryj<<(xLW`jnceJUv0sD4ffxc9$z^!1f234ANm;}uBF(0V8U@|)% zzzh!t#)H3c%EjxN-o)sI8NR9N07+-l10l(n#%N6*gTV2@3{fGX(IIV1XgSckU3>s+ z)|)F%azT?Xmtmg>$O}H%g}8L@vo6i=GN@8lid;lRw|6tpUf`Tjp35wkF@+sKQI+ky)p>%BDyo=(S9*Sd03d}|) z=pZi2V-&TGiYN?kX0oR#F z;z0_9^bj$H{E|>+X!H`gSZijjmbZ%GO;SWG0Tt`X!~if{2~HsZx;5IX_jF+n!$^72!&l*XC`;=8E4jx@y*X6O;!mH zz|w=ITe{pu&*3ffJoNmg2Qew_(%UlrxcL>bB5!X{4Vju)r#>>NTl!}ve77?H+dF+n z%pVe%+IgfJVGEhvpC`U*r6L0g**sb`Y}{tP&a6mu$>|`*6&xOKtfN4M95p%p*M;n ze~l&7T~tQfx7JL@ya$HRU&p*-$)91oVahU->jzQ># znW4Yj%ym$HP=^fWHc^$~fQp=I`0_K<4GbPSHj0Mfw`kCXW&@W(JRv_2CY`DEWstJ< zriKY2fpBorj_!GNuQVxiaE(OJ0K(S%pYMcF`|AINA$|O+KrP{?2w^YlD7d`q-N$ti zSHdB3k*GtWa>%A~wN2%LaJWTXn4i{}iIioDzbE_Xh3dPKdy!J4r1D%T5Dl4S92iuCJo+ z)%abR_y!+u5&|J8e~FPjTnSpkA+kfBh`fL6N{)+$p{{Ysb +# --output_file + +# Output: +# A tab separated file of rsIDs mapped to genomic coordinates + +library(checkpoint) +suppressMessages(checkpoint("2016-02-25")) + +library(dplyr) + +# Load in command arguments +option_list <- list(optparse::make_option(c("-s", "--snp_file"), + type = "character", + help = "Location of rsID SNP file"), + optparse::make_option(c("-o", "--output_file"), + type = "character", + help = "File name to save results")) + +opt_parser <- optparse::OptionParser(option_list = option_list); +opt <- optparse::parse_args(opt_parser); + +# Load arguments +snp_file <- opt$snp_file +output_file <- opt$output_file + +# Map rsids to genomic location +snps <- readr::read_csv(snp_file) +snp <- biomaRt::useEnsembl(biomart = "snp", GRCh = 37, + dataset = "hsapiens_snp") + +results_full <- list() +for (group in 1:ncol(snps)) { + results <- biomaRt::getBM(attributes = c("refsnp_id", "refsnp_source", + "chr_name", "chrom_start", + "chrom_end", "minor_allele"), + filters = "snp_filter", values = snps[, group], + mart = snp) + results <- results %>% dplyr::filter(!duplicated(refsnp_id)) + results$Group <- colnames(snps)[group] + results_full[[group]] <- results +} + +# Process results and write to file +results_full <- do.call(rbind, results_full) +results_full$chr_name <- as.numeric(results_full$chr_name) +results_full <- results_full %>% dplyr::filter(!is.na(chr_name)) +colnames(results_full) <- c("snp", "refsnp_source", "chrom", "position", + "snp_end", "minor_allele", "group") +write.table(results_full, output_file, row.names = FALSE, sep = "\t") diff --git a/scripts/tad_util/convert_GWAS_catalog_hg19.py b/scripts/tad_util/convert_GWAS_catalog_hg19.py new file mode 100644 index 0000000..06e55c5 --- /dev/null +++ b/scripts/tad_util/convert_GWAS_catalog_hg19.py @@ -0,0 +1,56 @@ +""" +(C) 2016 Gregory Way +convert_GWAS_catalog_hg19.py + +Description: +The GWAS catalog is downloaded in hg38 coordinates. Use pyliftover to convert +coordinates to hg19. + +Usage: +Called by ANALYSIS.sh + +Output: +The GWAS Catalog but with hg19 coordinates +""" + +from pyliftover import LiftOver +lo = LiftOver('data/hg38ToHg19.over.chain.gz') + +new_coordinates = [] +with open('data/gwas_catalog_v1.0.1.tsv', 'r') as gwas_fh: + header = next(gwas_fh) + for snp in gwas_fh: + snp = snp.split('\t') + + # Get Coordinates + chrom = 'chr' + str(snp[11]) + + if len(snp[12]) > 0: + coord = int(snp[12]) + 1 + + # Convert from hg38 to hg19 + converted = lo.convert_coordinate(chrom, coord) + if converted is not None: + if len(converted) > 0: + new_coord = converted[0][1] + new_chrom = converted[0][0] + else: + new_coord = 'Not Mapped' + new_chrom = 'Not Mapped' + else: + new_coord = 'Not Mapped' + new_chrom = 'Not Mapped' + else: + new_coord = 'NA' + new_chrom = 'NA' + + # Reassign back to original line + snp[11] = str(new_chrom) + snp[12] = str(new_coord) + + new_coordinates.append(snp) + +with open('data/gwas_catalog_hg19.tsv', 'w') as gwas_fh: + gwas_fh.write(header) + for snp in new_coordinates: + gwas_fh.write('\t'.join(snp)) diff --git a/scripts/tad_util/grab_TAD_genes.py b/scripts/tad_util/grab_TAD_genes.py new file mode 100644 index 0000000..8e39c86 --- /dev/null +++ b/scripts/tad_util/grab_TAD_genes.py @@ -0,0 +1,46 @@ +""" +2016 Gregory Way +TAD Pathways +scripts/tad_util/grab_TAD_genes.py + +Description: +Uses intemediate files and gene assignment in TADs index file to curate +a final list of all trait-specific genes that fall in signal TADs + +Usage: +Is called by 'scripts/run_pipeline.sh' + +Output: +Trait specific .tsv files of one column each indicating all the genes that fall +in signal TADs +""" + +import argparse +import pandas as pd + +# Load Command Arguments + +parser = argparse.ArgumentParser() +parser.add_argument("-f", "--tad_gwas_file", help="Location of TAD/GWAS data") +parser.add_argument("-o", "--output_tad_file", + help="Name of the full genelist output file") +parser.add_argument("-g", "--output_gwas_file", + help="Name of the GWAS genelist output file") +args = parser.parse_args() + +# Load Constants +tad_gwas_loc = args.tad_gwas_file +output_file = args.output_tad_file + +# Load data +tad_genes_df = pd.read_table('index/GENE_index_hg19_hESC.tsv.bz2', index_col=0) +tad_gwas_df = pd.read_table(tad_gwas_loc) +tad_gwas_df = tad_gwas_df[~tad_gwas_df.TADidx.isnull()] +tad_gwas_df.TADidx = tad_gwas_df.TADidx.astype(int) + +# Get all TAD based genes +tad_ids = map(str, tad_gwas_df['TADidx'].tolist()) +tad_genes_df = tad_genes_df[tad_genes_df["TAD_id"].isin(tad_ids)]\ + .sort_values(by='gene_name') + +tad_genes_df.to_csv(output_file, index=False, header=True, sep='\t') diff --git a/scripts/tad_util/util.py b/scripts/tad_util/util.py new file mode 100644 index 0000000..1a821b8 --- /dev/null +++ b/scripts/tad_util/util.py @@ -0,0 +1,152 @@ +""" +scripts/tad_util/util.py +Author: Greg Way + +Description: +Location for useful methods for interacting with TADs/SNPs/Genes + +Usage: +Import into python scripts - do not envoke directly + +Output: +See specific functions +""" + + +def load_tad(TAD_LOC): + """ + Parameters: + TAD_LOC: the location of the TAD boundary coordinate file + + Output: + an empty dictionary with TAD information as keys. Key structure + is 'TAD_ID:TADstart-TADend'. + """ + + import pandas as pd + + snp_header = ['chromosome', 'start', 'end'] + TAD_df = pd.read_table(TAD_LOC, names=snp_header) + TAD_df['chromosome'] = TAD_df['chromosome'].map(lambda x: x[3:]) + + return TAD_df + + +def assign_bin(row, bins, ID): + ''' + Assign a genomic element to the bin inside a TAD + + Parameters: + :param row: a row of an index file + :param bins: the number of bins to distribute each gene into + :param ID: the type of index file (either 'SNP', 'gene' or 'repeat') + + Output: + The appropriate bin number for the given genomic information. + ''' + + tadstart = int(row['TAD_start']) + tadend = int(row['TAD_end']) + + if row['TAD_id'] == 'Boundary': + return -1 + + if ID == 'SNP': + start_pos = int(row['position']) + + elif ID in ['gene', 'repeat']: + start_pos = int(row['start']) + + # Determine the bin the gene belongs in + diff = start_pos - tadstart + bin_assign = int(diff/(tadend - tadstart) * bins) + + # Remove overlapping elements + if ID in ['gene', 'repeat']: + if diff < 0: + bin_assign = -1 + elif tadend < start_pos: + bin_assign = -1 + + return bin_assign + + +def parse_TAD_name(tad_name): + """ + Parameters: + tad_name - a single dictionary key with format 'TAD_ID:TADstart-TADend' + + Output: + a list with the parsed TAD information + """ + tad_name = str(tad_name) + tad_name_ID_pos = tad_name.split(':') + tad_position = tad_name_ID_pos[1].split('-') + return [tad_name_ID_pos[0], int(tad_position[0]), int(tad_position[1])] + + +def parse_gene_gtf(gene_info): + """ + Parameters: + gene_info - a row from the input gtf file. + + Output: + Parsed gene information from the gtf file [gene_type, gene_name] + """ + + import pandas as pd + + info = gene_info['info'].split(';') + build_info = {} + for attrb in range(1, (len(info) - 1)): + attrb_s = info[attrb].split(' ') + attrb_name = attrb_s[1].strip('"') + new_attrb = attrb_s[2].strip('"') + build_info[attrb_name] = new_attrb + return_list = [build_info['gene_type'], build_info['gene_name']] + + return pd.Series(return_list) + + +def parse_SNP_position(snp_info): + ''' + Parameters: + snp_info - a row within a single pandas DataFrame in the pickle dictionary + + Output: + The position of the SNP + ''' + return int(snp_info['POSITION']) + + +def parse_gene_info(gene_info): + ''' + Parameters: + gene_info - a row within a single pandas DataFrame in the pickle dictionary + + Output: + gene information in the form [type, chromosome, start_site] + ''' + gtype = gene_info['type'] + chrom = gene_info['chrom'] + strnd = gene_info['strand'] + if strnd == '+': + start = int(gene_info['start']) + else: + start = int(gene_info['end']) + output = [gtype, chrom, start] + return output + + +def parse_repeat_info(repeat_info): + ''' + Parameters: + repeat_info - a row in repeat pandas DataFrame + + Output: + repeat information [type, chromosome, start] + ''' + repeat_type = repeat_info['repeat'] + chrom = repeat_info['chrom'] + start = repeat_info['begin'] + return [repeat_type, chrom, start] diff --git a/scripts/tad_util/viz/gc_content_distribution.py b/scripts/tad_util/viz/gc_content_distribution.py new file mode 100644 index 0000000..11e5e8f --- /dev/null +++ b/scripts/tad_util/viz/gc_content_distribution.py @@ -0,0 +1,450 @@ +""" +(C) 2016 Gregory Way +gc_content_distribution.py + +Description: +Observe GC Content distributions and locations across TADs (hg19) + +Usage: +Is called by 'ANALYSIS.sh' but can also be run through command line. + + python gc_content_distribution.py -g + +Where can be either 'hg' or 'mm' for human and mouse. + +Output: +GC Content distribution and histogram across TADs as a .png file +""" + +import sys +sys.path.append('bin/') +import random +import pandas as pd +import matplotlib.pyplot as plt +from Bio import SeqIO +import argparse +from util import parse_TAD_name +from util import ID_TAD_bins +from util import parse_repeat_info +plt.figure.max_open_warning = 0 + +random.seed(123) +################## +# Load Command Arguments +################## +parser = argparse.ArgumentParser() +parser.add_argument('-g', '--genome', help='Can be either hg19 or mm9') +args = parser.parse_args() + +################## +# Define Constants +################## +NUM_BINS = 50 +GENOME = args.genome + +if GENOME == 'hg': + FASTA_LOC = 'data/hg/hg19_fasta/' + + TAD_DICT_A = 'index/REPEATSindex_hg19_hESC.p' + TAD_DICT_B = 'index/REPEATSindex_hg19_IMR90.p' + + OUTPUT_FH_A = 'figures/hg19/hg19_hESC_gc_distribution.png' + OUTPUT_FH_B = 'figures/hg19/hg19_IMR90_gc_distribution.png' + + PLT_TITLE_A = 'hg19 GC Content Across hESC TADs' + PLT_TITLE_B = 'hg19 GC Content Across IMR90 TADs' + + OUTPUT_FH_DIV_A = 'figures/hg19/repeats/divergence/hg19_hESC_divergence_' + OUTPUT_FH_DIV_B = 'figures/hg19/repeats/divergence/hg19_IMR90_divergence_' + + PLT_TITLE_DIV_A = 'hg19 hESC Divergence: ' + PLT_TITLE_DIV_B = 'hg19 IMR90 Divergence: ' + +elif GENOME == 'mm': + FASTA_LOC = 'data/mm/mm9_fasta/' + + TAD_DICT_A = 'index/REPEATSindex_mm9_mESC.p' + TAD_DICT_B = 'index/REPEATSindex_mm9_cortex.p' + + OUTPUT_FH_A = 'figures/mm9/mm9_mESC_gc_distribution.png' + OUTPUT_FH_B = 'figures/mm9/mm9_cortex_gc_distribution.png' + + PLT_TITLE_A = 'mm9 GC Content Across mESC TADs' + PLT_TITLE_B = 'mm9 GC Content Across cortex TADs' + + OUTPUT_FH_DIV_A = 'figures/mm9/repeats/divergence/mm9_mESC_divergence_' + OUTPUT_FH_DIV_B = 'figures/mm9/repeats/divergence/mm9_cortex_divergence_' + + PLT_TITLE_DIV_A = 'mm9 mESC Divergence: ' + PLT_TITLE_DIV_B = 'mm9 Cortex Divergence: ' + +else: + raise ValueError('Please input either "hg" or "mm" for -g') + +#################################### +# Set matplotlib defaults +#################################### +fig_size = 4, 3 +margin = 2.5 +font_size = 10 +plt.rcParams['figure.figsize'] = fig_size +plt.rcParams['font.size'] = font_size +x0, x1, y0, y1 = plt.axis() +plt.axis((x0 + margin, x1 + margin, y0 + margin, y1 + margin)) + +#################################### +# Define Functions +#################################### + + +def load_fasta(chrom, fasta_loc): + """ + Retrieve fasta file + + Arguments: + :param chrom: the chromosome of interest (format 'chr#') + :param fasta_loc: the location that stores the hg19 fasta files + + Output: + fasta file for the given chromosome + """ + + chrom_fa = fasta_loc + chrom + '.fa' + record = SeqIO.read(open(chrom_fa), 'fasta') + + nucleotides = str(record.seq) + # FASTA file has upper and lowercase letters + # lower case = repetative elements (ignore for now) + nucleotides = nucleotides.upper() + + return nucleotides + + +def parse_fasta_tad(tadname, nuc): + """ + Retrieve nucleotide sequence of tad + + Arguments: + :param tadname: of the format tadid:tadstart-tadend + :param nuc: the nucleotides for the same chromosome as the TAD + + Output: + a list of nucleotides in the TAD + """ + + tadname = parse_TAD_name(tadname) + start = tadname[1] + end = tadname[2] + + tadsequence = nuc[start:end] + + return tadsequence + + +def determine_gc_content(seq, start, end): + """ + Determine the gc content for a given sequence given bin coordinates + + Arguments: + :param seq: a nucleotide sequence + :param start: where to subset the sequence + :param end: where to subset the sequence + + Output: + A count of GC content within the specific coordinates + """ + + if len(seq) < end: + end = len(seq) + subset_seq = seq[start:end] + + A = subset_seq.count('A') + C = subset_seq.count('C') + G = subset_seq.count('G') + T = subset_seq.count('T') + N = subset_seq.count('N') + + known_length = A + C + G + T + + if known_length + N == N: + GC = 0.5 + else: + GC = (G + C) / float(known_length) + + return float(GC) + + +def split_TAD_bins(tadlength, num_bins): + """ + Return a list of coordinates to partition the TAD + + Arguments: + :param tadlength: how long the TAD is + :param num_bins: how many bins to split + + Output: + a list of tuples with the locations for starting and ending bins + """ + + avgbin = tadlength / num_bins + remainder = tadlength % num_bins + if remainder > 0: + randadd = random.sample(range(0, num_bins), remainder) + else: + randadd = [] + + return_list = [] + current_idx = 0 + for binID in range(0, num_bins): + next_idx = current_idx + avgbin + if binID in randadd: + return_list.append([current_idx + 1, next_idx + 1]) + current_idx = next_idx + 1 + else: + return_list.append([current_idx + 1, next_idx]) + current_idx = next_idx + return return_list + + +def get_gc_content(tads, seq, chrom, num_bins): + """ + Determine the gc content of all TADs across TAD bins + + Arguments: + :param tads: The lookup dictionary for TAD locations + :param seq: the seqIO object for the chromosome fasta + :param chrom: the chromosome we're currently using + :param num_bins: how to split the TAD bins for determining gc content + + Output: + A list of gc contant of all TADs across bins + """ + for TAD in tads[chrom].keys(): + tad_sequence = parse_fasta_tad(TAD, seq) + tad_length = len(tad_sequence) + + # Get the TAD bins + tad_bins = split_TAD_bins(tad_length, num_bins) + + # Now, loop over the TAD bins and extract GC Content + tad_gc = [] + + for coord_idx, coord in enumerate(tad_bins): + start = tad_bins[coord_idx][0] + end = tad_bins[coord_idx][1] + gc = determine_gc_content(tad_sequence, start, end) + tad_gc.append(gc) + + return tad_gc + + +def identify_TAD_repeats(tads): + """ + Return the divergence + """ + all_repeat_types = [] + for key in tads.keys(): + if key in ['Y', 'Boundary']: + continue + for tadkey in tads[key].keys(): + repeat_elements = tads[key][tadkey] + repeat_elements = repeat_elements['repeat'].tolist() + all_repeat_types = all_repeat_types + repeat_elements + + all_repeat_types = set(all_repeat_types) + repeat_types = [] + for repeat in all_repeat_types: + if '?' not in repeat: + repeat_types.append(repeat) + + repeat_types.append('all') + # Initialize dictionary sthat will store divergence information for repeats + TADrepeat_div = dict.fromkeys(repeat_types) + for repeatkey in repeat_types: + # Create a list of zeros of len(NUM_BINS) + TADrepeat_div[repeatkey] = [[] for _ in range(NUM_BINS)] + + return TADrepeat_div + + +def plot_gc_content(gc_distrib, title, out_fh): + """ + Output gc content distribution plots + + Arguments: + :param gc_distrib: a list of gc content across TADs + :param title: title for plot + :param out_fh: the file handle to save + + Output: + None -- saves plot to file + """ + gc_distrib = pd.DataFrame(gc_distrib) + + fig, ax = plt.subplots() + gc_distrib.boxplot(column=range(0, 50), notch=True, positions=range(0, 50), + return_type='dict') + ax.set_xticklabels('' * NUM_BINS) + ax.tick_params(axis=u'both', which=u'both', length=0) + ax.spines['right'].set_visible(False) + ax.spines['top'].set_visible(False) + plt.grid(False) + plt.xlabel('Bins (Normalized TAD length)') + plt.ylabel('GC Percentage') + plt.title(title) + plt.savefig(out_fh) + plt.close() + + +def plot_divergence(div, title_base, out_base): + """ + Output divergence plots + + Arguments: + :param div: a list of divergence across TADs + :param title_base: base name for title of plot + :param out_fh: the base file handle to save + + Output: + None -- saves plot to file + """ + for divkey in div.keys(): + + title = title_base + divkey + out_fh = out_base + divkey.replace('/', '_') + '.png' + + fig, ax = plt.subplots() + plt.boxplot(div[divkey]) + ax.set_xticklabels('' * NUM_BINS) + ax.tick_params(axis=u'both', which=u'both', length=0) + ax.spines['right'].set_visible(False) + ax.spines['top'].set_visible(False) + plt.grid(False) + plt.xlabel('Bins (Normalized TAD length)') + plt.ylabel('Percent Divergence from Consensus Sequence') + plt.title(title) + plt.savefig(out_fh) + plt.close() + +#################################### +# Load Data +#################################### +TADrepeats_A = pd.read_pickle(TAD_DICT_A) +TADrepeats_div_A = identify_TAD_repeats(TADrepeats_A) +TADrepeats_B = pd.read_pickle(TAD_DICT_B) +TADrepeats_div_B = identify_TAD_repeats(TADrepeats_B) + +#################################### +# Analysis +#################################### +gc_distrib_A = [] +gc_distrib_B = [] + +for chrom in TADrepeats_A.keys(): + if chrom in ['Boundary', 'Y']: + continue + + # Build key to lookup fasta + lookup_chrom = 'chr' + str(chrom) + + # Get the TAD sequence: + chr_seq = load_fasta(lookup_chrom, FASTA_LOC) + + # Determine GC content and Divergence + for TAD, tadval in TADrepeats_A[chrom].iteritems(): + + tad_sequence = parse_fasta_tad(TAD, chr_seq) + tad_length = len(tad_sequence) + + # Get the TAD bins + tad_bins = split_TAD_bins(tad_length, NUM_BINS) + + # Now, loop over the TAD bins and extract GC Content + tad_gc = [] + + for coord_idx, coord in enumerate(tad_bins): + start = tad_bins[coord_idx][0] + end = tad_bins[coord_idx][1] + gc = determine_gc_content(tad_sequence, start, end) + tad_gc.append(gc) + + gc_distrib_A.append(tad_gc) + + # Now, store divergence + tadkey = parse_TAD_name(TAD) + for repeat in range(len(tadval)): + # repeat_info stores [gene_type, chromosome, start_pos, divergence] + repeat_info = parse_repeat_info(tadval.ix[repeat, :]) + + repeat_name = repeat_info[0] + repeat_div = float(repeat_info[3]) + + if '?' not in repeat_name: + binID = ID_TAD_bins(tadkey, NUM_BINS, repeat_info[2], + IDtype='gene') + + if binID == -1: + continue + + # if the start is exactly on a TAD boundary, put it in the + # previous bin + if binID == 50: + binID = 49 + + # Add divergence info to specific bin + TADrepeats_div_A[repeat_name][binID].append(repeat_div) + + # Add the bin number of all repeats + TADrepeats_div_A['all'][binID].append(repeat_div) + + # Determine GC content and Divergence + for TAD, tadval in TADrepeats_B[chrom].iteritems(): + tad_sequence = parse_fasta_tad(TAD, chr_seq) + tad_length = len(tad_sequence) + + # Get the TAD bins + tad_bins = split_TAD_bins(tad_length, NUM_BINS) + + # Loop over the TAD bins and extract GC Content + tad_gc = [] + + for coord_idx, coord in enumerate(tad_bins): + start = tad_bins[coord_idx][0] + end = tad_bins[coord_idx][1] + gc = determine_gc_content(tad_sequence, start, end) + tad_gc.append(gc) + + gc_distrib_B.append(tad_gc) + + # Store divergence + tadkey = parse_TAD_name(TAD) + for repeat in range(len(tadval)): + # repeat_info stores [gene_type, chromosome, start_pos, divergence] + repeat_info = parse_repeat_info(tadval.ix[repeat, :]) + repeat_name = repeat_info[0] + repeat_div = repeat_info[3] + if '?' not in repeat_name: + binID = ID_TAD_bins(tadkey, NUM_BINS, repeat_info[2], + IDtype='gene') + if binID == -1: + continue + + # if the start is exactly on a TAD boundary, put it in the + # previous bin + if binID == 50: + binID = 49 + + # Add divergence info to specific bin + TADrepeats_div_B[repeat_name][binID].append(repeat_div) + + # Add the bin number of all repeats + TADrepeats_div_B['all'][binID].append(repeat_div) + +#################################### +# Plot +#################################### +plot_gc_content(gc_distrib_A, PLT_TITLE_A, OUTPUT_FH_A) +plot_gc_content(gc_distrib_B, PLT_TITLE_B, OUTPUT_FH_B) + +plot_divergence(TADrepeats_div_A, PLT_TITLE_DIV_A, OUTPUT_FH_DIV_A) +plot_divergence(TADrepeats_div_B, PLT_TITLE_DIV_B, OUTPUT_FH_DIV_B) diff --git a/scripts/tad_util/viz/visualize.sh b/scripts/tad_util/viz/visualize.sh new file mode 100644 index 0000000..a51f50b --- /dev/null +++ b/scripts/tad_util/viz/visualize.sh @@ -0,0 +1,10 @@ +#!/bin/bash + +python scripts/viz/visualize_TAD_locations.py -t 'hESC' -g 'hg19' +python scripts/viz/visualize_TAD_locations.py -t 'IMR90' -g 'hg19' +python scripts/viz/visualize_TAD_locations.py -t 'mESC' -g 'mm9' +python scripts/viz/visualize_TAD_locations.py -t 'cortex' -g 'mm9' + +python scripts/viz/gc_content_distribution.py -g 'hg' +python scripts/viz/gc_content_distribution.py -g 'mm' + diff --git a/scripts/tad_util/viz/visualize_TAD_locations.py b/scripts/tad_util/viz/visualize_TAD_locations.py new file mode 100644 index 0000000..c6e9a7d --- /dev/null +++ b/scripts/tad_util/viz/visualize_TAD_locations.py @@ -0,0 +1,677 @@ +""" +(C) 2016 Gregory Way +visualize_TAD_locations.py + +Description: +Observe SNP/gene/repeat distributions and locations across TADs (hg19) + +Usage: +Is called by 'ANALYSIS.sh'. + + python visualize_TAD_locations.py --genome 'hg19' --TAD-Boundary 'hESC' + +Where flags for --TAD-Boundary are: "hESC", "IMR90", "mESC", or "cortex" +and the flags for --genome are: "hg19" or "mm9" + +Output: +1) SNP distribution and histogram across TADs +2) Gene distribution + A) Several matplotlib plots in the 'figures/' folder + B) Several gene location plots across TADs in 'figures/gene/' + C) Chisquare analysis results for gene start sites near boundaries +3) Repeat distribution + A) Several matplotlib plots in the 'figures/' folder + B) Several repeat location plots across TADs in 'figures/repeats/' +""" + +import argparse +import matplotlib.pyplot as plt + +import numpy as np +import pandas as pd +from scipy.stats import chisquare + +from tad_util.util import parse_TAD_name, parse_SNP_position, parse_gene_info +from tad_util.util import parse_repeat_info, ID_TAD_bins + +plt.figure.max_open_warning = 0 + +# Load Command Arguments +parser = argparse.ArgumentParser() +parser.add_argument('-g', '--genome', help='Can be either hg19 or mm9') +parser.add_argument('-t', '--TAD-Boundary', help='boundary cell type. The' + 'options can be "hESC", "IMR90", "mESC", or "cortex"') +args = parser.parse_args() + +#################################### +# Load Constants +#################################### +NUM_BINS = 50 +TAD_CELL = args.TAD_Boundary +GENOME = args.genome + +# Generate file names depending on input +if TAD_CELL in ['hESC', 'IMR90', 'mESC', 'cortex']: + if GENOME in ['hg19', 'mm9']: + # Files to load + INDEX_BASE = GENOME + '_' + TAD_CELL + '.p' + SNP_INDEX = 'index/SNP_index_' + INDEX_BASE + GENE_INDEX = 'index/GENE_index_' + INDEX_BASE + REPEAT_INDEX = 'index/REPEAT_index_' + INDEX_BASE + + # Consistent file name conventions + FIG_BASE = 'figures/' + GENOME + '/' + FIG_END = GENOME + '_' + TAD_CELL + '.png' + + # Files to save + TAD_SNP_CHI = 'results/TAD_SNP_rightness_Chisquare_' + \ + GENOME + '_' + TAD_CELL + '.txt' + SNP_DIST = FIG_BASE + 'SNPdist_' + FIG_END + SNP_CHROM = FIG_BASE + 'chrom/SNPdistribution_chrom_' + SNP_HIST = FIG_BASE + 'SNPcounts_' + FIG_END + GENE_TAD_BOUND = 'tables/genes_at_' + TAD_CELL + '_TAD_boundaries.tsv' + GENE_CHI = 'results/' + TAD_CELL + '_TADBoundary_Chisquare.txt' + GENE_LINE = FIG_BASE + 'gene/genelocation_' + GENE_CHROM = FIG_BASE + 'chrom/GeneDistribution_chrom_' + GENE_ALL_CHROM = FIG_BASE + 'chrom/GeneDist_chromo' + FIG_END + GENE_HIST = FIG_BASE + TAD_CELL + '_TAD_Gene_histogram.png' + TAD_LEN_HIST = FIG_BASE + TAD_CELL + '_TAD_length_histogram.png' + REP_TYPE = FIG_BASE + 'repeats/repeat_' + TAD_CELL + '_' + REP_CHROM = FIG_BASE + 'chrom/RepeatDist_chrom_' + REP_ALL_CHROM = FIG_BASE + 'chrom/RepeaDist_chrom_' + FIG_END + REP_HIST = FIG_BASE + TAD_CELL + '_TAD_Repeat_histogram.png' + else: + raise ValueError('Please input either "hg19" or "mm9"') + +else: + raise ValueError('Please input either "hESC", "IMR90", "mESC", or ' + '"cortex"') + +# Gene types described http://www.gencodegenes.org/gencode_biotypes.html +gene_types = ['protein_coding', 'pseudogene', 'miRNA', 'snRNA', 'snoRNA', + 'lincRNA', 'rRNA', 'all', 'misc_RNA', 'sense_intronic', + 'processed_transcript', 'sense_overlapping', 'IG_pseudogene', + 'TR_pseudogene', 'TR_gene', 'polymorphic_pseudogene', + 'antisense', 'IG_gene'] + +TR_genes = ['TR_V_gene', 'TR_J_gene', 'TR_D_gene', 'TR_C_gene'] +IG_genes = ['IG_V_gene', 'IG_C_gene', 'IG_C_gene', 'IG_J_gene', + 'IG_D_gene'] +TR_pseud = ['TR_V_pseudogene', 'TR_J_pseudogene'] +IG_pseud = ['IG_V_pseudogene', 'IG_C_pseudogene', 'IG_J_pseudogene'] + +if GENOME == 'mm9': + gene_types = gene_types + ['processed_pseudogene', 'TEC', + 'transcribed_processed_pseudogene', + 'unprocessed_pseudogene', 'scaRNA', + 'transcribed_unprocessed_pseudogene', + 'ribozyme', 'unitary_pseudogene', + '3prime_overlapping_ncRNA', + 'bidirectional_promoter_lncRNA', 'scRNA', + 'translated_unprocessed_pseudogene', + 'transcribed_unitary_pseudogene', 'sRNA', + 'IG_LV_gene', 'IG_D_pseudogene', 'macro_lncRNA'] +else: + # Gene types described http://www.gencodegenes.org/gencode_biotypes.html + gene_types = gene_types + ['3prime_overlapping_ncrna'] + +#################################### +# Load Data +#################################### +KG_TADs = pd.read_pickle(SNP_INDEX) +TADdictgenes = pd.read_pickle(GENE_INDEX) +TADdictrepeats = pd.read_pickle(REPEAT_INDEX) + +#################################### +# Set matplotlib defaults +#################################### +fig_size = 4, 3 +margin = 2.5 +plt.rcParams['figure.figsize'] = fig_size +x0, x1, y0, y1 = plt.axis() +fig, ax = plt.subplots() +#plt.axis((x0 + margin, x1 + margin, y0 + margin, y1 + margin)) +plt.tight_layout() + +#################################### +# PART 1 - SNPs #################### +#################################### + +#################################### +# Observe location of SNPs in TADs +#################################### +# Initialize a dictionary that will store location information for gene types +TADdict = range(NUM_BINS) +TADdict = dict.fromkeys(TADdict) +for key in TADdict.iterkeys(): + TADdict[key] = 0 + +# Initialize a chromosome specific dictionary holding bin specific info +Chromosome_Specific_TAD = dict.fromkeys(KG_TADs.keys()) +for chromkey in Chromosome_Specific_TAD.keys(): + # Create a list of zeros of len(NUM_BINS) + Chromosome_Specific_TAD[chromkey] = [0] * (NUM_BINS) + +# Also observe distribution of amount of SNPs in each TAD +howmanySNPsinTAD = [] + +# Loop through each TAD and SNP to fill the histogram +SNP_side = [0, 0] +for key in KG_TADs.iterkeys(): + print key + if key in ['NoTAD', 'Boundary', 'X', 'Y']: + continue + for tadkey, tadval in KG_TADs[key].iteritems(): + howmanySNPsinTAD.append(len(tadval)) + if len(tadval) > 0: + tadname = parse_TAD_name(tadkey) + for snp in range(len(tadval)): + snp_loc = parse_SNP_position(tadval.ix[snp, :]) + bin_assign = ID_TAD_bins(tadname, NUM_BINS, snp_loc) + TADdict[bin_assign] += 1 + + # Count the number of SNPs in left/right + if bin_assign < 25: + SNP_side[0] += 1 + else: + SNP_side[1] += 1 + + # Add a count for chromsome specificity + Chromosome_Specific_TAD[key][bin_assign] += 1 + +# Convert to DataFrame +SNPLocations = pd.DataFrame.from_dict(TADdict, orient='index') +SNPLoc_chrom = pd.DataFrame.from_dict(Chromosome_Specific_TAD, orient='index') +SNPLoc_chrom = SNPLoc_chrom.transpose() + +#################### +# Perform ChiSquare test of SNPs to 'right' of TAD +#################### +TAD_SNP_sig = chisquare(SNP_side) + +with open(TAD_SNP_CHI, 'w') as chisq_fh: + chisq_fh.write('SNPs in the left vs. right of ' + TAD_CELL + ' TAD\n') + chisq_fh.write('left,right\n') + chisq_fh.write(','.join('%s' % x for x in SNP_side) + '\n') + chisq_fh.write(','.join('%s' % x for x in TAD_SNP_sig)) + +#################################### +# Visualization +#################################### +# SNP Distribution +if GENOME == 'mm9': + fig_size = 4, 3 + margin = 10 + plt.rcParams['figure.figsize'] = fig_size + x0, x1, y0, y1 = plt.axis() + #plt.axis((x0 + margin, x1 + margin, y0 + margin, y1 + margin)) + font_size = 8 + plt.rcParams['font.size'] = font_size +else: + font_size = 10 + plt.rcParams['font.size'] = font_size + +ax = SNPLocations.plot(legend=False) +ax.spines["right"].set_visible(False) +ax.spines["top"].set_visible(False) +plt.xlabel('Bins (Normalized TAD length)') +plt.ylabel('Frequency') +plt.title('SNP location inside ' + TAD_CELL + ' TADs') +plt.grid(False) +plt.tick_params(axis='both', which='both', bottom='off', left='off', top='off', + right='off') +plt.savefig(SNP_DIST) +plt.close() + +##################################### +# Plot Chromosome Specific Line Graphs +##################################### +for chrom in Chromosome_Specific_TAD.keys(): + if chrom in ['NoTAD', 'Boundary', 'X', 'Y']: + continue + nameplot = SNP_CHROM + chrom + '_' + GENOME + '_' + TAD_CELL + '.png' + chrom_loc = SNPLoc_chrom[chrom] + chrom_loc.plot() + plt.xlabel('Bins (Normalized TAD length)') + plt.ylabel('Frequency') + plt.title('SNP location inside ' + TAD_CELL + ' TADs\nChromosome ' + + str(chrom)) + plt.grid(False) + plt.savefig(nameplot) + plt.close() + +# Histogram +if GENOME == 'mm9': + margin = 10 + x0, x1, y0, y1 = plt.axis() + #plt.axis((x0 + margin, x1 + margin, y0 + margin, y1 + margin)) + font_size = 8 + plt.rcParams['font.size'] = font_size +else: + plt.rcParams['font.size'] = 9 + +n, bins, patches = plt.hist(howmanySNPsinTAD, NUM_BINS, normed=1, + facecolor='green', alpha=0.75) +plt.xlabel('Number of SNPs') +plt.ylabel('Frequency') +plt.title('Distribution of number of SNPs in ' + TAD_CELL + ' TADs') +addtext = 'mean = ' + str(round(np.mean(howmanySNPsinTAD), 2)) + '\n' + \ + 'std = ' + str(round(np.std(howmanySNPsinTAD), 2)) +if GENOME == 'mm9': + plt.axis([min(howmanySNPsinTAD), max(howmanySNPsinTAD), 0, 0.0001]) + plt.text(max(howmanySNPsinTAD), .00004, addtext, verticalalignment='top', + horizontalalignment='right') +else: + plt.axis([min(howmanySNPsinTAD), max(howmanySNPsinTAD), 0, 0.0005]) + plt.text(max(howmanySNPsinTAD), .0003, addtext, verticalalignment='top', + horizontalalignment='right') +plt.grid(False) +plt.savefig(SNP_HIST) +plt.close() + +#################################### +# PART 2 - Genes ################### +#################################### +if GENOME == 'mm9': + fig_size = 4, 3 + margin = 2.5 + plt.rcParams['figure.figsize'] = fig_size + x0, x1, y0, y1 = plt.axis() + #plt.axis((x0 + margin, x1 + margin, y0 + margin, y1 + margin)) + +#################################### +# Observe location of genes in TADs +#################################### +# Initialize a dictionary that will store location information for gene types +TADgenepos = dict.fromkeys(gene_types) +for genekey in gene_types: + # Create a list of zeros of len(NUM_BINS) + TADgenepos[genekey] = [0] * (NUM_BINS) + +# Initialize a chromosome specific dictionary holding bin specific info +Chromosome_Specific_TAD = dict.fromkeys(TADdictgenes.keys()) +for chromkey in Chromosome_Specific_TAD.keys(): + if chromkey in ['Boundary']: + continue + # Create a list of zeros of len(NUM_BINS) + Chromosome_Specific_TAD[chromkey] = [0] * (NUM_BINS) + +# Determine significance of 'leftness' of TADs +TAD_near_boundary = [0, 0] +TAD_nb_protein = [0, 0] +TAD_nb_rRNA = [0, 0] +left_bin = NUM_BINS / 2 + +# Also, we're interested in the genes near TAD boundaries +gene_TAD_boundary = [] +# Obtain the gene position information +for key, value in TADdictgenes.iteritems(): + if key in ['Y', 'Boundary']: + continue + for tadkey, tadval in TADdictgenes[key].iteritems(): + tadkey = parse_TAD_name(tadkey) + for gene in range(len(tadval)): + # gene_info stores [gene_type, chromosome, start_pos] + gene_info = parse_gene_info(tadval.ix[gene, :]) + gene_name = tadval.ix[gene, :]['gene'] + + binID = ID_TAD_bins(tadkey, NUM_BINS, gene_info[2], + IDtype='gene') + if binID == -1: + continue + + # Add the bin number to the appropriate dictionary + gene_type = gene_info[0] + if gene_type in TR_genes: + TADgenepos['TR_gene'][binID] += 1 + elif gene_type in IG_genes: + TADgenepos['IG_gene'][binID] += 1 + elif gene_type in TR_pseud: + TADgenepos['TR_pseudogene'][binID] += 1 + elif gene_type in IG_pseud: + TADgenepos['IG_pseudogene'][binID] += 1 + else: + TADgenepos[gene_type][binID] += 1 + + # Add the bin number of all genes + TADgenepos['all'][binID] += 1 + + # Determine which half of bin gene belongs in and store + if binID in [0, 1, 48, 49]: + if GENOME == 'hg19': + if gene_type == 'protein_coding': + TAD_nb_protein[0] += 1 + elif gene_type == 'rRNA': + TAD_nb_rRNA[0] += 1 + TAD_near_boundary[0] += 1 + gene_TAD_boundary.append([gene_name, binID]) + + else: + if GENOME == 'hg19': + if gene_type == 'protein_coding': + TAD_nb_protein[1] += 1 + elif gene_type == 'rRNA': + TAD_nb_rRNA[1] += 1 + TAD_near_boundary[1] += 1 + + # Add a count for chromsome specificity + Chromosome_Specific_TAD[key][binID] += 1 + +# Convert to pandas dataframe +geneLocations = pd.DataFrame(TADgenepos) +chromLocations = pd.DataFrame(Chromosome_Specific_TAD) +gene_TAD_boundary = pd.DataFrame(gene_TAD_boundary, columns=['gene', 'bin']) + +# Write gene TAD boundary to csv +gene_TAD_boundary.to_csv(GENE_TAD_BOUND, sep='\t') + +#################### +# Perform ChiSquare test of TAD near boundary +#################### +# Expected values for each bin +ex_all = sum(TAD_near_boundary) / NUM_BINS +TAD_nb_sig = chisquare(TAD_near_boundary, f_exp=[ex_all * 4, ex_all * 46]) +if GENOME == 'hg19': + ex_pro = sum(TAD_nb_protein) / NUM_BINS + ex_rRNA = sum(TAD_nb_rRNA) / NUM_BINS + TAD_nb_sig_pro = chisquare(TAD_nb_protein, f_exp=[ex_pro * 4, ex_pro * 46]) + TAD_nb_sig_rRNA = chisquare(TAD_nb_rRNA, f_exp=[ex_rRNA * 4, ex_rRNA * 46]) + +with open(GENE_CHI, 'w') as chisq_fh: + chisq_fh.write(TAD_CELL + ' near boundaries of all genes\n') + chisq_fh.write(','.join('%s' % x for x in TAD_near_boundary) + '\n') + chisq_fh.write(','.join('%s' % x for x in TAD_nb_sig) + '\n') + if GENOME == 'hg19': + chisq_fh.write(TAD_CELL + ' near boundaries of protein coding genes\n') + chisq_fh.write(','.join('%s' % x for x in TAD_nb_protein) + '\n') + chisq_fh.write(','.join('%s' % x for x in TAD_nb_sig_pro) + '\n') + chisq_fh.write(TAD_CELL + ' near boundaries of rRNA genes\n') + chisq_fh.write(','.join('%s' % x for x in TAD_nb_rRNA) + '\n') + chisq_fh.write(','.join('%s' % x for x in TAD_nb_sig_rRNA) + '\n') + +##################################### +# Plot line graphs for each gene type +##################################### +font_size = 12 +plt.rcParams['font.size'] = font_size +for g in gene_types: + nameplot = GENE_LINE + g + '_' + TAD_CELL + '.png' + g_loc = geneLocations[g] + fig, ax = plt.subplots(1) + g_loc.plot() + plt.xlabel('Bins (Normalized TAD length)') + plt.ylabel('Frequency') + plt.title('Gene Location across ' + TAD_CELL + ' TADs\n' + g) + plt.grid(False) + ax.spines['right'].set_visible(False) + ax.spines['top'].set_visible(False) + ax.xaxis.set_ticks_position('none') + ax.yaxis.set_ticks_position('none') + plt.savefig(nameplot) + plt.close() + +##################################### +# Plot Chromosome Specific Line Graphs +##################################### +# Separate Graphs +for chrom in Chromosome_Specific_TAD.keys(): + if chrom in ['Boundary', 'Y']: + continue + nameplot = GENE_CHROM + chrom + '_' + TAD_CELL + '.png' + chrom_loc = chromLocations[chrom] + fig, ax = plt.subplots(1) + chrom_loc.plot() + plt.xlabel('Bins (Normalized TAD length)') + plt.ylabel('Frequency') + plt.title('Gene location (Start Site) across ' + TAD_CELL + + ' TADs\nChromosome ' + str(chrom)) + plt.grid(False) + ax.spines['right'].set_visible(False) + ax.spines['top'].set_visible(False) + ax.xaxis.set_ticks_position('none') + ax.yaxis.set_ticks_position('none') + plt.savefig(nameplot) + plt.close() + +# Combined Graph +fig, ax = plt.subplots(1) +plt.xlabel('Bins (Normalized TAD length)') +plt.ylabel('Frequency') +plt.title('Gene location (Start Site) across TADs\nby Chromosome') +plt.grid(False) +ax.spines['right'].set_visible(False) +ax.spines['top'].set_visible(False) +ax.xaxis.set_ticks_position('none') +ax.yaxis.set_ticks_position('none') + +for chrom in Chromosome_Specific_TAD.keys(): + if chrom in ['Boundary']: + continue + chrom_loc = chromLocations[chrom] + chrom_loc.plot() + +plt.savefig(GENE_ALL_CHROM) +plt.close() + +#################################### +# Obtain the number of genes in each TAD +#################################### +howmanygenesinTAD = [] +TADlength = [] +for key, value in TADdictgenes.iteritems(): + if key in ['Y', 'Boundary']: + continue + for tadkey, tadval in TADdictgenes[key].iteritems(): + howmanygenesinTAD.append(len(tadval)) + tadname = parse_TAD_name(tadkey) + TADlength.append((tadname[2] - tadname[1])/1000) + +#################################### +# Output Histograms +#################################### +# Plot number of genes in tads +font_size = 9 +plt.rcParams['font.size'] = font_size +n, bins, patches = plt.hist(howmanygenesinTAD, NUM_BINS, normed=1, + facecolor='green', alpha=0.75) +plt.xlabel('Number of genes') +plt.ylabel('Frequency') +plt.title('Distribution of number of genes in ' + TAD_CELL + ' TADs') +plt.axis([min(howmanygenesinTAD), max(howmanygenesinTAD), 0, 0.06]) +plt.grid(False) +addtext = 'mean = ' + str(round(np.mean(howmanygenesinTAD), 2)) + '\n' + \ + 'std = ' + str(round(np.std(howmanygenesinTAD), 2)) +plt.text(130, .055, addtext, verticalalignment='top', + horizontalalignment='right') +plt.savefig(GENE_HIST) +plt.close() + +# Plot how long TADs are +n, bins, patches = plt.hist(TADlength, NUM_BINS * 2, normed=1, + facecolor='green', alpha=0.75) +plt.xlabel('TAD length (kb)') +plt.ylabel('Frequency') +plt.title('How long are ' + TAD_CELL + ' TADs?') +addtext = 'mean = ' + str(round(np.mean(TADlength), 2)) + '\n' + 'std = ' + \ + str(round(np.std(TADlength), 2)) +if TAD_CELL == 'hESC': + plt.axis([min(TADlength), max(TADlength), 0, 0.0023]) + plt.text(4000, .0021, addtext, verticalalignment='top', + horizontalalignment='right') +else: + plt.axis([min(TADlength), max(TADlength), 0, 0.0015]) + plt.text(4000, .0011, addtext, verticalalignment='top', + horizontalalignment='right') +plt.grid(False) +plt.savefig(TAD_LEN_HIST) +plt.close() + +#################################### +# PART 3 - Repeats ################# +#################################### + +#################################### +# Process repeat picklefile +#################################### +all_repeat_types = [] +for key in TADdictrepeats.keys(): + if key in ['Y', 'Boundary']: + continue + for tadkey in TADdictrepeats[key].keys(): + repeat_elements = TADdictrepeats[key][tadkey] + repeat_elements = repeat_elements['repeat'].tolist() + all_repeat_types = all_repeat_types + repeat_elements + +all_repeat_types = set(all_repeat_types) +repeat_types = [] +for repeat in all_repeat_types: + if '?' not in repeat: + repeat_types.append(repeat) + +repeat_types.append('all') + +#################################### +# Observe location of repeats in TADs +#################################### +# Initialize a dictionary that will store location information for repeats +TADrepeatpos = dict.fromkeys(repeat_types) +for repeatkey in repeat_types: + # Create a list of zeros of len(NUM_BINS) + TADrepeatpos[repeatkey] = [0] * (NUM_BINS) + +# Initialize a chromosome specific dictionary holding bin specific info +Chromosome_Specific_TAD = dict.fromkeys(TADdictrepeats.keys()) +for chromkey in Chromosome_Specific_TAD.keys(): + if chromkey not in ['Boundary']: + # Create a list of zeros of len(NUM_BINS) + Chromosome_Specific_TAD[chromkey] = [0] * (NUM_BINS) + +# Obtain the repeat position information +for key, value in TADdictrepeats.iteritems(): + if key in ['Y', 'Boundary']: + continue + for tadkey, tadval in TADdictrepeats[key].iteritems(): + tadkey = parse_TAD_name(tadkey) + for repeat in range(len(tadval)): + # repeat_info stores [gene_type, chromosome, start_pos, divergence] + repeat_info = parse_repeat_info(tadval.ix[repeat, :]) + repeat_name = repeat_info[0] + + if '?' not in repeat_name: + binID = ID_TAD_bins(tadkey, NUM_BINS, repeat_info[2], + IDtype='gene') + if binID == -1: + continue + + # if the start is exactly on a TAD boundary, put it in the + # previous bin + if binID == 50: + binID = 49 + + # Add to bin of specific repeat + TADrepeatpos[repeat_name][binID] += 1 + + # Add the bin number of all repeats + TADrepeatpos['all'][binID] += 1 + + # Add a count for chromsome specificity + Chromosome_Specific_TAD[key][binID] += 1 + +# Convert to pandas dataframe +repeatLocations = pd.DataFrame(TADrepeatpos) +chromLocations = pd.DataFrame(Chromosome_Specific_TAD) + +#################################### +# Obtain the number of Repeats in each TAD +#################################### +howmanyrepeatsinTAD = [] +tad_names = [] +for key, value in TADdictrepeats.iteritems(): + if key not in ['Y', 'Boundary']: + for tadkey, tadval in TADdictrepeats[key].iteritems(): + howmanyrepeatsinTAD.append(len(tadval)) + tad_names.append(tadkey) + +howmanyrepeatsinTAD = np.array(howmanyrepeatsinTAD) + +#################################### +# Output Histograms +#################################### +# Plot number of genes in tads +n, bins, patches = plt.hist(howmanyrepeatsinTAD, NUM_BINS, normed=1, + facecolor='green', alpha=0.75) +plt.xlabel('Number of Repeat Elements') +plt.ylabel('Frequency') +plt.title('Distribution of number of Repeat Elements in ' + TAD_CELL + ' TADs') +plt.axis([min(howmanyrepeatsinTAD), max(howmanyrepeatsinTAD), 0, 0.0008]) +plt.grid(False) +addtext = 'mean = ' + str(round(np.mean(howmanyrepeatsinTAD), 2)) + '\n' + \ + 'std = ' + str(round(np.std(howmanyrepeatsinTAD), 2)) +plt.text(5000, .00055, addtext, verticalalignment='top', + horizontalalignment='right') +plt.savefig(REP_HIST) +plt.close() + +##################################### +# Plot line graphs for each gene type +##################################### +font_size = 10 +plt.rcParams['font.size'] = font_size +for r in repeat_types: + fn = r.replace('/', '_') + nameplot = REP_TYPE + fn + '.png' + g_loc = repeatLocations[r] + fig, ax = plt.subplots(1) + g_loc.plot() + plt.xlabel('Bins (Normalized TAD length)') + plt.ylabel('Frequency') + plt.title('Repeat Location across ' + TAD_CELL + ' TADs\n' + r) + plt.grid(False) + ax.spines['right'].set_visible(False) + ax.spines['top'].set_visible(False) + ax.xaxis.set_ticks_position('none') + ax.yaxis.set_ticks_position('none') + plt.savefig(nameplot) + plt.close() + +##################################### +# Plot Chromosome Specific Line Graphs +##################################### +# Separate Graphs +for chrom in Chromosome_Specific_TAD.keys(): + if chrom in ['Y', 'Boundary']: + continue + nameplot = REP_CHROM + chrom + '_' + TAD_CELL + '.png' + chrom_loc = chromLocations[chrom] + fig, ax = plt.subplots(1) + chrom_loc.plot() + plt.xlabel('Bins (Normalized TAD length)') + plt.ylabel('Frequency') + plt.title('Repeat location across ' + TAD_CELL + 'TADs\nChromosome ' + + str(chrom)) + plt.grid(False) + ax.spines['right'].set_visible(False) + ax.spines['top'].set_visible(False) + ax.xaxis.set_ticks_position('none') + ax.yaxis.set_ticks_position('none') + plt.savefig(nameplot) + plt.close() + +# Combined Graph +fig, ax = plt.subplots(1) +plt.xlabel('Bins (Normalized TAD length)') +plt.ylabel('Frequency') +plt.title('Repeat location across ' + TAD_CELL + ' TADs\nby Chromosome') +plt.grid(False) +ax.spines['right'].set_visible(False) +ax.spines['top'].set_visible(False) +ax.xaxis.set_ticks_position('none') +ax.yaxis.set_ticks_position('none') + +for chrom in Chromosome_Specific_TAD.keys(): + if chrom not in ['Y', 'Boundary']: + chrom_loc = chromLocations[chrom] + chrom_loc.plot() + +plt.savefig(REP_ALL_CHROM) +plt.close() From 6003eba08183bd34959b74a3c52eef9e65a54854 Mon Sep 17 00:00:00 2001 From: Wei Cheng <36087657+Colin-Cheng@users.noreply.github.com> Date: Fri, 6 Jul 2018 15:14:24 -0400 Subject: [PATCH 05/46] add the TAD_boundary argument --- scripts/build_custom_tad_genelist.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/scripts/build_custom_tad_genelist.py b/scripts/build_custom_tad_genelist.py index eff051c..de65c53 100644 --- a/scripts/build_custom_tad_genelist.py +++ b/scripts/build_custom_tad_genelist.py @@ -16,6 +16,7 @@ --snp_data_file The file name of where SNP data is stored. SNP data is generated by `scripts/build_snp_list.R` --output_file The name of the results file to build + --TAD_Boundary The name of tad cell to use Output: Trait specific .tsv files of one column each indicating all the genes that fall @@ -30,6 +31,7 @@ parser = argparse.ArgumentParser() parser.add_argument("-s", "--snp_data_file", help="Location of SNP data") parser.add_argument("-o", "--output_file", help="Name of the output file") +parser.add_argument("-t", "--TAD_Boundary", help="Name of the tad cell") args = parser.parse_args() @@ -63,8 +65,8 @@ def assign_custom_snp_to_tad(snp_signal, tad_boundary): os.path.splitext(output_file)[0]) # Load data -tad_genes_df = pd.read_table(os.path.join('data', - 'GENE_index_hg19_hESC.tsv.bz2'), +index_file = "GENE_index_hg19_" + tad_cell + ".tsv.bz2" +tad_genes_df = pd.read_table(os.path.join('data',index_file), index_col=0) # The SNP DataFrame has the columns [RSid, database source, chromosome, # genomic position, minor allele, and group] From ad0eeecae105ab3de7c49ad341f96b51f1803bde Mon Sep 17 00:00:00 2001 From: Wei Cheng <36087657+Colin-Cheng@users.noreply.github.com> Date: Fri, 6 Jul 2018 15:20:28 -0400 Subject: [PATCH 06/46] Update build_custom_tad_genelist.py --- scripts/build_custom_tad_genelist.py | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/build_custom_tad_genelist.py b/scripts/build_custom_tad_genelist.py index de65c53..9d3c1bb 100644 --- a/scripts/build_custom_tad_genelist.py +++ b/scripts/build_custom_tad_genelist.py @@ -61,6 +61,7 @@ def assign_custom_snp_to_tad(snp_signal, tad_boundary): # Load Constants snp_data_file = args.snp_data_file output_file = args.output_file +tad_cell = args.TAD_Boundary output_nearest_gene_file = '{}_nearest_gene.tsv'.format( os.path.splitext(output_file)[0]) From 38caa541211d3a7f64f87d578f58d67a06bdbf99 Mon Sep 17 00:00:00 2001 From: Wei Cheng <36087657+Colin-Cheng@users.noreply.github.com> Date: Tue, 10 Jul 2018 21:24:41 -0400 Subject: [PATCH 07/46] Update build_custom_tad_genelist.py --- scripts/build_custom_tad_genelist.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/build_custom_tad_genelist.py b/scripts/build_custom_tad_genelist.py index 9d3c1bb..65ddedd 100644 --- a/scripts/build_custom_tad_genelist.py +++ b/scripts/build_custom_tad_genelist.py @@ -67,7 +67,7 @@ def assign_custom_snp_to_tad(snp_signal, tad_boundary): # Load data index_file = "GENE_index_hg19_" + tad_cell + ".tsv.bz2" -tad_genes_df = pd.read_table(os.path.join('data',index_file), +tad_genes_df = pd.read_table(os.path.join('index',index_file), index_col=0) # The SNP DataFrame has the columns [RSid, database source, chromosome, # genomic position, minor allele, and group] From 19c6d5fa92748cc3de9f867f393ce1b1d546cfc7 Mon Sep 17 00:00:00 2001 From: Wei Cheng <36087657+Colin-Cheng@users.noreply.github.com> Date: Thu, 12 Jul 2018 18:43:53 -0400 Subject: [PATCH 08/46] update data directory --- initialize.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/initialize.sh b/initialize.sh index 69addf3..9ffa554 100644 --- a/initialize.sh +++ b/initialize.sh @@ -4,7 +4,7 @@ set -o errexit # Download necessary index and curation files -url=https://zenodo.org/record/232520/files/tad_pathways_data.tar.gz +url=https://zenodo.org/record/1311211/files/tad_pathways_data.tar.gz wget $url # Extract data From 9dc1f0272f6f618e596f71de11e22af689609aba Mon Sep 17 00:00:00 2001 From: Wei Cheng <36087657+Colin-Cheng@users.noreply.github.com> Date: Thu, 12 Jul 2018 19:04:15 -0400 Subject: [PATCH 09/46] add tables directory --- tables/gene_classification.tsv | 46 ++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 tables/gene_classification.tsv diff --git a/tables/gene_classification.tsv b/tables/gene_classification.tsv new file mode 100644 index 0000000..402b835 --- /dev/null +++ b/tables/gene_classification.tsv @@ -0,0 +1,46 @@ +gene_type gene_class hg19 mm9 +protein_coding std 1 1 +pseudogene std 1 1 +miRNA std 1 1 +snRNA std 1 1 +snoRNA std 1 1 +lincRNA std 1 1 +rRNA std 1 1 +misc_RNA std 1 1 +sense_intronic std 1 1 +processed_transcript std 1 1 +sense_overlapping std 1 1 +IG_pseudogene std 0 1 +polymorphic_pseudogene std 1 1 +antisense std 1 1 +all std 1 1 +TR_V_gene tr_gene 1 1 +TR_J_gene tr_gene 1 1 +TR_D_gene tr_gene 1 1 +TR_C_gene tr_gene 1 1 +IG_V_gene ig_gene 1 1 +IG_C_gene ig_gene 1 1 +IG_J_gene ig_gene 1 1 +IG_D_gene ig_gene 1 1 +TR_V_pseudogene tr_pseud 1 1 +TR_J_pseudogene tr_pseud 1 1 +IG_V_pseudogene ig_pseud 1 1 +IG_C_pseudogene ig_pseud 1 1 +IG_J_pseudogene ig_pseud 1 0 +processed_pseudogene std 0 1 +TEC std 0 1 +transcribed_processed_pseudogene std 0 1 +unprocessed_pseudogene std 0 1 +scaRNA std 0 1 +transcribed_unprocessed_pseudogene std 0 1 +ribozyme std 0 1 +unitary_pseudogene std 0 1 +3prime_overlapping_ncRNA std 0 1 +bidirectional_promoter_lncRNA std 0 1 +scRNA std 0 1 +translated_unprocessed_pseudogene std 0 1 +transcribed_unitary_pseudogene std 0 1 +sRNA std 0 1 +IG_LV_gene std 0 1 +IG_D_pseudogene std 0 1 +3prime_overlapping_ncrna std 1 0 From 74b04767db1e0fe6224b144b8ad3172b078db85b Mon Sep 17 00:00:00 2001 From: Wei Cheng <36087657+Colin-Cheng@users.noreply.github.com> Date: Thu, 12 Jul 2018 19:14:31 -0400 Subject: [PATCH 10/46] Delete example_pipeline_bmd.sh --- example_pipeline_bmd.sh | 31 ------------------------------- 1 file changed, 31 deletions(-) delete mode 100644 example_pipeline_bmd.sh diff --git a/example_pipeline_bmd.sh b/example_pipeline_bmd.sh deleted file mode 100644 index e726e96..0000000 --- a/example_pipeline_bmd.sh +++ /dev/null @@ -1,31 +0,0 @@ -#!/bin/bash - -# Example of a TAD_Pathways Analysis applied to Bone Mineral Density GWAS -set -o errexit - -gwas_file='data/gwas_catalog/Bone_mineral_density_hg19.tsv' -snp_file='data/gwas_tad_snps/Bone_mineral_density_hg19_SNPs.tsv' -tad_file='data/gwas_tad_genes/Bone_mineral_density_hg19_SNPs_TAD_genelists.tsv' -trait='bmd' -evidence_file='results/bmd_gene_evidence.csv' - -# Perform WebGestalt pathway analysis and parse results -Rscript --vanilla scripts/webgestalt_run.R \ - --tad_genelist_file $tad_file \ - --output_name $trait - -# Construct an evidence file - Nearest gene to gwas or not -python scripts/construct_evidence.py \ - --trait $trait \ - --gwas $gwas_file \ - --pathway 'skeletal system development' - -# Summarize the evidence file -python scripts/summarize_evidence.py \ - --evidence $evidence_file \ - --snps $snp_file \ - --output_file 'results/BMD_gene_evidence_summary.tsv' - -# Visualize overlap in TAD pathways curation -R --no-save --args $evidence_file \ - < scripts/integrative_summary.R From 4c2fa018fa82685c2bf138fab3c273de204cd577 Mon Sep 17 00:00:00 2001 From: Wei Cheng <36087657+Colin-Cheng@users.noreply.github.com> Date: Thu, 12 Jul 2018 19:14:42 -0400 Subject: [PATCH 11/46] Delete example_pipeline_t2d.sh --- example_pipeline_t2d.sh | 33 --------------------------------- 1 file changed, 33 deletions(-) delete mode 100644 example_pipeline_t2d.sh diff --git a/example_pipeline_t2d.sh b/example_pipeline_t2d.sh deleted file mode 100644 index ea53dc5..0000000 --- a/example_pipeline_t2d.sh +++ /dev/null @@ -1,33 +0,0 @@ -#!/bin/bash - -# Example of a TAD_Pathways Analysis applied to Type 2 Diabetes GWAS -set -o errexit - -gwas_file='data/gwas_catalog/Type_2_diabetes_hg19.tsv' -snp_file='data/gwas_tad_snps/Type_2_diabetes_hg19_SNPs.tsv' -tad_file='data/gwas_tad_genes/Type_2_diabetes_hg19_SNPs_TAD_genelists.tsv' -trait='t2d' -evidence_file='results/t2d_gene_evidence.csv' -pathway_p_values_file='gestalt/t2d_pvals.tsv' - -# Perform WebGestalt pathway analysis and parse results -Rscript --vanilla scripts/webgestalt_run.R \ - --tad_genelist_file $tad_file \ - --output_name $trait - -# Construct an evidence file -# In this case, select all significant pathways, no preselection required -python scripts/construct_evidence.py \ - --trait $trait \ - --gwas $gwas_file \ - --pathway $pathway_p_values_file - -# Summarize the evidence file -python scripts/summarize_evidence.py \ - --evidence $evidence_file \ - --snps $snp_file \ - --output_file 'results/t2d_gene_evidence_summary.tsv' - -# Visualize overlap in TAD pathways curation -R --no-save --args $evidence_file \ - < scripts/integrative_summary.R From 3e536d200f7a94302bbf7f96ce1517f0f8ca04cd Mon Sep 17 00:00:00 2001 From: Wei Cheng <36087657+Colin-Cheng@users.noreply.github.com> Date: Thu, 12 Jul 2018 19:15:02 -0400 Subject: [PATCH 12/46] Delete bmd_gene_evidence.csv --- results/bmd_gene_evidence.csv | 129 ---------------------------------- 1 file changed, 129 deletions(-) delete mode 100644 results/bmd_gene_evidence.csv diff --git a/results/bmd_gene_evidence.csv b/results/bmd_gene_evidence.csv deleted file mode 100644 index 4378e69..0000000 --- a/results/bmd_gene_evidence.csv +++ /dev/null @@ -1,129 +0,0 @@ -gene,evidence -JAG1,gwas -FAM210A,gwas -EN1,gwas_tad -LOC102724957,gwas -FOXL1,gwas -HOXC4,gwas_tad -KIAA2018,gwas -HOXC11,tad -LINC01152,gwas -SOX9,tad -TIPARP,tad -HIGD1AP18,gwas -KLHL42,gwas -RPS3AP2,gwas -LINC00581,gwas -SOX4,tad -PKDCC,gwas_tad -XKR9,gwas -RPS27P4,gwas -PDXDC1,gwas -PRKRIRP3,gwas -TNFSF11,gwas_tad -MPP7,gwas -ZNF385A,tad -IDUA,gwas -MALAT1,gwas -HSP90AB3P,gwas -LINC00942,gwas -STARD3NL,gwas -RERE,gwas -CSRNP3,gwas -ANAPC1,gwas -HOXC9,tad -RUNX2,tad -MIR4418,gwas -RARG,tad -HOXC10,tad -WFIKKN1,tad -CPED1,gwas -SULF1,tad -INSIG2,gwas_tad -NOV,tad -WHSC1L2P,gwas -SOX6,tad -DEAF1,tad -DNM3,gwas -IFT140,tad -BET1L,gwas -WLS,gwas -DCDC5,gwas -DSPP,tad -SMG6,gwas -MAPT,gwas -MBL2,gwas -PTHLH,gwas_tad -CCDC170,gwas -ARHGAP1,gwas -RNA5SP426,gwas -HOXC6,gwas_tad -CASC17,gwas -RHEBL1,gwas -DHH,gwas -LRP5,gwas_tad -RUNX1,tad -DLX5,tad -SOD1P2,gwas -C17orf53,gwas -DLX6,tad -WNT16,gwas -MEPE,gwas_tad -AXIN1,gwas_tad -RBBP6P1,gwas -RPL39P30,gwas -ACP2,tad -CPN1,gwas -ABCF2,gwas -C2orf91,gwas -SUPT3H,gwas -FUBP3,gwas -LOC102724063,gwas -RPL36AP25,gwas -LOC102724072,gwas -SOST,gwas -MRPS31P1,gwas -RPS6KA5,gwas -FBXL14,gwas -MARK3,gwas -RPL34P8,gwas -LOC100133286,gwas -IFITM5,tad -C7orf76,gwas -RSPO3,gwas -ZNF408,gwas -CTNNB1,tad -RSPH14,gwas -FABP3P2,gwas -EPDR1,gwas -RPS4XP9,gwas -RPS26P35,gwas -COL11A1,gwas_tad -ZBTB40,gwas -MIR3660,gwas -SP7,gwas -COLEC10,gwas -NME8,gwas -TNFRSF11B,gwas_tad -RNA5SP321,gwas -FOXC2,tad -FGFRL1,tad -SFRP4,tad -GALNT3,gwas -TMEM263,gwas -MEF2C,tad -MEF2C-AS1,gwas -MIR4642,gwas -GPATCH1,gwas -PKIA,gwas -LEKR1,gwas -HOXC5,gwas -GNG12-AS1,gwas -HOXC8,tad -MKKS,tad -TNFRSF11A,gwas -PTX4,gwas -RPL37AP7,gwas -WNT5B,tad -GRB10,gwas -MIR612,gwas From c76577b976b6c581f1ef43aa7cb8204330205beb Mon Sep 17 00:00:00 2001 From: Wei Cheng <36087657+Colin-Cheng@users.noreply.github.com> Date: Thu, 12 Jul 2018 19:15:15 -0400 Subject: [PATCH 13/46] Delete bmd_gene_evidence_summary.tsv --- results/bmd_gene_evidence_summary.tsv | 99 --------------------------- 1 file changed, 99 deletions(-) delete mode 100644 results/bmd_gene_evidence_summary.tsv diff --git a/results/bmd_gene_evidence_summary.tsv b/results/bmd_gene_evidence_summary.tsv deleted file mode 100644 index 037a75a..0000000 --- a/results/bmd_gene_evidence_summary.tsv +++ /dev/null @@ -1,99 +0,0 @@ -gene evidence TAD ID chromosome TAD Start TAD End UCSC -MPP7 gwas 1819 chr10 27639994 28719994 chr10:27639994-28719994 -FUBP3 gwas 1779 chr9 133290179 133570179 chr9:133290179-133570179 -SOST gwas 2601 chr17 41404474 41844474 chr17:41404474-41844474 -WLS gwas 119 chr1 68547412 68907412 chr1:68547412-68907412 -GNG12-AS1 gwas 119 chr1 68547412 68907412 chr1:68547412-68907412 -FOXC2 tad 2561 chr16 86562499 87362499 chr16:86562499-87362499 -FOXL1 gwas_tad 2561 chr16 86562499 87362499 chr16:86562499-87362499 -GPATCH1 gwas 2754 chr19 33068160 33708160 chr19:33068160-33708160 -RERE gwas 10 chr1 7997413 8517413 chr1:7997413-8517413 -DNM3 gwas 236 chr1 171973377 172413377 chr1:171973377-172413377 -CCDC170 gwas 1313 chr6 151718307 153038307 chr6:151718307-153038307 -RPS3AP2 gwas 2470 chr16 1139999 2099999 chr16:1139999-2099999 -PTX4 gwas 2470 chr16 1139999 2099999 chr16:1139999-2099999 -FBXL14 gwas 2076 chr12 145739 1729739 chr12:145739-1729739 -LINC00942 gwas 2076 chr12 145739 1729739 chr12:145739-1729739 -WNT5B tad 2076 chr12 145739 1729739 chr12:145739-1729739 -DSPP tad 873 chr4 88180976 88940976 chr4:88180976-88940976 -MEPE gwas_tad 873 chr4 88180976 88940976 chr4:88180976-88940976 -HSP90AB3P gwas 873 chr4 88180976 88940976 chr4:88180976-88940976 -RUNX2 tad 1214 chr6 44372022 45932041 chr6:44372022-45932041 -MIR4642 gwas 1214 chr6 44372022 45932041 chr6:44372022-45932041 -SUPT3H gwas 1214 chr6 44372022 45932041 chr6:44372022-45932041 -CASC17 gwas 2626 chr17 68648405 70528405 chr17:68648405-70528405 -SOX9 tad 2626 chr17 68648405 70528405 chr17:68648405-70528405 -MIR3660 gwas 1065 chr5 88004244 90124244 chr5:88004244-90124244 -MEF2C tad 1065 chr5 88004244 90124244 chr5:88004244-90124244 -MEF2C-AS1 gwas 1065 chr5 88004244 90124244 chr5:88004244-90124244 -LTBP3 tad 1988 chr11 64603424 65363424 chr11:64603424-65363424 -MALAT1 gwas 1988 chr11 64603424 65363424 chr11:64603424-65363424 -CPN1 gwas 1884 chr10 101490010 102290010 chr10:101490010-102290010 -SULF1 tad 1557 chr8 70557446 71597446 chr8:70557446-71597446 -XKR9 gwas 1557 chr8 70557446 71597446 chr8:70557446-71597446 -TIPARP tad 751 chr3 156277306 156877306 chr3:156277306-156877306 -LEKR1 gwas 751 chr3 156277306 156877306 chr3:156277306-156877306 -COLEC10 gwas 1606 chr8 119730819 120450819 chr8:119730819-120450819 -RPS26P35 gwas 1606 chr8 119730819 120450819 chr8:119730819-120450819 -TNFRSF11B gwas_tad 1606 chr8 119730819 120450819 chr8:119730819-120450819 -RNA5SP426 gwas 2518 chr16 50842499 52042499 chr16:50842499-52042499 -SOD1P2 gwas 2518 chr16 50842499 52042499 chr16:50842499-52042499 -HIGD1AP18 gwas 1564 chr8 77277445 79357445 chr8:77277445-79357445 -RSPO3 gwas 1282 chr6 126318307 127518307 chr6:126318307-127518307 -RPS4XP9 gwas 1282 chr6 126318307 127518307 chr6:126318307-127518307 -MARK3 gwas 2380 chr14 103530247 104010247 chr14:103530247-104010247 -GALNT3 gwas 500 chr2 165571754 166811754 chr2:165571754-166811754 -CSRNP3 gwas 500 chr2 165571754 166811754 chr2:165571754-166811754 -TNFRSF11A gwas 2702 chr18 59849020 60649020 chr18:59849020-60649020 -PDXDC1 gwas 2486 chr16 15012499 15172499 chr16:15012499-15172499 -RNA5SP321 gwas 1862 chr10 78889994 79769994 chr10:78889994-79769994 -MAPT gwas 2604 chr17 43684217 44404237 chr17:43684217-44404237 -CTNNB1 tad 628 chr3 40344996 42264996 chr3:40344996-42264996 -ABCF2 gwas 1485 chr7 149489067 150929067 chr7:149489067-150929067 -COL11A1 gwas_tad 164 chr1 102947412 103787412 chr1:102947412-103787412 -AXIN1 gwas_tad 2468 chr16 60000 739999 chr16:60000-739999 -WNT16 gwas 1457 chr7 120772764 121692764 chr7:120772764-121692764 -CPED1 gwas 1457 chr7 120772764 121692764 chr7:120772764-121692764 -FAM210A gwas 2656 chr18 13010000 13810000 chr18:13010000-13810000 -BET1L gwas 1916 chr11 170000 850000 chr11:170000-850000 -DEAF1 tad 1916 chr11 170000 850000 chr11:170000-850000 -C7orf76 gwas 1430 chr7 95362064 96682064 chr7:95362064-96682064 -DLX6 tad 1430 chr7 95362064 96682064 chr7:95362064-96682064 -DLX5 tad 1430 chr7 95362064 96682064 chr7:95362064-96682064 -HOXC9 tad 2134 chr12 54073733 54793733 chr12:54073733-54793733 -HOXC4 gwas_tad 2134 chr12 54073733 54793733 chr12:54073733-54793733 -HOXC11 tad 2134 chr12 54073733 54793733 chr12:54073733-54793733 -HOXC6 gwas_tad 2134 chr12 54073733 54793733 chr12:54073733-54793733 -HOXC10 tad 2134 chr12 54073733 54793733 chr12:54073733-54793733 -HOXC5 gwas_tad 2134 chr12 54073733 54793733 chr12:54073733-54793733 -HOXC8 tad 2134 chr12 54073733 54793733 chr12:54073733-54793733 -EN1 gwas_tad 459 chr2 118763530 119643530 chr2:118763530-119643530 -INSIG2 gwas_tad 459 chr2 118763530 119643530 chr2:118763530-119643530 -SOX6 tad 1936 chr11 15283424 16803424 chr11:15283424-16803424 -TNFSF11 gwas 2236 chr13 42862000 44462000 chr13:42862000-44462000 -FABP3P2 gwas 2236 chr13 42862000 44462000 chr13:42862000-44462000 -RPS6KA5 gwas 2367 chr14 91370247 91650247 chr14:91370247-91650247 -SOX4 tad 1188 chr6 20092021 21932021 chr6:20092021-21932021 -JAG1 gwas 2812 chr20 10412000 11572000 chr20:10412000-11572000 -SMG6 gwas 2568 chr17 1133250 2253250 chr17:1133250-2253250 -MIR4418 gwas 37 chr1 22327413 22767413 chr1:22327413-22767413 -STARD3NL gwas 1375 chr7 37913475 38393475 chr7:37913475-38393475 -EPDR1 gwas 1375 chr7 37913475 38393475 chr7:37913475-38393475 -NME8 gwas 1375 chr7 37913475 38393475 chr7:37913475-38393475 -GRB10 gwas 1390 chr7 50512506 51232506 chr7:50512506-51232506 -FGFRL1 tad 794 chr4 10000 1670202 chr4:10000-1670202 -IDUA gwas_tad 794 chr4 10000 1670202 chr4:10000-1670202 -C2orf91 gwas 389 chr2 42066496 42586496 chr2:42066496-42586496 -PKDCC gwas_tad 389 chr2 42066496 42586496 chr2:42066496-42586496 -ACP2 tad 1971 chr11 46643424 47443424 chr11:46643424-47443424 -ZNF408 gwas 1971 chr11 46643424 47443424 chr11:46643424-47443424 -ARHGAP1 gwas 1971 chr11 46643424 47443424 chr11:46643424-47443424 -RARG tad 2133 chr12 53433733 53873733 chr12:53433733-53873733 -SP1 tad 2133 chr12 53433733 53873733 chr12:53433733-53873733 -SP7 gwas 2133 chr12 53433733 53873733 chr12:53433733-53873733 -DHH gwas 2127 chr12 49473733 50033733 chr12:49473733-50033733 -LRP5 gwas_tad 1995 chr11 67763424 68843424 chr11:67763424-68843424 -KLHL42 gwas 2110 chr12 27868733 29188733 chr12:27868733-29188733 -PTHLH gwas_tad 2110 chr12 27868733 29188733 chr12:27868733-29188733 -RUNX1 tad 2883 chr21 36038130 37518130 chr21:36038130-37518130 -C17orf53 gwas 2602 chr17 41964474 43204474 chr17:41964474-43204474 From e3655f9c6b1faf243c977f875e8f14f380815e1e Mon Sep 17 00:00:00 2001 From: Wei Cheng <36087657+Colin-Cheng@users.noreply.github.com> Date: Thu, 12 Jul 2018 19:15:26 -0400 Subject: [PATCH 14/46] Delete t2d_gene_evidence.csv --- results/t2d_gene_evidence.csv | 161 ---------------------------------- 1 file changed, 161 deletions(-) delete mode 100644 results/t2d_gene_evidence.csv diff --git a/results/t2d_gene_evidence.csv b/results/t2d_gene_evidence.csv deleted file mode 100644 index bfd7a4c..0000000 --- a/results/t2d_gene_evidence.csv +++ /dev/null @@ -1,161 +0,0 @@ -gene,evidence -ZNF800,gwas -CTSH,tad -ZFAND6,gwas -SSR1,gwas -RPS14P6,gwas -LRTM1,gwas -SERINC3,tad -RBMX2P4,gwas -HNRNPKP3,gwas -TGFB2,tad -WWOX,tad -RFX3,tad -PRC1,gwas -R3HDML,gwas -RPL5P26,gwas -KCNK16,gwas -BCAP31,tad -PTEN,tad -RPL9P23,gwas -RPS3AP18,gwas -HNF1B,gwas_tad -ST6GAL1,gwas -STK4,tad -RAF1,tad -HMG20A,gwas -RNA5SP94,gwas -TP53INP1,gwas_tad -SLC30A8,gwas_tad -RNA5SP431,gwas -RPSAP52,gwas -TMEM18,gwas -CCNE2,gwas -PRC1-AS1,gwas -GLIS3,gwas -ZFAND3,gwas -POU5F1,gwas -LINC00977,gwas -FAM150B,gwas -DYNLL1,tad -VPS33B,gwas -KCNK17,gwas -KRT18P24,gwas -FBXW7,tad -LPP-AS2,gwas -YWHAB,tad -PCBD2,gwas -FTO,gwas -C10orf35,gwas -RPL11P3,gwas -DUSP9,gwas -RPS3AP42,gwas -PSMD6,gwas -ADCY5,gwas_tad -ANK1,gwas -IL20RA,tad -OASL,gwas -PRICKLE2-AS1,gwas -PPIF,tad -ABCC8,tad -MPHOSPH9,gwas -CDC123,gwas -TSPAN8,gwas -MIR4432,gwas -YAP1P3,gwas -FITM2,gwas -MTNR1B,gwas_tad -EML2-AS1,gwas -CRHR2,gwas -RPL26P21,gwas -SPRY2,gwas -ADAMTS9-AS2,gwas -RPL35AP3,gwas -ZC3H11B,gwas -DMRTA1,gwas -SOX4,tad -CMIP,gwas -KLHL42,gwas -ZBED3-AS1,gwas -PDE8B,tad -LOC101927502,gwas -SLC16A11,gwas -GIPR,gwas_tad -ARMS2,gwas -CDKN2B-AS1,gwas -DCD,gwas -SIRT4,tad -THADA,gwas -BCLAF1,tad -FAF1,gwas_tad -NPM1P47,gwas -CAMK1D,gwas -HHEX,gwas -GLP1R,tad -MC4R,gwas_tad -C15orf38-AP3S2,gwas -ARL15,gwas -VDAC1P5,gwas -DGKB,gwas -IGF2BP2,gwas -LINGO2,gwas -C2CD4B,gwas -MIR5702,gwas -LINC00824,gwas -RPS3AP49,gwas -NOTCH2,gwas -IRS1,tad -MAEA,gwas -KLF14,gwas -PMAIP1,tad -UBA52P6,gwas -RIMKLBP2,gwas -KCNJ11,gwas_tad -CDKAL1,gwas -EXOC6,gwas -BCL6,gwas -LINC01080,gwas -PTHLH,gwas -MIR29A,gwas -WNT5A,gwas -GSTM5P1,gwas -LINC01512,gwas -LGR5,gwas -NYAP2,gwas -RREB1,gwas -ANXA5,gwas -AP3S2,gwas -KCNQ1,gwas -KCNQ1OT1,gwas -ARAP1,gwas -HIGD1C,gwas -GCC1,gwas -TCF7L2,gwas_tad -TMEM155,gwas -PROX1-AS1,gwas -HNF1A,gwas -PEPD,gwas -SLC35D3,gwas -FAH,gwas -PPARG,gwas -VPS26A,gwas -CPLX1,tad -UBE2E2,gwas -MIR3941,gwas -KRT18P48,gwas -COBLL1,gwas -LOC646736,gwas -TIMP4,gwas -HNF4A,gwas_tad -WFS1,gwas -VEGFA,gwas -MIR486-1,gwas -RNF6,gwas -JAZF1,gwas -CHCHD2P9,gwas -PRELID1P1,gwas -ZMIZ1,gwas -EIF3EP3,gwas -HIP1R,tad -MED6P1,gwas -MAF,gwas From bc5b510d48e2ceaee745d193a98d5049712c2603 Mon Sep 17 00:00:00 2001 From: Wei Cheng <36087657+Colin-Cheng@users.noreply.github.com> Date: Thu, 12 Jul 2018 19:15:34 -0400 Subject: [PATCH 15/46] Delete t2d_gene_evidence_summary.tsv --- results/t2d_gene_evidence_summary.tsv | 127 -------------------------- 1 file changed, 127 deletions(-) delete mode 100644 results/t2d_gene_evidence_summary.tsv diff --git a/results/t2d_gene_evidence_summary.tsv b/results/t2d_gene_evidence_summary.tsv deleted file mode 100644 index b9aba6e..0000000 --- a/results/t2d_gene_evidence_summary.tsv +++ /dev/null @@ -1,127 +0,0 @@ -gene evidence TAD ID chromosome TAD Start TAD End UCSC -ABCC8 tad 1938 chr11 17243424 17563424 chr11:17243424-17563424 -KCNJ11 gwas_tad 1938 chr11 17243424 17563424 chr11:17243424-17563424 -SLC16A11 gwas 2573 chr17 6539276 7099276 chr17:6539276-7099276 -JAZF1 gwas 1361 chr7 28153475 28913475 chr7:28153475-28913475 -ANXA5 gwas 908 chr4 120980552 122740550 chr4:120980552-122740550 -TMEM155 gwas 908 chr4 120980552 122740550 chr4:120980552-122740550 -SPRY2 gwas 2266 chr13 80141999 81621999 chr13:80141999-81621999 -PEPD gwas 2755 chr19 33708160 34268160 chr19:33708160-34268160 -POU5F1 gwas 1197 chr6 30412021 31372021 chr6:30412021-31372021 -ZNF800 gwas 1461 chr7 124532764 127212764 chr7:124532764-127212764 -HNRNPKP3 gwas 1964 chr11 41243424 43283424 chr11:41243424-43283424 -VPS26A gwas 1851 chr10 70769994 71169994 chr10:70769994-71169994 -GIPR gwas_tad 2778 chr19 45868160 46228160 chr19:45868160-46228160 -LINC00977 gwas 1617 chr8 127850818 130770818 chr8:127850818-130770818 -C15orf38-AP3S2 gwas 2454 chr15 89878996 90798996 chr15:89878996-90798996 -AP3S2 gwas 2454 chr15 89878996 90798996 chr15:89878996-90798996 -LRTM1 gwas 647 chr3 54424960 55464960 chr3:54424960-55464960 -CHCHD2P9 gwas 1706 chr9 81730180 82770180 chr9:81730180-82770180 -RAF1 tad 591 chr3 11105000 12865000 chr3:11105000-12865000 -GSTM5P1 gwas 591 chr3 11105000 12865000 chr3:11105000-12865000 -PPARG gwas 591 chr3 11105000 12865000 chr3:11105000-12865000 -TIMP4 gwas 591 chr3 11105000 12865000 chr3:11105000-12865000 -KLF14 gwas 1464 chr7 129692764 130549460 chr7:129692764-130549460 -CMIP gwas 2554 chr16 81042499 81922499 chr16:81042499-81922499 -WWOX tad 2552 chr16 78122499 80562499 chr16:78122499-80562499 -RNA5SP431 gwas 2552 chr16 78122499 80562499 chr16:78122499-80562499 -MAF gwas 2552 chr16 78122499 80562499 chr16:78122499-80562499 -TGFB2 tad 307 chr1 218413377 220013377 chr1:218413377-220013377 -ZC3H11B gwas 307 chr1 218413377 220013377 chr1:218413377-220013377 -RIMKLBP2 gwas 307 chr1 218413377 220013377 chr1:218413377-220013377 -FTO gwas 2520 chr16 53562499 55442499 chr16:53562499-55442499 -TMEM18 gwas 347 chr2 10000 1860993 chr2:10000-1860993 -FAM150B gwas 347 chr2 10000 1860993 chr2:10000-1860993 -LINGO2 gwas 1670 chr9 28090000 29770000 chr9:28090000-29770000 -MTNR1B gwas_tad 2023 chr11 92680352 93480352 chr11:92680352-93480352 -WFS1 gwas 802 chr4 5949099 6589099 chr4:5949099-6589099 -MIR3941 gwas 1908 chr10 124010010 124210010 chr10:124010010-124210010 -FAF1 gwas_tad 92 chr1 50827413 51227412 chr1:50827413-51227412 -VEGFA gwas 1213 chr6 43572022 44332022 chr6:43572022-44332022 -THADA gwas 391 chr2 43026496 43826496 chr2:43026496-43826496 -HNF1B gwas_tad 2598 chr17 34805887 36295000 chr17:34805887-36295000 -DYNLL1 tad 2200 chr12 120635617 121675617 chr12:120635617-121675617 -OASL gwas 2200 chr12 120635617 121675617 chr12:120635617-121675617 -SIRT4 tad 2200 chr12 120635617 121675617 chr12:120635617-121675617 -HNF1A gwas 2200 chr12 120635617 121675617 chr12:120635617-121675617 -ZBED3-AS1 gwas 1054 chr5 76404244 76804244 chr5:76404244-76804244 -PDE8B tad 1054 chr5 76404244 76804244 chr5:76404244-76804244 -SOX4 tad 1188 chr6 20092021 21932021 chr6:20092021-21932021 -CDKAL1 gwas 1188 chr6 20092021 21932021 chr6:20092021-21932021 -KLHL42 gwas 2110 chr12 27868733 29188733 chr12:27868733-29188733 -PTHLH gwas 2110 chr12 27868733 29188733 chr12:27868733-29188733 -ADCY5 gwas_tad 710 chr3 122437310 123317310 chr3:122437310-123317310 -ARL15 gwas 1026 chr5 52404243 53804243 chr5:52404243-53804243 -TCF7L2 gwas_tad 1897 chr10 114210010 115410010 chr10:114210010-115410010 -FBXW7 tad 942 chr4 153340550 153700550 chr4:153340550-153700550 -MPHOSPH9 gwas 2202 chr12 123314047 123754047 chr12:123314047-123754047 -HIP1R tad 2202 chr12 123314047 123754047 chr12:123314047-123754047 -HIGD1C gwas 2130 chr12 51153733 51793733 chr12:51153733-51793733 -ADAMTS9-AS2 gwas 659 chr3 64544960 65304960 chr3:64544960-65304960 -PPIF tad 1863 chr10 79809994 81289994 chr10:79809994-81289994 -ZMIZ1 gwas 1863 chr10 79809994 81289994 chr10:79809994-81289994 -RPSAP52 gwas 2146 chr12 65153733 66513733 chr12:65153733-66513733 -UBE2E2 gwas 607 chr3 23024996 24024996 chr3:23024996-24024996 -IL20RA tad 1295 chr6 136598307 137998307 chr6:136598307-137998307 -RPL35AP3 gwas 1295 chr6 136598307 137998307 chr6:136598307-137998307 -BCLAF1 tad 1295 chr6 136598307 137998307 chr6:136598307-137998307 -SLC35D3 gwas 1295 chr6 136598307 137998307 chr6:136598307-137998307 -CDKN2B-AS1 gwas 1661 chr9 21810000 22250000 chr9:21810000-22250000 -UBA52P6 gwas 1661 chr9 21810000 22250000 chr9:21810000-22250000 -PROX1-AS1 gwas 300 chr1 213253377 214373377 chr1:213253377-214373377 -DGKB gwas 1343 chr7 14753475 16113475 chr7:14753475-16113475 -KCNK16 gwas 1206 chr6 38812022 39292022 chr6:38812022-39292022 -KCNK17 gwas 1206 chr6 38812022 39292022 chr6:38812022-39292022 -GLP1R tad 1206 chr6 38812022 39292022 chr6:38812022-39292022 -MIR5702 gwas 562 chr2 226531756 227971756 chr2:226531756-227971756 -IRS1 tad 562 chr2 226531756 227971756 chr2:226531756-227971756 -MC4R gwas_tad 2699 chr18 57569020 58249020 chr18:57569020-58249020 -RPS3AP49 gwas 2699 chr18 57569020 58249020 chr18:57569020-58249020 -PMAIP1 tad 2699 chr18 57569020 58249020 chr18:57569020-58249020 -KCNQ1 gwas 1919 chr11 2443424 2923424 chr11:2443424-2923424 -KCNQ1OT1 gwas 1919 chr11 2443424 2923424 chr11:2443424-2923424 -PRELID1P1 gwas 1282 chr6 126318307 127518307 chr6:126318307-127518307 -DCD gwas 2135 chr12 54873733 55393733 chr12:54873733-55393733 -VDAC1P5 gwas 2135 chr12 54873733 55393733 chr12:54873733-55393733 -TSPAN8 gwas 2152 chr12 70033733 72153733 chr12:70033733-72153733 -LGR5 gwas 2152 chr12 70033733 72153733 chr12:70033733-72153733 -HHEX gwas 1877 chr10 94410020 95290010 chr10:94410020-95290010 -EXOC6 gwas 1877 chr10 94410020 95290010 chr10:94410020-95290010 -BCAP31 tad 3059 chrX 152786806 153426806 chrX:152786806-153426806 -DUSP9 gwas 3059 chrX 152786806 153426806 chrX:152786806-153426806 -KRT18P48 gwas 3059 chrX 152786806 153426806 chrX:152786806-153426806 -MAEA gwas 794 chr4 10000 1670202 chr4:10000-1670202 -CPLX1 tad 794 chr4 10000 1670202 chr4:10000-1670202 -LPP-AS2 gwas 782 chr3 187517306 188957306 chr3:187517306-188957306 -RNA5SP94 gwas 405 chr2 57786496 60906496 chr2:57786496-60906496 -MIR4432 gwas 405 chr2 57786496 60906496 chr2:57786496-60906496 -SLC30A8 gwas_tad 1604 chr8 115850824 118330819 chr8:115850824-118330819 -CTSH tad 2445 chr15 79212945 80692945 chr15:79212945-80692945 -ZFAND6 gwas 2445 chr15 79212945 80692945 chr15:79212945-80692945 -FAH gwas 2445 chr15 79212945 80692945 chr15:79212945-80692945 -RNF6 gwas 2217 chr13 26742000 27502000 chr13:26742000-27502000 -PTEN tad 1871 chr10 89570020 90370020 chr10:89570020-90370020 -MED6P1 gwas 1871 chr10 89570020 90370020 chr10:89570020-90370020 -PSMD6 gwas 658 chr3 63984960 64544960 chr3:63984960-64544960 -PRICKLE2-AS1 gwas 658 chr3 63984960 64544960 chr3:63984960-64544960 -RFX3 tad 1637 chr9 2850000 4370000 chr9:2850000-4370000 -GLIS3 gwas 1637 chr9 2850000 4370000 chr9:2850000-4370000 -HMG20A gwas 2442 chr15 77292945 78172945 chr15:77292945-78172945 -NPM1P47 gwas 2421 chr15 61412708 62612708 chr15:61412708-62612708 -C2CD4B gwas 2421 chr15 61412708 62612708 chr15:61412708-62612708 -IGF2BP2 gwas 777 chr3 185357306 185637306 chr3:185357306-185637306 -ZFAND3 gwas 1205 chr6 37332022 38732022 chr6:37332022-38732022 -DGKB gwas 1342 chr7 13313475 14753475 chr7:13313475-14753475 -TP53INP1 gwas_tad 1582 chr8 95570824 96290824 chr8:95570824-96290824 -CCNE2 gwas 1582 chr8 95570824 96290824 chr8:95570824-96290824 -SERINC3 tad 2838 chr20 42846586 43926586 chr20:42846586-43926586 -R3HDML gwas 2838 chr20 42846586 43926586 chr20:42846586-43926586 -STK4 tad 2838 chr20 42846586 43926586 chr20:42846586-43926586 -YWHAB tad 2838 chr20 42846586 43926586 chr20:42846586-43926586 -FITM2 gwas 2838 chr20 42846586 43926586 chr20:42846586-43926586 -HNF4A gwas_tad 2838 chr20 42846586 43926586 chr20:42846586-43926586 -ANK1 gwas 1532 chr8 41480843 42240843 chr8:41480843-42240843 -NOTCH2 gwas 190 chr1 118518477 120558477 chr1:118518477-120558477 -ST6GAL1 gwas 780 chr3 186557306 186877306 chr3:186557306-186877306 -CDC123 gwas 1805 chr10 12239994 13399994 chr10:12239994-13399994 -CAMK1D gwas 1805 chr10 12239994 13399994 chr10:12239994-13399994 From 178411edabeab7762929ee745335c03bfe93a8dc Mon Sep 17 00:00:00 2001 From: Wei Cheng <36087657+Colin-Cheng@users.noreply.github.com> Date: Thu, 12 Jul 2018 19:15:43 -0400 Subject: [PATCH 16/46] Delete venn_bmd.tiff --- results/venn_bmd.tiff | Bin 108202 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 results/venn_bmd.tiff diff --git a/results/venn_bmd.tiff b/results/venn_bmd.tiff deleted file mode 100644 index c3ca6f7ac12340bd6bc0a6e7e20f7a7db6b6f8c1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 108202 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