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.
scripts/main.py ADDED
@@ -0,0 +1,650 @@
1
+ #!/usr/bin/env python
2
+
3
+ """
4
+ Oncodrive3D is a fast and accurate computational method designed to analyze
5
+ patterns of somatic mutation across tumors, with the goal of identifying
6
+ three-dimensional (3D) clusters of missense mutations and detecting genes
7
+ under positive selection. The method leverages AlphaFold 2-predicted protein
8
+ structures and Predicted Aligned Error (PAE) to define residue contacts
9
+ within the protein's 3D space. When available, it also integrates mutational
10
+ profiles to build an accurate background model of neutral mutagenesis, which
11
+ is used to score potential clusters and simulate synthetic mutations.
12
+ By applying a novel rank-based statistical approach, Oncodrive3D scores
13
+ potential 3D clusters and computes empirical p-values."
14
+ """
15
+
16
+ import os
17
+ import click
18
+ import daiquiri
19
+ import numpy as np
20
+
21
+ from scripts import __logger_name__, __version__
22
+ from scripts.globals import DATE, setup_logging_decorator, startup_message
23
+
24
+ logger = daiquiri.getLogger(__logger_name__)
25
+
26
+
27
+ @click.group(context_settings={'help_option_names': ['-h', '--help']})
28
+ @click.version_option(__version__)
29
+ def oncodrive3D():
30
+ """
31
+ Oncodrive3D: software for the identification of 3D-clustering
32
+ of missense mutations for cancer driver genes detection.
33
+ """
34
+ pass
35
+
36
+
37
+ # =============================================================================
38
+ # BUILD DATASETS
39
+ # =============================================================================
40
+
41
+ @oncodrive3D.command(context_settings=dict(help_option_names=['-h', '--help']),
42
+ help="Build datasets - Required once after installation.")
43
+ @click.option("-o", "--output_dir",
44
+ help="Directory where to save the files", type=str, default='datasets')
45
+ @click.option("-s", "--organism", type=click.Choice(["Homo sapiens", 'human', "Mus musculus", 'mouse']),
46
+ help="Organism name", default="Homo sapiens")
47
+ @click.option("-m", "--mane",
48
+ help="Use structures predicted from MANE Select transcripts (Homo sapiens only)", is_flag=True)
49
+ @click.option("-M", "--mane_version", default=1.3,
50
+ help="Version of the MANE Select release from NCBI")
51
+ @click.option("-d", "--distance_threshold", type=click.INT, default=10,
52
+ help="Distance threshold (Å) to define contact between amino acids")
53
+ @click.option("-c", "--cores", type=click.IntRange(min=1, max=len(os.sched_getaffinity(0)), clamp=False), default=len(os.sched_getaffinity(0)),
54
+ help="Number of cores to use in the computation")
55
+ @click.option("--af_version", type=click.IntRange(min=1, max=4, clamp=False), default=4,
56
+ help="Version of AlphaFold 2 predictions")
57
+ @click.option("-y", "--yes",
58
+ help="No interaction", is_flag=True)
59
+ @click.option("-v", "--verbose",
60
+ help="Verbose", is_flag=True)
61
+ @setup_logging_decorator
62
+ def build_datasets(output_dir,
63
+ organism,
64
+ mane,
65
+ distance_threshold,
66
+ cores,
67
+ af_version,
68
+ mane_version,
69
+ yes,
70
+ verbose):
71
+ """"Build datasets necessary to run Oncodrive3D."""
72
+
73
+ from scripts.datasets.build_datasets import build
74
+
75
+ startup_message(__version__, "Initializing building datasets..")
76
+
77
+ logger.info(f"Current working directory: {os.getcwd()}")
78
+ logger.info(f"Build folder path: {output_dir}")
79
+ logger.info(f"Organism: {organism}")
80
+ logger.info(f"MANE Select: {mane}")
81
+ logger.info(f"Distance threshold: {distance_threshold}Å")
82
+ logger.info(f"CPU cores: {cores}")
83
+ logger.info(f"AlphaFold version: {af_version}")
84
+ logger.info(f"MANE version: {mane_version}")
85
+ logger.info(f"Verbose: {verbose}")
86
+ logger.info(f'Log path: {os.path.join(output_dir, "log")}')
87
+ logger.info("")
88
+
89
+ build(output_dir,
90
+ organism,
91
+ mane,
92
+ distance_threshold,
93
+ cores,
94
+ af_version,
95
+ mane_version)
96
+
97
+
98
+
99
+ # =============================================================================
100
+ # RUN
101
+ # =============================================================================
102
+
103
+ @oncodrive3D.command(context_settings=dict(help_option_names=['-h', '--help']),
104
+ help="Run 3D-clustering analysis.")
105
+ @click.option("-i", "--input_path", type=click.Path(exists=True), required=True,
106
+ help="Path of the MAF file (or direct VEP output) used as input")
107
+ @click.option("-p", "--mut_profile_path", type=click.Path(exists=True),
108
+ help="Path of the mutation profile (192 trinucleotide contexts) used as optional input")
109
+ @click.option("-m", "--mutability_config_path", type=click.Path(exists=True),
110
+ help="Path of the config file with information on mutability")
111
+ @click.option("-o", "--output_dir", type=str, default='output',
112
+ help="Path to output directory")
113
+ @click.option("-d", "--data_dir", type=click.Path(exists=True), default = os.path.join('datasets'),
114
+ help="Path to datasets")
115
+ @click.option("-n", "--n_iterations", type=int, default=10000,
116
+ help="Number of densities to be simulated")
117
+ @click.option("-a", "--alpha", type=float, default=0.01,
118
+ help="Significant threshold for the p-value of res and gene")
119
+ @click.option("-P", "--cmap_prob_thr", type=float, default=0.5,
120
+ help="Threshold to define AAs contacts based on distance on predicted structure and PAE")
121
+ @click.option("-c", "--cores", type=click.IntRange(min=1, max=len(os.sched_getaffinity(0)), clamp=False), default=len(os.sched_getaffinity(0)),
122
+ help="Set the number of cores to use in the computation")
123
+ @click.option("-s", "--seed", type=int,
124
+ help="Set seed to ensure reproducible results")
125
+ @click.option("-v", "--verbose",
126
+ help="Verbose", is_flag=True)
127
+ @click.option("-t", "--cancer_type",
128
+ help="Cancer type", type=str)
129
+ @click.option("-C", "--cohort",
130
+ help="Name of the cohort", type=str)
131
+ @click.option("--no_fragments", is_flag=True,
132
+ help="Disable processing of fragmented (AF-F) proteins")
133
+ @click.option("--only_processed", is_flag=True,
134
+ help="Include only processed genes in the output")
135
+ @click.option("--thr_mapping_issue", type=float, default=0.1,
136
+ help="Threshold to filter out genes by the ratio of mutations with mapping issue (out of structure, WT AA mismatch, zero prob to mutate). Threshold of 1 disable any WT AA mismatch mutations filtering.")
137
+ @click.option("--o3d_transcripts", is_flag=True,
138
+ help="Filter mutations by keeping transcripts included in Oncodrive3D built sequence dataframe. Only if input file (--i) is a raw VEP output")
139
+ @click.option("--use_input_symbols", is_flag=True,
140
+ help="Update HUGO symbols in Oncodrive3D built datasets by using input file entries. Only if input file (--i) is a raw VEP output")
141
+ @click.option("--mane", is_flag=True,
142
+ help="If multiple structures are associated to the same HUGO symbol in the input file, use the MANE ones.")
143
+ @click.option("--sample_info", is_flag=True,
144
+ help="Include sample information in position-level result (currently unavailable).") # TODO: enable sample info in output
145
+ @setup_logging_decorator
146
+ def run(input_path,
147
+ mut_profile_path,
148
+ mutability_config_path,
149
+ output_dir,
150
+ data_dir,
151
+ n_iterations,
152
+ alpha,
153
+ cmap_prob_thr,
154
+ cores,
155
+ seed,
156
+ verbose,
157
+ cancer_type,
158
+ cohort,
159
+ no_fragments,
160
+ only_processed,
161
+ thr_mapping_issue,
162
+ o3d_transcripts,
163
+ use_input_symbols,
164
+ mane,
165
+ sample_info):
166
+ """Run Oncodrive3D."""
167
+
168
+ from scripts.run.clustering import run_clustering
169
+
170
+ # Initialize
171
+ plddt_path = os.path.join(data_dir, "confidence.tsv")
172
+ cmap_path = os.path.join(data_dir, "prob_cmaps")
173
+ seq_df_path = os.path.join(data_dir, "seq_for_mut_prob.tsv")
174
+ pae_path = os.path.join(data_dir, "pae")
175
+ cancer_type = cancer_type if cancer_type else np.nan
176
+ cohort = cohort if cohort else f"cohort_{DATE}"
177
+ path_prob = mut_profile_path if mut_profile_path else "Not provided, mutabilities will be used" if mutability_config_path else "Not provided, uniform distribution will be used"
178
+ path_mutability_config = mutability_config_path if mutability_config_path else "Not provided, mutabilities will not be used"
179
+
180
+ # Log
181
+ startup_message(__version__, "Initializing analysis..")
182
+
183
+ logger.info(f"Input MAF: {input_path}")
184
+ logger.info(f"Input mut profile: {path_prob}")
185
+ logger.info(f"Input mutability config: {path_mutability_config}")
186
+ logger.info(f"Build directory: {data_dir}")
187
+ logger.info(f"Output directory: {output_dir}")
188
+ logger.debug(f"Path to CMAPs: {cmap_path}")
189
+ logger.debug(f"Path to DNA sequences: {seq_df_path}")
190
+ logger.debug(f"Path to PAE: {pae_path}")
191
+ logger.debug(f"Path to pLDDT scores: {plddt_path}")
192
+ logger.info(f"CPU cores: {cores}")
193
+ logger.info(f"Iterations: {n_iterations}")
194
+ logger.info(f"Significant level: {alpha}")
195
+ logger.info(f"Probability threshold for CMAPs: {cmap_prob_thr}")
196
+ logger.info(f"Cohort: {cohort}")
197
+ logger.info(f"Cancer type: {cancer_type}")
198
+ logger.info(f"Disable fragments: {no_fragments}")
199
+ logger.info(f"Output only processed genes: {only_processed}")
200
+ logger.info(f"Ratio threshold mutations with mapping issue: {thr_mapping_issue}")
201
+ logger.info(f"Seed: {seed}")
202
+ logger.info(f"Filter input by Oncodrive3D transcripts: {o3d_transcripts}")
203
+ logger.info(f"Use HUGO symbols of input file: {use_input_symbols}")
204
+ logger.info(f"Prioritize MANE transcripts when using input HUGO symbols: {mane}")
205
+ logger.info(f"Include sample informations in output: {sample_info}")
206
+ logger.info(f"Verbose: {verbose}")
207
+ logger.info(f'Log path: {os.path.join(output_dir, "log")}')
208
+ logger.info("")
209
+
210
+ run_clustering(input_path,
211
+ mut_profile_path,
212
+ mutability_config_path,
213
+ output_dir,
214
+ cmap_path,
215
+ seq_df_path,
216
+ plddt_path,
217
+ pae_path,
218
+ n_iterations,
219
+ alpha,
220
+ cmap_prob_thr,
221
+ cores,
222
+ seed,
223
+ verbose,
224
+ cancer_type,
225
+ cohort,
226
+ no_fragments,
227
+ only_processed,
228
+ thr_mapping_issue,
229
+ o3d_transcripts,
230
+ use_input_symbols,
231
+ mane,
232
+ sample_info)
233
+
234
+
235
+
236
+ # =============================================================================
237
+ # BUILD ANNOTATIONS
238
+ # =============================================================================
239
+
240
+ @oncodrive3D.command(context_settings=dict(help_option_names=['-h', '--help']),
241
+ help="Build annotations - Required (once) only to plot annotations.")
242
+ @click.option("-d", "--data_dir", help="Path to datasets", type=str, required=True)
243
+ @click.option("-o", "--output_dir", help="Path to dir where to store annotations", type=str, default="annotations")
244
+ @click.option("-g", "--ddg_dir", help="Path to custom ddG predictions", type=str)
245
+ #@click.option("-S", "--path_pdb_tool_sif", help="Path to the PDB_Tool SIF", type=str, required=True)
246
+ @click.option("-s", "--organism", type=click.Choice(["Homo sapiens", 'human', "Mus musculus", 'mouse']), help="Organism name", default="Homo sapiens")
247
+ @click.option("-c", "--cores", type=click.IntRange(min=1, max=len(os.sched_getaffinity(0)), clamp=False), default=len(os.sched_getaffinity(0)),
248
+ help="Number of cores to use in the computation")
249
+ @click.option("-y", "--yes", help="No interaction", is_flag=True)
250
+ @click.option("-v", "--verbose", help="Verbose", is_flag=True)
251
+ @setup_logging_decorator
252
+ def build_annotations(data_dir,
253
+ output_dir,
254
+ ddg_dir,
255
+ #path_pdb_tool_sif,
256
+ organism,
257
+ cores,
258
+ yes,
259
+ verbose):
260
+ """
261
+ Build datasets to plot protein annotations.
262
+ """
263
+
264
+ startup_message(__version__, "Initializing building annotations..")
265
+
266
+ logger.info(f"Output directory: {output_dir}")
267
+ logger.info(f"Path to datasets: {data_dir}")
268
+ logger.info(f"Path to custom ddG predictions: {ddg_dir}")
269
+ #logger.info(f"Path to PDB_Tool SIF: {path_pdb_tool_sif}")
270
+ logger.info(f"Organism: {organism}")
271
+ logger.info(f"Cores: {cores}")
272
+ logger.info(f"Verbose: {bool(verbose)}")
273
+ logger.info(f'Log path: {os.path.join(output_dir, "log")}')
274
+ logger.info("")
275
+
276
+ from scripts.plotting.build_annotations import get_annotations
277
+
278
+ get_annotations(data_dir,
279
+ output_dir,
280
+ ddg_dir,
281
+ #path_pdb_tool_sif,
282
+ organism,
283
+ cores)
284
+
285
+
286
+
287
+ # =============================================================================
288
+ # PLOT
289
+ # =============================================================================
290
+
291
+ @oncodrive3D.command(context_settings=dict(help_option_names=['-h', '--help']),
292
+ help="Generate plots for a quick interpretation of the 3D-clustering analysis.")
293
+ @click.option("-g", "--gene_result_path", type=click.Path(exists=True), required=True,
294
+ help="Path to genes-level O3D result")
295
+ @click.option("-p", "--pos_result_path", type=click.Path(exists=True), required=True,
296
+ help="Path to positions-level O3D result")
297
+ @click.option("-i", "--maf_path", type=click.Path(exists=True), required=True,
298
+ help="Path to input mutations file")
299
+ @click.option("-m", "--miss_prob_path", type=click.Path(exists=True), required=True,
300
+ help="Path to missense mutations probability dictionary")
301
+ @click.option("-s", "--seq_df_path", type=click.Path(exists=True), required=True,
302
+ help="Path to dataframe of sequences")
303
+ @click.option("-d", "--datasets_dir", type=click.Path(exists=True), required=True,
304
+ help="Path to datasets directory")
305
+ @click.option("-a", "--annotations_dir", type=click.Path(exists=True), required=True,
306
+ help="Path to annotations directory")
307
+ @click.option("-o", "--output_dir", default="./",
308
+ help="Path to output directory where to save plots")
309
+ @click.option("-c", "--cohort",
310
+ help="Cohort name", type=str, required=True)
311
+ @click.option("--title", ## Might be redundant
312
+ help="Plot title", type=str)
313
+ @click.option("--maf_for_nonmiss_path", type=click.Path(exists=True),
314
+ help="Path to input mutations file including non-missense mutations")
315
+ @click.option("--lst_summary_tracks", type=str,
316
+ help="List of tracks to be included in the summary plot (e.g., score,miss_count,clusters)",
317
+ default="score,miss_count,res_count,res_clust_mut,clusters")
318
+ @click.option("--lst_summary_hratios", type=str,
319
+ help="List of float to define horizontal ratio of each track of the summary plot")
320
+ @click.option("--lst_gene_tracks", type=str,
321
+ help="List of tracks to be included in the gene plots (e.g., miss_count,miss_prob,score)",
322
+ default="miss_count,miss_prob,score,clusters,ddg,disorder,pacc,ptm,site,sse,pfam,prosite,membrane,motif")
323
+ @click.option("--lst_gene_hratios", type=str,
324
+ help="List of floats to define horizontal ratio of each track of the gene plot")
325
+ @click.option("--summary_fsize_x", help="Figure size x-axis for summary plots (dynamically adjusted)", type=float, default=0.5)
326
+ @click.option("--summary_fsize_y", help="Figure size y-axis for summary plots", type=int, default=8)
327
+ @click.option("--gene_fsize_x", help="Figure size x-axis for gene plots", type=int, default=24)
328
+ @click.option("--gene_fsize_y", help="Figure size y-axis for gene plots", type=int, default=12)
329
+ @click.option("--summary_alpha", help="Alpha value for score track in summary plot", type=float, default=0.7)
330
+ @click.option("--dist_thr", help="Threshold of ratios to avoid clashing feature names (e.g., domains and motifs)", type=float, default=0.1)
331
+ @click.option("--genes", help="List of genes to be analysed in the report (e.g., --genes TP53,KRAS,PIK3CA)", type=str)
332
+ @click.option("--c_genes_only", help="Generate gene plots only for significant genes (use --no-c_genes_only to disable)", is_flag=True, default=True)
333
+ @click.option("--max_n_genes", help="Max number of genes to plot", type=int, default=30)
334
+ @click.option("--volcano_top_n", help="Top associations to annotate in volcano plot", type=int, default=15)
335
+ @click.option("--volcano_fsize_x", help="Figure size x-axis for volcano plot", type=float, default=10)
336
+ @click.option("--volcano_fsize_y", help="Figure size y-axis for volcano plot", type=float, default=6)
337
+ @click.option("--volcano_subplots_fsize_x", help="Figure size x-axis for volcano subplots (dynamically adjusted)", type=float, default=3.2)
338
+ @click.option("--volcano_subplots_fsize_y", help="Figure size y-axis for volcano subplots (dynamically adjusted)", type=float, default=3)
339
+ @click.option("--log_odds_fsize_x", help="Figure size x-axis for log odds plot (dynamically adjusted)", type=float, default=1.7)
340
+ @click.option("--log_odds_fsize_y", help="Figure size y-axis for log odds plot (dynamically adjusted)", type=float, default=3.6)
341
+ @click.option("--output_csv", help="Output csv file including annotated Oncodrive3D result", is_flag=True)
342
+ @click.option("--output_all_pos", help="Include all position (including non-mutated ones) in the Oncodrive3D enriched result", is_flag=True)
343
+ @click.option("-v", "--verbose", help="Verbose", is_flag=True)
344
+ @setup_logging_decorator
345
+ def plot(gene_result_path,
346
+ pos_result_path,
347
+ maf_path,
348
+ miss_prob_path,
349
+ seq_df_path,
350
+ datasets_dir,
351
+ annotations_dir,
352
+ output_dir,
353
+ cohort,
354
+ title,
355
+ maf_for_nonmiss_path,
356
+ lst_summary_tracks,
357
+ lst_summary_hratios,
358
+ lst_gene_tracks,
359
+ lst_gene_hratios,
360
+ summary_fsize_x,
361
+ summary_fsize_y,
362
+ gene_fsize_x,
363
+ gene_fsize_y,
364
+ summary_alpha,
365
+ dist_thr,
366
+ genes,
367
+ c_genes_only,
368
+ max_n_genes,
369
+ volcano_top_n,
370
+ volcano_fsize_x,
371
+ volcano_fsize_y,
372
+ volcano_subplots_fsize_x,
373
+ volcano_subplots_fsize_y,
374
+ log_odds_fsize_x,
375
+ log_odds_fsize_y,
376
+ output_csv,
377
+ output_all_pos,
378
+ verbose):
379
+ """"Generate summary and individual gene plots for a quick interpretation of the 3D-clustering analysis."""
380
+
381
+ from scripts.plotting.plot import generate_plots
382
+ from scripts.plotting.utils import init_plot_pars, parse_lst_tracks
383
+
384
+ startup_message(__version__, "Starting plot generation..")
385
+ logger.info(f"O3D genes-result: {gene_result_path}")
386
+ logger.info(f"O3D positions-result: {pos_result_path}")
387
+ logger.info(f"O3D input mutations: {maf_path}")
388
+ logger.info(f"O3D missense mut prob: {miss_prob_path}")
389
+ logger.info(f"O3D sequences df: {seq_df_path}")
390
+ logger.info(f"O3D datasets: {datasets_dir}")
391
+ logger.info(f"O3D annotations: {annotations_dir}")
392
+ logger.info(f"Output: {output_dir}")
393
+ logger.info(f"Cohort: {cohort}")
394
+ logger.info(f"Title: {title}")
395
+ logger.info(f"Input mutations including non-missense: {maf_for_nonmiss_path}")
396
+ logger.info(f"Custom summary plot tracks: {lst_summary_tracks}")
397
+ logger.info(f"Custom summary plot h-ratios: {lst_summary_hratios}")
398
+ logger.info(f"Custom gene plots tracks: {lst_gene_tracks}")
399
+ logger.info(f"Custom gene plots h-ratios: {lst_gene_hratios}")
400
+ logger.info(f"Summary plot fsize_x (dynamically adjusted): {summary_fsize_x}")
401
+ logger.info(f"Summary plot fsize_y: {summary_fsize_y}")
402
+ logger.info(f"Gene plots fsize_x: {gene_fsize_x}")
403
+ logger.info(f"Gene plots fsize_y: {gene_fsize_y}")
404
+ logger.info(f"Volcano plot fsize_x: {volcano_fsize_x}")
405
+ logger.info(f"Volcano plot fsize_y: {volcano_fsize_y}")
406
+ logger.info(f"Volcano subplot fsize_x (dynamically adjusted): {volcano_subplots_fsize_x}")
407
+ logger.info(f"Volcano subplot fsize_y (dynamically adjusted): {volcano_subplots_fsize_y}")
408
+ logger.info(f"Log odds plot fsize_x (dynamically adjusted): {log_odds_fsize_x}")
409
+ logger.info(f"Log odds plot fsize_y (dynamically adjusted): {log_odds_fsize_y}")
410
+ logger.info(f"Summary plot score alpha: {summary_alpha}")
411
+ logger.info(f"Threshold for clashing feat: {dist_thr}")
412
+ logger.info(f"Subset of genes: {genes}")
413
+ logger.info(f"Gene plots for significant genes only: {bool(c_genes_only)}")
414
+ logger.info(f"Max number of genes to plot: {max_n_genes}")
415
+ logger.info(f"Volcano plot top associations to annotate: {volcano_top_n}")
416
+ logger.info(f"Output csv file: {bool(output_csv)}")
417
+ logger.info(f"Include non-mutated positions in csv file: {bool(output_all_pos)}")
418
+ logger.info(f"Verbose: {bool(verbose)}")
419
+ logger.info(f'Log path: {os.path.join(output_dir, "log")}')
420
+ logger.info("")
421
+
422
+ lst_summary_tracks = parse_lst_tracks(lst_summary_tracks, plot_type="summary")
423
+ lst_gene_tracks = parse_lst_tracks(lst_gene_tracks, plot_type="gene")
424
+ plot_pars = init_plot_pars(summary_fsize_x=summary_fsize_x,
425
+ summary_fsize_y=summary_fsize_y,
426
+ gene_fsize_x=gene_fsize_x,
427
+ gene_fsize_y=gene_fsize_y,
428
+ volcano_fsize_x=volcano_fsize_x,
429
+ volcano_fsize_y=volcano_fsize_y,
430
+ volcano_subplots_fsize_x=volcano_subplots_fsize_x,
431
+ volcano_subplots_fsize_y=volcano_subplots_fsize_y,
432
+ log_odds_fsize_x=log_odds_fsize_x,
433
+ log_odds_fsize_y=log_odds_fsize_y,
434
+ dist_thr=dist_thr,
435
+ summary_alpha=summary_alpha,
436
+ lst_summary_tracks=lst_summary_tracks,
437
+ lst_summary_hratios=lst_summary_hratios,
438
+ lst_gene_annot=lst_gene_tracks,
439
+ lst_gene_hratios=lst_gene_hratios,
440
+ volcano_top_n=volcano_top_n)
441
+
442
+ generate_plots(gene_result_path=gene_result_path,
443
+ pos_result_path=pos_result_path,
444
+ maf_path=maf_path,
445
+ miss_prob_path=miss_prob_path,
446
+ seq_df_path=seq_df_path,
447
+ cohort=cohort,
448
+ datasets_dir=datasets_dir,
449
+ annotations_dir=annotations_dir,
450
+ output_dir=output_dir,
451
+ plot_pars=plot_pars,
452
+ maf_path_for_nonmiss=maf_for_nonmiss_path,
453
+ c_genes_only=c_genes_only,
454
+ n_genes=max_n_genes,
455
+ lst_genes=genes,
456
+ save_plot=True,
457
+ show_plot=False,
458
+ save_csv=output_csv,
459
+ include_all_pos=output_all_pos,
460
+ title=title)
461
+
462
+
463
+
464
+ # =============================================================================
465
+ # COMPARATIVE PLOTS
466
+ # =============================================================================
467
+
468
+ @oncodrive3D.command(context_settings=dict(help_option_names=['-h', '--help']),
469
+ help="Generate plots to compare two runs of 3D-clustering analysis.")
470
+ @click.option("-i", "--o3d_result_dir_1", type=click.Path(exists=True), required=True,
471
+ help="Path to result A directory (including gene- and pos-level result for run A)")
472
+ @click.option("-I", "--o3d_result_dir_2", type=click.Path(exists=True), required=True,
473
+ help="Path to result B directory (including gene- and pos-level result for run B)")
474
+ @click.option("-c", "--cohort_1",
475
+ help="Cohort A name (it should match the basename of the files in o3d_result_dir)", type=str, required=True)
476
+ @click.option("-C", "--cohort_2",
477
+ help="Cohort B name (it should match the basename of the files in o3d_result_dir)", type=str, required=True)
478
+ @click.option("-d", "--datasets_dir", type=click.Path(exists=True), required=True,
479
+ help="Path to datasets directory")
480
+ @click.option("-a", "--annotations_dir", type=click.Path(exists=True), required=True,
481
+ help="Path to annotations directory")
482
+ @click.option("-o", "--output_dir", required=True,
483
+ help="Path to output directory where to save plots")
484
+ @click.option("--maf_path_nonmiss_1", type=click.Path(exists=True),
485
+ help="Path to input mutations file A including non-missense mutations")
486
+ @click.option("--maf_path_nonmiss_2", type=click.Path(exists=True),
487
+ help="Path to input mutations file B including non-missense mutations (e.g., miss_count,miss_prob,score)")
488
+ @click.option("--lst_tracks", type=str,
489
+ help="List of tracks to plot",
490
+ default="miss_count,miss_prob,score,clusters,ddg,disorder,pacc,ptm,site,sse,pfam,prosite,membrane,motif")
491
+ @click.option("--lst_hratios", type=str,
492
+ help="List of float to define horizontal ratio of each track of the plot")
493
+ @click.option("--fsize_x", help="Figure size x-axis", type=float, default=24)
494
+ @click.option("--fsize_y", help="Figure size y-axis", type=float, default=12)
495
+ @click.option("--dist_thr", help="Threshold of ratios to avoid clashing feature names (e.g., domains and motifs)", type=float, default=0.1)
496
+ @click.option("--genes", help="List of genes to be analysed in the report (e.g., --genes TP53,KRAS,PIK3CA)", type=str)
497
+ @click.option("--max_n_genes", help="Max number of genes to plot", type=int, default=30)
498
+ @click.option("--count_mirror", help="Missense mutation count track as mirror image", is_flag=True)
499
+ @click.option("--prob_mirror", help="Missense mutation prob track as mirror image", is_flag=True)
500
+ @click.option("--score_mirror", help="Clustering score track as mirror image", is_flag=True)
501
+ @click.option("-v", "--verbose", help="Verbose", is_flag=True)
502
+ @setup_logging_decorator
503
+ def comparative_plot(o3d_result_dir_1,
504
+ cohort_1,
505
+ o3d_result_dir_2,
506
+ cohort_2,
507
+ datasets_dir,
508
+ annotations_dir,
509
+ output_dir,
510
+ maf_path_nonmiss_1,
511
+ maf_path_nonmiss_2,
512
+ lst_tracks,
513
+ lst_hratios,
514
+ fsize_x,
515
+ fsize_y,
516
+ dist_thr,
517
+ count_mirror,
518
+ prob_mirror,
519
+ score_mirror,
520
+ genes,
521
+ max_n_genes,
522
+ verbose):
523
+ """"Generate genes comparative plots to comprare two runs of 3D-clustering analysis."""
524
+
525
+ from scripts.plotting.plot import generate_comparative_plots
526
+ from scripts.plotting.utils import init_comp_plot_pars, parse_lst_tracks
527
+
528
+ startup_message(__version__, "Starting plot generation..")
529
+ logger.info(f"Oncodrive3D result A: {o3d_result_dir_1}")
530
+ logger.info(f"Cohort B: {cohort_1}")
531
+ logger.info(f"Oncodrive3D result B: {o3d_result_dir_2}")
532
+ logger.info(f"Cohort B: {cohort_2}")
533
+ logger.info(f"Oncodrive3D datasets: {datasets_dir}")
534
+ logger.info(f"Oncodrive3D annotations: {annotations_dir}")
535
+ logger.info(f"Output: {output_dir}")
536
+ logger.info(f"Input mutations including non-missense A: {maf_path_nonmiss_1}")
537
+ logger.info(f"Input mutations including non-missense B: {maf_path_nonmiss_2}")
538
+ logger.info(f"Custom gene plots tracks: {lst_tracks}")
539
+ logger.info(f"Custom gene plots h-ratios: {lst_hratios}")
540
+ logger.info(f"Summary plot fsize_x: {fsize_x}")
541
+ logger.info(f"Summary plot fsize_y: {fsize_y}")
542
+ logger.info(f"Threshold for clashing feat: {dist_thr}")
543
+ logger.info(f"Missense mut as mirror image: {bool(count_mirror)}")
544
+ logger.info(f"Missense mut prob as mirror image: {bool(prob_mirror)}")
545
+ logger.info(f"Score as mirror image: {bool(score_mirror)}")
546
+ logger.info(f"Verbose: {bool(verbose)}")
547
+ logger.info(f"Subset of genes: {genes}")
548
+ logger.info(f"Max number of genes to plot: {max_n_genes}")
549
+ logger.info(f"Verbose: {bool(verbose)}")
550
+ logger.info(f'Log path: {os.path.join(output_dir, "log")}')
551
+ logger.info("")
552
+
553
+ lst_tracks = parse_lst_tracks(lst_tracks, plot_type="gene")
554
+ plot_pars = init_comp_plot_pars(fsize_x=fsize_x,
555
+ fsize_y=fsize_y,
556
+ dist_thr=dist_thr,
557
+ lst_tracks=lst_tracks,
558
+ lst_hratios=lst_hratios,
559
+ count_mirror=count_mirror,
560
+ score_mirror=score_mirror,
561
+ prob_mirror=prob_mirror)
562
+
563
+ generate_comparative_plots(o3d_result_dir_1=o3d_result_dir_1,
564
+ cohort_1=cohort_1,
565
+ o3d_result_dir_2=o3d_result_dir_2,
566
+ cohort_2=cohort_2,
567
+ datasets_dir=datasets_dir,
568
+ annotations_dir=annotations_dir,
569
+ output_dir=output_dir,
570
+ plot_pars=plot_pars,
571
+ maf_path_nonmiss_1=maf_path_nonmiss_1,
572
+ maf_path_nonmiss_2=maf_path_nonmiss_2,
573
+ n_genes=max_n_genes,
574
+ lst_genes=genes)
575
+
576
+
577
+ # =============================================================================
578
+ # CHIMERAX PLOTS
579
+ # =============================================================================
580
+
581
+ @oncodrive3D.command(context_settings=dict(help_option_names=['-h', '--help']),
582
+ help="Generate 3D plots using CHimeraX.")
583
+ @click.option("-o", "--output_dir",
584
+ help="Directory where to save the plots", type=str, required=True)
585
+ @click.option("-g", "--gene_result_path",
586
+ help="Path to genes-level O3D result", type=click.Path(exists=True), required=True)
587
+ @click.option("-p", "--pos_result_path",
588
+ help="Path to positions-level O3D result", type=click.Path(exists=True), required=True)
589
+ @click.option("-d", "--datasets_dir",
590
+ help="Path to datasets", type=click.Path(exists=True), required=True)
591
+ @click.option("-s", "--seq_df_path",
592
+ help="Path to sequences dataframe", type=click.Path(exists=True), required=True)
593
+ @click.option("-c", "--cohort",
594
+ help="Cohort name", default="")
595
+ @click.option("--max_n_genes", help="Maximum number of genes to plot", type=int, default=30)
596
+ @click.option("--pixel_size", help="Pixel size (smaller value is larger number of pixels)", type=float, default=0.08)
597
+ @click.option("--cluster_ext", help="Include extended clusters", is_flag=True)
598
+ @click.option("--fragmented_proteins", help="Include fragmented proteins", is_flag=True)
599
+ @click.option("--transparent_bg", help="Set background as transparent", type=str, is_flag=True)
600
+ @click.option("--chimerax_bin", help="Path to chimerax installation", type=str, default="/usr/bin/chimerax")
601
+ @click.option("-v", "--verbose", help="Verbose", is_flag=True)
602
+ @setup_logging_decorator
603
+ def chimerax_plot(output_dir,
604
+ gene_result_path,
605
+ pos_result_path,
606
+ datasets_dir,
607
+ seq_df_path,
608
+ cohort,
609
+ max_n_genes,
610
+ pixel_size,
611
+ cluster_ext,
612
+ fragmented_proteins,
613
+ transparent_bg,
614
+ chimerax_bin,
615
+ verbose):
616
+ """"Generate images of structures annotated with clustering metrics."""
617
+
618
+ from scripts.plotting.chimerax_plot import generate_chimerax_plot
619
+
620
+ startup_message(__version__, "Starting plot generation..")
621
+ logger.info(f"Output dir: {output_dir}")
622
+ logger.info(f"Gene result path: {gene_result_path}")
623
+ logger.info(f"Position result path: {pos_result_path}")
624
+ logger.info(f"Datasets dir: {datasets_dir}")
625
+ logger.info(f"Sequence dataframe path: {seq_df_path}")
626
+ logger.info(f"Cohort: {cohort}")
627
+ logger.info(f"Max number of genes to plot: {max_n_genes}")
628
+ logger.info(f"Pixel size: {pixel_size}")
629
+ logger.info(f"Cluster extended: {cluster_ext}")
630
+ logger.info(f"Fragmented proteins: {fragmented_proteins}")
631
+ logger.info(f"Transparent background: {transparent_bg}")
632
+ logger.info(f"Verbose: {bool(verbose)}")
633
+ logger.info(f'Log path: {os.path.join(output_dir, "log")}')
634
+ logger.info("")
635
+
636
+ generate_chimerax_plot(output_dir,
637
+ gene_result_path,
638
+ pos_result_path,
639
+ datasets_dir,
640
+ seq_df_path,
641
+ cohort,
642
+ max_n_genes,
643
+ pixel_size,
644
+ cluster_ext,
645
+ fragmented_proteins,
646
+ transparent_bg,
647
+ chimerax_bin)
648
+
649
+ if __name__ == "__main__":
650
+ oncodrive3D()
File without changes