Mercurial > repos > glogobyte > isoread
view mirbase_functions.py @ 39:1bfac419081d draft default tip
Uploaded
author | glogobyte |
---|---|
date | Tue, 17 Oct 2023 09:02:24 +0000 |
parents | |
children |
line wrap: on
line source
import itertools import re import urllib.request import gzip import copy from collections import OrderedDict # Read a file and return it as a list def read(path, flag): if flag == 0: with open(path) as fp: file=fp.readlines() fp.close() return file if flag == 1: with open(path) as fp: file = fp.read().splitlines() fp.close() return file # Write a list to a txt file def write(path, list): with open(path,'w') as fp: for x in list: fp.write(str("\t".join(x[1:-1]))) fp.close() #################################################################################################################> # Detect the longest common substring sequence between two mirnas def longestSubstring(str1, str2): from difflib import SequenceMatcher # initialize SequenceMatcher object with # input string seqMatch = SequenceMatcher(None, str1, str2) # find match of longest sub-string # output will be like Match(a=0, b=0, size=5) match = seqMatch.find_longest_match(0, len(str1), 0, len(str2)) # print longest substring if (match.size != 0): return str1[match.a: match.a + match.size] else: print('No longest common sub-string found') ################################################################################################################################################################################################################# """ This function concatenates miRNAs which are generated from different chromosomes and eliminates the duplications of miRNAs on every sample input: detected miRNAs output: collpased miRNAs without duplicates """ def remove_duplicates(mirnas): # Detection of canonical mirRNAs whicha are generated from different chromosomes dupes=[[x[9],x[0],x[2]] for x in mirnas] for x in mirnas: for y in dupes: if x[9] == y[0] and x[0] == y[1] and x[2].split("_")[0] == y[2].split("_")[0] and x[2] != y[2]: y.append(x[2]) # Detection of different chromosomes for every miRNA chr_order = [] for x in dupes: temp = [] for i in range(2,len(x)): if x[i].split("chr")[1].split("(")[0].isdigit(): temp.append(int(x[i].split("chr")[1].split("(")[1][0]+x[i].split("chr")[1].split("(")[0])) else: temp.append(x[i].split("chr")[1][0:4]) for z in temp: if 'X(-)'==z or 'Y(-)'==z or 'X(+)'==z or 'Y(+)'==z: temp = [str(j) for j in temp] temp = list(set(temp)) temp.sort() chr_order.append(temp) # Collapsing the miRNAs with the same sequence from different chromosomes collapsed_dupes=[] for i in range(len(dupes)): collapsed_dupes.append([dupes[i][0],dupes[i][2].split("_")[0],dupes[i][1]]) for x in chr_order[i]: chr_check = re.match("[-+]?\d+$", str(x)) # check if chromosome is 'X' or 'Y' if chr_check is not None: if int(x)<0: # Check the strand (+) or (-) collapsed_dupes[i][1]= collapsed_dupes[i][1]+"_chr"+str(abs(int(x)))+"(-)" else: collapsed_dupes[i][1] = collapsed_dupes[i][1] + "_chr" + str(abs(int(x)))+"(+)" else: collapsed_dupes[i][1] = collapsed_dupes[i][1] + "_chr" + str(x) # Remove duplicates from collapsed_dupes collapsed_dupes.sort() collapsed_dupes = list(collapsed_dupes for collapsed_dupes,_ in itertools.groupby(collapsed_dupes)) for i in range(len(mirnas)): for x in collapsed_dupes: # Naming of template isomirs (adding positions in the names) if mirnas[i][9] == x[0] and mirnas[i][0] == x[2] and len(mirnas[i][2].split("_")) >3 and mirnas[i][2].split("_")[0]==x[1].split("_")[0]: gg=str("_t_"+mirnas[i][2].split("_")[-2]+"_"+mirnas[i][2].split("_")[-1]) mirnas[i][2] = x[1]+gg break # Naming of canonical miRNAs (collpsed names) if mirnas[i][9]==x[0] and mirnas[i][0]== x[2] and len(mirnas[i][2].split("_"))==3 and mirnas[i][2].split("_")[0]==x[1].split("_")[0]: mirnas[i][2] = x[1] break # Remove duplicates mirnas.sort() mirnas=list(mirnas for mirnas,_ in itertools.groupby(mirnas)) return mirnas ############################################################################################################################################################################################################# """ This function indentifies and classifies the miRNAs which are detected from the alignment tool. """ def sam_edit(mature_mirnas,path,file,case,l,samples,data,file_order,unmap_seq,names_n_seqs,deseq,mirna_names,ini_sample,unmap_counts): # read the sam file ini_sam=read(path,0) main_sam = [x.rstrip("\n").split("\t") for x in ini_sam if "@" not in x.split("\t")[0]] # remove introduction unique_seq = [x for x in main_sam if x[1] == '0' and len(x[9])>=18 and len(x[9])<=26] # keeps only the functional miRNAs filter_sam = [[x[0],x[1],x[2],len(x[9])] for x in main_sam] # keeps only the necessary info of miRNAs from sam files (name, sequence, counts, etc) sorted_uni_arms = [] for i in range(0,len(mature_mirnas,),2): tmp_count_reads = 0 # calculate the total number of reads tmp_count_seq = 0 # calculate the total number of sequences for j in range(len(unique_seq)): if "{" in unique_seq[j][2].split("_")[0]: # checks if a miRNA is generated from two different locis on the same chromosome mirna=unique_seq[j][2].split("_")[0][:-4] else: mirna=unique_seq[j][2].split("_")[0] # Detection of differences between the canonical miRNA and the detected miRNA if mature_mirnas[i].split(" ")[0][1:] == mirna: temp_mature = mature_mirnas[i+1].strip().replace("U", "T") off_part = longestSubstring(temp_mature, unique_seq[j][9]) mat_diff = temp_mature.split(off_part) mat_diff = [len(mat_diff[0]), len(mat_diff[1])] unique_diff = unique_seq[j][9].split(off_part) unique_diff = [len(unique_diff[0]), len(unique_diff[1])] # Handling of some special mirnas like (hsa-miR-8485) if mat_diff[1]!=0 and unique_diff[1]!=0: unique_seq[j]=1 pre_pos = 0 post_pos = 0 elif mat_diff[0]!=0 and unique_diff[0]!=0: unique_seq[j]=1 pre_pos = 0 post_pos = 0 else: # Keep the findings pre_pos = mat_diff[0]-unique_diff[0] post_pos = unique_diff[1]-mat_diff[1] tmp_count_reads = tmp_count_reads + int(unique_seq[j][0].split("-")[1]) tmp_count_seq = tmp_count_seq+1 # Store the detected miRNAs with new names according to the findings if pre_pos != 0 or post_pos != 0: if pre_pos == 0: unique_seq[j][2] = unique_seq[j][2].split("_")[0]+"_"+unique_seq[j][2].split("_")[2]+ "_t_" +str(pre_pos) + "_" + '{:+d}'.format(post_pos) elif post_pos == 0: unique_seq[j][2] = unique_seq[j][2].split("_")[0]+"_"+unique_seq[j][2].split("_")[2] + "_t_" + '{:+d}'.format(pre_pos) + "_" + str(post_pos) else: unique_seq[j][2] = unique_seq[j][2].split("_")[0]+"_"+unique_seq[j][2].split("_")[2]+"_t_"+'{:+d}'.format(pre_pos)+"_"+'{:+d}'.format(post_pos) # Remove the values "1" from the handling of special mirnas (hsa-miR-8485) for x in range(unique_seq.count(1)): unique_seq.remove(1) # metrics for the production of database if tmp_count_reads != 0 and tmp_count_seq != 0: sorted_uni_arms.append([mature_mirnas[i].split(" ")[0][1:], tmp_count_seq, tmp_count_reads]) # Sorting of the metrics for database sorted_uni_arms = sorted(sorted_uni_arms, key=lambda x: x[1], reverse=True) # Collapsing of miRNAs and removing of duplicates collapsed_mirnas = remove_duplicates(unique_seq) # Correction of metrics due to the collapsing and removing of duplicates for the production of Database for y in sorted_uni_arms: counts=0 seqs=0 for x in collapsed_mirnas: if y[0] in x[2].split("_")[0]: counts+=int(x[0].split("-")[1]) seqs+=1 y[1]=seqs y[2]=counts # Output variables temp_mirna_names=[] l.acquire() if case == "c" or case == "t": temp_mirna_names.extend(z[2] for z in collapsed_mirnas) names_n_seqs.extend([[y[2],y[9]] for y in collapsed_mirnas]) deseq.append([[x[2], x[0].split('-')[1], x[9]] for x in collapsed_mirnas]) mirna_names.extend(temp_mirna_names) unmap_seq.value += sum([1 for x in main_sam if x[1] == '4']) # Keeps the unmap unique sequences for the production of a graph unmap_counts.value += sum([int(x[0].split("-")[1]) for x in main_sam if x[1] == '4']) # Keeps the unmap counts of sequences for the production of a graph file_order.append(file) #Keeps the names of SAM files with the order of reading by the fuction (avoid problems due to multiprocesssing) samples.append(collapsed_mirnas) # return the processed detected miRNAs data.append([case,file,collapsed_mirnas,sorted_uni_arms]) ini_sample.append(filter_sam) # returns the filtered sam file l.release() ###################################################################################################################################### """ Read a sam file from Bowtie and do the followings: 1) Remove reverse stranded mapped reads 2) Remove unmapped reads 3) Remove all sequences with reads less than 11 reads 4) Sort the arms with the most sequences in decreading rate 5) Sort the sequences of every arm with the most reads in decreasing rate 6) Calculate total number of sequences of every arm 7) Calculate total number of reads of sequences of every arm. 8) Store all the informations in a txt file """ def non_sam_edit(mature_mirnas,path,file,case,l,data,file_order,n_deseq,names_n_seqs): # read the sam file ini_sam=read(path,0) main_sam = [x.rstrip("\n").split("\t") for x in ini_sam if "@" not in x.split("\t")[0]] unique_seq=[] unique_seq = [x for x in main_sam if x[1] == '4' and len(x[9])>=18 and len(x[9])<=26] uni_seq=[] # Calculate the shifted positions for every non template mirna and add them to the name of it sorted_uni_arms = [] for i in range(1,len(mature_mirnas),2): tmp_count_reads = 0 # calculate the total number of reads tmp_count_seq = 0 # calculate the total number of sequences for j in range(len(unique_seq)): temp_mature = mature_mirnas[i].strip().replace("U", "T") # Detection of differences between the canonical miRNA and the detected non template miRNA if temp_mature in unique_seq[j][9]: off_part = longestSubstring(temp_mature, unique_seq[j][9]) mat_diff = temp_mature.split(off_part) mat_diff = [len(mat_diff[0]), len(mat_diff[1])] unique_diff = unique_seq[j][9].split(off_part) if len(unique_diff)<=2: unique_diff = [len(unique_diff[0]), len(unique_diff[1])] pre_pos = mat_diff[0]-unique_diff[0] post_pos = unique_diff[1]-mat_diff[1] lengthofmir = len(off_part) + post_pos if pre_pos == 0 and post_pos<4: tmp_count_reads = tmp_count_reads + int(unique_seq[j][0].split("-")[1]) tmp_count_seq = tmp_count_seq + 1 t_name=unique_seq[j].copy() t_name[2]=mature_mirnas[i - 1].split(" ")[0][1:] + "_nont_" + str(pre_pos) + "_" + '{:+d}'.format(post_pos) + "_" + str(unique_seq[j][9][len(off_part):]) uni_seq.append(t_name) # metrics for the production of database if tmp_count_reads != 0 and tmp_count_seq != 0: sorted_uni_arms.append([mature_mirnas[i-1].split(" ")[0][1:], tmp_count_seq, tmp_count_reads]) sorted_uni_arms = sorted(sorted_uni_arms, key=lambda x: x[1], reverse=True) unique_seq = list(map(list, OrderedDict.fromkeys(map(tuple,uni_seq)))) # Output variables l.acquire() if case=="c" or case=="t": names_n_seqs.extend([[y[2],y[9]] for y in unique_seq if y[2]!="*"]) n_deseq.append([[x[2], x[0].split('-')[1], x[9]] for x in unique_seq if x[2]!="*"]) file_order.append(file) data.append([case,file,unique_seq,sorted_uni_arms]) l.release() ################################################################################################################################################################################################################# def black_white(mirna_names_1,mirna_names_2,group,manager): add_names = [x for x in mirna_names_1 if x not in mirna_names_2] add_names.sort() add_names = list(add_names for add_names,_ in itertools.groupby(add_names)) group.sort() group = list(group for group,_ in itertools.groupby(group)) zeros=["0"]*(len(group[0])-2) [add_names[i].extend(zeros) for i,_ in enumerate(add_names)] group=group+add_names manager.extend(group) ################################################################################################################################################################################################################################ def merging_dupes(group,f_dupes): dupes=[] final_mat =[] for num,_ in enumerate(group): if group[num][1] not in final_mat and group[num][0] not in final_mat: final_mat.append(group[num][1]) final_mat.append(group[num][0]) else: dupes.append(group[num][1]) dupes=list(set(dupes)) dupes=[[x] for x in dupes] for x in group: for y in dupes: if x[1]==y[0]: fl=0 if len(y)==1: y.append(x[0]) else: for i in range(1,len(y)): if y[i].split("_")[0]==x[0].split("_")[0]: fl=1 if len(x[0])<len(y[i]): del y[i] y.append(x[0]) break if fl==0: y.append((x[0])) for y in dupes: if len(y)>2: for i in range(len(y)-1,1,-1): y[1]=y[1]+"/"+y[i] del y[i] f_dupes.extend(dupes) ########################################################################################################################################################################################################################################## def apply_merging_dupes(group,dupes,managger): for x in group: for y in dupes: if x[1]==y[0]: x[0]=y[1] group.sort() group=list(group for group,_ in itertools.groupby(group)) managger.extend(group) ############################################################################################################################################################################################################################### def filter_low_counts(c_group,t_group,fil_c_group,fil_t_group,per,counts): t_group_new=[] c_group_new=[] percent=int(per)/100 c_col_filter=round(percent*(len(c_group[1])-2)) t_col_filter=round(percent*(len(t_group[1])-2)) for i, _ in enumerate(c_group): c_cols=0 t_cols=0 c_cols=sum([1 for j in range(len(c_group[i])-2) if int(c_group[i][j+2])>=int(counts)]) t_cols=sum([1 for j in range(len(t_group[i])-2) if int(t_group[i][j+2])>=int(counts)]) if c_cols>=c_col_filter or t_cols>=t_col_filter: t_group_new.append(t_group[i]) c_group_new.append(c_group[i]) fil_c_group.extend(c_group_new) fil_t_group.extend(t_group_new) ################################################################################################################################################################################################################## def write_main(raw_con, raw_tre, fil_con, fil_tre, con_file_order, tre_file_order, flag, group_name1, group_name2, per): if flag == 1 and int(per)!=-1: fp = open('Counts/Filtered '+group_name2 +' Templated Counts', 'w') fp.write("Name\t") fp.write("Sequence") for y in tre_file_order: fp.write("\t"+y) for x in fil_tre: fp.write("\n%s" % "\t".join(x)) fp.close() fp = open('Counts/Filtered '+group_name1+' Templated Counts', 'w') fp.write("Name\t") fp.write("Sequence") for y in con_file_order: fp.write("\t"+y) for x in fil_con: fp.write("\n%s" % "\t".join(x)) fp.close() if flag == 2 and int(per)!=-1: fp = open('Counts/Filtered '+group_name2+' Non-Templated Counts', 'w') fp.write("Name\t") fp.write("Sequence") for y in tre_file_order: fp.write("\t"+y) for x in fil_tre: fp.write("\n%s" % "\t".join(x)) fp.close() fp = open('Counts/Filtered '+group_name1+' Non-Templated Counts', 'w') fp.write("Name\t") fp.write("Sequence") for y in con_file_order: fp.write("\t"+y) for x in fil_con: fp.write("\n%s" % "\t".join(x)) fp.close() if flag == 1: fp = open('Counts/Raw '+group_name2+' Templated Counts', 'w') fp.write("Name\t") fp.write("Sequence") for y in tre_file_order: fp.write("\t"+y) for x in raw_tre: fp.write("\n%s" % "\t".join(x)) fp.close() fp = open('Counts/Raw '+group_name1+' Templated Counts', 'w') fp.write("Name\t") fp.write("Sequence") for y in con_file_order: fp.write("\t"+y) for x in raw_con: fp.write("\n%s" % "\t".join(x)) fp.close() if flag == 2: fp = open('Counts/Raw '+group_name2+' Non-Templated Counts', 'w') fp.write("Name\t") fp.write("Sequence") for y in tre_file_order: fp.write("\t"+y) for x in raw_tre: fp.write("\n%s" % "\t".join(x)) fp.close() fp = open('Counts/Raw '+group_name1+' Non-Templated Counts', 'w') fp.write("Name\t") fp.write("Sequence") for y in con_file_order: fp.write("\t"+y) for x in raw_con: fp.write("\n%s" % "\t".join(x)) fp.close() ######################################################################################################################################### def temp_counts_to_diff(names,samp,folder): for i in range(2,len(samp[0])): fp = open(folder+names[i-2]+'.txt','w') fp.write("miRNA id"+"\t"+names[i-2]+"\n") for x in samp: fp.write("%s" % "\t".join([x[0],x[i]])+"\n") fp.close() ################################################################################################################## def DB_write(con,name,unique_seq,sorted_uni_arms,f): if f==1: # Write a txt file with all the information if con=="c": fp = open('split1/'+name, 'w') fp.write("%s\t%-42s\t%s\n\n" % ("Number of Reads","Name of isomir","Sequence")) if con=="t": fp = open('split2/'+name, 'w') fp.write("%s\t%-42s\t%s\n\n" % ("Number of Reads","Name of isomir","Sequence")) for i in range(len(sorted_uni_arms)): temp = [] for j in range(len(unique_seq)): if sorted_uni_arms[i][0] in unique_seq[j][2].split("_")[0]: temp.append(unique_seq[j]) temp = sorted(temp, key=lambda x: int(x[0].split('-')[1]), reverse=True) fp.write("*********************************************************************************************************\n") fp.write("%-8s\t%-22s\t%-25s\t%-30s\t%s\n" % ("|",str(sorted_uni_arms[i][0]),"Sequence count = "+str(sorted_uni_arms[i][1]),"Total reads = "+str(sorted_uni_arms[i][2]),"|")) fp.write("*********************************************************************************************************\n\n") [fp.write("%-8s\t%-40s\t%s\n" % (x[0].split("-")[1], x[2],x[9])) for x in temp] fp.write("\n" + "\n") fp.close() if f==2: if con=="c": fp = open('split3/'+name, 'w') fp.write("%s\t%-42s\t%s\n\n" % ("Number of Reads","Name of isomir","Sequence")) if con=="t": fp = open('split4/'+name, 'w') fp.write("%s\t%-42s\t%s\n\n" % ("Number of Reads","Name of isomir","Sequence")) for i in range(len(sorted_uni_arms)): temp = [] for j in range(len(unique_seq)): if sorted_uni_arms[i][0]==unique_seq[j][2].split("_nont_")[0]: temp.append(unique_seq[j]) if temp!=[]: temp = sorted(temp, key=lambda x: int(x[0].split('-')[1]), reverse=True) fp.write("*********************************************************************************************************\n") fp.write("%-8s\t%-22s\t%-25s\t%-30s\t%s\n" % ("|",str(sorted_uni_arms[i][0]),"Sequence count = "+str(sorted_uni_arms[i][1]),"Total reads = "+str(sorted_uni_arms[i][2]),"|")) fp.write("*********************************************************************************************************\n\n") [fp.write("%-8s\t%-40s\t%s\n" % (x[0].split("-")[1], x[2],x[9])) for x in temp] fp.write("\n" + "\n") fp.close() ########################################################################################################################## def new_mat_seq(pre_unique_seq,mat_mirnas,l): unique_iso = [] for x in pre_unique_seq: if len(x[2].split("_"))==3: for y in pre_unique_seq: if x[2] in y[2] and int(x[0].split("-")[1])<int(y[0].split("-")[1]): if any(y[2] in lst2 for lst2 in unique_iso)==False: y[2]=">"+y[2] unique_iso.append(y) l.acquire() for x in unique_iso: mat_mirnas.append(x[2]) mat_mirnas.append(x[9]) l.release() ######################################################################################################################### def merging_names(ini_mat,new): dupes=[] final_mat =[] for num in range(len(ini_mat)): if ini_mat[num][1] not in final_mat and ini_mat[num][0] not in final_mat: final_mat.append(ini_mat[num][1]) final_mat.append(ini_mat[num][0]) else: dupes.append(ini_mat[num][1]) dupes=list(set(dupes)) for i in range(len(dupes)): dupes[i]=[dupes[i]] for x in ini_mat: for y in dupes: if x[1]==y[0]: fl=0 if len(y)==1: y.append(x[0]) else: for i in range(1,len(y)): if y[i].split("_")[0]==x[0].split("_")[0]: fl=1 if len(x[0])<len(y[i]): del y[i] y.append(x[0]) break if fl==0: y.append((x[0])) for y in dupes: if len(y)>2: for i in range(len(y)-1,1,-1): y[1]=y[1]+"/"+y[i] del y[i] for x in ini_mat: for y in dupes: if x[1]==y[0]: x[0]=y[1] ini_mat.sort() ini_mat=list(ini_mat for ini_mat,_ in itertools.groupby(ini_mat)) new.extend(ini_mat) ###################################################################################################################################################### def nontemp_counts_to_diff(tem_names,tem_samp,non_names,non_samp,folder): for i in range(2,len(tem_samp[0])): fp = open(folder+tem_names[i-2]+'.txt','w') fp.write("miRNA id"+"\t"+tem_names[i-2]+"\n") for x in tem_samp: fp.write("%s" % "\t".join([x[0],x[i]])+"\n") for j in range(len(non_names)): if non_names[j]==tem_names[i-2]: for x in non_samp: fp.write("%s" % "\t".join([x[0],x[j+2]])+"\n") fp.close() ################################################################################################################################################################################################################### """ This function downloads all the miRNAs of all the species from MirBase and filters them by the requested organism input : Organism output: A list with the miRNA sequences in fasta format """ def download_matures(matures,org_name): url = 'https://mirbase.org/download/CURRENT/mature.fa' data = urllib.request.urlopen(url).read().decode('utf-8') file_mirna = data.split("<br>") file_mirna = list(map(lambda x: x.replace('>', ''), file_mirna)) for i in range(0,len(file_mirna)-1,2): if org_name in file_mirna[i]: matures.append(">"+file_mirna[i]) matures.append(file_mirna[i+1]) ################################################################################################################################################################################################################### """ This function keeps all mirna isoforms which are detected on SAM files from the first part of the analysis These isoforms will be used as refence sequences with canonical (ref) mirnas for the detection of non-template mirnas """ def non_template_ref(c_samples,t_samples,all_isoforms): pre_uni_seq_con = list(c_samples) pre_uni_seq_tre = list(t_samples) for x in pre_uni_seq_con: for y in x: #if ">"+y[2] not in all_isoforms and ")_" in y[2] : if ">"+y[2] not in all_isoforms and "_t_" in y[2] : all_isoforms.append(">"+y[2]) all_isoforms.append(y[9]) for x in pre_uni_seq_tre: for y in x: #if ">"+y[2] not in all_isoforms and ")_" in y[2]: if ">"+y[2] not in all_isoforms and "_t_" in y[2] : all_isoforms.append(">"+y[2]) all_isoforms.append(y[9]) ################################################################################################################################################################################################ """ This function adds the uncommon detected miRNAs among samples. As a result all samples will have the same length. """ def uncommon_mirnas(sample,mir_names,l,new_d,sample_name,sample_order): for y in mir_names: flag=0 for x in sample: if y[0]==x[0]: # check if miRNA exists in the sample flag=1 break if flag==0: sample.append([y[0],"0",y[1]]) # add the name of mirna to the sample with zero counts and its sequence # sorting and remove duplicates sample.sort(key=lambda x: x[0]) sample=list(sample for sample,_ in itertools.groupby(sample)) # Return the updated sample l.acquire() new_d.append(sample) sample_order.append(sample_name) l.release() ###############################################################################################################################################################################################