OSCR

Extensive genetic interactions (epistasis) linked to alcohol use disorder in a high-risk population.

Code ↔ Paper

2 matches between paragraphs of the paper and lines of its authors' code, computed by the harvester (lexical-v1). Click a colored paragraph or line to see its counterpart.

The 2 matches
  1. [1] § Methods › Bi-clustering of SNP x SNP epistasis analysis results ↔ BiClustering.py, lines 1127–1192 · score 0.52 · chromosome pair, bi clustering, smaller, conservative, hypergeometric, intervals
  2. [2] § Methods › Replication in all of us research database ↔ hg19_to_hg38_ranges.py, lines 408–433 · score 0.51 · interacting intervals, ACAF, hg38, boundaries, hg19, mapped

Paper

Loaded from Europe PMC by your browser, not stored by OSCR: doi.org · Europe PMC

The paper is loaded when this pane is shown.

The authors' code

Python · 1,800 lines · 80 KB · no license · 1 match

  1. # -*- coding: utf-8 -*-
  2. """
  3. Created on Mon Feb 19 02:54:48 2024
  4. @author: staslist
  5. """
  6. import re
  7. import csv
  8. import unittest
  9. import numpy as np
  10. import os
  11. #import time
  12. from scipy.stats import hypergeom
  13. from datetime import datetime
  14. from numba import jit
  15. # Bi-Clustering Algorithm Code
  16. # Assume I have a file that lists all indices in the matrix that are 1.
  17. # GLOBAL VARIABLES
  18. # For tested interaction matrix, assume that every interaction has been tested (exhaustive algorithm)
  19. def merge_list(input_list:list):
  20. output = []
  21. eliminated_indeces = set()
  22. outer_index = 0
  23. while outer_index < len(input_list):
  24. if(outer_index in eliminated_indeces):
  25. outer_index += 1
  26. continue
  27. #to_merge_indeces = []
  28. current_set = input_list[outer_index]
  29. inner_index = 0
  30. while inner_index < len(input_list):
  31. if(inner_index in eliminated_indeces):
  32. inner_index += 1
  33. continue
  34. if(input_list[outer_index] == input_list[inner_index]):
  35. inner_index += 1
  36. continue
  37. if(len(input_list[outer_index].intersection(input_list[inner_index])) > 0):
  38. #to_merge_indeces.append(inner_index)
  39. current_set = current_set.union(input_list[inner_index])
  40. eliminated_indeces.add(inner_index)
  41. inner_index += 1
  42. output.append(current_set)
  43. outer_index += 1
  44. #print(output)
  45. if(output == input_list):
  46. return output
  47. else:
  48. return merge_list(output)
  49. def generate_gene_networks(gene_inter_file:str):
  50. # Convert a collection of gene pairs into a set of gene networks
  51. # The interacting gene pairs are stored in a text file, one gene pair per line
  52. gene_pairs = []
  53. gene_networks = []
  54. with open(gene_inter_file) as csv_file:
  55. csv_reader = csv.reader(csv_file, delimiter=',')
  56. for row in csv_reader:
  57. gene_pairs.append({row[0], row[1]})
  58. gene_networks = merge_list(gene_pairs)
  59. return gene_networks
  60. def check_collection_overlap(collection1, collection2):
  61. for ele in collection1:
  62. if(ele in collection2):
  63. return True
  64. return False
  65. def generate_gene_blocks(fname:str, distance:int):
  66. # Take in a plink range file and aggregate together genes/regulatory elements
  67. # that are located closely together into blocks.
  68. # Write out blocks, one per line, into a new file.
  69. ranges = dict()
  70. pairs = []
  71. blocks = []
  72. with open(fname) as csv_file:
  73. csv_reader = csv.reader(csv_file, delimiter=' ')
  74. for row in csv_reader:
  75. ranges[row[3]] = ((row[0]), int(row[1]), int(row[2]))
  76. for k,v in ranges.items():
  77. chrom1 = v[0]
  78. start1 = v[1]
  79. end1 = v[2]
  80. paired = False
  81. for k2,v2 in ranges.items():
  82. if(v == v2):
  83. continue
  84. #print(k, k2)
  85. chrom2 = v2[0]
  86. start2 = v2[1]
  87. end2 = v2[2]
  88. # Detect one element within another element
  89. if(chrom1 == chrom2 and ((start1 < start2 < end1) or (start1 < end2 < end1)
  90. or (start2 < start1 < end2) or (start2 < end1 < end2))):
  91. pairs.append((k,k2))
  92. paired = True
  93. # Detect neighboring elements
  94. elif(chrom1 == chrom2 and (abs(start2 - end1)<=distance or abs(start1 - end2)<=distance)):
  95. pairs.append((k,k2))
  96. paired = True
  97. if(not paired):
  98. blocks.append({k})
  99. #print("Pairs: ", pairs)
  100. used_pairs = []
  101. # Now conglomerate the pairs into blocks
  102. for pair in pairs:
  103. reverse_pair = (pair[1], pair[0])
  104. if(pair in used_pairs or reverse_pair in used_pairs):
  105. continue
  106. curr_block = {pair[0], pair[1]}
  107. for pair2 in pairs:
  108. if(pair2 in used_pairs):
  109. pass
  110. elif(pair == pair2):
  111. pass
  112. elif(check_collection_overlap(curr_block, pair2)):
  113. curr_block.add(pair2[0])
  114. curr_block.add(pair2[1])
  115. used_pairs.append(pair2)
  116. used_pairs.append(pair)
  117. blocks.append(curr_block)
  118. return blocks
  119. def summation_func(n:int):
  120. # Sum (n-1) + (n-2) + ... + 2 + 1 + 0
  121. assert(n > 1)
  122. result = 0
  123. n = n-1
  124. while n > 0:
  125. result += n
  126. n -= 1
  127. return result
  128. def generate_multicpu_files(anno_files:list, bim_file:str, total_markers:int, num_cpus:int,
  129. out_dir:str, chrom1:str, chrom2:str, pval_cutoff:float):
  130. interval_length = total_markers//num_cpus
  131. i_start = 0
  132. i_end = total_markers
  133. current_i = 0
  134. i_intervals = []
  135. while current_i < total_markers:
  136. if( (current_i + interval_length) < total_markers):
  137. i_intervals.append((current_i, current_i + interval_length))
  138. current_i = current_i + interval_length
  139. else:
  140. i_intervals.append((current_i, total_markers))
  141. current_i = total_markers
  142. counter = 0
  143. for i_interval in i_intervals:
  144. i_s = str(i_interval[0])
  145. i_e = str(i_interval[1])
  146. tot_marks = str(total_markers)
  147. fname_out_py = out_dir + 'BiClustering_Launcher_chr' + chrom1 + '_chr' + chrom2
  148. fname_out_py += '_' + str(counter) + '.py'
  149. with open(fname_out_py, 'w') as writer:
  150. writer.write('from BiClustering import *\n')
  151. writer.write('import sys\n')
  152. writer.write('if __name__ == "__main__":\n')
  153. writer.write('\tassert sys.version_info.major == 3\n')
  154. writer.write('\tassert sys.version_info.minor >= 7\n')
  155. writer.write("\tindir = '/gpfs/group/home/slistopad/BiClustering/'\n")
  156. r = 1
  157. for anno_file in anno_files:
  158. writer.write("\tmarker_file" + str(r) + " = indir + '" + str(anno_file) + "'\n")
  159. r += 1
  160. r = 1
  161. writer.write('\tmarker_files = [')
  162. while r <= len(anno_files):
  163. writer.write('marker_file' + str(r))
  164. if(r != len(anno_files)):
  165. writer.write(',')
  166. r += 1
  167. writer.write(']\n')
  168. writer.write("\tbim_file = indir + '" + str(bim_file) + "'\n")
  169. writer.write("\tchrom1,chrom2 = '" + chrom1 + "','" + chrom2 + "'\n")
  170. writer.write('\tN,n,inter_matrix,up_tri = initialize_matrices2(bim_file,marker_files, chrom1, chrom2, ' + str(pval_cutoff) + ')\n')
  171. writer.write("\tout_dir = '/gpfs/group/home/slistopad/BiClustering/'\n")
  172. writer.write('\ti_start, i_end = '+i_s+', '+i_e+'\n')
  173. writer.write('\tkm_results = compute_k_m_parallel(60, inter_matrix, up_tri, i_start, i_end, N, n)\n')
  174. writer.write('\tcompute_interval_pval_parallel(km_results, N, n, i_start, i_end, 60, out_dir, chrom1=chrom1, chrom2=chrom2)\n')
  175. if(counter == 0):
  176. writer.write('\tpval_results = dict()\n')
  177. writer.write('\ti_intervals = [')
  178. counter_inner = 0
  179. for i_inter in i_intervals:
  180. counter_inner += 1
  181. writer.write('('+str(i_inter[0])+','+str(i_inter[1])+')')
  182. if(counter_inner < len(i_intervals)):
  183. writer.write(',')
  184. else:
  185. writer.write(']\n')
  186. writer.write('\tfor i_pair in i_intervals:\n')
  187. writer.write("\t\tfilename = out_dir + 'chr" + chrom1 + "_chr" + chrom2 + "_pval_results_' + str(i_pair[0]) + '_' + str(i_pair[1]) + '.csv'\n")
  188. writer.write('\t\twith open(filename) as csv_file:\n')
  189. writer.write("\t\t\tcsv_reader = csv.reader(csv_file, delimiter=',')\n")
  190. writer.write("\t\t\tfor row in csv_reader:\n")
  191. writer.write("\t\t\t\tpval_results[(int(row[0]),int(row[1]),int(row[2]),int(row[3]))] = float(row[6])\n")
  192. writer.write("\ts_inter_pairs = sorted(pval_results.items(), key = lambda x: abs(x[1]), reverse = False)\n")
  193. writer.write("\ttrimmed_inter_pairs = trim_intervals(s_inter_pairs)\n")
  194. writer.write("\tfilename = out_dir + 'biclustering_results_chr" + chrom1 + "_chr" + chrom2 + ".txt'\n")
  195. writer.write("\twith open(filename, 'w') as writer:\n")
  196. writer.write("\t\tfor inter_pair in trimmed_inter_pairs:\n")
  197. writer.write("\t\t\twriter.write(str(inter_pair[0][0])+','+str(inter_pair[0][1])+','+str(inter_pair[0][2])+','+str(inter_pair[0][3])+','+str(inter_pair[1]) + '\\n')\n")
  198. counter += 1
  199. fname_out_sh = out_dir + 'BiClustering_Launcher_chr' + chrom1 + '_chr' + chrom2 + '.sh'
  200. with open(fname_out_sh, 'w') as writer:
  201. writer.write("#!/bin/sh\n")
  202. writer.write("#SBATCH --job-name=SL_BiClustering_Launcher_chr" + chrom1 + '_chr' + chrom2 + "\n")
  203. writer.write("#SBATCH --array=1-" + str(len(i_intervals)-1) + "\n")
  204. writer.write("#SBATCH --ntasks=1\n")
  205. writer.write("#SBATCH --mem=48gb\n")
  206. writer.write("#SBATCH --time=240:00:00\n")
  207. writer.write("#SBATCH --partition=shared\n\n")
  208. writer.write("cd $SLURM_SUBMIT_DIR\n")
  209. writer.write("module load use.own\n")
  210. writer.write("module load python/3.8.3\n")
  211. writer.write("export PYTHONPATH=/gpfs/home/slistopad/.local/lib/python3.8/site-packages:$PYTHONPATH\n")
  212. writer.write("python3 " + 'BiClustering_Launcher_chr' + chrom1 + '_chr' + chrom2 + '_${SLURM_ARRAY_TASK_ID}.py' + '\n')
  213. writer.write("python3 " + 'BiClustering_Launcher_chr' + chrom1 + '_chr' + chrom2 + '_0.py' + '\n')
  214. def get_number_of_interacting_snps_in_interval(biclustering_file:str, bim_file:str, gene_location_file:str,
  215. chrom1:str, chrom2:str, interaction_files:list, pval_cutoff:float):
  216. interacting_pairs_per_interval = dict()
  217. chrom1_snps, chrom2_snps = parse_plink_bim_file(bim_file, chrom1, chrom2)
  218. chrom1_ranges, chrom2_ranges = [], []
  219. with open(biclustering_file) as csv_file:
  220. csv_reader = csv.reader(csv_file, delimiter=',')
  221. for row in csv_reader:
  222. range1 = (int(row[0]), int(row[0]) + int(row[2]))
  223. chrom1_ranges.append(range1)
  224. range2 = (int(row[1]), int(row[1]) + int(row[3]))
  225. chrom2_ranges.append(range2)
  226. interactions = parse_remma_interaction_data(interaction_files, pval_cutoff, chrom1, chrom2)
  227. #print('goodbye')
  228. print('chrom1_ranges: ', chrom1_ranges)
  229. print('chrom2_ranges: ', chrom2_ranges)
  230. gene_reg_locations = []
  231. with open(gene_location_file) as csv_file:
  232. csv_reader = csv.reader(csv_file, delimiter=' ')
  233. for row in csv_reader:
  234. gene_reg_locations.append((row[0],row[1],row[2],row[3]))
  235. i = 0
  236. num_interval_pairs = len(chrom1_ranges)
  237. while i < num_interval_pairs:
  238. interval1 = chrom1_snps[chrom1_ranges[i][0]:chrom1_ranges[i][1]]
  239. interval2 = chrom2_snps[chrom2_ranges[i][0]:chrom2_ranges[i][1]]
  240. #print(len(interval1))
  241. #print(len(interval2))
  242. #print(interval1)
  243. #print(interval2)
  244. #print(interactions)
  245. for snp in interval1:
  246. for snp2 in interval2:
  247. if( (snp, snp2) in interactions or (snp2, snp) in interactions ):
  248. chrom1_loc1 = snp.split(':')
  249. chrom1 = chrom1_loc1[0]
  250. loc1 = chrom1_loc1[1]
  251. element1 = ''
  252. for ele_loc in gene_reg_locations:
  253. if(chrom1 == ele_loc[0] and int(loc1) >= int(ele_loc[1]) and int(loc1) <= int(ele_loc[2])):
  254. element1 += ele_loc[3] + ' '
  255. #print(element1)
  256. chrom2_loc2 = snp2.split(':')
  257. chrom2 = chrom2_loc2[0]
  258. loc2 = chrom2_loc2[1]
  259. element2 = ''
  260. for ele_loc in gene_reg_locations:
  261. if(chrom2 == ele_loc[0] and int(loc2) >= int(ele_loc[1]) and int(loc2) <= int(ele_loc[2])):
  262. element2 += ele_loc[3] + ' '
  263. #print(element2)
  264. if (element1, element2) not in interacting_pairs_per_interval:
  265. interacting_pairs_per_interval[(element1, element2)] = 1
  266. else:
  267. interacting_pairs_per_interval[(element1, element2)] += 1
  268. i += 1
  269. print(interacting_pairs_per_interval)
  270. return interacting_pairs_per_interval
  271. def get_msigdb_enrichment(gene_pairs:set, out_dir:str):
  272. #print(pairs)
  273. pairs_map = dict()
  274. fname = 'C:/Stas/LabWork/Bioinformatics/Projects/Ch5_AI_AUD/Pathways/c2.all.v2023.2.Hs.symbols.gmt'
  275. with open(fname) as csv_file:
  276. csv_reader = csv.reader(csv_file, delimiter='\t')
  277. for row in csv_reader:
  278. pathway_name = row[0]
  279. pathway_genes = row[2:]
  280. for pair in gene_pairs:
  281. if(pair[0] in pathway_genes and pair[1] in pathway_genes):
  282. try:
  283. pairs_map[pair].append(pathway_name)
  284. except KeyError:
  285. pairs_map[pair] = [pathway_name]
  286. fname_out = out_dir + 'biclustering_results_msigdb_enrichment.txt'
  287. with open(fname_out, 'w') as writer:
  288. for k,v in pairs_map.items():
  289. writer.write(str(k) + ' : ' + str(v) + '\n')
  290. def parse_biclustering_annotation(bicluster_file_annot:str):
  291. element_pairs_dict = dict()
  292. element_pairs_annotated = []
  293. element_pairs_per_interval = []
  294. unique_interacting_snps = []
  295. interacting_snp_pairs_all_intervals = []
  296. regulatory_elements_all = set()
  297. with open(bicluster_file_annot) as csv_file:
  298. csv_reader = csv.reader(csv_file, delimiter='\t')
  299. for row in csv_reader:
  300. # If the row is not empty
  301. if(len(row) == 0):
  302. continue
  303. if(len(row[0]) > 0 and 'Interacting snp pairs:' not in row[0] and
  304. 'Interacting num snp pairs:' not in row[0] and 'Total number of unique' not in row[0]):
  305. # There must be at least one gene/reg element pair
  306. # It must be surrounded by (" ")
  307. interval_pair = row[0]
  308. interval_pair_split = interval_pair.split("),")
  309. pval = row[1]
  310. element_pairs_annotated2 = []
  311. for element_pair in interval_pair_split:
  312. #print(element_pair)
  313. element2_begin = element_pair.find('element2:')
  314. r = 0
  315. record_element = False
  316. element1_set = set()
  317. element1 = ''
  318. while r < (element2_begin-1):
  319. #print(element_pair)
  320. #print(i)
  321. char = element_pair[r]
  322. if(char == "'"):
  323. if(record_element):
  324. if('GH' in element1 and len(element1) == 11):
  325. regulatory_elements_all.add(element1)
  326. element1 = ''
  327. else:
  328. element1_set.add(element1)
  329. element1 = ''
  330. record_element = not record_element
  331. if(record_element and char!= "'"):
  332. element1 += char
  333. r += 1
  334. #print('Element1: ', element1_list)
  335. r = element2_begin
  336. record_element = False
  337. element2_set = set()
  338. element2 = ''
  339. while r < len(element_pair):
  340. #print(interval_pair)
  341. #print(r)
  342. #print(element_pair_end-2)
  343. #print(char)
  344. char = element_pair[r]
  345. #print(char)
  346. if(char == "'"):
  347. if(record_element):
  348. if('GH' in element2 and len(element2) == 11):
  349. regulatory_elements_all.add(element2)
  350. element2 = ''
  351. else:
  352. element2_set.add(element2)
  353. element2 = ''
  354. record_element = not record_element
  355. if(record_element and char!= "'"):
  356. element2 += char
  357. r += 1
  358. #print('Element2: ', element2_list)
  359. element_pair_tuple = (element1_set, element2_set)
  360. if(element_pair_tuple not in element_pairs_annotated):
  361. element_pairs_annotated.append((element1_set, element2_set))
  362. if(element_pair_tuple not in element_pairs_annotated2):
  363. element_pairs_annotated2.append((element1_set, element2_set))
  364. element_pair_str = str((element1_set, element2_set))
  365. element_pair_str_reverse = str((element2_set, element1_set))
  366. if(element_pair_str in element_pairs_dict):
  367. if(pval < element_pairs_dict[element_pair_str]):
  368. element_pairs_dict[element_pair_str] = pval
  369. elif(element_pair_str_reverse in element_pairs_dict):
  370. if(pval < element_pairs_dict[element_pair_str_reverse]):
  371. element_pairs_dict[element_pair_str_reverse] = pval
  372. else:
  373. element_pairs_dict[element_pair_str] = pval
  374. element_pairs_per_interval.append(element_pairs_annotated2)
  375. elif('Total number of unique' in row[0]):
  376. split_row = row[0].split(';')[1:]
  377. #print(split_row)
  378. unique_interacting_snps_in_interval = set()
  379. for unique_snp in split_row:
  380. if(':' in unique_snp):
  381. unique_interacting_snps_in_interval.add(unique_snp)
  382. unique_interacting_snps.append(unique_interacting_snps_in_interval)
  383. elif('Interacting snp pairs:' in row[0]):
  384. current_row = row[0]
  385. pattern = "('\d+:\d+', '\d+:\d+')"
  386. matches = re.findall(pattern, current_row)
  387. interacting_snp_pairs_all = set()
  388. for snp_pair_string in matches:
  389. snp_pair_string = snp_pair_string.replace("'", "")
  390. match_split = snp_pair_string.split(', ')
  391. #print(match_split)
  392. if((match_split[1], match_split[0]) not in interacting_snp_pairs_all):
  393. interacting_snp_pairs_all.add( (match_split[0], match_split[1]) )
  394. interacting_snp_pairs_all_intervals.append(interacting_snp_pairs_all)
  395. return element_pairs_dict, element_pairs_annotated, unique_interacting_snps, interacting_snp_pairs_all_intervals, element_pairs_per_interval, regulatory_elements_all
  396. def parse_biclustering_results(biclustering_file:str, bim_file:str, gene_location_file:str,
  397. gene_hancer_file:str, chrom1:str, chrom2:str, interaction_files:list,
  398. pval_cutoff:float, out_dir:str, single_file_output:bool = False,
  399. snp_list_output:bool = False, strict_annotation:bool = True):
  400. # WARNING, The pval_cutoff should match the p-value cutoff used to conduct the biclustering analysis.
  401. # Otherwise, the mapping of the interacting intervals to interacting genes will not make sense.
  402. # strict annotation = only map interacting snp pairs to genes/reg elements,
  403. # loose annotation = map all snp pairs contained within interacting interval to genes/reg elements
  404. chrom1_snps, chrom2_snps = parse_plink_bim_file(bim_file, chrom1, chrom2)
  405. chrom1_ranges, chrom2_ranges = [], []
  406. p_values = []
  407. with open(biclustering_file) as csv_file:
  408. csv_reader = csv.reader(csv_file, delimiter=',')
  409. for row in csv_reader:
  410. range1 = (int(row[0]), int(row[0]) + int(row[2]))
  411. chrom1_ranges.append(range1)
  412. range2 = (int(row[1]), int(row[1]) + int(row[3]))
  413. chrom2_ranges.append(range2)
  414. p_values.append(row[4])
  415. # modify this section depending on the gene_location_file used
  416. # herein I assume usage of ucsc-hg19
  417. # first read in and map the transcripts to the gene names
  418. transcript_to_gene_name = dict()
  419. kgXref_file = 'C:/Stas/LabWork/Bioinformatics/Projects/Ch5_AI_AUD/Gene_Annotations/ucsc-hg19-kgXref.txt'
  420. with open(kgXref_file) as csv_file:
  421. csv_reader = csv.reader(csv_file, delimiter='\t')
  422. for row in csv_reader:
  423. transcript_to_gene_name[row[0]] = row[1]
  424. gene_reg_locations = []
  425. with open(gene_location_file) as csv_file:
  426. csv_reader = csv.reader(csv_file, delimiter='\t')
  427. for row in csv_reader:
  428. gene_reg_locations.append((row[1][3:],row[2],row[3],transcript_to_gene_name[row[0]]))
  429. # We also need to account for all the regulatory elements located within the genes
  430. # that were used in epistasis analysis
  431. with open(gene_hancer_file) as csv_file:
  432. csv_reader = csv.reader(csv_file, delimiter='\t')
  433. first_line = True
  434. for row in csv_reader:
  435. if(first_line):
  436. first_line = False
  437. continue
  438. gene_reg_locations.append((row[0][3:],row[1],row[2],row[3]))
  439. #print("gene_reg_locations: ", gene_reg_locations)
  440. #print('chrom1_ranges: ', chrom1_ranges)
  441. #print('chrom2_ranges: ', chrom2_ranges)
  442. interactions = parse_remma_interaction_data(interaction_files, pval_cutoff, chrom1, chrom2)
  443. #print("Interactions: ", interactions)
  444. if(not single_file_output):
  445. if(not snp_list_output):
  446. if(strict_annotation):
  447. filename = out_dir + 'biclustering_results_chr' + chrom1 + '_chr' + chrom2 + '_annotated.txt'
  448. else:
  449. filename = out_dir + 'biclustering_results_chr' + chrom1 + '_chr' + chrom2 + '_annotated_loosely.txt'
  450. with open(filename, 'w') as writer:
  451. i = 0
  452. num_interval_pairs = len(chrom1_ranges)
  453. while i < num_interval_pairs:
  454. gene_pair_to_num_interacting_snp_pairs = dict()
  455. gene_pair_to_interacting_snp_pairs = dict()
  456. gene_pairs = set()
  457. interval1 = chrom1_snps[chrom1_ranges[i][0]:chrom1_ranges[i][1]]
  458. interval2 = chrom2_snps[chrom2_ranges[i][0]:chrom2_ranges[i][1]]
  459. p_val = p_values[i]
  460. #print("Interval1: ", interval1)
  461. #print("Interval2: ", interval2)
  462. if(strict_annotation):
  463. for snp in interval1:
  464. for snp2 in interval2:
  465. #print(snp, snp2)
  466. if( (snp, snp2) in interactions or (snp2, snp) in interactions ):
  467. # Need to identify number of interacting snp pairs belonging to each gene pair
  468. #print("Found SNP pair in interactions!")
  469. chrom1_loc1 = snp.split(':')
  470. chrom1 = chrom1_loc1[0]
  471. loc1 = chrom1_loc1[1]
  472. element1 = set()
  473. #print('chrom1: ', chrom1)
  474. #print('loc1: ', loc1)
  475. element_name1 = 'intergenic'
  476. for ele_loc in gene_reg_locations:
  477. if(chrom1 == ele_loc[0] and int(loc1) >= int(ele_loc[1]) and int(loc1) <= int(ele_loc[2])):
  478. # There are a small number of overlapping genes, these are the
  479. # poorly defined genes, such as MICB and HLA-C, for whom the exact
  480. # loci are not yet fully established.
  481. element_name1 = ele_loc[3]
  482. element1.add(element_name1)
  483. #print('Element1: ', element1)
  484. if(len(element1) == 0):
  485. element1.add(element_name1)
  486. chrom2_loc2 = snp2.split(':')
  487. chrom2 = chrom2_loc2[0]
  488. loc2 = chrom2_loc2[1]
  489. element2 = set()
  490. #print('chrom2: ', chrom2)
  491. #print('loc2: ', loc2)
  492. element_name2 = 'intergenic'
  493. for ele_loc in gene_reg_locations:
  494. if(chrom2 == ele_loc[0] and int(loc2) >= int(ele_loc[1]) and int(loc2) <= int(ele_loc[2])):
  495. element_name2 = ele_loc[3]
  496. element2.add(element_name2)
  497. #print('Element2: ', element2)
  498. if(len(element2) == 0):
  499. element2.add(element_name2)
  500. for ele_name1 in element1:
  501. for ele_name2 in element2:
  502. if((ele_name1, ele_name2) not in gene_pair_to_num_interacting_snp_pairs and
  503. (ele_name2, ele_name1) not in gene_pair_to_num_interacting_snp_pairs):
  504. gene_pair_to_num_interacting_snp_pairs[(ele_name1, ele_name2)] = 1
  505. gene_pair_to_interacting_snp_pairs[(ele_name1, ele_name2)] = [(snp, snp2)]
  506. elif((ele_name1, ele_name2) in gene_pair_to_num_interacting_snp_pairs):
  507. gene_pair_to_num_interacting_snp_pairs[(ele_name1, ele_name2)] += 1
  508. gene_pair_to_interacting_snp_pairs[(ele_name1, ele_name2)].append((snp, snp2))
  509. elif((ele_name2, ele_name1) in gene_pair_to_num_interacting_snp_pairs):
  510. gene_pair_to_num_interacting_snp_pairs[(ele_name2, ele_name1)] += 1
  511. gene_pair_to_interacting_snp_pairs[(ele_name2, ele_name1)].append((snp2, snp))
  512. #print(gene_pair_to_num_interacting_snp_pairs)
  513. gene_pairs.add( ('element1: '+ str(element1), 'element2: ' + str(element2)) )
  514. writer.write(str(gene_pairs) + '\t')
  515. writer.write(p_values[i] + '\n')
  516. writer.write('Interacting num snp pairs: ' + str(gene_pair_to_num_interacting_snp_pairs) + '\n')
  517. writer.write('Interacting snp pairs: ' + str(gene_pair_to_interacting_snp_pairs) + '\n')
  518. current_union = set()
  519. for k,v in gene_pair_to_interacting_snp_pairs.items():
  520. current_union = current_union | set(v)
  521. writer.write('Total number of unique interacting pairs: ' + str(len(current_union)) + ';')
  522. unique_interacting_snps = set()
  523. for unique_snp_pair in current_union:
  524. unique_interacting_snps.add(unique_snp_pair[0])
  525. unique_interacting_snps.add(unique_snp_pair[1])
  526. for unique_snp in unique_interacting_snps:
  527. writer.write(str(unique_snp) + ';')
  528. writer.write('\n\n')
  529. else:
  530. elements1 = set()
  531. for snp in interval1:
  532. chrom1_loc1 = snp.split(':')
  533. chrom1 = chrom1_loc1[0]
  534. loc1 = chrom1_loc1[1]
  535. element1 = set()
  536. for ele_loc in gene_reg_locations:
  537. if(chrom1 == ele_loc[0] and int(loc1) >= int(ele_loc[1]) and int(loc1) <= int(ele_loc[2])):
  538. element1.add(ele_loc[3])
  539. #print(element1)
  540. elements1.add(str(element1))
  541. elements2 = set()
  542. for snp2 in interval2:
  543. chrom2_loc2 = snp2.split(':')
  544. chrom2 = chrom2_loc2[0]
  545. loc2 = chrom2_loc2[1]
  546. element2 = set()
  547. #print(loc2)
  548. for ele_loc in gene_reg_locations:
  549. if(chrom2 == ele_loc[0] and int(loc2) >= int(ele_loc[1]) and int(loc2) <= int(ele_loc[2])):
  550. element2.add(ele_loc[3])
  551. elements2.add(str(element2))
  552. writer.write(str( (elements1,elements2) ) + '\t')
  553. writer.write(p_values[i] + '\n')
  554. i += 1
  555. else:
  556. #print("HELLO!")
  557. filename = out_dir + 'biclustering_results_chr' + chrom1 + '_chr' + chrom2 + '_snplist_interacting_pairs.txt'
  558. with open(filename, 'w') as writer:
  559. num_interval_pairs = len(chrom1_ranges)
  560. i = 0
  561. while i < num_interval_pairs:
  562. gene_pairs = set()
  563. interval1 = chrom1_snps[chrom1_ranges[i][0]:chrom1_ranges[i][1]]
  564. interval2 = chrom2_snps[chrom2_ranges[i][0]:chrom2_ranges[i][1]]
  565. # format for liftover tool
  566. snp1_info = interval1[0].split(':')
  567. snp1_chrom,snp1_loci = snp1_info[0],snp1_info[1]
  568. snp2_info = interval1[-1].split(':')
  569. snp2_chrom,snp2_loci = snp2_info[0],snp2_info[1]
  570. #writer.write(snp1_chrom + ' ' + snp1_loci + ' ' + snp2_loci + '\n')
  571. snp1_info = interval2[0].split(':')
  572. snp1_chrom,snp1_loci = snp1_info[0],snp1_info[1]
  573. snp2_info = interval2[-1].split(':')
  574. snp2_chrom,snp2_loci = snp2_info[0],snp2_info[1]
  575. #writer.write(snp1_chrom + ' ' + snp1_loci + ' ' + snp2_loci + '\n')
  576. for snp in interval1:
  577. for snp2 in interval2:
  578. #print(snp, snp2)
  579. if( (snp, snp2) in interactions or (snp2, snp) in interactions ):
  580. writer.write(snp + ' : ')
  581. writer.write(snp2 + '\n')
  582. snp1_info = snp.split(':')
  583. snp1_chrom,snp1_loci = snp1_info[0],snp1_info[1]
  584. snp2_info = snp2.split(':')
  585. snp2_chrom,snp2_loci = snp2_info[0],snp2_info[1]
  586. print("plink --bfile /gpfs/group/home/slistopad/REMMA/data/native_american/", end='')
  587. print('NA3_Combined_Fixed_Set_score900_db001_and_exp001_1_and_genehancer', end='')
  588. print('_score25_maf001_region_qc3 --ld ' + snp + ' ' + snp2 + ' --r2 ', end='')
  589. print('--out /gpfs/group/home/slistopad/REMMA/data/native_american/Biclustering_SNPLists/', end='')
  590. print('Combined_Fixed2_Set_Biclustering/biclustering_results_ld_' + snp1_chrom, end='')
  591. print('_' + snp1_loci + '_' + snp2_chrom + '_' + snp2_loci)
  592. i += 1
  593. else:
  594. # Note, what is put into the file, are the locations of the genes, which contain
  595. # interacting SNPs within the interacting intervals.
  596. # This file is made for generation of Circo plots. In it we don't want to see the same gene pairs even if they
  597. # belong to different interval pairs.
  598. filename = out_dir + 'biclustering_results_all.txt'
  599. with open(filename, 'a') as writer:
  600. i = 0
  601. tracker = set()
  602. num_interval_pairs = len(chrom1_ranges)
  603. while i < num_interval_pairs:
  604. gene_pairs = set()
  605. interval1 = chrom1_snps[chrom1_ranges[i][0]:chrom1_ranges[i][1]]
  606. interval2 = chrom2_snps[chrom2_ranges[i][0]:chrom2_ranges[i][1]]
  607. p_val = p_values[i]
  608. #print('interval1: ', interval1)
  609. #print('interval2: ', interval2)
  610. for snp in interval1:
  611. for snp2 in interval2:
  612. if( (snp, snp2) in interactions or (snp2, snp) in interactions ):
  613. chrom1_loc1 = snp.split(':')
  614. chrom1 = chrom1_loc1[0]
  615. loc1 = chrom1_loc1[1]
  616. element1 = ''
  617. for ele_loc in gene_reg_locations:
  618. if(chrom1 == ele_loc[0] and int(loc1) >= int(ele_loc[1]) and int(loc1) <= int(ele_loc[2])):
  619. element1 = 'chr' + ele_loc[0] + ',' + ele_loc[1] + ',' + ele_loc[2]
  620. chrom2_loc2 = snp2.split(':')
  621. chrom2 = chrom2_loc2[0]
  622. loc2 = chrom2_loc2[1]
  623. element2 = ''
  624. for ele_loc in gene_reg_locations:
  625. if(chrom2 == ele_loc[0] and int(loc2) >= int(ele_loc[1]) and int(loc2) <= int(ele_loc[2])):
  626. element2 = 'chr' + ele_loc[0] + ',' + ele_loc[1] + ',' + ele_loc[2]
  627. gene_pairs.add((element1, element2))
  628. #print(gene_pairs)
  629. #print(p_val)
  630. for pair in gene_pairs:
  631. if(pair not in tracker):
  632. writer.write(pair[0] + ',' + pair[1] + ',' + str(p_val) + '\n')
  633. tracker.add(pair)
  634. i += 1
  635. def parse_remma_interaction_data(interaction_files:list, pval_cutoff:float, chrom1:str, chrom2:str):
  636. #print(pval_cutoff)
  637. #print(chrom1)
  638. #print(chrom2)
  639. interactions = dict()
  640. for interaction_file in interaction_files:
  641. with open(interaction_file) as csv_file:
  642. csv_reader = csv.reader(csv_file, delimiter=' ')
  643. header = True
  644. for row in csv_reader:
  645. if(header):
  646. header = False
  647. continue
  648. # Check if entry passes p-value cutoff and matches target chromosomes.
  649. if(float(row[18]) < pval_cutoff and ((row[1] == chrom1 and row[8] == chrom2) or
  650. (row[8] == chrom1 and row[1] == chrom2))):
  651. # If this entry already is recorded in interactions (presumably from another
  652. # interaction file), then overwrite the p-value for the record only if the
  653. # new p-value is smaller.
  654. if((row[2], row[9]) in interactions):
  655. if(float(row[18]) < interactions[(row[2], row[9])]):
  656. interactions[(row[2], row[9])] = float(row[18])
  657. elif((row[9], row[2]) in interactions):
  658. if(float(row[18]) < interactions[(row[9], row[2])]):
  659. interactions[(row[9], row[2])] = float(row[18])
  660. else:
  661. interactions[(row[2], row[9])] = float(row[18])
  662. return interactions
  663. def parse_plink_bim_file(bim_file:str, chrom1:str, chrom2:str):
  664. chrom1_snps = []
  665. chrom2_snps = []
  666. with open(bim_file) as csv_file:
  667. csv_reader = csv.reader(csv_file, delimiter='\t')
  668. for row in csv_reader:
  669. if(chrom1 == row[0]):
  670. chrom1_snps.append(row[1])
  671. if(chrom2 == row[0]):
  672. chrom2_snps.append(row[1])
  673. return chrom1_snps, chrom2_snps
  674. def initialize_matrices2(bim_file:str, interaction_files:list, chrom1:str, chrom2:str,
  675. pval_cutoff:float):
  676. # Assume that testing is always done using all relevant SNPs on one chromosome vs
  677. # all relevant SNPs on another chromosome. A chromosome can be also tested against itself.
  678. # The matrix size is number of SNPs on chromosome 1 vs number of SNPs on chromosome 2.
  679. # Relevant SNPs means SNPs that were included in the epistasis analysis.
  680. # Bim file informs us the number of relevant SNPs on each chromosome, and which SNPs pair
  681. # a given (i,j) value in the matrix represents.
  682. # Interaction file informs us which SNP pairs were found to interact.
  683. # Generally it is expected that the number of interactions is small.
  684. # Whenever the chromosomes are different, all SNP pairs are assumed to have been tested
  685. # for interaction.
  686. # If chromsome is the same, the tested interaction matrix is an upper triangular matrix.
  687. # Important assumption regarding bim file, for each chromosome all SNPs are ordered based
  688. # on their location, from beginning of chromosome to end of chromosome.
  689. # The interaction file is assumed to be a REMMA .anno file.
  690. chrom1_snps, chrom2_snps = parse_plink_bim_file(bim_file, chrom1, chrom2)
  691. interactions = parse_remma_interaction_data(interaction_files, pval_cutoff, chrom1, chrom2)
  692. #print(interactions)
  693. upper_triangular = False
  694. if(chrom1 == chrom2):
  695. upper_triangular = True
  696. N = 0
  697. n = 0
  698. total_markers1 = len(chrom1_snps)
  699. total_markers2 = len(chrom2_snps)
  700. if(upper_triangular):
  701. i = 0
  702. while i < total_markers1:
  703. N += i
  704. i += 1
  705. else:
  706. N = total_markers1 * total_markers2
  707. inter_array = np.zeros((total_markers1, total_markers2), dtype=int)
  708. i = 0
  709. while i < total_markers1:
  710. j = 0
  711. while j < total_markers2:
  712. if((chrom1_snps[i], chrom2_snps[j]) in interactions or
  713. (chrom2_snps[j], chrom1_snps[i]) in interactions):
  714. if(upper_triangular):
  715. if(i >= j):
  716. j += 1
  717. continue
  718. #print(i,j)
  719. inter_array[i][j] = 1
  720. n += 1
  721. j += 1
  722. i += 1
  723. print("Interaction matarix initialized.")
  724. print("N: ", N)
  725. print("n: ", n)
  726. print("Chromosome1: ", chrom1)
  727. print("Chromosome2: ", chrom2)
  728. print("P-Value Cutoff: ", pval_cutoff)
  729. now = datetime.now()
  730. current_time = now.strftime("%H:%M:%S")
  731. print("Current Time =", current_time)
  732. return N, n, inter_array, upper_triangular
  733. def initialize_matrices(total_markers:int, marker_file:str, upper_triangular:bool = True):
  734. # Also, we assume that all values in the interaction matrices are 1s and 0s.
  735. # We assume that all interaction and tested-interaction matrices are square.
  736. # We assume that all tested interaction matrices are either upper triangular or full (of 1s).
  737. # Upper triangular tested interaction matrix represents a set of marker being tested against
  738. # itself for epistasis.
  739. # Full tested interaction matrix represents two completely different sets of markers being
  740. # tested against each other for epistasis.
  741. N = 0
  742. n = 0
  743. inter_matrix = dict()
  744. if(upper_triangular):
  745. i = 0
  746. while i < total_markers:
  747. N += i
  748. i += 1
  749. #print("N = ", N)
  750. else:
  751. N = total_markers**2
  752. i = 0
  753. j = 0
  754. while i < total_markers:
  755. while j < total_markers:
  756. inter_matrix[(i,j)] = 0
  757. j += 1
  758. j = 0
  759. i += 1
  760. with open(marker_file) as csv_file:
  761. csv_reader = csv.reader(csv_file, delimiter=',')
  762. for row in csv_reader:
  763. i,j = int(row[0]), int(row[1])
  764. inter_matrix[(i,j)] = 1
  765. n += 1
  766. return N, n, inter_matrix, upper_triangular
  767. def check_overlap(i:int, j:int, a:int, b:int, i2:int, j2:int, a2:int, b2:int):
  768. # Note if two matrices are identical we return false.
  769. if(i == i2 and j == j2 and a==a2 and b==b2):
  770. return False
  771. assert(i >= 0 and j >= 0 and i2 >= 0 and j2 >= 0)
  772. assert(a >= 1 and b>= 1 and a2 >= 1 and b2 >= 1)
  773. origin_test = ( ((i+a-1) >= i2 >= i) and ((j+b-1) >= j2 >= j) ) or ( ((i2+a2-1) >= i >= i2) and ((j2+b2-1) >= j >= j2) )
  774. if(origin_test):
  775. return True
  776. bottom_left_test = ( (i2 <= (i+a-1) <= (i2+a2-1)) and ((j2+b2-1) >= j >= j2) ) or ( (i <= (i2+a2-1) <= (i+a -1)) and ((j+b-1) >= j2 >= j) )
  777. if(bottom_left_test):
  778. return True
  779. bottom_right_test = ( (i2 <= (i+a-1) <= (i2+a2-1)) and ((j2+b2-1) >= (j+b-1) >= j2) ) or ( (i <= (i2+a2-1) <= (i+a-1)) and ((j+b-1) >= (j2+b2-1) >= j) )
  780. if(bottom_right_test):
  781. return True
  782. upper_right_test = ( ((i+a-1) >= i2 >= i) and ((j2+b2-1) >= (j+b-1) >= j2) ) or ( ((i2+a2-1) >= i >= i2) and ((j+b-1) >= (j2+b2-1) >= j) )
  783. if(upper_right_test):
  784. return True
  785. return False
  786. '''
  787. def comp(i:int, j:int, a:int, b:int, val:str, inter_matrix:dict, tested_inter_matrix:dict):
  788. #print("i =",i,";j = ",j,";a = ", a, ";b = ", b)
  789. if(i < 0):
  790. raise ValueError("Invalid i value.")
  791. elif(j < 0):
  792. raise ValueError("Invalid j value.")
  793. elif(a < 0):
  794. raise ValueError("Invalid a value.")
  795. elif(b < 0):
  796. raise ValueError("Invalid b value.")
  797. if(a == 0 or b == 0):
  798. return 0
  799. elif(a == 1 and b == 1):
  800. if(val == 'k'):
  801. return inter_matrix[(i,j)]
  802. elif(val == 'm'):
  803. return tested_inter_matrix[(i,j)]
  804. else:
  805. raise ValueError("This parameter must be either 'k' or 'm'.")
  806. else:
  807. return comp(i,j,a-1,b-1,val,inter_matrix,tested_inter_matrix) + comp(i+a-1,j,1,b-1,val,inter_matrix,tested_inter_matrix) + comp(i,j+b-1,a-1,1,val,inter_matrix,tested_inter_matrix) + comp(i+a-1,j+b-1,1,1,val,inter_matrix,tested_inter_matrix)
  808. '''
  809. def convert_dict_to_2D_numpy_array(input_dict:dict):
  810. # This function converts a dictionary that maps (row_index, column_index) tuple to integer values.
  811. # It does so using the correct ordering.
  812. s_matrix_values = sorted(input_dict.items(), key = lambda x: x[0], reverse = False)
  813. TwoDList = []
  814. curr_inner = []
  815. prev_row = 0
  816. for ele in s_matrix_values:
  817. if(ele[0][0] > prev_row):
  818. TwoDList.append(curr_inner)
  819. curr_inner = [ele[1]]
  820. prev_row = ele[0][0]
  821. else:
  822. curr_inner.append(ele[1])
  823. return np.array(TwoDList)
  824. @jit(nopython=True)
  825. def comp_alt(i:int, j:int, a:int, b:int, inter_matrix:'np.array', upper_triangular:bool = True,
  826. compute_k:bool = True):
  827. # Assume that tested interaction matrix is either upper triangular or full of 1s.
  828. # In that case m_val can be computed quickly. Assume that one of the two is always true.
  829. #print("i =",i,";j = ",j,";a = ", a, ";b = ", b)
  830. if(i < 0):
  831. raise ValueError("Invalid i value.")
  832. elif(j < 0):
  833. raise ValueError("Invalid j value.")
  834. elif(a < 0):
  835. raise ValueError("Invalid a value.")
  836. elif(b < 0):
  837. raise ValueError("Invalid b value.")
  838. k_val = 0
  839. m_val = 0
  840. if(compute_k):
  841. if(not upper_triangular):
  842. m_val = a * b
  843. else:
  844. i2 = i
  845. while i2 < (i+a):
  846. # At which index do 1s start in this row. That is simpy row_index + 1.
  847. if(j < (i2 + 1)):
  848. m_val += max(j + b - (i2 + 1), 0)
  849. else:
  850. m_val += b
  851. i2 += 1
  852. k_val = np.count_nonzero(inter_matrix[i:(i+a),j:(j+b)])
  853. '''
  854. i2 = i
  855. while i2 < (i+a):
  856. j2 = j
  857. while j2 < (j+b):
  858. k_val += inter_matrix[i2,j2]
  859. j2 += 1
  860. i2 += 1
  861. '''
  862. return k_val, m_val
  863. @jit(nopython=True)
  864. def compute_k_m_parallel(max_inter_length:int, inter_array,
  865. upper_triangular:bool, i_start:int, i_end:int, N:int, n:int):
  866. # Our only knowledge about inter_matrix is that it consists of 1s and 0s
  867. # and that 1s are typically very sparce.
  868. # We have stronger assumptions about tested_inter_matrix which we deem to be either
  869. # upper trinagular (with 1s and 0s) or completely filled with 1s.
  870. # Given this we do not need to actually parse tested_inter_matrix to compute m.
  871. # Convert inter_matrix and tested_inter_matrix into numpy arrays.
  872. dimensions = inter_array.shape
  873. total_markers1 = dimensions[0]
  874. total_markers2 = dimensions[1]
  875. i = i_start
  876. j = 0
  877. a = max_inter_length
  878. b = max_inter_length
  879. km_results = dict()
  880. # filename = out_dir + 'km_results_' + str(i_start) + '_' + str(i_end) + '.csv'
  881. # with open(filename, 'w') as writer:
  882. # writer.write('#i,j,a,b,k,m')
  883. while i < i_end:
  884. #skipped_comp_k = 0
  885. #computed_k = 0
  886. while j < total_markers2:
  887. # If we the biggest matrix at (i,j) has k = 0, then all of the matrices within it
  888. # will also have k = 0.
  889. k_is_zero = False
  890. # a_thresh and b_thresh represent biggest submatrix that is all zeros
  891. a_thresh = 0
  892. b_thresh = 0
  893. while a >= 1:
  894. while b >= 1:
  895. if((i + a) <= total_markers1 and (j+b) <= total_markers2):
  896. if(k_is_zero and a <= a_thresh and b <= b_thresh):
  897. #skipped_comp_k += 1
  898. k,m = comp_alt(i,j,a,b, inter_array, upper_triangular, compute_k=False)
  899. else:
  900. k,m = comp_alt(i,j,a,b, inter_array, upper_triangular)
  901. #computed_k += 1
  902. if(k == 0):
  903. k_is_zero = True
  904. a_thresh = a
  905. b_thresh = b
  906. # Do not store the k,m pair if k <= expected value (m*n/N)
  907. if(k > (m*n/N)):
  908. km_results[(i,j,a,b)] = (k,m)
  909. else:
  910. pass
  911. # writer.write(str(i)+','+str(j)+','+str(a)+','+str(b)+','+str(k)+','+str(m))
  912. b -= 1
  913. b = max_inter_length
  914. a -= 1
  915. a = max_inter_length
  916. b = max_inter_length
  917. j += 1
  918. #print('j = ', j)
  919. #a = max_inter_length
  920. #b = max_inter_length
  921. j = 0
  922. i += 1
  923. print('i = ', i)
  924. #print("Number of skipped k computations: ", skipped_comp_k)
  925. #print("Number of completed k computations: ", computed_k)
  926. print("Length of km_results: ", len(km_results))
  927. #now = datetime.now()
  928. #current_time = now.strftime("%H:%M:%S")
  929. #print("Current Time =", current_time)
  930. return km_results
  931. #@jit(nopython=True)
  932. def compute_interval_pval_parallel(km_results:dict, N:int, n:int, i_start:int, i_end:int,
  933. max_inter_length:int, out_dir:str, chrom1:str = '-1',
  934. chrom2:str = '-1'):
  935. # Assume that all k values are bigger than expected k-value of (m*n/N)
  936. computed_pvals = dict()
  937. # Conservative Bonferonni Correction
  938. # In practice the number of tests is much smaller
  939. correction = 0.05 / (N * (max_inter_length**2))
  940. # this would be correct if we only computed
  941. # one chromosome pair, but unfortunately we need to account for all pairs
  942. # hard coded correction:
  943. #correction = 0.05 / (60055879978 * 3600)
  944. if(chrom1 == '-1' or chrom2 == '-1'):
  945. filename = out_dir + 'pval_results_' + str(i_start) + '_' + str(i_end) + '.csv'
  946. else:
  947. filename = out_dir + 'chr' + chrom1 + '_chr' + chrom2 + '_pval_results_'
  948. filename += str(i_start) + '_' + str(i_end) + '.csv'
  949. with open(filename, 'w') as writer:
  950. pval_results = dict()
  951. # i = 0
  952. for key,val in km_results.items():
  953. k,m = val[0], val[1]
  954. max_k = min(m, n)
  955. # min_k = max(0, m-(N-n))
  956. pval_results[key] = 0
  957. # First check if a p-value for the following k,m pair has already been computed.
  958. try:
  959. pval_results[key] = computed_pvals[(val[0],m)]
  960. except KeyError:
  961. # If it has not been, then compute the p-value and store it.
  962. # if(k > (m*n/N)):
  963. pval_results[key] = hypergeom.sf(k-1,N,n,m)
  964. # while k <= max_k:
  965. # pval_results[key] += hypergeom.pmf(k,N,n,m)
  966. # k += 1
  967. if(pval_results[key] < correction):
  968. #print(pval_results[key])
  969. writer.write(str(key[0])+','+str(key[1])+','+str(key[2])+','+str(key[3])+',')
  970. writer.write(str(val[0]) + ',' + str(m) + ',' + str(pval_results[key]) + '\n')
  971. # We do not care about interval pairs that have unusually low
  972. # number of interacting pairs
  973. #else:
  974. # while k >= min_k:
  975. # pval_results[key] += hypergeom.pmf(k, N, n, m)
  976. # k -= 1
  977. computed_pvals[(val[0],m)] = pval_results[key]
  978. # i += 1
  979. # if(i%1000 == 0):
  980. # print(i)
  981. # print(len(computed_pvals))
  982. print("Computed p-values.")
  983. # now = datetime.now()
  984. # current_time = now.strftime("%H:%M:%S")
  985. # print("Current Time =", current_time)
  986. return pval_results
  987. def trim_intervals(sorted_intervals:list):
  988. # Now go through interval pairs starting from most significant, and remove all overlapping
  989. # intervals for the current interval
  990. outer_count = 0
  991. indeces_to_delete = set()
  992. for tup in sorted_intervals:
  993. # Skip this interval pair if it is already marked for delition
  994. if(outer_count in indeces_to_delete):
  995. outer_count += 1
  996. #print('SKIPPED!')
  997. continue
  998. inner_count = 0
  999. curr_tup = tup
  1000. i,j,a,b = curr_tup[0][0],curr_tup[0][1],curr_tup[0][2],curr_tup[0][3]
  1001. pval_outer = curr_tup[1]
  1002. for tup in sorted_intervals:
  1003. if(inner_count in indeces_to_delete):
  1004. inner_count += 1
  1005. #print('SKIPPED!')
  1006. continue
  1007. i2,j2,a2,b2 = tup[0][0],tup[0][1],tup[0][2],tup[0][3]
  1008. pval_inner = tup[1]
  1009. #print(i,j,a,b)
  1010. #print(i2,j2,a2,b2)
  1011. if(check_overlap(i,j,a,b,i2,j2,a2,b2)):
  1012. if(pval_inner < pval_outer):
  1013. indeces_to_delete.add(outer_count)
  1014. else:
  1015. indeces_to_delete.add(inner_count)
  1016. #print("bye!")
  1017. inner_count += 1
  1018. outer_count += 1
  1019. #print(indeces_to_delete)
  1020. culled_inter_pairs = []
  1021. i = 0
  1022. while i < len(sorted_intervals):
  1023. if(i not in indeces_to_delete):
  1024. culled_inter_pairs.append(sorted_intervals[i])
  1025. i += 1
  1026. return culled_inter_pairs
  1027. class TestBiClusterCodeBase(unittest.TestCase):
  1028. def test_get_msigdb_enrichment(self):
  1029. gene_pairs = {('ABAT', 'ACOX1'), ('CSMD1', 'DLGAP1')}
  1030. out_dir = 'C:/Stas/LabWork/Bioinformatics/Projects/Ch5_AI_AUD/Test/'
  1031. get_msigdb_enrichment(gene_pairs, out_dir)
  1032. fname = out_dir + 'biclustering_results_msigdb_enrichment.txt'
  1033. with open(fname) as msig_fname:
  1034. line = msig_fname.readline()
  1035. exp_line = "('ABAT', 'ACOX1') : ['AFFAR_YY1_TARGETS_UP', "
  1036. exp_line += "'CARRILLOREIXACH_HEPATOBLASTOMA_VS_NORMAL_DN', 'FLECHNER_BIOPSY_KIDNEY_"
  1037. exp_line += "TRANSPLANT_REJECTED_VS_OK_DN', 'LEE_LIVER_CANCER_MYC_TGFA_DN', 'RODRIGUES_"
  1038. exp_line += "DCC_TARGETS_DN', 'RODRIGUES_THYROID_CARCINOMA_ANAPLASTIC_DN', "
  1039. exp_line += "'RODRIGUES_THYROID_CARCINOMA_POORLY_DIFFERENTIATED_DN']\n"
  1040. self.assertEqual(line, exp_line)
  1041. def test_parse_remma_interaction_data(self):
  1042. indir = 'C:/Stas/LabWork/Bioinformatics/Projects/Ch5_AI_AUD/Test/'
  1043. ad_anno = indir + 'epiAD_ad_NA3_Combined_Strict_Set_Brief.anno'
  1044. dd_anno = indir + 'epiDD_dd_NA3_Combined_Strict_Set_Brief.anno'
  1045. interactions = parse_remma_interaction_data([ad_anno, dd_anno], 1e-6, '1', '20')
  1046. self.assertEqual(len(interactions), 7)
  1047. self.assertEqual(interactions[('1:7863293', '20:8515243')], 3.0037315721644386e-07)
  1048. self.assertEqual(interactions[('1:7863293', '20:8515956')], 3.0037315721644386e-07)
  1049. self.assertEqual(interactions[('1:7865063', '20:33467717')], 8.801979806253102e-07)
  1050. self.assertEqual(interactions[('1:7865063', '20:33488013')], 7.014568812762179e-07)
  1051. self.assertEqual(interactions[('1:7865063', '20:33514465')], 7.070270435022684e-07)
  1052. self.assertEqual(interactions[('1:7865691', '20:33488013')], 9.85547891823227e-09)
  1053. self.assertEqual(interactions[('1:1725760', '20:9588420')], 7.018367391361476e-07)
  1054. def test_get_number_of_interacting_snps_in_interval(self):
  1055. indir = 'C:/Stas/LabWork/Bioinformatics/Projects/Ch5_AI_AUD/Test/'
  1056. biclustering_file = indir + 'biclustering_results_chr1_chr5.txt'
  1057. bim_file = indir + 'NA3_Combined_Strict_Set_score900_db001_or_exp001_1_and_genehancer_score10_maf001_region_qc3.bim'
  1058. gene_location_file = indir + 'Combined_Strict_Set_score900_db001_or_exp001_1_and_genehancer_score10_ranges.txt'
  1059. marker_files = [indir + 'epiDD_dd_NA3_Combined_Strict_Set.anno']
  1060. inter_pairs_per_interval = get_number_of_interacting_snps_in_interval(biclustering_file, bim_file, gene_location_file,
  1061. '1', '5', marker_files, 1e-7)
  1062. self.assertEqual(inter_pairs_per_interval[('LHX4 ', 'PPP2R2B ')], 12)
  1063. self.assertEqual(inter_pairs_per_interval[('DISC1 ', 'SLIT3 ')], 5)
  1064. def test_parse_biclustering_results(self):
  1065. indir = 'C:/Stas/LabWork/Bioinformatics/Projects/Ch5_AI_AUD/REMMA_Results/'
  1066. marker_file1 = 'epiAA_aa1_approx_parallel_merged_NA3_Combined_Strict_Set_score900_db001_or_exp001_1_and_genehancer_score10_maf001_region_qc3.anno'
  1067. marker_file2 = 'epiAA_aa2_approx_parallel_merged_NA3_Combined_Strict_Set_score900_db001_or_exp001_1_and_genehancer_score10_maf001_region_qc3.anno'
  1068. marker_file3 = 'epiAA_aa3_approx_parallel_merged_NA3_Combined_Strict_Set_score900_db001_or_exp001_1_and_genehancer_score10_maf001_region_qc3.anno'
  1069. marker_file4 = 'epiAD_ad_approx_parallel_merged_NA3_Combined_Strict_Set_score900_db001_or_exp001_1_and_genehancer_score10_maf001_region_qc3.anno'
  1070. marker_file5 = 'epiDD_dd_approx_parallel_merged_NA3_Combined_Strict_Set_score900_db001_or_exp001_1_and_genehancer_score10_maf001_region_qc3.anno'
  1071. marker_files = [indir + marker_file1, indir + marker_file2, indir + marker_file3, indir + marker_file4, indir + marker_file5]
  1072. indir = 'C:/Stas/LabWork/Bioinformatics/Projects/Ch5_AI_AUD/Test/'
  1073. biclustering_file = indir + 'biclustering_results_chr1_chr3.txt'
  1074. bim_file = indir + 'NA3_Combined_Strict_Set_score900_db001_or_exp001_1_and_genehancer_score10_maf001_region_qc3.bim'
  1075. gene_location_file = indir + 'Combined_Strict_Set_score900_db001_or_exp001_1_and_genehancer_score10_ranges.txt'
  1076. out_dir = indir
  1077. parse_biclustering_results(biclustering_file, bim_file, gene_location_file, '1', '3', marker_files, 1e-7, out_dir, False)
  1078. filename = indir + 'biclustering_results_chr1_chr3_annotated.txt'
  1079. rows = []
  1080. with open(filename) as csv_file:
  1081. csv_reader = csv.reader(csv_file, delimiter='\t')
  1082. for row in csv_reader:
  1083. rows.append(row)
  1084. self.assertEqual(rows[0], ["{('DTL ', 'SRGAP3 ')}", '9.605131888649506e-62'])
  1085. self.assertEqual(rows[1], ["{('DTL ', 'SRGAP3 ')}", '6.4212833992207265e-27'])
  1086. self.assertEqual(rows[2], ["{('SRGAP2 ', 'ROBO2 ')}", '4.0199636843080785e-19'])
  1087. parse_biclustering_results(biclustering_file, bim_file, gene_location_file, '1', '3', marker_files, 1e-7, out_dir, True)
  1088. biclustering_file = indir + 'biclustering_results_chr4_chr10.txt'
  1089. parse_biclustering_results(biclustering_file, bim_file, gene_location_file, '4', '10', marker_files, 1e-7, out_dir, True)
  1090. biclustering_file = indir + 'biclustering_results_chr4_chr5.txt'
  1091. parse_biclustering_results(biclustering_file, bim_file, gene_location_file, '4', '5', marker_files, 1e-7, out_dir, True)
  1092. biclustering_file = indir + 'biclustering_results_chr8_chr17.txt'
  1093. parse_biclustering_results(biclustering_file, bim_file, gene_location_file, '8', '17', marker_files, 1e-7, out_dir, True)
  1094. filename = indir + 'biclustering_results_all.txt'
  1095. rows = []
  1096. with open(filename) as csv_file:
  1097. csv_reader = csv.reader(csv_file, delimiter='\t')
  1098. for row in csv_reader:
  1099. rows.append(row)
  1100. self.assertEqual(rows[0], ['chr1,212206918,212280187,chr3,9020275,9293369,9.605131888649506e-62'])
  1101. self.assertEqual(rows[1], ['chr1,206514199,206639783,chr3,75984644,77701114,4.0199636843080785e-19'])
  1102. self.assertEqual(rows[2], ['chr4,6320304,6567327,chr10,52748910,54060110,2.993577604860245e-295'])
  1103. self.assertEqual(rows[3], ['chr4,88080213,88143674,chr5,145967066,146463083,5.967210373347171e-208'])
  1104. self.assertEqual(rows[4], ['chr4,20253234,20622788,chr5,15498304,15941900,4.7347537763144387e-20'])
  1105. self.assertTrue(['chr8,8957214,8964665,chr17,28519336,28564986,1.1381827143817773e-19'] in rows)
  1106. self.assertTrue(['chr8,8957214,8964665,chr17,28443018,28446019,1.1381827143817773e-19'] in rows)
  1107. os.remove(indir + 'biclustering_results_all.txt')
  1108. def test_generate_gene_blocks(self):
  1109. fname = 'C:/Stas/LabWork/Bioinformatics/Projects/Ch5_AI_AUD/Biclustering/Test_Input/'
  1110. fname += 'Test_Ranges.txt'
  1111. blocks = generate_gene_blocks(fname, 3000)
  1112. expected_blocks = [{'TEST3'}, {'TEST4'}, {'TEST5'}, {'TEST6'}, {'TEST11'}, {'TEST12'},
  1113. {'TEST22'}, {'TEST2', 'TEST1'}, {'TEST9', 'TEST10', 'TEST8', 'TEST7'},
  1114. {'TEST13', 'TEST14', 'TEST16', 'TEST18'},
  1115. {'TEST15', 'TEST19', 'TEST21', 'TEST20', 'TEST17'}]
  1116. self.assertTrue(len(blocks) == len(expected_blocks))
  1117. for block in expected_blocks:
  1118. self.assertTrue(block in blocks)
  1119. blocks = generate_gene_blocks(fname, 200)
  1120. expected_blocks = [{'TEST1'}, {'TEST2'}, {'TEST3'}, {'TEST4'}, {'TEST5'},
  1121. {'TEST6'}, {'TEST8'}, {'TEST9'}, {'TEST11'}, {'TEST12'},
  1122. {'TEST16'}, {'TEST18'}, {'TEST20'}, {'TEST21'}, {'TEST22'},
  1123. {'TEST10', 'TEST7'}, {'TEST13', 'TEST14'},
  1124. {'TEST19', 'TEST15', 'TEST17'}]
  1125. self.assertTrue(len(blocks) == len(expected_blocks))
  1126. for block in expected_blocks:
  1127. self.assertTrue(block in blocks)
  1128. blocks = generate_gene_blocks(fname, 1000)
  1129. expected_blocks = [{'TEST1'}, {'TEST2'}, {'TEST3'}, {'TEST4'}, {'TEST5'}, {'TEST6'},
  1130. {'TEST11'}, {'TEST12'}, {'TEST22'},
  1131. {'TEST9', 'TEST10', 'TEST8', 'TEST7'},
  1132. {'TEST13', 'TEST14', 'TEST18', 'TEST16'},
  1133. {'TEST15', 'TEST19', 'TEST21', 'TEST20', 'TEST17'}]
  1134. self.assertTrue(len(blocks) == len(expected_blocks))
  1135. for block in expected_blocks:
  1136. self.assertTrue(block in blocks)
  1137. def test_check_overlap(self):
  1138. # Simple Cases
  1139. self.assertTrue(check_overlap(166,621,10,40,167,620,9,42))
  1140. self.assertTrue(check_overlap(0,491,36,11,0,491,35,11))
  1141. self.assertTrue(check_overlap(10,10,5,5,5,12,8,5))
  1142. self.assertTrue(check_overlap(0,0,2,2,1,1,2,2))
  1143. self.assertTrue(check_overlap(2,2,3,6,1,1,3,3))
  1144. self.assertFalse(check_overlap(0,0,2,2,3,2,1,1))
  1145. self.assertFalse(check_overlap(0,0,10,10,40,40,2,2))
  1146. # Challenging/Border Cases
  1147. self.assertFalse(check_overlap(0,0,2,2,0,0,2,2))
  1148. self.assertFalse(check_overlap(0,0,2,2,1,2,1,1))
  1149. self.assertFalse(check_overlap(0,0,2,2,2,2,1,1))
  1150. self.assertFalse(check_overlap(2,2,3,6,1,1,1,3))
  1151. def test_initialize_matrices(self):
  1152. total_markers = 10
  1153. fname = 'C:/Stas/LabWork/Bioinformatics/Projects/Ch5_AI_AUD/Biclustering/Test_Input/TenByTen.txt'
  1154. N, n, inter_matrix, upper_tri = initialize_matrices(total_markers, fname)
  1155. inter_matrix_exp = dict()
  1156. i, j = 0, 0
  1157. while i < 10:
  1158. j = 0
  1159. while j < 10:
  1160. inter_matrix_exp[(i,j)] = 0
  1161. j += 1
  1162. i += 1
  1163. inter_matrix_exp[(2,8)] = 1
  1164. inter_matrix_exp[(5,8)] = 1
  1165. inter_matrix_exp[(5,9)] = 1
  1166. self.assertEqual(N, 45)
  1167. self.assertEqual(n, 3)
  1168. self.assertTrue(upper_tri)
  1169. i, j = 0, 0
  1170. while i < 10:
  1171. j = 0
  1172. while j < 10:
  1173. self.assertEqual(inter_matrix[(i,j)], inter_matrix_exp[(i,j)])
  1174. j += 1
  1175. i += 1
  1176. N, n, inter_matrix, upper_tri = initialize_matrices(total_markers, fname, False)
  1177. self.assertEqual(N, 100)
  1178. self.assertEqual(n, 3)
  1179. self.assertFalse(upper_tri)
  1180. i, j = 0, 0
  1181. while i < 10:
  1182. j = 0
  1183. while j < 10:
  1184. self.assertEqual(inter_matrix[(i,j)], inter_matrix_exp[(i,j)])
  1185. j += 1
  1186. i += 1
  1187. def test_initialize_matrices2(self):
  1188. indir = 'C:/Stas/LabWork/Bioinformatics/Projects/Ch5_AI_AUD/Biclustering/Test_Input/'
  1189. bim_file = indir + 'Test_Data.bim'
  1190. inter_file = indir + 'Test_Interaction.anno'
  1191. chrom1 = '1'
  1192. chrom2 = '1'
  1193. N, n, inter_array, upper_tri = initialize_matrices2(bim_file, [inter_file], chrom1, chrom2, 1e-5)
  1194. self.assertEqual(N, 435)
  1195. self.assertEqual(n, 1)
  1196. self.assertTrue(upper_tri)
  1197. expected_inter_array = np.zeros((inter_array.shape[0],inter_array.shape[1]))
  1198. expected_inter_array[12][19] = 1
  1199. i = 0
  1200. while i < inter_array.shape[0]:
  1201. j = 0
  1202. while j < inter_array.shape[1]:
  1203. self.assertEqual(inter_array[i][j], expected_inter_array[i][j])
  1204. j += 1
  1205. i += 1
  1206. indir = 'C:/Stas/LabWork/Bioinformatics/Projects/Ch5_AI_AUD/Biclustering/Test_Input/'
  1207. bim_file = indir + 'Test_Data.bim'
  1208. inter_file = indir + 'Test_Interaction.anno'
  1209. chrom1 = '2'
  1210. chrom2 = '3'
  1211. N, n, inter_array, upper_tri = initialize_matrices2(bim_file, [inter_file], chrom1, chrom2, 1e-5)
  1212. self.assertEqual(N, 900)
  1213. self.assertEqual(n, 5)
  1214. self.assertFalse(upper_tri)
  1215. expected_inter_array = np.zeros((inter_array.shape[0],inter_array.shape[1]))
  1216. for k in [(1,0), (8,11), (10,11), (12,14), (14,14)]:
  1217. expected_inter_array[k[0]][k[1]] = 1
  1218. i = 0
  1219. while i < inter_array.shape[0]:
  1220. j = 0
  1221. while j < inter_array.shape[1]:
  1222. self.assertEqual(inter_array[i][j], expected_inter_array[i][j])
  1223. j += 1
  1224. i += 1
  1225. N, n, inter_array, upper_tri = initialize_matrices2(bim_file, [inter_file], chrom1, chrom2, 1e-6)
  1226. self.assertEqual(N, 900)
  1227. self.assertEqual(n, 1)
  1228. self.assertFalse(upper_tri)
  1229. expected_inter_array = np.zeros((inter_array.shape[0],inter_array.shape[1]))
  1230. for k in [(1,0)]:
  1231. expected_inter_array[k[0]][k[1]] = 1
  1232. i = 0
  1233. while i < inter_array.shape[0]:
  1234. j = 0
  1235. while j < inter_array.shape[1]:
  1236. self.assertEqual(inter_array[i][j], expected_inter_array[i][j])
  1237. j += 1
  1238. i += 1
  1239. chrom1 = '3'
  1240. chrom2 = '2'
  1241. N, n, inter_array, upper_tri = initialize_matrices2(bim_file, [inter_file], chrom1, chrom2, 1e-5)
  1242. self.assertEqual(N, 900)
  1243. self.assertEqual(n, 5)
  1244. self.assertFalse(upper_tri)
  1245. expected_inter_array = np.zeros((inter_array.shape[0],inter_array.shape[1]))
  1246. for k in [(0,1), (11,8), (11,10), (14,12), (14,14)]:
  1247. expected_inter_array[k[0]][k[1]] = 1
  1248. i = 0
  1249. while i < inter_array.shape[0]:
  1250. j = 0
  1251. while j < inter_array.shape[1]:
  1252. self.assertEqual(inter_array[i][j], expected_inter_array[i][j])
  1253. j += 1
  1254. i += 1
  1255. chrom1 = '2'
  1256. chrom2 = '3'
  1257. inter_file2 = indir + 'Test_Interaction2.anno'
  1258. N, n, inter_array, upper_tri = initialize_matrices2(bim_file, [inter_file, inter_file2], chrom1, chrom2, 1e-5)
  1259. self.assertEqual(N, 900)
  1260. self.assertEqual(n, 6)
  1261. self.assertFalse(upper_tri)
  1262. expected_inter_array = np.zeros((inter_array.shape[0],inter_array.shape[1]))
  1263. for k in [(1,0), (8,11), (10,11), (12,14), (14,14), (27, 25)]:
  1264. expected_inter_array[k[0]][k[1]] = 1
  1265. i = 0
  1266. while i < inter_array.shape[0]:
  1267. j = 0
  1268. while j < inter_array.shape[1]:
  1269. self.assertEqual(inter_array[i][j], expected_inter_array[i][j])
  1270. j += 1
  1271. i += 1
  1272. N, n, inter_array, upper_tri = initialize_matrices2(bim_file, [inter_file, inter_file2], chrom1, chrom2, 1e-8)
  1273. self.assertEqual(N, 900)
  1274. self.assertEqual(n, 2)
  1275. self.assertFalse(upper_tri)
  1276. expected_inter_array = np.zeros((inter_array.shape[0],inter_array.shape[1]))
  1277. for k in [(8,11), (27, 25)]:
  1278. expected_inter_array[k[0]][k[1]] = 1
  1279. i = 0
  1280. while i < inter_array.shape[0]:
  1281. j = 0
  1282. while j < inter_array.shape[1]:
  1283. self.assertEqual(inter_array[i][j], expected_inter_array[i][j])
  1284. j += 1
  1285. i += 1
  1286. def test_comp_alt(self):
  1287. inter_matrix = dict()
  1288. i, j = 0, 0
  1289. while i < 10:
  1290. j = 0
  1291. while j < 10:
  1292. inter_matrix[(i,j)] = 0
  1293. j += 1
  1294. i += 1
  1295. inter_matrix[(2,8)] = 1
  1296. inter_matrix[(5,8)] = 1
  1297. inter_matrix[(5,9)] = 1
  1298. inter_array = convert_dict_to_2D_numpy_array(inter_matrix)
  1299. #print(inter_array)
  1300. self.assertEqual(comp_alt(0,0,2,2, inter_array, upper_triangular=True), (0,1))
  1301. self.assertEqual(comp_alt(0,0,2,2, inter_array, upper_triangular=False), (0,4))
  1302. self.assertEqual(comp_alt(0,0,2,4, inter_array, upper_triangular=True), (0,5))
  1303. self.assertEqual(comp_alt(0,0,2,4, inter_array, upper_triangular=False), (0,8))
  1304. self.assertEqual(comp_alt(0,0,3,10, inter_array, upper_triangular=True), (1,24))
  1305. self.assertEqual(comp_alt(0,0,3,10, inter_array, upper_triangular=False), (1,30))
  1306. self.assertEqual(comp_alt(5,0,4,4, inter_array, upper_triangular=True), (0,0))
  1307. self.assertEqual(comp_alt(5,3,4,4, inter_array, upper_triangular=True), (0,1))
  1308. self.assertEqual(comp_alt(5,6,2,4, inter_array, upper_triangular=True), (2,7))
  1309. self.assertEqual(comp_alt(5,8,1,1, inter_array, upper_triangular=True), (1,1))
  1310. self.assertEqual(comp_alt(5,8,1,2, inter_array, upper_triangular=True), (2,2))
  1311. self.assertEqual(comp_alt(5,8,2,1, inter_array, upper_triangular=True), (1,2))
  1312. # Performance testing
  1313. '''
  1314. inter_matrix = dict()
  1315. i, j = 0, 0
  1316. while i < 2000:
  1317. j = 0
  1318. while j < 2000:
  1319. inter_matrix[(i,j)] = 0
  1320. j += 1
  1321. i += 1
  1322. inter_matrix[(2,8)] = 1
  1323. inter_matrix[(5,8)] = 1
  1324. inter_matrix[(5,9)] = 1
  1325. inter_array = convert_dict_to_2D_numpy_array(inter_matrix)
  1326. start = time.time()
  1327. self.assertEqual(comp_alt(0,0,1850,1900, inter_array, upper_triangular = False), (3, 3515000))
  1328. print(time.time()-start)
  1329. '''
  1330. def test_compute_k_m_parallel(self):
  1331. inter_array = np.zeros((10,10))
  1332. for k in [(2,8), (5,8), (5,9)]:
  1333. inter_array[k[0]][k[1]] = 1
  1334. # Note, technically, the last parameter should be 3, but we enter 0
  1335. # to force all k,m pairs to be written.
  1336. km_results = compute_k_m_parallel(4, inter_array, True, 0, 9, 45, 0)
  1337. self.assertEqual(km_results[(0,5,4,4)], (1,16))
  1338. self.assertEqual(km_results[(0,8,3,1)], (1,3))
  1339. self.assertEqual(km_results[(1,7,2,2)], (1,4))
  1340. self.assertEqual(km_results[(2,5,4,4)], (2,15))
  1341. self.assertEqual(km_results[(2,8,4,2)], (3,8))
  1342. self.assertEqual(km_results[(4,7,3,3)], (2,9))
  1343. self.assertEqual(km_results[(5,5,4,4)], (1,6))
  1344. self.assertEqual(km_results[(5,5,3,4)], (1,6))
  1345. self.assertEqual(km_results[(5,5,2,4)], (1,5))
  1346. self.assertEqual(km_results[(5,5,1,4)], (1,3))
  1347. self.assertEqual(km_results[(5,6,4,4)], (2,10))
  1348. self.assertEqual(km_results[(5,6,4,3)], (1,6))
  1349. self.assertEqual(km_results[(5,6,3,4)], (2,9))
  1350. self.assertEqual(km_results[(5,6,3,4)], (2,9))
  1351. self.assertEqual(km_results[(5,6,3,4)], (2,9))
  1352. self.assertEqual(km_results[(5,6,3,3)], (1,6))
  1353. self.assertEqual(km_results[(5,6,2,4)], (2,7))
  1354. self.assertEqual(km_results[(5,6,3,4)], (2,9))
  1355. self.assertEqual(km_results[(5,6,3,4)], (2,9))
  1356. self.assertEqual(km_results[(5,6,3,4)], (2,9))
  1357. self.assertEqual(km_results[(5,6,3,4)], (2,9))
  1358. self.assertEqual(km_results[(5,6,3,4)], (2,9))
  1359. self.assertEqual(km_results[(5,6,3,4)], (2,9))
  1360. self.assertEqual(km_results[(5,6,3,4)], (2,9))
  1361. self.assertEqual(km_results[(5,6,2,4)], (2,7))
  1362. self.assertEqual(km_results[(5,8,1,1)], (1,1))
  1363. self.assertEqual(km_results[(5,8,1,2)], (2,2))
  1364. self.assertEqual(km_results[(5,8,2,1)], (1,2))
  1365. inter_array = np.zeros((10,10))
  1366. for k in [(2,8)]:
  1367. inter_array[k[0]][k[1]] = 1
  1368. # Note, technically, the last parameter should be 1, but we enter 0
  1369. # to force all k,m pairs to be written.
  1370. km_results = compute_k_m_parallel(4, inter_array, True, 0, 9, 45, 0)
  1371. self.assertEqual(len(km_results), 63)
  1372. def test_compute_interval_pval_parallel(self):
  1373. inter_array = np.zeros((10,10))
  1374. for k in [(2,8), (5,8), (5,9)]:
  1375. inter_array[k[0]][k[1]] = 1
  1376. # Note, technically, the last parameter should be 3, but we enter 0
  1377. # to force all k,m pairs to be written.
  1378. km_results = compute_k_m_parallel(4, inter_array, True, 0, 9, 45, 0)
  1379. out_dir = 'C:/Stas/LabWork/Bioinformatics/Projects/Ch5_AI_AUD/Biclustering/Test_Output/'
  1380. pval_results = compute_interval_pval_parallel(km_results, 45, 3, 0, 9, 4, out_dir)
  1381. #print(pval_results)
  1382. self.assertAlmostEqual(pval_results[(0,5,4,4)], 0.7424947145877379)
  1383. self.assertAlmostEqual(pval_results[(0,8,3,1)], 0.19097956307258637)
  1384. self.assertAlmostEqual(pval_results[(1,7,2,2)], 0.24876673713883019)
  1385. self.assertAlmostEqual(pval_results[(2,5,4,4)], 0.25405214940098664)
  1386. self.assertAlmostEqual(pval_results[(2,8,4,2)], 0.0039464411557434895)
  1387. self.assertAlmostEqual(pval_results[(4,7,3,3)], 0.09725158562367894)
  1388. self.assertAlmostEqual(pval_results[(5,5,4,4)], 0.35595489781536405)
  1389. self.assertAlmostEqual(pval_results[(5,5,3,4)], 0.35595489781536405)
  1390. self.assertAlmostEqual(pval_results[(5,5,2,4)], 0.30373502466525815)
  1391. self.assertAlmostEqual(pval_results[(5,5,1,4)], 0.19097956307258632)
  1392. self.assertAlmostEqual(pval_results[(5,6,4,4)], 0.11945031712473582)
  1393. self.assertAlmostEqual(pval_results[(5,6,4,3)], 0.35595489781536405)
  1394. self.assertAlmostEqual(pval_results[(5,6,3,4)], 0.09725158562367894)
  1395. self.assertAlmostEqual(pval_results[(5,6,3,4)], 0.09725158562367894)
  1396. self.assertAlmostEqual(pval_results[(5,6,3,4)], 0.09725158562367894)
  1397. self.assertAlmostEqual(pval_results[(5,6,3,3)], 0.35595489781536405)
  1398. self.assertAlmostEqual(pval_results[(5,6,2,4)], 0.058703312191684544)
  1399. self.assertAlmostEqual(pval_results[(5,6,3,4)], 0.09725158562367894)
  1400. self.assertAlmostEqual(pval_results[(5,6,3,4)], 0.09725158562367894)
  1401. self.assertAlmostEqual(pval_results[(5,6,3,4)], 0.09725158562367894)
  1402. self.assertAlmostEqual(pval_results[(5,6,3,4)], 0.09725158562367894)
  1403. self.assertAlmostEqual(pval_results[(5,6,3,4)], 0.09725158562367894)
  1404. self.assertAlmostEqual(pval_results[(5,6,3,4)], 0.09725158562367894)
  1405. self.assertAlmostEqual(pval_results[(5,6,3,4)], 0.09725158562367894)
  1406. self.assertAlmostEqual(pval_results[(5,6,2,4)], 0.058703312191684544)
  1407. self.assertAlmostEqual(pval_results[(5,8,1,1)], 0.06666666666666664)
  1408. self.assertAlmostEqual(pval_results[(5,8,1,2)], 0.003030303030303028)
  1409. self.assertAlmostEqual(pval_results[(5,8,2,1)], 0.13030303030303028)
  1410. def test_trim_intervals(self):
  1411. in_dir = 'C:/Stas/LabWork/Bioinformatics/Projects/Ch5_AI_AUD/Biclustering/Test_Input/'
  1412. filename = in_dir + 'pval_results_0_1.csv'
  1413. pval_results = dict()
  1414. with open(filename) as csv_file:
  1415. csv_reader = csv.reader(csv_file, delimiter=',')
  1416. for row in csv_reader:
  1417. pval_results[(int(row[0]),int(row[1]),int(row[2]),int(row[3]))] = float(row[6])
  1418. s_inter_pairs = sorted(pval_results.items(), key = lambda x: abs(x[1]), reverse = False)
  1419. #print(len(s_inter_pairs))
  1420. #print(s_inter_pairs)
  1421. trimmed_inter_pairs = trim_intervals(s_inter_pairs)
  1422. #print(trimmed_inter_pairs)
  1423. #print(len(trimmed_inter_pairs))
  1424. #print(trimmed_inter_pairs)
  1425. expected_trimmed_inter_pairs = [((0, 816, 48, 8), 2.5317372178516744e-24),
  1426. ((0, 999, 35, 3), 8.785313396735072e-16),
  1427. ((0, 494, 35, 8), 3.520342278584121e-15)]
  1428. i = 0
  1429. for inter_pair in trimmed_inter_pairs:
  1430. self.assertEqual(inter_pair, expected_trimmed_inter_pairs[i])
  1431. i += 1
  1432. # COMPLETE THIS TEST CASE
  1433. filename = in_dir + 'chr1_chr2_pval_results.csv'
  1434. pval_results = dict()
  1435. with open(filename) as csv_file:
  1436. csv_reader = csv.reader(csv_file, delimiter=',')
  1437. for row in csv_reader:
  1438. pval_results[(int(row[0]),int(row[1]),int(row[2]),int(row[3]))] = float(row[6])
  1439. s_inter_pairs = sorted(pval_results.items(), key = lambda x: abs(x[1]), reverse = False)
  1440. trimmed_inter_pairs = trim_intervals(s_inter_pairs)
  1441. #print(trimmed_inter_pairs)
  1442. expected_trimmed_inter_pairs = [((1, 41, 57, 59), 1.5052159828764328e-29),
  1443. ((65, 53, 35, 47), 5.109419105661788e-22),
  1444. ((45, 1, 55, 33), 1.5051851637750398e-21)]
  1445. i = 0
  1446. for inter_pair in trimmed_inter_pairs:
  1447. self.assertEqual(inter_pair, expected_trimmed_inter_pairs[i])
  1448. i += 1
  1449. def test_convert_dict_to_2D_numpy_array(self):
  1450. tested_inter_matrix = dict()
  1451. i, j = 0, 0
  1452. while i < 10:
  1453. j = 0
  1454. while j < 10:
  1455. if (j > i):
  1456. tested_inter_matrix[(i,j)] = 1
  1457. else:
  1458. tested_inter_matrix[(i,j)] = 0
  1459. j += 1
  1460. i += 1
  1461. array = convert_dict_to_2D_numpy_array(tested_inter_matrix)
  1462. #print(array)
  1463. #for x in np.nditer(array):
  1464. # print(x)
  1465. def test_suite():
  1466. # Unit Tests
  1467. unit_test_suite = unittest.TestSuite()
  1468. unit_test_suite.addTest(TestBiClusterCodeBase('test_initialize_matrices'))
  1469. unit_test_suite.addTest(TestBiClusterCodeBase('test_check_overlap'))
  1470. unit_test_suite.addTest(TestBiClusterCodeBase('test_comp_alt'))
  1471. unit_test_suite.addTest(TestBiClusterCodeBase('test_convert_dict_to_2D_numpy_array'))
  1472. unit_test_suite.addTest(TestBiClusterCodeBase('test_compute_k_m_parallel'))
  1473. unit_test_suite.addTest(TestBiClusterCodeBase('test_compute_interval_pval_parallel'))
  1474. unit_test_suite.addTest(TestBiClusterCodeBase('test_generate_gene_blocks'))
  1475. unit_test_suite.addTest(TestBiClusterCodeBase('test_trim_intervals'))
  1476. unit_test_suite.addTest(TestBiClusterCodeBase('test_initialize_matrices2'))
  1477. unit_test_suite.addTest(TestBiClusterCodeBase('test_parse_biclustering_results'))
  1478. unit_test_suite.addTest(TestBiClusterCodeBase('test_get_number_of_interacting_snps_in_interval'))
  1479. unit_test_suite.addTest(TestBiClusterCodeBase('test_parse_remma_interaction_data'))
  1480. unit_test_suite.addTest(TestBiClusterCodeBase('test_get_msigdb_enrichment'))
  1481. runner = unittest.TextTestRunner()
  1482. runner.run(unit_test_suite)

BiClustering.py at commit effebb8, no license · at the source

Overview

  1. Department of Neuroscience, The Scripps Research Institute, La Jolla, CA USA
Institutions: Scripps Research Institute (United States)
Journal: Communications biology, volume 9, issue 1, article 750
Dates: received 10 March 2025; accepted 21 March 2026; published online 6 April 2026
Type: Research article · Language: English
License: CC BY-NC-ND
Identifiers: DOI 10.1038/s42003-026-09971-7 · PMID 41942605 · PMCID PMC13230857 · OpenAlex W4405907369
Open access: gold, a free copy (OpenAlex)
Status: code verified
Categories: genetics / omics (modality), human (organism), other condition (population)
Methods: Statistics, Smoothing, state filtering, decompositions, Connectivity
Keywords: Diagnostic markers, Addiction, Genome-wide association studies, Quantitative trait
MeSH: Alcoholism*, Epistasis, Genetic*, Genetic Predisposition to Disease*, Female, Genome-Wide Association Study, Humans, Male, Polymorphism, Single Nucleotide (* major topic)
Topic: Genetic Associations and Epidemiology (Genetics, Biochemistry, Genetics and Molecular Biology), according to OpenAlex
Funding: NIAAA NIH HHS (T32 AA007456); U.S. Department of Health & Human Services | NIH | National Institute on Alcohol Abuse and Alcoholism (NIAAA) (T32AA007456); U.S. Department of Health &amp; Human Services | NIH | National Institute on Alcohol Abuse and Alcoholism (T32AA007456); U.S. Department of Health & Human Services | NIH | National Institute on Drug Abuse (NIDA) (DP1DA054373); U.S. Department of Health &amp; Human Services | NIH | National Institute on Drug Abuse (DP1DA054373); NIDA NIH HHS (DP1 DA054373)
Citations: cited by 3 papers (Europe PMC); 90 references in the paper

Abstract

The abstract is not reproduced here: the paper's license (CC BY-NC-ND) does not allow it. Read it in the paper, at the publisher or on Europe PMC.

Repositories

Its files are read in the Code ↔ Paper reader above, with 2 matches between paragraphs and lines of code.

staslist/Biclustering_Epistasis

License: none: the authors keep all their rights
State: the link answers, verified on 29 September 2026
Evidence: files inventoried
Commit: effebb849231932f9d91d26d654dac8b09b13c4d, 8 January 2026
Languages: Python (6)
Size: 38 files, 6 scripts
Software Heritage: not archived
Found in: “Code availability”
Holds: README
Not found: license file, CITATION.cff, environment file, tests, continuous integration, documentation
Tools: NumPy (2 files), Matplotlib (1 file), Numba (1 file), SciPy (1 file)
Availability: 1 check, the latest on 29 September 2026: the link answers
  • 29 September 2026: the link answers
7 files

njdjyxz/geno-bicluster

License: none: the authors keep all their rights
State: the link answers, verified on 29 September 2026
Evidence: files inventoried
Commit: b0fb2f378c52280c258ea09a640f4aa47a86aa7a, 10 October 2025
Languages: Python (6)
Size: 8 files, 6 scripts
Software Heritage: not archived
Found in: “Code availability”
Holds: README, environment (pyproject.toml), tests
Not found: license file, CITATION.cff, continuous integration, documentation
Tools: Numba (4 files), NumPy (4 files), SciPy (4 files), pandas (1 file)
Availability: 1 check, the latest on 29 September 2026: the link answers
  • 29 September 2026: the link answers
7 files

Zenodo 18960797

License: CC-BY-4.0
State: the link answers, verified on 29 September 2026
Evidence: files inventoried
Size: 2 files
Software Heritage: not checked
Found in: “Code availability”
Not found: README, license file, CITATION.cff, environment file, tests, continuous integration, documentation
Tools: NumPy (6 files), Numba (5 files), SciPy (5 files), Matplotlib (1 file), pandas (1 file)
Availability: 1 check, the latest on 29 September 2026: the link answers (HTTP 200)
  • 29 September 2026: the link answers (HTTP 200)
14 files
At the source:

Zenodo 18961359

License: CC-BY-4.0
State: the link answers, verified on 29 September 2026
Evidence: files inventoried
Size: 2 files
Software Heritage: not checked
Found in: the references
Not found: README, license file, CITATION.cff, environment file, tests, continuous integration, documentation
Tools: NumPy (6 files), Numba (5 files), SciPy (5 files), Matplotlib (1 file), pandas (1 file)
Availability: 1 check, the latest on 29 September 2026: the link answers (HTTP 200)
  • 29 September 2026: the link answers (HTTP 200)
14 files
At the source:

Code availability statement

The paper has a code availability statement. Its license (CC BY-NC-ND) does not allow reproducing it here; in short, from what the harvester recognized in it:

Read it in the paper: doi.org/10.1038/s42003-026-09971-7.

Tracing map

Proposed by the machine: these links were found in the paper and verified at the source, without human review. The map will receive a Zenodo DOI once one of the paper's authors has validated it with their ORCID.

What the map holds:

  • 4 repositories of the authors' code, each at its verified commit, with its license and how the link was found in the paper;
  • 36 scripts, each with its path and the digest of its content;
  • 2 matches between paragraphs of the paper and lines of the code (method lexical-v1);
  • neither the text of the paper nor the code itself.

Its JSON (tracing-map.json) is deposited on Zenodo with its DOI once the map is validated.

Data

No dataset and no data link were found in the paper.

Data availability statement

The paper has a data availability statement. Its license (CC BY-NC-ND) does not allow reproducing it here; in short, from what the harvester recognized in it:

  • it says that the data are available on request

Read it in the paper: doi.org/10.1038/s42003-026-09971-7.

Versions

The history of this record: each version stored by the harvester or made by a correction of its authors or of the maintainers of its code, and what changed in its facts. The texts of the paper (its abstract, its availability statements) are not part of it; versions that changed only those are not listed.

Version 1, 29 September 2026: the first record

Recorded: type, language, journal, volume, issue, pages, dates, 2 authors, 4 keywords, 8 MeSH terms, 6 funders, 88 references.

Cite

This paper

Listopad, S., & Peng, Q. (2026). Extensive genetic interactions (epistasis) linked to alcohol use disorder in a high-risk population. Communications biology, 9(1), 750. https://doi.org/10.1038/s42003-026-09971-7

BibTeX

@article{listopad2026extensive,
author = {Listopad, Stanislav and Peng, Qian},
title = {{Extensive genetic interactions (epistasis) linked to alcohol use disorder in a high-risk population}},
journal = {Communications biology},
year = {2026},
month = apr,
volume = {9},
number = {1},
pages = {750},
publisher = {Nature Publishing Group},
issn = {2399-3642},
doi = {10.1038/s42003-026-09971-7},
url = {https://doi.org/10.1038/s42003-026-09971-7},
pmid = {41942605},
pmcid = {PMC13230857}
}

RIS

TY - JOUR
AU - Listopad, Stanislav
AU - Peng, Qian
TI - Extensive genetic interactions (epistasis) linked to alcohol use disorder in a high-risk population
T2 - Communications biology
J2 - Commun Biol
PY - 2026
DA - 2026/04/06
VL - 9
IS - 1
SP - 750
SN - 2399-3642
PB - Nature Publishing Group
DO - 10.1038/s42003-026-09971-7
UR - https://doi.org/10.1038/s42003-026-09971-7
LA - en
ER -

CSL-JSON

{
"id": "10.1038/s42003-026-09971-7",
"type": "article-journal",
"title": "Extensive genetic interactions (epistasis) linked to alcohol use disorder in a high-risk population",
"container-title": "Communications biology",
"author": [
{
"family": "Listopad",
"given": "Stanislav"
},
{
"family": "Peng",
"given": "Qian"
}
],
"container-title-short": "Commun Biol",
"volume": "9",
"issue": "1",
"page": "750",
"DOI": "10.1038/s42003-026-09971-7",
"PMID": "41942605",
"PMCID": "PMC13230857",
"ISSN": "2399-3642",
"publisher": "Nature Publishing Group",
"URL": "https://doi.org/10.1038/s42003-026-09971-7",
"language": "en",
"issued": {
"date-parts": [
[
2026,
4,
6
]
]
}
}

The tracing map gets a citation of its own once an author has validated it and it has a DOI.

Similar papers

The papers with a page that share the most with this one: the tools found in their code, their categories, datasets, cited references and authors, the rarest counting most.

[1] doi:10.1002/gps3.70017 [code]
Shared genetic variants across substance use disorders implicate common neurobiological pathways, a genome-wide mixed methods study.
Journal: General psychiatry
In common: pandas, SciPy, Matplotlib, 1 other tool, genetics / omics, other condition, 3 references
[2] doi:10.1038/s43856-026-01510-z [code]
Mapping genetic convergence across brain structure, mental health, and cardiometabolic disease.
Journal: Communications medicine
In common: Numba, pandas, SciPy, 2 other tools, genetics / omics, other condition, 2 references
[3] doi:10.1016/j.xcrm.2026.102766 [code]
A longitudinal single-cell and spatial multiomic atlas of pediatric high-grade glioma.
Journal: Cell reports. Medicine
In common: Numba, pandas, SciPy, 2 other tools, genetics / omics, other condition, 1 reference
[4] doi:10.1038/s41467-026-71803-3 [code]
Charting the transition from in vitro gliogenesis to the in vivo maturation of human glial progenitor cells transplanted into the hypomyelinated mouse brain.
Journal: Nature communications
In common: Numba, pandas, SciPy, 2 other tools, genetics / omics, 1 reference
[5] doi:10.1038/s41467-026-76676-0 [code]
Determinants of functional burden pleiotropy and gene dosage responses across human traits.
Journal: Nature communications
In common: Numba, pandas, SciPy, 2 other tools, genetics / omics, 1 reference
[6] doi:10.1038/s41398-026-04137-9 [code]
An integrative mendelian randomisation and drug mechanism framework for target prioritisation and therapeutic repurposing in major depression.
Journal: Translational psychiatry
In common: Numba, pandas, SciPy, 2 other tools, genetics / omics, 1 reference
[7] doi:10.1038/s41514-026-00391-9 [code]
Region-specific transcriptional signatures of brain aging in the absence of neuropathology at the single-cell level.
Journal: npj aging
In common: Numba, pandas, SciPy, 2 other tools, genetics / omics, 1 reference
[8] doi:10.1038/s41467-026-73996-z [code]
Genetic architecture of white matter microstructure captured by unsupervised deep representation learning of fractional anisotropy maps.
Journal: Nature communications
In common: pandas, SciPy, Matplotlib, 1 other tool, genetics / omics, 2 references
[9] doi:10.1038/s41467-026-71682-8 [code]
GWAS meta-analysis of cerebrospinal fluid Alzheimer's biomarkers reveals loci regulating lipids, brain volume and autophagy.
Journal: Nature communications
In common: pandas, SciPy, NumPy, genetics / omics, 3 references
[10] doi:10.1016/j.xgen.2026.101284 [code]
NERINE reveals rare variant associations in gene networks across phenotypes and implicates an SNCA-PRL-LRRK2 subnetwork in Parkinson's disease.
Journal: Cell genomics
In common: pandas, SciPy, Matplotlib, 1 other tool, other condition, 2 references

Contribute

The authors of this paper can claim it, correct its record and validate its tracing map, and the maintainers of its code (its owner, or a public member of its organization) correct what it says of their repository; anyone signed in can ask for its removal. Every request goes to OSCR's own machine, which answers it; your account page follows them.

Sign in with ORCID to claim this paper as one of its authors, correct its record or validate its tracing map: when the paper's metadata lists your ORCID iD, you are recognized at once. Maintainers of its code: sign in with GitHub, then claim the repository on your account page.

Request its removal

To ask OSCR to remove this record, the copies of its authors' scripts or its tracing map, use the removal request page: signed in, you say who you are, what to remove and why, then review and confirm the request. Published rules decide every request (how).

Discussion, reproductions, activity

Discussion: questions and error reports about this paper and its code, from signed-in readers and its authors. It opens with sign-in.

Reproductions: reports from readers who ran the authors' code: what they reproduced, with which environment, commit and data. It opens with sign-in.

Activity: what happens around this paper: new versions of its record, its map's validation, discussions and reproductions. It opens with sign-in.