Oncodrive3D 1.0.4__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.
@@ -0,0 +1,594 @@
1
+ import logging
2
+ import os
3
+
4
+ import daiquiri
5
+ import subprocess
6
+ import click
7
+ import sys
8
+ import numpy as np
9
+ import pandas as pd
10
+ import json
11
+
12
+ from scripts import __logger_name__
13
+
14
+ logger = daiquiri.getLogger(__logger_name__ + ".plotting.utils")
15
+
16
+ logging.getLogger('urllib3.connectionpool').setLevel(logging.WARNING)
17
+
18
+
19
+
20
+ def get_species(species):
21
+ """
22
+ Simply change species name to accepted format.
23
+ """
24
+
25
+ if species.capitalize() == "Human" or species.capitalize() == "Homo sapiens":
26
+ species = "Homo sapiens"
27
+ elif species.capitalize() == "Mouse" or species.capitalize() == "Mus musculus":
28
+ species = "Mus musculus"
29
+ else:
30
+ raise RuntimeError(f"Failed to recognize '{species}' as species. Currently accepted ones are 'Homo sapiens' and 'Mus musculus'. Exiting...")
31
+
32
+ return species
33
+
34
+
35
+ def clean_annotations_dir(path: str, loc: str) -> None:
36
+ """
37
+ Clean the annotations directory by removing specific files
38
+ and subdirectories.
39
+
40
+ Args:
41
+ path (str): Path to the directory to be cleaned.
42
+ """
43
+
44
+ if loc == "d":
45
+
46
+ clean_files = f"rm -rf {os.path.join(path, '*.csv')} {os.path.join(path, '*.tsv')} {os.path.join(path, '*.json')} {os.path.join(path, '.*.txt')}"
47
+ clean_ddg = ["rm", "-rf", os.path.join(path, "stability_change")]
48
+ clean_pdbtool = ["rm", "-rf", os.path.join(path, "pdb_tool")]
49
+ #clean_log = ["rm", "-rf", os.path.join(path, "log")]
50
+
51
+ logger.debug(clean_files)
52
+ subprocess.run(clean_files, shell=True)
53
+
54
+ logger.debug(' '.join(clean_ddg))
55
+ subprocess.run(clean_ddg)
56
+
57
+ logger.debug(' '.join(clean_pdbtool))
58
+ subprocess.run(clean_pdbtool)
59
+
60
+ # logger.debug(' '.join(clean_log))
61
+ # subprocess.run(clean_log)
62
+
63
+ elif loc == "r":
64
+ # TODO: implement cleaning function for output
65
+ pass
66
+
67
+
68
+ def clean_annot_dir(path: str, loc: str = 'd') -> None:
69
+ """
70
+ Clean it upon request if it already exists.
71
+
72
+ Args:
73
+ path (str): Path to the directory to be created or cleaned.
74
+ """
75
+
76
+ if os.listdir(path) != ['log']:
77
+ logger.warning(f"Directory {path} already exists and is not empty.")
78
+
79
+ overwrite = "y" if click.get_current_context().params['yes'] else input("Clean existing directory? (y/n): ")
80
+ while overwrite.lower() not in ["y", "yes", "n", "no"]:
81
+ print("Please choose yes or no")
82
+ overwrite = input("Clean existing directory? (y/n): ")
83
+
84
+ if overwrite.lower() in ["y", "yes"]:
85
+ clean_annotations_dir(path, loc)
86
+ logger.info(f"Dataset files in {path} have been removed.")
87
+ else:
88
+ logger.warning(f"Dataset files in {path} have not been removed.")
89
+ else:
90
+ pass
91
+
92
+
93
+ def get_broad_consequence(list_of_annotations):
94
+ """
95
+ Group variants into broader consequence types.
96
+ """
97
+
98
+ CONSEQUENCES_LIST = [
99
+ 'transcript_ablation',
100
+ 'splice_acceptor_variant',
101
+ 'splice_donor_variant',
102
+ 'stop_gained',
103
+ 'frameshift_variant',
104
+ 'stop_lost',
105
+ 'start_lost',
106
+ 'transcript_amplification',
107
+ 'inframe_insertion',
108
+ 'inframe_deletion',
109
+ 'missense_variant',
110
+ 'protein_altering_variant',
111
+ 'splice_region_variant',
112
+ 'splice_donor_5th_base_variant',
113
+ 'splice_donor_region_variant',
114
+ 'splice_polypyrimidine_tract_variant',
115
+ 'incomplete_terminal_codon_variant',
116
+ 'start_retained_variant',
117
+ 'stop_retained_variant',
118
+ 'synonymous_variant',
119
+ 'coding_sequence_variant',
120
+ 'mature_miRNA_variant',
121
+ '5_prime_UTR_variant',
122
+ '3_prime_UTR_variant',
123
+ 'non_coding_transcript_exon_variant',
124
+ 'intron_variant',
125
+ 'NMD_transcript_variant',
126
+ 'non_coding_transcript_variant',
127
+ 'upstream_gene_variant',
128
+ 'downstream_gene_variant',
129
+ 'TFBS_ablation',
130
+ 'TFBS_amplification',
131
+ 'TF_binding_site_variant',
132
+ 'regulatory_region_ablation',
133
+ 'regulatory_region_amplification',
134
+ 'feature_elongation',
135
+ 'regulatory_region_variant',
136
+ 'feature_truncation',
137
+ 'intergenic_variant'
138
+ ]
139
+
140
+ GROUPING_DICT = {
141
+ 'transcript_ablation': 'nonsense',
142
+ 'splice_acceptor_variant': 'nonsense',
143
+ 'splice_donor_variant': 'nonsense',
144
+ 'stop_gained': 'nonsense',
145
+ 'frameshift_variant': 'nonsense',
146
+ 'stop_lost': 'nonsense',
147
+ 'start_lost': 'nonsense',
148
+ 'missense_variant': 'missense',
149
+ 'inframe_insertion': 'indel',
150
+ 'inframe_deletion': 'indel',
151
+ 'splice_donor_variant': 'splicing',
152
+ 'splice_acceptor_variant': 'splicing',
153
+ 'splice_region_variant': 'splicing',
154
+ 'splice_donor_5th_base_variant': 'splicing',
155
+ 'splice_donor_region_variant': 'splicing',
156
+ 'splice_polypyrimidine_tract_variant': 'splicing',
157
+ 'synonymous_variant': 'synonymous',
158
+ 'incomplete_terminal_codon_variant': 'synonymous',
159
+ 'start_retained_variant': 'synonymous',
160
+ 'stop_retained_variant': 'synonymous',
161
+ 'protein_altering_variant' : 'protein_altering_variant',
162
+ 'transcript_amplification' : 'transcript_amplification',
163
+ 'coding_sequence_variant': 'coding_sequence_variant',
164
+ 'mature_miRNA_variant': 'non_coding_exon_region',
165
+ '5_prime_UTR_variant': 'non_coding_exon_region',
166
+ '3_prime_UTR_variant': 'non_coding_exon_region',
167
+ 'non_coding_transcript_exon_variant': 'non_coding_exon_region',
168
+ 'NMD_transcript_variant': 'non_coding_exon_region',
169
+ 'intron_variant': 'intron_variant',
170
+ 'non_coding_transcript_variant' : 'non_coding_transcript_variant',
171
+ 'upstream_gene_variant': 'non_genic_variant',
172
+ 'downstream_gene_variant': 'non_genic_variant',
173
+ 'TFBS_ablation': 'non_genic_variant',
174
+ 'TFBS_amplification': 'non_genic_variant',
175
+ 'TF_binding_site_variant': 'non_genic_variant',
176
+ 'regulatory_region_ablation': 'non_genic_variant',
177
+ 'regulatory_region_amplification': 'non_genic_variant',
178
+ 'feature_elongation': 'non_genic_variant',
179
+ 'regulatory_region_variant': 'non_genic_variant',
180
+ 'feature_truncation': 'non_genic_variant',
181
+ 'intergenic_variant': 'non_genic_variant',
182
+ '-' : '-'
183
+ }
184
+
185
+ consequence_rank_dict = { consequence : rank for rank, consequence in enumerate(CONSEQUENCES_LIST) }
186
+ rank_consequence_dict = { rank : consequence for rank, consequence in enumerate(CONSEQUENCES_LIST) }
187
+
188
+ list_of_single_annotations = []
189
+ list_of_broad_annotations = []
190
+ for x in list_of_annotations:
191
+ all_consequences = x.split(",")
192
+ all_consequences_ranks = map(lambda x: consequence_rank_dict[x], all_consequences)
193
+ single_consequence = rank_consequence_dict[min(all_consequences_ranks)]
194
+ list_of_single_annotations.append(single_consequence)
195
+ if single_consequence in GROUPING_DICT:
196
+ list_of_broad_annotations.append(GROUPING_DICT[single_consequence])
197
+ else:
198
+ list_of_broad_annotations.append(single_consequence)
199
+
200
+ return list_of_broad_annotations
201
+
202
+
203
+ def init_plot_pars(summary_fsize_x=0.4, # It will be moltiplied for the number of genes
204
+ summary_fsize_y=8,
205
+ gene_fsize_x=24,
206
+ gene_fsize_y=12,
207
+ volcano_fsize_x=15,
208
+ volcano_fsize_y=10,
209
+ volcano_subplots_fsize_x=4,
210
+ volcano_subplots_fsize_y=2,
211
+ log_odds_fsize_x=20,
212
+ log_odds_fsize_y=4,
213
+ s_lw=0.2,
214
+ sse_fill_width=0.43,
215
+ dist_thr=0.1,
216
+ summary_alpha=0.3,
217
+ lst_summary_tracks=None,
218
+ lst_summary_hratios=None,
219
+ lst_gene_annot=None,
220
+ lst_gene_hratios=None,
221
+ volcano_top_n=15):
222
+ """
223
+ Initialize plotting parameters.
224
+ """
225
+
226
+ plot_pars = {}
227
+
228
+ plot_pars["summary_figsize"] = summary_fsize_x, summary_fsize_y
229
+ plot_pars["figsize"] = gene_fsize_x, gene_fsize_y
230
+ plot_pars["s_lw"] = s_lw
231
+ plot_pars["sse_fill_width"] = sse_fill_width
232
+ plot_pars["dist_thr"] = dist_thr
233
+ plot_pars["summary_alpha"] = summary_alpha
234
+
235
+
236
+ # Summary-plot
237
+ # ============
238
+
239
+ # Default values
240
+ plot_pars["summary_h_ratios"] = {"score" : 0.3,
241
+ "miss_count" : 0.2,
242
+ "res_count" : 0.2,
243
+ "res_clust_mut" : 0.2,
244
+ "clusters" : 0.2}
245
+
246
+ # Custom values
247
+ if not lst_summary_tracks:
248
+ lst_summary_tracks = plot_pars["summary_h_ratios"].keys()
249
+ if lst_summary_hratios:
250
+ plot_pars["summary_h_ratios"] = {lst_summary_tracks[i] : h_ratio for i, h_ratio in enumerate(lst_summary_hratios)}
251
+ else:
252
+ plot_pars["summary_h_ratios"] = {annot : plot_pars["summary_h_ratios"][annot] for annot in lst_summary_tracks}
253
+ plot_pars["summary_h_ratios"] = {k:v/sum(plot_pars["summary_h_ratios"].values()) for k,v in plot_pars["summary_h_ratios"].items()}
254
+
255
+
256
+ # Gene-plots
257
+ # ==========
258
+
259
+ # Default values
260
+ plot_pars["h_ratios"] = {"nonmiss_count" : 0.13,
261
+ "miss_count" : 0.13,
262
+ "miss_prob" : 0.13,
263
+ "score" : 0.13,
264
+ "pae" : 0.1,
265
+ "disorder" : 0.1,
266
+ "pacc" : 0.1,
267
+ "ddg" : 0.1,
268
+ "ptm" : 0.022,
269
+ "site" : 0.022,
270
+ "clusters" : 0.04,
271
+ "sse" : 0.065,
272
+ "pfam" : 0.04,
273
+ "prosite" : 0.04,
274
+ "membrane" : 0.04,
275
+ "motif" : 0.04}
276
+
277
+ plot_pars["color_cnsq"] = {"splicing" : "C2",
278
+ "missense" : "C5",
279
+ "synonymous" : "C9",
280
+ "coding_sequence_variant" : "C1",
281
+ "nonsense" : "C6",
282
+ "intron_variant" : "C7",
283
+ "indel" : "C8",
284
+ "protein_altering_variant" : "C3"}
285
+
286
+ # Custom values
287
+ if not lst_gene_annot:
288
+ lst_gene_annot = plot_pars["h_ratios"].keys()
289
+ if lst_gene_hratios:
290
+ plot_pars["h_ratios"] = {lst_gene_annot[i] : h_ratio for i, h_ratio in enumerate(lst_gene_hratios)}
291
+ else:
292
+ plot_pars["h_ratios"] = {annot : plot_pars["h_ratios"][annot] for annot in lst_gene_annot}
293
+
294
+
295
+ # Associations-plots
296
+ # ==================
297
+
298
+ plot_pars["volcano_fsize_x"] = volcano_fsize_x
299
+ plot_pars["volcano_fsize_y"] =volcano_fsize_y
300
+ plot_pars["volcano_subplots_fsize_x"] = volcano_subplots_fsize_x
301
+ plot_pars["volcano_subplots_fsize_y"] = volcano_subplots_fsize_y
302
+ plot_pars["log_odds_fsize_x"] = log_odds_fsize_x
303
+ plot_pars["log_odds_fsize_y"] = log_odds_fsize_y
304
+ plot_pars["volcano_top_n"] = volcano_top_n
305
+
306
+ return plot_pars
307
+
308
+
309
+ def init_comp_plot_pars(fsize_x=24,
310
+ fsize_y=12,
311
+ s_lw=0.2,
312
+ sse_fill_width=0.43,
313
+ dist_thr=0.1,
314
+ lst_tracks=None,
315
+ lst_hratios=None,
316
+ count_mirror=False,
317
+ score_mirror=False,
318
+ prob_mirror=False):
319
+ """
320
+ Initialize plotting parameters.
321
+ """
322
+
323
+ plot_pars = {}
324
+
325
+ plot_pars["figsize"] = fsize_x, fsize_y
326
+ plot_pars["s_lw"] = s_lw
327
+ plot_pars["sse_fill_width"] = sse_fill_width
328
+ plot_pars["dist_thr"] = dist_thr
329
+ plot_pars["count_mirror"] = count_mirror
330
+ plot_pars["score_mirror"] = score_mirror
331
+ plot_pars["prob_mirror"] = prob_mirror
332
+
333
+ # Default values
334
+ plot_pars["h_ratios"] = {"nonmiss_count" : 0.13,
335
+ "miss_count" : 0.13,
336
+ "miss_prob" : 0.13,
337
+ "score" : 0.13,
338
+ "clusters" : 0.04,
339
+ "pae" : 0.1,
340
+ "disorder" : 0.1,
341
+ "pacc" : 0.1,
342
+ "ddg" : 0.1,
343
+ "ptm" : 0.022,
344
+ "site" : 0.022,
345
+ "sse" : 0.065,
346
+ "pfam" : 0.04,
347
+ "prosite" : 0.04,
348
+ "membrane" : 0.04,
349
+ "motif" : 0.04}
350
+
351
+ plot_pars["color_cnsq"] = {"splicing" : "C2",
352
+ "missense" : "C5",
353
+ "synonymous" : "C9",
354
+ "coding_sequence_variant" : "C1",
355
+ "nonsense" : "C6",
356
+ "intron_variant" : "C7",
357
+ "indel" : "C8",
358
+ "protein_altering_variant" : "C3"}
359
+
360
+ # Custom values
361
+ if not lst_tracks:
362
+ lst_tracks = list(plot_pars["h_ratios"].keys())
363
+
364
+ if not count_mirror and "nonmiss_count" in lst_tracks:
365
+ ix = lst_tracks.index("nonmiss_count")
366
+ lst_tracks.insert(ix+1, "nonmiss_count_2")
367
+ plot_pars["h_ratios"]["nonmiss_count_2"] = plot_pars["h_ratios"]["nonmiss_count"]
368
+
369
+ if not count_mirror and "miss_count" in lst_tracks:
370
+ ix = lst_tracks.index("miss_count")
371
+ lst_tracks.insert(ix+1, "miss_count_2")
372
+ plot_pars["h_ratios"]["miss_count_2"] = plot_pars["h_ratios"]["miss_count"]
373
+
374
+ if not score_mirror and "score" in lst_tracks:
375
+ ix = lst_tracks.index("score")
376
+ lst_tracks.insert(ix+1, "score_2")
377
+ plot_pars["h_ratios"]["score_2"] = plot_pars["h_ratios"]["score"]
378
+
379
+ if "clusters" in lst_tracks:
380
+ ix = lst_tracks.index("clusters")
381
+ lst_tracks.insert(ix+1, "clusters_2")
382
+ plot_pars["h_ratios"]["clusters_2"] = plot_pars["h_ratios"]["clusters"]
383
+
384
+ if "ddg" in lst_tracks:
385
+ ix = lst_tracks.index("ddg")
386
+ lst_tracks.insert(ix+1, "ddg_2")
387
+ plot_pars["h_ratios"]["ddg_2"] = plot_pars["h_ratios"]["ddg"]
388
+
389
+ if lst_hratios:
390
+ plot_pars["h_ratios"] = {lst_tracks[i] : h_ratio for i, h_ratio in enumerate(lst_hratios)}
391
+ else:
392
+ plot_pars["h_ratios"] = {annot : plot_pars["h_ratios"][annot] for annot in lst_tracks}
393
+
394
+ plot_pars["h_ratios"] = {k:v/sum(plot_pars["h_ratios"].values()) for k,v in plot_pars["h_ratios"].items()}
395
+
396
+ return plot_pars
397
+
398
+
399
+ def load_o3d_result(o3d_result_path, cohort):
400
+ """
401
+ Load all files generated by 3D clustering analysis of Oncodrive3D.
402
+ """
403
+
404
+ gene_result_path = f"{o3d_result_path}/{cohort}/{cohort}.3d_clustering_genes.csv"
405
+ pos_result_path = f"{o3d_result_path}/{cohort}/{cohort}.3d_clustering_pos.csv"
406
+ maf_path = f"{o3d_result_path}/{cohort}/{cohort}.mutations.processed.tsv"
407
+ miss_prob_dict_path = f"{o3d_result_path}/{cohort}/{cohort}.miss_prob.processed.json"
408
+ gene_result = pd.read_csv(gene_result_path)
409
+ pos_result = pd.read_csv(pos_result_path)
410
+ maf = pd.read_csv(maf_path, sep="\t")
411
+ miss_prob_dict = json.load(open(miss_prob_dict_path))
412
+
413
+ return gene_result, pos_result, maf, miss_prob_dict
414
+
415
+
416
+ def subset_genes_and_ids(genes,
417
+ uni_ids,
418
+ seq_df,
419
+ disorder,
420
+ pdb_tool,
421
+ uniprot_feat):
422
+ """
423
+ Subset each dataframe by keeping only selected genes and proteins IDs.
424
+ """
425
+
426
+ seq_df = seq_df.copy()
427
+ disorder = disorder.copy()
428
+ pdb_tool = pdb_tool.copy()
429
+ uniprot_feat = uniprot_feat.copy()
430
+ # Filter genes in the other df
431
+ seq_df = seq_df[seq_df["Gene"].isin(genes)]
432
+ disorder = disorder[disorder["Uniprot_ID"].isin(uni_ids)].reset_index(drop=True)
433
+ pdb_tool = pdb_tool[pdb_tool["Uniprot_ID"].isin(uni_ids)].reset_index(drop=True)
434
+ uniprot_feat = uniprot_feat[uniprot_feat["Gene"].isin(genes)]
435
+
436
+ return seq_df, disorder, pdb_tool, uniprot_feat
437
+
438
+
439
+ def filter_o3d_result(gene_result, pos_result, n_genes=None, lst_genes=None):
440
+ """
441
+ Subset gene-level and position-level Oncodrive3D result.
442
+ """
443
+
444
+ if isinstance(lst_genes, str):
445
+ lst_genes = lst_genes.replace(" ", "")
446
+ lst_genes = lst_genes.split(",")
447
+ gene_result = gene_result[gene_result["Gene"].isin(lst_genes)]
448
+ gene_result = gene_result[gene_result["Status"] == "Processed"]
449
+ if n_genes:
450
+ gene_result = gene_result[:n_genes]
451
+ uni_ids = gene_result.Uniprot_ID.values
452
+ genes = gene_result.Gene.values
453
+ pos_result = pos_result[pos_result["Gene"].isin(genes)]
454
+
455
+ return gene_result, pos_result, genes, uni_ids
456
+
457
+
458
+ def get_enriched_result(pos_result_gene,
459
+ disorder_gene,
460
+ pdb_tool_gene,
461
+ seq_df):
462
+ """
463
+ Add annotations to Oncodrive3D result to return an annotated tsv.
464
+ """
465
+
466
+ pos_result_gene = pos_result_gene.copy()
467
+
468
+ # DDG
469
+ pos_result_gene.loc[pos_result_gene["Mut_in_res"] == 0, "DDG"] = np.nan
470
+
471
+ # Disorder
472
+ pos_result_gene = pos_result_gene.merge(disorder_gene, how="left", on=["Pos"])
473
+ pos_result_gene = pos_result_gene.rename(columns={"Confidence" : "pLDDT_res"})
474
+
475
+ # PDB_Tool
476
+ pos_result_gene = pos_result_gene.rename(columns={"AF_F" : "F"}).merge(
477
+ pdb_tool_gene.drop(columns="F"), on=["Res", "Uniprot_ID", "Pos"], how="left")
478
+
479
+ # Transcript and gene IDs
480
+ pos_result_gene = pos_result_gene.merge(
481
+ seq_df[["Gene", "Uniprot_ID", "Ens_Gene_ID", "Ens_Transcr_ID"]],
482
+ how="left", on=["Uniprot_ID"])
483
+
484
+ return pos_result_gene
485
+
486
+
487
+ def reorganize_df_to_save(pos_result_df):
488
+
489
+ pos_result_df = pos_result_df.rename(columns={"Res" : "WT_res"})
490
+ cols = ['Gene', 'Ens_Gene_ID', 'Ens_Transcr_ID', 'Uniprot_ID', 'F', 'Pos', "WT_res",
491
+ 'Mut_in_gene', 'Mut_in_res', 'Mut_in_vol',
492
+ 'Score', 'Score_obs_sim', 'pval', 'C', 'C_ext', 'Cluster', 'Rank',
493
+ 'Tot_samples', 'Samples_in_vol', 'Samples_in_cl_vol', 'Mut_in_cl_vol', 'Res_in_cl',
494
+ 'PAE_vol', 'pLDDT_res', 'pLDDT_vol', 'pLDDT_cl_vol',
495
+ 'Cancer', 'Cohort',
496
+ 'SSE', 'pACC', 'DDG', "Domain", "Ptm", "Membrane", "Site"]
497
+
498
+ return pos_result_df[[col for col in cols if col in pos_result_df.columns]]
499
+
500
+
501
+ def save_annotated_result(pos_result,
502
+ annot_pos_result,
503
+ uni_feat_processed,
504
+ output_dir,
505
+ run_name,
506
+ output_all_pos=False):
507
+ """
508
+ Save the annotated pos-level result.
509
+ """
510
+
511
+ # Do not include non-mutated positions (default)
512
+ if output_all_pos == False:
513
+ annot_pos_result = annot_pos_result[annot_pos_result["Mut_in_res"] > 0].reset_index(drop=True)
514
+
515
+ # Merge with 'original' one to retrieve dropped cols
516
+ output_pos_result = os.path.join(output_dir, f"{run_name}.3d_clustering_pos.annotated.csv")
517
+ output_uniprot_feat = os.path.join(output_dir, f"{run_name}.uniprot_feat.tsv")
518
+ cols = ["Gene", "Uniprot_ID", "F", "Ens_Gene_ID", "Ens_Transcr_ID",
519
+ "Pos", "Res", "pLDDT_res", "SSE", "pACC", "DDG",
520
+ "Domain", "Ptm", "Membrane", "Site"]
521
+ annot_pos_result = pos_result.drop(columns=["F", "pLDDT_res"]).merge(
522
+ annot_pos_result[[col for col in cols if col in annot_pos_result.columns]],
523
+ how="right", on=["Gene", "Uniprot_ID", "Pos"])
524
+ annot_pos_result = annot_pos_result.sort_values(["Gene", "Pos"])
525
+
526
+ # Fill the NA of the non-mutated positions in features
527
+ for col in ["Cancer", "Cohort"]:
528
+ if annot_pos_result[col].isnull().all():
529
+ annot_pos_result[col] = np.nan
530
+ else:
531
+ annot_pos_result[col] = annot_pos_result[col].dropna().unique()[0]
532
+ annot_pos_result["Mut_in_res"] = annot_pos_result["Mut_in_res"].fillna(0)
533
+ for gene in annot_pos_result.Gene.unique():
534
+ mut_in_gene = annot_pos_result.loc[annot_pos_result["Gene"] == gene, "Mut_in_gene"].dropna().unique()[0]
535
+ annot_pos_result.loc[annot_pos_result["Gene"] == gene, "Mut_in_gene"] = mut_in_gene
536
+ if "Tot_samples" in annot_pos_result.columns:
537
+ tot_samples = annot_pos_result.loc[annot_pos_result["Gene"] == gene, "Tot_samples"].dropna().unique()
538
+ if tot_samples:
539
+ tot_samples = tot_samples[0]
540
+ else:
541
+ tot_samples = np.nan
542
+ annot_pos_result.loc[annot_pos_result["Gene"] == gene, "Tot_samples"] = tot_samples
543
+
544
+ # Save
545
+ annot_pos_result = reorganize_df_to_save(annot_pos_result)
546
+ annot_pos_result.to_csv(output_pos_result, index=False)
547
+ logger.info(f"Saved annotated position-level result to {output_pos_result}")
548
+ uni_feat_processed.to_csv(output_uniprot_feat, sep="\t", index=False)
549
+ logger.info(f"Saved Uniprot features annotations to {output_uniprot_feat}")
550
+
551
+
552
+ def parse_lst_tracks(lst, plot_type):
553
+ """
554
+ Parse the list of tracks from click arg.
555
+ """
556
+
557
+ summary_tracks = ["score",
558
+ "miss_count",
559
+ "res_count",
560
+ "res_clust_mut",
561
+ "clusters"]
562
+
563
+ gene_tracks = ["nonmiss_count",
564
+ "miss_count",
565
+ "miss_prob",
566
+ "score",
567
+ "pae",
568
+ "disorder",
569
+ "pacc",
570
+ "ddg",
571
+ "ptm",
572
+ "site",
573
+ "clusters",
574
+ "sse",
575
+ "pfam",
576
+ "prosite",
577
+ "membrane",
578
+ "motif"]
579
+
580
+ if plot_type == "summary":
581
+ available_tracks = summary_tracks
582
+ elif plot_type == "gene":
583
+ available_tracks = gene_tracks
584
+ lst = lst.split(",")
585
+
586
+ is_valid = np.array([track not in available_tracks for track in lst])
587
+ if is_valid.any():
588
+ invalid_tracks = list(np.array(lst)[np.where(is_valid)])
589
+ logger.error(f"One or more track names for {plot_type} plot are not accepted: {invalid_tracks}")
590
+ logger.error(f"Available track names are: {available_tracks}")
591
+ logger.error(f"Exiting..")
592
+ sys.exit(1)
593
+
594
+ return lst
File without changes