mlbi-lab 0.1.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.
mlbi_lab/__init__.py ADDED
@@ -0,0 +1,4 @@
1
+ # __init__.py
2
+ # Copyright (c) 2021 (syoon@dku.edu) and contributors
3
+ # https://github.com/combio-dku/MarkerCount/tree/master
4
+ print('https://github.com/combio-dku')
mlbi_lab/deiso.py ADDED
@@ -0,0 +1,652 @@
1
+ import time, os, sys, warnings, collections
2
+ import numpy as np
3
+ import pandas as pd
4
+ from scipy import stats
5
+ from multiprocessing import Pool, cpu_count
6
+
7
+ SKLEARN = True
8
+ try:
9
+ from sklearn.decomposition import PCA
10
+ except ImportError:
11
+ SKLEARN = False
12
+ print('DEiso ERROR: scikit-learn not installed.')
13
+
14
+ TQDM = True
15
+ try:
16
+ from tqdm.auto import tqdm
17
+ except ImportError:
18
+ TQDM = False
19
+ print('DEiso ERROR: tqdm not installed.')
20
+
21
+
22
+ def DEiso_pca( dfs, n_comp = 2 ):
23
+
24
+ rownames = ['PC%i' % (i+1) for i in range(int(n_comp))]
25
+ pca_obj = PCA(n_components=int(n_comp))
26
+ X_pca = pca_obj.fit_transform(dfs.transpose()).transpose()
27
+ df_pca = pd.DataFrame(X_pca, index = rownames, columns = dfs.columns.values)
28
+ return df_pca
29
+
30
+
31
+ def get_mean_and_cov(dfx):
32
+ m = dfx.mean(axis = 1)
33
+ dfy = dfx.sub(m, axis = 0)
34
+ C = dfy.dot(dfy.transpose())/(dfy.shape[1]-1)
35
+ return m, C
36
+
37
+
38
+ def DEiso_anal_per_gene( dfs_in, groups, gr, norm = False, test = 't2', log = False,
39
+ n_pca_comp = 0, cn_th = 1e-10, ro = 0.01, nth = 0.8 ):
40
+
41
+ dfs = dfs_in.copy(deep = True)
42
+ if norm:
43
+ dfs = dfs.div(dfs.sum(axis = 0), axis = 1)*100
44
+ if log:
45
+ dfs = np.log2(dfs + 1)
46
+
47
+ if (n_pca_comp > 0) & (n_pca_comp < dfs.shape[0]):
48
+ dfs = DEiso_pca( dfs, n_comp = min(n_pca_comp, dfs.shape[0]) )
49
+ if (n_pca_comp == 0) & (dfs.shape[0] > (dfs.shape[1]-2)):
50
+ dfs = DEiso_pca( dfs, n_comp = (dfs.shape[1]-2) )
51
+
52
+ samples = np.array(list(dfs.columns.values))
53
+ glst = list(groups)
54
+ glst = list(set(glst))
55
+ glst.sort()
56
+ if gr in glst:
57
+ glst.remove(gr)
58
+
59
+ cov = {}
60
+ mns = {}
61
+
62
+ b = np.array(groups) == gr
63
+ ssel = list(samples[b])
64
+
65
+ bt = ((dfs[ssel] > 0).sum(axis = 0) > 0)
66
+ if bt.sum() < dfs[ssel].shape[1]*nth:
67
+ return None
68
+
69
+ # Cr = np.array( dfs[ssel].transpose().cov() )
70
+ # mr = np.array( dfs[ssel].mean(axis = 1) )
71
+ mr, Cr = get_mean_and_cov(dfs[ssel])
72
+ nr = len(ssel)
73
+
74
+ res = {}
75
+ for i, g in enumerate(glst):
76
+ b = np.array(groups) == g
77
+ ssel = list(samples[b])
78
+
79
+ bt = ((dfs[ssel] > 0).sum(axis = 0) > 0)
80
+ if bt.sum() >= dfs[ssel].shape[1]*nth:
81
+
82
+ # Ct = np.array( dfs[ssel].transpose().cov() )
83
+ # mt = np.array( dfs[ssel].mean(axis = 1) )
84
+ mt, Ct = get_mean_and_cov(dfs[ssel])
85
+ nt = len(ssel)
86
+
87
+ m = mt - mr
88
+
89
+ # C = ((nr-1)*Cr + (nt-1)*Ct)/(nr + nt - 2)
90
+ C = (0.5*Cr + 0.5*Ct)
91
+ C = C + (np.diag(C).mean()*ro)*np.eye(C.shape[0])
92
+
93
+ if np.linalg.det(C) < cn_th:
94
+ c1 = 0
95
+ else:
96
+ C = np.linalg.inv(C)
97
+ c1 = m.dot(C.dot(m))*(nr*nt)/(nr+nt)
98
+
99
+ dofn = dfs.shape[0]
100
+ if dofn <= (nr + nt - 2):
101
+ dofd = nr + nt - 1 - dofn
102
+ else:
103
+ dofd = 1
104
+ c1 = c1*(dofd)/((nr + nt - 2)*dofn)
105
+
106
+ if test == 't2':
107
+ p1 = stats.f.sf(c1, dofn, dofd, loc=0, scale=1)
108
+ else:
109
+ c1 = np.sqrt(c1)
110
+ p1 = stats.t.sf(c1, df = dofd)*2
111
+
112
+ res['%s_vs_%s' % (g, gr)] = (c1, p1, dfs.shape[0], dofd)
113
+
114
+ return res
115
+
116
+
117
+ def DEiso_anal_single( df, gene_names, groups, ref_group, norm = True, test = 't2', log = False,
118
+ n_pca_comp = 0, rho = 0.1, nth = 0.8, verbose = True ):
119
+
120
+ if not SKLEARN:
121
+ print('DEiso ERROR: scikit-learn not installed.', flush=True)
122
+ return None
123
+
124
+ gr = ref_group
125
+ glst = list(set(gene_names))
126
+ glst.sort()
127
+ idxs = {}
128
+ for g in glst:
129
+ idxs[g] = []
130
+
131
+ ilst = list(df.index.values)
132
+ nlst = list(gene_names)
133
+ for g, t in zip(nlst, ilst):
134
+ idxs[g].append(t)
135
+
136
+ start = time.time()
137
+
138
+ df_res = None
139
+ cnt = 0
140
+ for k, g in enumerate(glst):
141
+ idx = idxs[g]
142
+ if len(idx) >= 2:
143
+ dfs = df.loc[idx,:]
144
+
145
+ bt = ((dfs > 0).sum(axis = 0) > 1)
146
+ if bt.sum() >= dfs.shape[1]:
147
+
148
+ # v = None
149
+ v = DEiso_anal_per_gene( dfs, groups, gr, norm = norm, test = test, log = log,
150
+ n_pca_comp = n_pca_comp, ro = rho, nth = nth )
151
+ if v is not None:
152
+ if isinstance(v, dict):
153
+ keys = v.keys()
154
+ if cnt == 0:
155
+ df_res = {}
156
+ for key in keys:
157
+ df_res[key] = pd.DataFrame(columns = ['stat', 'pval', 'Niso', 'DoF'])
158
+
159
+ for key in keys:
160
+ if key in list(df_res.keys()):
161
+ df_res[key].loc[g, :] = list(v[key])
162
+ else:
163
+ df_res[key] = pd.DataFrame(columns = ['stat', 'pval', 'Niso', 'DoF'])
164
+
165
+ else:
166
+ if cnt == 0:
167
+ df_res = pd.DataFrame(columns = ['stat', 'pval', 'Niso', 'DoF'])
168
+ df_res.loc[g, :] = list(v)
169
+
170
+ cnt += 1
171
+
172
+ if verbose:
173
+ if k%100 == 0:
174
+ print('DEiso Progress: %i/%i(%i) ' % (k, len(glst), cnt), end = '\r', flush=True)
175
+
176
+ elapsed = time.time() - start
177
+ if verbose: print('DEiso done (%i) .. %i ' % (elapsed, cnt), flush=True)
178
+
179
+ if df_res is not None:
180
+ if isinstance(df_res, dict):
181
+ for key in df_res.keys():
182
+ df_res[key]['pval_adj'] = df_res[key]['pval']*cnt
183
+ b = df_res[key]['pval_adj'] > 1
184
+ df_res[key].loc[b, 'pval_adj'] = 1
185
+ df_res[key] = df_res[key].sort_values(['stat'], ascending = False)
186
+ else:
187
+ df_res['pval_adj'] = df_res['pval']*cnt
188
+ b = df_res['pval_adj'] > 1
189
+ df_res.loc[b, 'pval_adj'] = 1
190
+ df_res = df_res.sort_values(['stat'], ascending = False)
191
+
192
+ return df_res
193
+
194
+
195
+ def mc_core_DEiso_anal_per_gene( rs_tuple ):
196
+
197
+ # rs_tuple.append( (dfx, groups, gr, norm, log, n_pca_comp, rho, nth, g ) )
198
+ df, groups, gr, norm, log, n_pca_comp, rho, nth, g, test = rs_tuple
199
+
200
+ df_res = DEiso_anal_single( df, g, groups, ref_group = gr, test = test,
201
+ norm = norm, log = log, n_pca_comp = n_pca_comp,
202
+ rho = rho, nth = nth, verbose = False )
203
+ return df_res
204
+
205
+
206
+ def DEiso_anal( df, gene_names, groups, ref_group, norm = True, test = 't2',
207
+ log = False, n_pca_comp = 0, rho = 0.1, nth = 0.8, verbose = True,
208
+ n_cores = 1, chunk_size = 0 ):
209
+
210
+ if not SKLEARN:
211
+ print('DEiso ERROR: scikit-learn not installed.', flush=True)
212
+ return None
213
+
214
+ gr = ref_group
215
+ glst = list(set(gene_names))
216
+ glst.sort()
217
+ idxs = {}
218
+ for g in glst:
219
+ idxs[g] = []
220
+
221
+ ilst = list(df.index.values)
222
+ nlst = list(gene_names)
223
+ for g, t in zip(nlst, ilst):
224
+ idxs[g].append(t)
225
+
226
+ if not isinstance(gene_names, pd.Series):
227
+ gene_names = pd.Series(gene_names, index = df.index)
228
+
229
+ start = time.time()
230
+ ###############################
231
+
232
+ if (chunk_size > 0) & (n_cores > 1):
233
+ ###############################
234
+ ## Prepare arguments to pass ##
235
+ df_res = None
236
+ cnt = 0
237
+ rs_tuple = []
238
+
239
+ cnt = 0
240
+ cnt_t = 0
241
+ df_res = {}
242
+ for k, g in enumerate(glst):
243
+ idx = idxs[g]
244
+ if len(idx) >= 2:
245
+ dfs = df.loc[idx,:]
246
+
247
+ bt = ((dfs > 0).sum(axis = 0) > 1)
248
+ if bt.sum() >= dfs.shape[1]:
249
+
250
+ if cnt == 0:
251
+ dfx = dfs
252
+ b = gene_names == g
253
+ gene_names_tmp = gene_names[idx]
254
+ else:
255
+ dfx = pd.concat([dfx, dfs], axis = 0)
256
+ gene_names_tmp = pd.concat([gene_names_tmp, gene_names[idx]], axis = 0)
257
+
258
+ cnt += 1
259
+ cnt_t += 1
260
+
261
+ if cnt == chunk_size:
262
+ gns = gene_names_tmp
263
+ rs_tuple.append( (dfx, groups, gr, norm, log, n_pca_comp, rho, nth, gns, test ) )
264
+ cnt = 0
265
+
266
+ if verbose:
267
+ if k%100 == 0:
268
+ print('DEiso preparing: %i/%i(%i chunks) ' % (k, len(glst), cnt_t), end = '\r', flush=True)
269
+
270
+ if cnt > 0:
271
+ rs_tuple.append( (dfx, groups, gr, norm, log, n_pca_comp, rho, nth, g, test ) )
272
+
273
+ k += 1
274
+ print('DEiso preparing: %i/%i(%i chunks) ' % (k, len(glst), len(rs_tuple)), flush=True)
275
+
276
+ ###############################
277
+ ## Run multicore processing ###
278
+ #'''
279
+ num_core = min( n_cores, (cpu_count() - 1) )
280
+ pool = Pool(int(num_core))
281
+ cnt = 0
282
+ df_res = {}
283
+ df_lst = []
284
+
285
+ if TQDM:
286
+ for dct in tqdm(pool.imap_unordered(mc_core_DEiso_anal_per_gene, rs_tuple), total=len(rs_tuple)):
287
+
288
+ if dct is not None:
289
+ for key in dct.keys():
290
+ if key in list(df_res.keys()):
291
+ df_res[key] = pd.concat([df_res[key], dct[key]], axis = 0)
292
+ else:
293
+ df_res[key] = dct[key]
294
+ cnt += 1
295
+
296
+ df_lst.append(dct)
297
+ else:
298
+ for dct in pool.imap_unordered(mc_core_DEiso_anal_per_gene, rs_tuple):
299
+
300
+ if dct is not None:
301
+ for key in dct.keys():
302
+ if key in list(df_res.keys()):
303
+ df_res[key] = pd.concat([df_res[key], dct[key]], axis = 0)
304
+ else:
305
+ df_res[key] = dct[key]
306
+ cnt += 1
307
+
308
+ df_lst.append(dct)
309
+
310
+
311
+ pool.close()
312
+ pool.join()
313
+ #'''
314
+
315
+ else:
316
+ df_res = None
317
+ cnt = 0
318
+ for k, g in enumerate(glst):
319
+ idx = idxs[g]
320
+ if len(idx) >= 2:
321
+ dfs = df.loc[idx,:]
322
+
323
+ bt = ((dfs > 0).sum(axis = 0) > 1)
324
+ if bt.sum() >= dfs.shape[1]:
325
+
326
+ # v = None
327
+ v = DEiso_anal_per_gene( dfs, groups, gr, norm = norm, log = log,
328
+ n_pca_comp = n_pca_comp, ro = rho, nth = nth )
329
+ if v is not None:
330
+ if isinstance(v, dict):
331
+ keys = v.keys()
332
+ if cnt == 0:
333
+ df_res = {}
334
+ for key in keys:
335
+ df_res[key] = pd.DataFrame(columns = ['stat', 'pval', 'Niso', 'DoF'])
336
+
337
+ for key in keys:
338
+ if key in list(df_res.keys()):
339
+ df_res[key].loc[g, :] = list(v[key])
340
+ else:
341
+ df_res[key] = pd.DataFrame(columns = ['stat', 'pval', 'Niso', 'DoF'])
342
+ df_res[key].loc[g, :] = list(v[key])
343
+
344
+ else:
345
+ if cnt == 0:
346
+ df_res = pd.DataFrame(columns = ['stat', 'pval', 'Niso', 'DoF'])
347
+ df_res.loc[g, :] = list(v)
348
+
349
+ cnt += 1
350
+
351
+ if verbose:
352
+ if k%100 == 0:
353
+ print('DEiso Progress: %i/%i(%i genes) ' % (k, len(glst), cnt), end = '\r', flush=True)
354
+
355
+ ###############################
356
+
357
+ elapsed = time.time() - start
358
+ if verbose: print('DEiso done (%i) .. %i ' % (elapsed, cnt), flush=True)
359
+
360
+ #'''
361
+ if df_res is not None:
362
+ if isinstance(df_res, dict):
363
+ for key in df_res.keys():
364
+ df_res[key]['pval_adj'] = df_res[key]['pval']*cnt
365
+ b = df_res[key]['pval_adj'] > 1
366
+ df_res[key].loc[b, 'pval_adj'] = 1
367
+ df_res[key] = df_res[key].sort_values(['stat'], ascending = False)
368
+ else:
369
+ df_res['pval_adj'] = df_res['pval']*cnt
370
+ b = df_res['pval_adj'] > 1
371
+ df_res.loc[b, 'pval_adj'] = 1
372
+ df_res = df_res.sort_values(['stat'], ascending = False)
373
+ #'''
374
+
375
+ return df_res
376
+
377
+
378
+ def save_to_excel(df_res_all, file_out, pv_cutoff = 0.1):
379
+
380
+ cnt = 0
381
+ for key in df_res_all.keys():
382
+
383
+ if cnt == 0:
384
+ with pd.ExcelWriter(file_out, mode='w') as writer:
385
+ b = df_res_all[key]['pval'] <= pv_cutoff
386
+ df_res_all[key].loc[b,:].to_excel(writer, sheet_name = key)
387
+ else:
388
+ with pd.ExcelWriter(file_out, mode='a', if_sheet_exists = 'replace') as writer:
389
+ b = df_res_all[key]['pval'] <= pv_cutoff
390
+ df_res_all[key].loc[b,:].to_excel(writer, sheet_name = key)
391
+ cnt += 1
392
+
393
+ return
394
+
395
+
396
+ def load_excel(file, index_col = 0):
397
+
398
+ xls = pd.ExcelFile(file)
399
+ lst = xls.sheet_names
400
+ df_res_all = {}
401
+ for s in lst:
402
+ df_res_all[s] = pd.read_excel(xls, s, index_col = index_col)
403
+
404
+ return df_res_all
405
+
406
+ '''
407
+ import matplotlib
408
+ matplotlib.use('Agg')
409
+ import matplotlib.pyplot as plt
410
+ matplotlib.style.use('ggplot')
411
+ import seaborn as sns
412
+ sns.set()
413
+
414
+ def plot_deiso_heatmap( dfs, file = 'plot.png', swap = False, figsize = (8,4), col_cluster = True, row_cluster = True ):
415
+
416
+ if swap:
417
+ sns_plot = sns.clustermap(dfs.transpose(), col_cluster = col_cluster, row_cluster = row_cluster, figsize = figsize)
418
+ else:
419
+ sns_plot = sns.clustermap(dfs, col_cluster = col_cluster, row_cluster = row_cluster, figsize = figsize)
420
+
421
+ plt.tight_layout()
422
+ sns_plot.savefig(file)
423
+ # plt.savefig(file)
424
+ # fig = sns_plot.figure()
425
+ # fig.savefig(file) # plt.show()
426
+ print('Figure saved to %s.' % file)
427
+ return
428
+
429
+ def plot_deiso_pca( dfs, groups, file = 'plot.png', figsize = (4,4), dpi = 100 ):
430
+
431
+ df_2d = DEiso_pca( dfs, n_comp = 2 )
432
+ df_pca = df_2d.transpose().copy(deep = True)
433
+ df_pca['group'] = list(groups)
434
+
435
+ plt.figure(figsize = figsize, dpi = dpi)
436
+ sns.scatterplot(x = df_pca['PC1'], y = df_pca['PC2'], hue = df_pca['group'])
437
+ mxv = np.abs(df_pca[['PC1', 'PC2']]).max().max()*1.1
438
+ plt.xlim([-mxv, mxv])
439
+ plt.ylim([-mxv, mxv])
440
+ plt.grid()
441
+ plt.legend(bbox_to_anchor = (1,0.5), loc = 'center left')
442
+ plt.grid()
443
+ plt.tight_layout()
444
+
445
+ plt.savefig(file)
446
+ # fig = sns_plot.get_figure()
447
+ # fig.savefig(file) # plt.show()
448
+ print('Figure saved to %s.' % file)
449
+ # plt.show()
450
+ return
451
+ '''
452
+
453
+ ##########################################################################
454
+ ## Functions and objects to handle GTF file
455
+ ##########################################################################
456
+
457
+ # GTF_line = collections.namedtuple('GTF_line', 'chr, src, feature, start, end, score, strand, frame, attr')
458
+ GTF_line = collections.namedtuple('GTF_line', 'chr, src, feature, start, end, score, strand, frame, attr, gid, gname, tid, tname, eid, biotype')
459
+ CHR, SRC, FEATURE, GSTART, GEND, SCORE, STRAND, FRAME, ATTR, GID, GNAME, TID, TNAME, EID, BIOTYPE = [i for i in range(15)]
460
+
461
+ def get_id_and_name_from_gtf_attr(str_attr):
462
+
463
+ gid = ''
464
+ gname = ''
465
+ tid = ''
466
+ tname = ''
467
+ biotype = ''
468
+ eid = ''
469
+
470
+ items = str_attr.split(';')
471
+ for item in items[:-1]:
472
+ sub_item = item.strip().split()
473
+ if sub_item[0] == 'gene_id':
474
+ gid = sub_item[1].replace('"','')
475
+ elif sub_item[0] == 'gene_name':
476
+ gname = sub_item[1].replace('"','')
477
+ elif sub_item[0] == 'transcript_id':
478
+ tid = sub_item[1].replace('"','')
479
+ elif sub_item[0] == 'transcript_name':
480
+ tname = sub_item[1].replace('"','')
481
+ elif sub_item[0] == 'exon_id':
482
+ eid = sub_item[1].replace('"','')
483
+ elif sub_item[0] == 'gene_biotype':
484
+ biotype = sub_item[1].replace('"','')
485
+ elif sub_item[0] == 'transcript_biotype':
486
+ biotype = sub_item[1].replace('"','')
487
+
488
+ return gid, gname, tid, tname, eid, biotype
489
+
490
+
491
+ def load_gtf( fname, verbose = True, ho = False ):
492
+
493
+ gtf_line_lst = []
494
+ hdr_lines = []
495
+ if verbose: print('Loading GTF ... ', end='', flush = True)
496
+
497
+ f = open(fname,'r')
498
+ if ho:
499
+ for line in f:
500
+
501
+ if line[0] == '#':
502
+ # line.replace('#','')
503
+ cnt = 0
504
+ for m, c in enumerate(list(line)):
505
+ if c != '#': break
506
+ else: cnt += 1
507
+ hdr_lines.append(line[cnt:-1])
508
+ else:
509
+ break
510
+ else:
511
+ for line in f:
512
+
513
+ if line[0] == '#':
514
+ # line.replace('#','')
515
+ cnt = 0
516
+ for m, c in enumerate(list(line)):
517
+ if c != '#': break
518
+ else: cnt += 1
519
+ hdr_lines.append(line[cnt:-1])
520
+ else:
521
+ items = line[:-1].split('\t')
522
+ if len(items) >= 9:
523
+ chrm = items[0]
524
+ src = items[1]
525
+ feature = items[2]
526
+ start = int(items[3])
527
+ end = int(items[4])
528
+ score = items[5]
529
+ strand = items[6]
530
+ frame = items[7]
531
+ attr = items[8]
532
+ gid, gname, tid, tname, eid, biotype = get_id_and_name_from_gtf_attr(attr)
533
+ gl = GTF_line(chrm, src, feature, start, end, score, strand, frame, attr, gid, gname, tid, tname, eid, biotype)
534
+ gtf_line_lst.append(gl)
535
+
536
+ f.close()
537
+ if verbose: print('done %i lines. ' % len(gtf_line_lst))
538
+
539
+ return(gtf_line_lst, hdr_lines)
540
+
541
+
542
+ def get_gene_mapping( gtf_file, target = 'exon', verbose = True):
543
+
544
+ chr_lst1 = ['chr1', 'chr2', 'chr3', 'chr4', 'chr5', 'chr6', 'chr7', 'chr8', 'chr9', 'chr10',
545
+ 'chr11', 'chr12', 'chr13', 'chr14', 'chr15', 'chr16', 'chr17', 'chr18', 'chr19', 'chr20',
546
+ 'chr21', 'chr22', 'chrX', 'chrY', 'chrM']
547
+
548
+ chr_lst2 = ['1', '2', '3', '4', '5', '6', '7', '8', '9', '10',
549
+ '11', '12', '13', '14', '15', '16', '17', '18', '19', '20',
550
+ '21', '22', 'X', 'Y', 'M']
551
+
552
+ ## Load GTF lines
553
+ gtf_lines, hdr_lines = load_gtf(gtf_file, verbose = verbose)
554
+
555
+ df = pd.DataFrame(gtf_lines)[['feature', 'gid', 'gname', 'tid', 'tname', 'eid', 'chr', 'start', 'end', 'strand']]
556
+ # df['order'] = list(df.index.values)
557
+
558
+ clst = list(df['chr'].unique())
559
+ clst_c = list(set(clst).intersection(chr_lst1))
560
+ if len(clst_c) > 10:
561
+ chr_lst = chr_lst1
562
+ else:
563
+ chr_lst = chr_lst2
564
+
565
+ b = df['chr'].isin(chr_lst)
566
+ df = df.loc[b,:]
567
+
568
+ df['chr_num'] = df['chr'].copy(deep = True)
569
+ chr_num_lst = list(np.arange(len(chr_lst)))
570
+ for c, cn in zip(chr_lst, chr_num_lst):
571
+ b = df['chr'] == c
572
+ df.loc[b, 'chr_num'] = cn
573
+
574
+ if target in ['exon', 'exon_id']:
575
+ tcol = 'eid'
576
+ target_feature = 'exon'
577
+ elif target in ['transcript', 'transcript_id']:
578
+ tcol = 'tid'
579
+ target_feature = 'transcript'
580
+ elif target in ['transcript_name']:
581
+ tcol = 'tname'
582
+ target_feature = 'transcript'
583
+ else:
584
+ tcol = 'gid'
585
+ target_feature = 'gene'
586
+
587
+ b = df['feature'] == target_feature
588
+ # df = df.loc[b, ['gname', tcol, 'chr', 'start', 'end', 'strand', 'order', 'chr_num']].sort_values(by = ['chr_num', 'start', 'end'])
589
+ df = df.loc[b, ['gname', tcol, 'chr', 'start', 'end', 'strand', 'chr_num']].sort_values(by = ['chr_num', 'start', 'end'])
590
+
591
+ df.set_index(tcol, inplace = True)
592
+ df = df[~df.index.duplicated(keep='first')]
593
+ gmap = df['gname']
594
+
595
+ return gmap
596
+
597
+
598
+ def get_feature_mapping( gtf_file, target = 'exon', verbose = True):
599
+
600
+ chr_lst1 = ['chr1', 'chr2', 'chr3', 'chr4', 'chr5', 'chr6', 'chr7', 'chr8', 'chr9', 'chr10',
601
+ 'chr11', 'chr12', 'chr13', 'chr14', 'chr15', 'chr16', 'chr17', 'chr18', 'chr19', 'chr20',
602
+ 'chr21', 'chr22', 'chrX', 'chrY', 'chrM']
603
+
604
+ chr_lst2 = ['1', '2', '3', '4', '5', '6', '7', '8', '9', '10',
605
+ '11', '12', '13', '14', '15', '16', '17', '18', '19', '20',
606
+ '21', '22', 'X', 'Y', 'M']
607
+
608
+ ## Load GTF lines
609
+ gtf_lines, hdr_lines = load_gtf(gtf_file, verbose = verbose)
610
+
611
+ df = pd.DataFrame(gtf_lines)[['feature', 'gid', 'gname', 'tid', 'tname', 'eid', 'chr', 'start', 'end', 'strand']]
612
+ # df['order'] = list(df.index.values)
613
+
614
+ clst = list(df['chr'].unique())
615
+ clst_c = list(set(clst).intersection(chr_lst1))
616
+ if len(clst_c) > 10:
617
+ chr_lst = chr_lst1
618
+ else:
619
+ chr_lst = chr_lst2
620
+
621
+ b = df['chr'].isin(chr_lst)
622
+ df = df.loc[b,:]
623
+
624
+ df['chr_num'] = df['chr'].copy(deep = True)
625
+ chr_num_lst = list(np.arange(len(chr_lst)))
626
+ for c, cn in zip(chr_lst, chr_num_lst):
627
+ b = df['chr'] == c
628
+ df.loc[b, 'chr_num'] = cn
629
+
630
+ if target in ['exon', 'exon_id']:
631
+ tcol = 'eid'
632
+ target_feature = 'exon'
633
+ elif target in ['transcript', 'transcript_id']:
634
+ tcol = 'tid'
635
+ target_feature = 'transcript'
636
+ elif target in ['transcript_name']:
637
+ tcol = 'tname'
638
+ target_feature = 'transcript'
639
+ else:
640
+ tcol = 'gid'
641
+ target_feature = 'gene'
642
+
643
+
644
+ b = df['feature'] == target_feature
645
+ # df = df.loc[b, ['gname', tcol, 'chr', 'start', 'end', 'strand', 'order', 'chr_num']].sort_values(by = ['chr_num', 'start', 'end'])
646
+ df = df.loc[b, ['gname', tcol, 'chr', 'start', 'end', 'strand', 'chr_num']].sort_values(by = ['chr_num', 'start', 'end'])
647
+
648
+ df.set_index(tcol, inplace = True)
649
+ df = df[~df.index.duplicated(keep='first')]
650
+ gmap = df['gname']
651
+
652
+ return gmap