hogprof 0.3.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- hogprof/__init__.py +5 -0
- hogprof/cli.py +484 -0
- hogprof/extract_levels_hits.py +518 -0
- hogprof/generate_jaccard_distr.py +516 -0
- hogprof/lshbuilder.py +710 -0
- hogprof/metadata.py +126 -0
- hogprof/presets.py +21 -0
- hogprof/profiler.py +333 -0
- hogprof/splitter.py +53 -0
- hogprof/utils/__init__.py +1 -0
- hogprof/utils/goautils.py +229 -0
- hogprof/utils/hashutils.py +190 -0
- hogprof/utils/orthoxml.py +83 -0
- hogprof/utils/phylo.py +305 -0
- hogprof/utils/pyhamutils.py +256 -0
- hogprof-0.3.0.dist-info/METADATA +231 -0
- hogprof-0.3.0.dist-info/RECORD +21 -0
- hogprof-0.3.0.dist-info/WHEEL +5 -0
- hogprof-0.3.0.dist-info/entry_points.txt +3 -0
- hogprof-0.3.0.dist-info/licenses/LICENSE +21 -0
- hogprof-0.3.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
|
|
2
|
+
from __future__ import print_function
|
|
3
|
+
|
|
4
|
+
from goatools import semantic
|
|
5
|
+
from pyoma.browser.models import ProteinEntry
|
|
6
|
+
from goatools.obo_parser import GODag
|
|
7
|
+
from . import hashutils
|
|
8
|
+
import pickle
|
|
9
|
+
from goatools.go_enrichment import GOEnrichmentStudy
|
|
10
|
+
from pyoma.browser import db
|
|
11
|
+
import multiprocessing as mp
|
|
12
|
+
from tables import *
|
|
13
|
+
import time
|
|
14
|
+
##############enrichment##############################################
|
|
15
|
+
|
|
16
|
+
def return_enrichment_study_obj(gaf_taxfiltered, obo = None):
|
|
17
|
+
'''
|
|
18
|
+
Generate go enrichment study object with a background dataset.
|
|
19
|
+
'''
|
|
20
|
+
if obo is None:
|
|
21
|
+
obodag = GODag(config_utils.datadir+"/GOData/go-basic.obo")
|
|
22
|
+
else:
|
|
23
|
+
obodag = GODag(obo)
|
|
24
|
+
|
|
25
|
+
goeaobj = GOEnrichmentStudy(
|
|
26
|
+
gaf_taxfiltered.keys(), #
|
|
27
|
+
gaf_taxfiltered, # geneid/GO associations possible with tree used for DB
|
|
28
|
+
obodag, # Ontologies
|
|
29
|
+
propagate_counts = False,
|
|
30
|
+
alpha = 0.15, # default significance cut-off
|
|
31
|
+
methods = ['fdr_bh']) # defult multipletest correction method
|
|
32
|
+
return goeaobj
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def buildGAF(gaf_file , universe= None):
|
|
36
|
+
|
|
37
|
+
gaf_filtered = {}
|
|
38
|
+
with open(gaf_file, mode='r') as gafin:
|
|
39
|
+
for line in gafin:
|
|
40
|
+
words = line.split()
|
|
41
|
+
if words[0] not in gaf_filtered:
|
|
42
|
+
gaf_filtered[words[0]]=set([words[1]])
|
|
43
|
+
else:
|
|
44
|
+
gaf_filtered[words[0]].add(words[1])
|
|
45
|
+
|
|
46
|
+
if universe:
|
|
47
|
+
gaf_filtered = { prot:gaf_filtered[prot] for prot in universe}
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
return gaf_filtered
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def return_hogs_timeout( result, retq):
|
|
54
|
+
print('started')
|
|
55
|
+
with open_file(config_utils.config['dir']['omadir']+'OmaServer.h5' , mode="r") as h5_oma:
|
|
56
|
+
db_obj = db.Database(h5_oma)
|
|
57
|
+
res = [ ProteinEntry(db_obj, e).omaid for e in db_obj.member_of_fam(int(result)) ]
|
|
58
|
+
retq.put(res)
|
|
59
|
+
|
|
60
|
+
def run_GOEA_onresults(results, db_obj, goeaobj, outname = None):
|
|
61
|
+
'''
|
|
62
|
+
Perform enrichment analysis on returned results
|
|
63
|
+
grabs all member protein of all hogs in result
|
|
64
|
+
returns goe results and HOG composition
|
|
65
|
+
'''
|
|
66
|
+
hogids =[ "HOG:" + (7-len(str(fam_id))) * '0' + str(fam_id) for fam_id in results ]
|
|
67
|
+
HOGS={}
|
|
68
|
+
print('compiling hogs')
|
|
69
|
+
prots = []
|
|
70
|
+
|
|
71
|
+
print('mod13')
|
|
72
|
+
retq = mp.Queue()
|
|
73
|
+
|
|
74
|
+
for i,result in enumerate(results):
|
|
75
|
+
if i %10 ==0:
|
|
76
|
+
print(i)
|
|
77
|
+
print(result)
|
|
78
|
+
HOGS[result]=[]
|
|
79
|
+
p = mp.Process( target= return_hogs_timeout , args= (result, retq))
|
|
80
|
+
p.start()
|
|
81
|
+
|
|
82
|
+
t0 = time.time()
|
|
83
|
+
timeout = False
|
|
84
|
+
|
|
85
|
+
while time.time()-t0 < 10 :
|
|
86
|
+
time.sleep(.1)
|
|
87
|
+
if p.is_alive() == False:
|
|
88
|
+
print('done')
|
|
89
|
+
break
|
|
90
|
+
if time.time()-t0 > 10:
|
|
91
|
+
timeout = True
|
|
92
|
+
print('Dead')
|
|
93
|
+
p.terminate()
|
|
94
|
+
del p
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
if retq.empty() == False:
|
|
98
|
+
iterobj = retq.get(10)
|
|
99
|
+
#retq get
|
|
100
|
+
for k,member in enumerate(iterobj):
|
|
101
|
+
if k < 1:
|
|
102
|
+
print(member)
|
|
103
|
+
if k > 500:
|
|
104
|
+
break
|
|
105
|
+
HOGS[result].append(member)
|
|
106
|
+
prots.append(member)
|
|
107
|
+
|
|
108
|
+
print('done')
|
|
109
|
+
print('running GO enrichment study')
|
|
110
|
+
goea_results_all = goeaobj.run_study(prots )
|
|
111
|
+
print('done')
|
|
112
|
+
if outname:
|
|
113
|
+
with open( config_utils.datadir + outname + 'Hogs2Prots.pkl' , 'wb' ) as save:
|
|
114
|
+
save.write(pickle.dumps(HOGS,2))
|
|
115
|
+
goeaobj.wr_txt(config_utils.datadir+ str(outname)+"enrichment.txt", goea_results_all)
|
|
116
|
+
print('DONE!')
|
|
117
|
+
return goea_results_all, HOGS
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
def run_GOEA_onresults_tar(results, tar, goeaobj, outname = None):
|
|
121
|
+
'''
|
|
122
|
+
Perform enrichment analysis on returned results
|
|
123
|
+
grabs all member protein of all hogs in result
|
|
124
|
+
returns goe results and HOG composition
|
|
125
|
+
'''
|
|
126
|
+
## TODO: finish this function with tar hog to list of prot IDS
|
|
127
|
+
#print(db_obj.member_of_hog_id(int(results[0])))
|
|
128
|
+
#hogids =[ "HOG:" + (7-len(fam_id)) * '0' + fam_id for fam_id in results ]
|
|
129
|
+
#print( db_obj.member_of_hog_id(hogids[0]) )
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
HOGS={}
|
|
133
|
+
print('compiling hogs')
|
|
134
|
+
prots = []
|
|
135
|
+
for i,result in enumerate(hogids):
|
|
136
|
+
if i %10 ==0:
|
|
137
|
+
print(i)
|
|
138
|
+
HOGS[result]=[]
|
|
139
|
+
for member in db_obj.iter_members_of_hog_id(result):
|
|
140
|
+
HOGS[result].append(member.omaid)
|
|
141
|
+
prots.append(member.omaid)
|
|
142
|
+
print('done')
|
|
143
|
+
print('running GO enrichment study')
|
|
144
|
+
|
|
145
|
+
goea_results_all = goeaobj.run_study(prots )
|
|
146
|
+
print('done')
|
|
147
|
+
with open( config_utils.datadir + outname + 'Hogs2Prots.pkl' , 'wb' ) as save:
|
|
148
|
+
save.write(pickle.dumps(HOGS,2))
|
|
149
|
+
|
|
150
|
+
goeaobj.wr_txt(config_utils.datadir+ str(outname)+"enrichment.txt", goea_results_all)
|
|
151
|
+
print('DONE!')
|
|
152
|
+
return goea_results_all, HOGS
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
######################resnik semsim ###################################################
|
|
156
|
+
|
|
157
|
+
def resnik_sim_hdf5(go_id1, go_id2, godag, termcounts, hdf5):
|
|
158
|
+
'''
|
|
159
|
+
Computes Resnik's similarity measure.
|
|
160
|
+
'''
|
|
161
|
+
try:
|
|
162
|
+
msca_goid = deepest_common_ancestor_hdf5([goterm2id(go_id1), goterm2id(go_id2)], godag, hdf5)
|
|
163
|
+
score = semantic.get_info_content(msca_goid, termcounts)
|
|
164
|
+
except:
|
|
165
|
+
score = -1
|
|
166
|
+
return score
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
def deepest_common_ancestor_hdf5(go_ids, godag, hdf5):
|
|
170
|
+
'''
|
|
171
|
+
Gets the nearest common ancestor
|
|
172
|
+
using the above function.
|
|
173
|
+
Only returns single most specific - assumes unique exists.
|
|
174
|
+
'''
|
|
175
|
+
# Take the element at maximum depth.
|
|
176
|
+
return max(common_parent_go_ids_hdf5(go_ids, hdf5), key=lambda t: godag[t].depth)
|
|
177
|
+
|
|
178
|
+
def common_parent_go_ids_hdf5(go_ids, hdf5_set):
|
|
179
|
+
'''
|
|
180
|
+
Finds the common ancestors in the GO
|
|
181
|
+
tree of the list of goids in the input.
|
|
182
|
+
'''
|
|
183
|
+
candidates = set(hdf5_set[go_ids[0]].tolist())
|
|
184
|
+
for go_id in go_ids[1:]:
|
|
185
|
+
candidates_to_add = set(hdf5_set[go_id].tolist())
|
|
186
|
+
candidates.intersection_update(candidates_to_add)
|
|
187
|
+
corrected_candidates = [id2goterm(c) for c in candidates]
|
|
188
|
+
return corrected_candidates
|
|
189
|
+
|
|
190
|
+
def resnik_sim_pandas(tup, df , termcounts):
|
|
191
|
+
'''
|
|
192
|
+
Computes Resnik's similarity measure.
|
|
193
|
+
'''
|
|
194
|
+
go_id1, go_id2 = tup
|
|
195
|
+
#print(df.head())
|
|
196
|
+
if go_id1 == go_id2:
|
|
197
|
+
return semantic.get_info_content(go_id1, termcounts)
|
|
198
|
+
|
|
199
|
+
elif go_id2 in df.index and go_id1 in df.index:
|
|
200
|
+
|
|
201
|
+
ancestors = df.loc[str(go_id2)].parents
|
|
202
|
+
ancestors += df.loc[str(go_id1)].parents
|
|
203
|
+
terms = df.loc[ancestors]
|
|
204
|
+
ancestors_set = terms.parents.tolist()
|
|
205
|
+
intersection = set(ancestors_set[0]).intersection(* ancestors_set[1:])
|
|
206
|
+
common_ancestors = df.loc[list(intersection)]
|
|
207
|
+
common_ancestors = common_ancestors.sort_values('depth', ascending= False)
|
|
208
|
+
msca_goid = common_ancestors.index.tolist()[0]
|
|
209
|
+
return semantic.get_info_content(msca_goid, termcounts)
|
|
210
|
+
|
|
211
|
+
else:
|
|
212
|
+
return -1
|
|
213
|
+
|
|
214
|
+
|
|
215
|
+
def get_go_terms_gaf(hog_id, pyoma_dbobj, gaf , genomes = None):
|
|
216
|
+
'''
|
|
217
|
+
iterate over hog members and get the go information from a gaf in memory
|
|
218
|
+
'''
|
|
219
|
+
fam = hashutils.hogid2fam(hog_id)
|
|
220
|
+
go_terms = { mr.omaid:gaf[mr.omaid] for mr in pyoma_dbobj.iter_members_of_hog_id(hog_id) if mr.omaid in gaf }
|
|
221
|
+
return go_terms
|
|
222
|
+
|
|
223
|
+
|
|
224
|
+
def goterm2id(go_term_to_modif):
|
|
225
|
+
|
|
226
|
+
return int(go_term_to_modif.split(':')[1])
|
|
227
|
+
|
|
228
|
+
def id2goterm(go_term_to_modif):
|
|
229
|
+
return 'GO:{:07d}'.format(go_term_to_modif)
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
import datasketch
|
|
2
|
+
import copy
|
|
3
|
+
import logging
|
|
4
|
+
import numpy as np
|
|
5
|
+
import pandas as pd
|
|
6
|
+
|
|
7
|
+
logger = logging.getLogger(__name__)
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def generate_treeweights( mastertree, taxaIndex , taxfilter= None, taxmask=None ):
|
|
11
|
+
#weighing function for tax level, masking levels etc. sets all weights to 1 if they are in taxmask or filter
|
|
12
|
+
#custom weights can also be used here
|
|
13
|
+
"""
|
|
14
|
+
Generate the weights of each taxonomic level to be applied during the
|
|
15
|
+
constructin of weighted minhashes
|
|
16
|
+
:param mastertree: full corrected ncbi taxonomy
|
|
17
|
+
:param taxaIndex: dict mapping taxa to columns
|
|
18
|
+
:param taxfilter: list of branches to delete
|
|
19
|
+
:param taxmask: if this is not NONE taxmask, the DB is constructed with this subtree
|
|
20
|
+
:return: weights: a vector of weights for each tax level
|
|
21
|
+
"""
|
|
22
|
+
#get max of taxa index
|
|
23
|
+
taxmax = max(taxaIndex.values())+1
|
|
24
|
+
weights = np.zeros((3*taxmax,1))
|
|
25
|
+
logger.info('making tree weights with %d taxa', len(taxaIndex))
|
|
26
|
+
newtree = copy.deepcopy(mastertree)
|
|
27
|
+
if taxmask:
|
|
28
|
+
for node in newtree.traverse():
|
|
29
|
+
if taxmask:
|
|
30
|
+
if str(node.name) == str(taxmask):
|
|
31
|
+
logger.info('Masking tree to %s', taxmask)
|
|
32
|
+
newtree = node
|
|
33
|
+
break
|
|
34
|
+
logger.info(
|
|
35
|
+
'Masked tree contains %d taxa',
|
|
36
|
+
len([n.name for n in newtree.traverse()]),
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
if taxfilter:
|
|
40
|
+
for n in newtree.traverse():
|
|
41
|
+
if n.name in taxfilter:
|
|
42
|
+
n.delete()
|
|
43
|
+
|
|
44
|
+
for i in range(3):
|
|
45
|
+
for n in newtree.traverse():
|
|
46
|
+
weights[taxmax*i + taxaIndex[n.name] ] = 1
|
|
47
|
+
return weights
|
|
48
|
+
|
|
49
|
+
def hash_tree(tp , taxaIndex , treeweights , wmg , lossonly = False , duplonly = False ):
|
|
50
|
+
"""
|
|
51
|
+
Generate a weighted minhash and binary matrix row for a tree profile
|
|
52
|
+
|
|
53
|
+
:param tp: a pyham tree profile
|
|
54
|
+
:param taxaIndex: dict mapping taxa to columns
|
|
55
|
+
:param treeweights: a vector of weights for each tax levels
|
|
56
|
+
:param wmg: Datasketch weighted minhash generator
|
|
57
|
+
:return hog_matrix: a vector of weights for each tax level
|
|
58
|
+
:return weighted_hash: a weighted minhash of a HOG
|
|
59
|
+
|
|
60
|
+
"""
|
|
61
|
+
if not tp:
|
|
62
|
+
return None, None
|
|
63
|
+
|
|
64
|
+
taxaIndex_max = max(taxaIndex.values())+1
|
|
65
|
+
hog_matrix_weighted = np.zeros((1, 3*taxaIndex_max))
|
|
66
|
+
hog_matrix_binary = np.zeros((1, 3*taxaIndex_max))
|
|
67
|
+
|
|
68
|
+
losses = [ taxaIndex[n.name] for n in tp.traverse() if n.lost and n.name in taxaIndex ]
|
|
69
|
+
dupl = [ taxaIndex[n.name] for n in tp.traverse() if n.dupl and n.name in taxaIndex ]
|
|
70
|
+
presence = [ taxaIndex[n.name] for n in tp.traverse() if n.nbr_genes > 0 and n.name in taxaIndex ]
|
|
71
|
+
indices = dict(zip (['presence', 'loss', 'dup'],[presence,losses,dupl] ) )
|
|
72
|
+
### Athina comment:
|
|
73
|
+
### change things here to do permutation test!!!!
|
|
74
|
+
for i,event in enumerate(indices):
|
|
75
|
+
if len(indices[event])>0:
|
|
76
|
+
try:
|
|
77
|
+
hogindex = np.asarray(indices[event])+i*taxaIndex_max
|
|
78
|
+
|
|
79
|
+
hog_matrix_weighted[:,hogindex] = treeweights[hogindex , : ].ravel()
|
|
80
|
+
|
|
81
|
+
if lossonly == True and event != 'loss':
|
|
82
|
+
hog_matrix_weighted[:,hogindex] = 0
|
|
83
|
+
if duplonly == True and event != 'dup':
|
|
84
|
+
hog_matrix_weighted[:,hogindex] = 0
|
|
85
|
+
if lossonly == False and duplonly == False:
|
|
86
|
+
hog_matrix_binary[:,hogindex] = 1
|
|
87
|
+
|
|
88
|
+
except Exception:
|
|
89
|
+
logger.exception(
|
|
90
|
+
'Error hashing event %s (indices=%s, hogindex=%s)',
|
|
91
|
+
event,
|
|
92
|
+
indices[event],
|
|
93
|
+
hogindex,
|
|
94
|
+
)
|
|
95
|
+
|
|
96
|
+
input_vec = list(hog_matrix_weighted.flatten())
|
|
97
|
+
|
|
98
|
+
if wmg.dim == len(input_vec) and sum(input_vec) > 0:
|
|
99
|
+
weighted_hash = wmg.minhash(input_vec)
|
|
100
|
+
return hog_matrix_binary , weighted_hash
|
|
101
|
+
|
|
102
|
+
else:
|
|
103
|
+
return None, None
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
def hash_trees_subhogs(hog_tps , taxaIndex , treeweights , wmg , lossonly = False , duplonly = False ):
|
|
109
|
+
"""
|
|
110
|
+
Generate a weighted minhash and binary matrix row for multiple tree profiles within a HOG
|
|
111
|
+
|
|
112
|
+
:param tp: a pyham tree profile
|
|
113
|
+
:param taxaIndex: dict mapping taxa to columns
|
|
114
|
+
:param treeweights: a vector of weights for each tax levels
|
|
115
|
+
:param wmg: Datasketch weighted minhash generator
|
|
116
|
+
:return hog_matrix: a vector of weights for each tax level
|
|
117
|
+
:return weighted_hash: a weighted minhash of a HOG
|
|
118
|
+
|
|
119
|
+
"""
|
|
120
|
+
#print(hog_tps.keys())
|
|
121
|
+
#print(hog_tps[['tree_dicts']].to_dict())
|
|
122
|
+
if hog_tps is None or 'tree_dicts' not in hog_tps or hog_tps['tree_dicts'] is None:
|
|
123
|
+
return {}
|
|
124
|
+
|
|
125
|
+
hashes_subhogs = {}
|
|
126
|
+
for key, tp in hog_tps['tree_dicts'].items():
|
|
127
|
+
matrix, hashed = hash_tree(tp, taxaIndex, treeweights, wmg,
|
|
128
|
+
lossonly=lossonly, duplonly=duplonly)
|
|
129
|
+
if hashed is not None:
|
|
130
|
+
hashes_subhogs[key] = (matrix, hashed)
|
|
131
|
+
return hashes_subhogs
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
def tree2str_DCA(tp , taxaIndex ):
|
|
135
|
+
"""
|
|
136
|
+
Generate a string where each column is a tax level
|
|
137
|
+
each letter code corresponds to an event type
|
|
138
|
+
each row is a protein family. for use with DCA pipelines
|
|
139
|
+
|
|
140
|
+
:param tp: a pyham tree profile
|
|
141
|
+
:param taxaIndex: dict mapping taxa to columns
|
|
142
|
+
:return dcaMat: a weighted minhash of a HOG
|
|
143
|
+
"""
|
|
144
|
+
#convert a tree profile to a weighted minhash
|
|
145
|
+
losses = [ taxaIndex[n.name] for n in tp.traverse() if n.lost and n.name in taxaIndex ]
|
|
146
|
+
dupl = [ taxaIndex[n.name] for n in tp.traverse() if n.dupl and n.name in taxaIndex ]
|
|
147
|
+
presence = [ taxaIndex[n.name] for n in tp.traverse() if n.nbr_genes > 0 and n.name in taxaIndex ]
|
|
148
|
+
Ds = list( set(dupl).intersection(set(presence)))
|
|
149
|
+
Ps= list(set(presence).difference(set(dupl)))
|
|
150
|
+
Ls= list(set(losses))
|
|
151
|
+
charar = np.chararray(len(taxaIndex) )
|
|
152
|
+
#set to absent
|
|
153
|
+
charar.fill( 'A')
|
|
154
|
+
charar[Ds] = 'D'
|
|
155
|
+
charar[Ls] = 'L'
|
|
156
|
+
charar[Ps] = 'P'
|
|
157
|
+
return charar
|
|
158
|
+
|
|
159
|
+
def row2hash(row , taxaIndex , treeweights , wmg , lossonly = False , duplonly = False):
|
|
160
|
+
"""
|
|
161
|
+
turn a dataframe row with an orthoxml file to hash and matrix row
|
|
162
|
+
:param row: lsh builder dataframe row
|
|
163
|
+
:param taxaIndex: dict mapping taxa to columnsfam
|
|
164
|
+
:param treeweights: a vector of weights for each tax levels
|
|
165
|
+
:param wmg: Datasketch weighted minhash generator
|
|
166
|
+
:return: hog_matrix: a vector of weights for each tax level
|
|
167
|
+
:return: weighted_hash: a weighted minhash of a HOG
|
|
168
|
+
"""
|
|
169
|
+
#convert a dataframe row to a weighted minhash
|
|
170
|
+
fam, treemap = row.tolist()
|
|
171
|
+
#print(f'Processing row in row2hash: fam={fam}, treemap={treemap}')
|
|
172
|
+
hog_matrix,weighted_hash = hash_tree(treemap , taxaIndex , treeweights , wmg , lossonly = lossonly , duplonly = duplonly)
|
|
173
|
+
#print(f'Generated hog_matrix: {hog_matrix}, weighted_hash: {weighted_hash}')
|
|
174
|
+
|
|
175
|
+
return pd.Series([weighted_hash,hog_matrix], index=['hash','rows'])
|
|
176
|
+
|
|
177
|
+
def fam2hash_hdf5(fam, hdf5, dataset=None, nsamples=128):
|
|
178
|
+
"""
|
|
179
|
+
Read the stored hash values and return a weighted minhash
|
|
180
|
+
:param fam: hog id
|
|
181
|
+
:param hdf5: h5py object of the hashvalues
|
|
182
|
+
:param dataset: which dataset to use when constructing the hash
|
|
183
|
+
:return: minhash1: the weighted hash of your HOG
|
|
184
|
+
"""
|
|
185
|
+
if dataset is None:
|
|
186
|
+
dataset = next(iter(hdf5.keys()))
|
|
187
|
+
|
|
188
|
+
hash_values = np.asarray(hdf5[dataset][fam, :].reshape(nsamples,2 )).astype('int64')
|
|
189
|
+
minhash1 = datasketch.WeightedMinHash(seed = 1, hashvalues=hash_values)
|
|
190
|
+
return minhash1
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import collections
|
|
2
|
+
import xml.etree.ElementTree as ET
|
|
3
|
+
from io import StringIO
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class OrthoXMLBuilder:
|
|
7
|
+
"""
|
|
8
|
+
This is a function for adding subHOG IDs to the OMA orthoxml files (from Adrian).
|
|
9
|
+
Will become redundant with the next version of OMA
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
def __init__(self):
|
|
13
|
+
self.NS = "http://orthoXML.org/2011/"
|
|
14
|
+
ET.register_namespace('', self.NS) # Register default namespace
|
|
15
|
+
|
|
16
|
+
def add_loft_ids(self, orthoxml: str | ET.Element) -> str:
|
|
17
|
+
"""Annotate XML text or an already parsed root, modifying it in place."""
|
|
18
|
+
|
|
19
|
+
def encode_paralog_cluster_id(prefix, nr):
|
|
20
|
+
letters = []
|
|
21
|
+
while nr // 26 > 0:
|
|
22
|
+
letters.append(chr(97 + (nr % 26)))
|
|
23
|
+
nr = nr // 26 - 1
|
|
24
|
+
letters.append(chr(97 + (nr % 26)))
|
|
25
|
+
return prefix + ''.join(letters[::-1])
|
|
26
|
+
|
|
27
|
+
def next_sub_hog_id(idx):
|
|
28
|
+
dups[idx] += 1
|
|
29
|
+
return dups[idx]
|
|
30
|
+
|
|
31
|
+
def rec_annotate(node, og, idx=0):
|
|
32
|
+
if node.tag == f"{{{self.NS}}}orthologGroup":
|
|
33
|
+
taxon_id = node.get('taxonId')
|
|
34
|
+
if taxon_id is not None:
|
|
35
|
+
node.set('id', og + "_" + taxon_id)
|
|
36
|
+
else:
|
|
37
|
+
# If no taxonId, just set the id to the og
|
|
38
|
+
node.set('id', og )
|
|
39
|
+
for child in list(node):
|
|
40
|
+
rec_annotate(child, og, idx)
|
|
41
|
+
elif node.tag == f"{{{self.NS}}}paralogGroup":
|
|
42
|
+
idx += 1
|
|
43
|
+
next_og = f"{og}.{next_sub_hog_id(idx)}"
|
|
44
|
+
for i, child in enumerate(list(node)):
|
|
45
|
+
rec_annotate(child, encode_paralog_cluster_id(next_og, i), idx)
|
|
46
|
+
elif node.tag == f"{{{self.NS}}}geneRef":
|
|
47
|
+
# Set the id to the geneRef id
|
|
48
|
+
node.set('LOFT', og)
|
|
49
|
+
|
|
50
|
+
xml = ET.fromstring(orthoxml) if isinstance(orthoxml, str) else orthoxml
|
|
51
|
+
doc = ET.ElementTree(xml)
|
|
52
|
+
for i, el in enumerate(xml.findall(".//groups/orthologGroup", {"": self.NS})):
|
|
53
|
+
og = el.get('id', f"HOG:{i+1:08d}")
|
|
54
|
+
dups = collections.defaultdict(int)
|
|
55
|
+
rec_annotate(el, og)
|
|
56
|
+
tree_str = StringIO()
|
|
57
|
+
### addition by Athina:
|
|
58
|
+
tree_str.write('<?xml version="1.0" encoding="UTF-8"?>\n')
|
|
59
|
+
doc.write(tree_str, encoding='unicode')
|
|
60
|
+
return tree_str.getvalue()
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def get_root_hog_id(orthoxml: str | ET.Element) -> str:
|
|
64
|
+
xml = ET.fromstring(orthoxml) if isinstance(orthoxml, str) else orthoxml
|
|
65
|
+
groups = xml.findall(
|
|
66
|
+
'{http://orthoXML.org/2011/}groups/{http://orthoXML.org/2011/}orthologGroup'
|
|
67
|
+
)
|
|
68
|
+
if len(groups) != 1:
|
|
69
|
+
raise ValueError(f'Expected one root HOG, found {len(groups)}')
|
|
70
|
+
return groups[0].attrib['id']
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def count_species(ortho_fam: str | ET.Element) -> int:
|
|
74
|
+
if isinstance(ortho_fam, ET.Element):
|
|
75
|
+
return len(ortho_fam.findall('{http://orthoXML.org/2011/}species'))
|
|
76
|
+
return ortho_fam.count('<species name=')
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def iter_species(filename):
|
|
80
|
+
root = ET.parse(filename).getroot()
|
|
81
|
+
for child in root:
|
|
82
|
+
if child.tag.rsplit("}", 1)[-1] == "species":
|
|
83
|
+
yield child
|