pico-ml 2.0.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.
Files changed (52) hide show
  1. pico/__init__.py +3 -0
  2. pico/__main__.py +3 -0
  3. pico/cli/__init__.py +2 -0
  4. pico/cli/main.py +117 -0
  5. pico/conf/SupportedCV.py +17 -0
  6. pico/conf/SupportedModels.py +73 -0
  7. pico/conf/algo_sklearn.json +51 -0
  8. pico/conf/parameters.py +14 -0
  9. pico/domain/ClassificationDesign.py +107 -0
  10. pico/domain/Controller.py +397 -0
  11. pico/domain/DataMatrix.py +147 -0
  12. pico/domain/ExperimentDTO.py +17 -0
  13. pico/domain/MetaData.py +229 -0
  14. pico/domain/MetaboExperiment.py +696 -0
  15. pico/domain/MetaboModel.py +53 -0
  16. pico/domain/ModelFactory.py +45 -0
  17. pico/domain/Results.py +602 -0
  18. pico/domain/SplitGroup.py +202 -0
  19. pico/domain/__init__.py +9 -0
  20. pico/domain/dumps/metadata/.gitkeep +0 -0
  21. pico/domain/dumps/splits/.gitkeep +0 -0
  22. pico/service/DataFormat.py +180 -0
  23. pico/service/ExperimentDesign.py +30 -0
  24. pico/service/LoggerConfig.py +150 -0
  25. pico/service/Plots.py +472 -0
  26. pico/service/RunMLalgo.py +93 -0
  27. pico/service/SamplesPairing.py +390 -0
  28. pico/service/Utils.py +497 -0
  29. pico/service/__init__.py +7 -0
  30. pico/ui/__init__.py +1 -0
  31. pico/ui/app.py +145 -0
  32. pico/ui/assets/000_Stylesheet.css +464 -0
  33. pico/ui/assets/DecisionTree.png +0 -0
  34. pico/ui/assets/Figure_home_wider.png +0 -0
  35. pico/ui/assets/favicon.ico +0 -0
  36. pico/ui/assets/help_icon.png +0 -0
  37. pico/ui/assets/help_icon.svg +15 -0
  38. pico/ui/assets/update_figure_steps_MeDIC_4.svg +1 -0
  39. pico/ui/tabs/AggregatedResultsTab.py +394 -0
  40. pico/ui/tabs/InfoTab.py +440 -0
  41. pico/ui/tabs/InterpretTab.py +21 -0
  42. pico/ui/tabs/MLTab.py +487 -0
  43. pico/ui/tabs/MetaTab.py +23 -0
  44. pico/ui/tabs/ResultsTab.py +1062 -0
  45. pico/ui/tabs/SplitsTab.py +1227 -0
  46. pico/ui/tabs/__init__.py +6 -0
  47. pico/ui/tabs/utils.py +101 -0
  48. pico_ml-2.0.0.dist-info/METADATA +86 -0
  49. pico_ml-2.0.0.dist-info/RECORD +52 -0
  50. pico_ml-2.0.0.dist-info/WHEEL +4 -0
  51. pico_ml-2.0.0.dist-info/entry_points.txt +2 -0
  52. pico_ml-2.0.0.dist-info/licenses/LICENSE +437 -0
@@ -0,0 +1,440 @@
1
+ import dash
2
+ import dash_bootstrap_components as dbc
3
+ from dash import html, dcc, Output, Input, State, callback_context, Dash
4
+
5
+ from .MetaTab import MetaTab
6
+ from ...service import decode_pickle_from_base64, Utils, init_logger, log_exceptions
7
+ from ...domain import Controller
8
+
9
+
10
+ class InfoTab(MetaTab):
11
+ def __init__(self, app: Dash, metabo_controller: Controller):
12
+ super().__init__(app, metabo_controller)
13
+ self._logger = init_logger()
14
+
15
+ def getLayout(self) -> dbc.Tab:
16
+ _docLink = dbc.Card(
17
+ className="cards_info",
18
+ children=[
19
+ dbc.CardHeader("Documentation link"),
20
+ dbc.CardBody(
21
+ [
22
+ "You can find the official documentation ",
23
+ html.A(
24
+ href="https://elinaff.github.io/PICO/",
25
+ target="_blank",
26
+ rel="noreferrer noopener",
27
+ children="here",
28
+ ),
29
+ ".",
30
+ ]
31
+ ),
32
+ ],
33
+ )
34
+
35
+ _splitsInfo = dbc.Card(
36
+ className="cards_info",
37
+ children=[
38
+ dbc.CardHeader("Splits"),
39
+ dbc.CardBody(
40
+ [
41
+ html.P(
42
+ "The Splits tab is where settings to run a machine learning experiment are decided and stored into a file. "
43
+ "At this step, you can decide the classification designs that you wish to explore, the number of splits, the sample pairing, etc. "
44
+ "In the case where you have 3 or more different classes (eg: healthy, sick, extremely sick or diet1, diet2, diet3, diet4), "
45
+ "you will be able to combine them in two groups (designated by labels) to compare the different conditions in different ways. "
46
+ "For example, can the algorithms discriminate between (diet1) vs (diet2, diet3 and diet4), or (diet1 and diet2) vs (diet3 and diet4) ?"
47
+ ),
48
+ html.P(
49
+ "There is a hash mecanism in place to ensure that the locally saved data fits an experiment file "
50
+ "that might be loaded into the PICO in the future. It is computed and stored in the file of settings. This mecanism can be compared to a lock and key mecanism. The key "
51
+ "to check a file will only fit this particular file. It ensures reproductibility reliability."
52
+ ),
53
+ ]
54
+ ),
55
+ ],
56
+ )
57
+
58
+ _MLInfo = dbc.Card(
59
+ className="cards_info",
60
+ children=[
61
+ dbc.CardHeader("Machine Learning"),
62
+ dbc.CardBody(
63
+ [
64
+ html.P(
65
+ "In this tab, you select the cross-validation algorithm and its parameters and the machine learning algorithms you wish to apply on your data."
66
+ "The cross-validation step is usefull to optimize the algorithm : it runs several time the algorithm on small"
67
+ "part of the dataset with different parameters, and will keep the best model which will be applied "
68
+ "to your real dataset and gives you the final results and analyses."
69
+ ),
70
+ html.P(
71
+ "For the algorithms selection, there is some already implemented by default in the tool, so you can simply "
72
+ "select them. But there is also the possibility to import manually other algorithms from Scikit-Learn. In this "
73
+ "case you need to provide several information about the algorithm you wish to add so it can be integrated in the "
74
+ "analysis."
75
+ ),
76
+ html.P(
77
+ "The possibility to add a completely custom algorithm is also available. But it requires "
78
+ "modifications directly in the code files. It is meant for people with more programming abilities."
79
+ ),
80
+ ]
81
+ ),
82
+ ],
83
+ )
84
+
85
+ _resultInfo = dbc.Card(
86
+ className="cards_info",
87
+ children=[
88
+ dbc.CardHeader("Results"),
89
+ dbc.CardBody(
90
+ [
91
+ html.P(
92
+ "The entire section of Results is based on the perspective of analysing the features selected "
93
+ "by the algorithms. For one classification design, multiple algorithms can be run. "
94
+ "Then, the results and performances of each algorithm can be explored one by one to ensure that "
95
+ "the prediction and therefore the selection of the features is valid. At the end, there is a "
96
+ "section that aggregates the results of all the algorithms to check for redundancies. The repeated use of an "
97
+ "ion(feature) across different algorithm is a good indicator of the relevance of this molecule.",
98
+ className="card-text",
99
+ ),
100
+ ]
101
+ ),
102
+ ],
103
+ )
104
+
105
+ _loadExpe = dbc.Card(
106
+ className="cards_info",
107
+ style={"margin-left": "2em"},
108
+ children=[
109
+ dbc.CardHeader("Load MetaboExperiment"),
110
+ dbc.CardBody(
111
+ [
112
+ html.P(
113
+ "You can load the file of a previous experiment and resume your analysis."
114
+ ),
115
+ dcc.Upload(
116
+ id="load_expe",
117
+ style={"width": "fit-content"},
118
+ children=[
119
+ dbc.Button(
120
+ "Select File",
121
+ id="load_expe_button",
122
+ className="custom_buttons",
123
+ color="primary",
124
+ )
125
+ ],
126
+ ),
127
+ ]
128
+ ),
129
+ ],
130
+ )
131
+
132
+ _infoFigure = dbc.Card(
133
+ className="card_body_fig",
134
+ children=[
135
+ # dbc.Card("Amazing figure here", className="card_body_fig", body=True),
136
+ dbc.CardImg(src="/assets/update_figure_steps_MeDIC_4.svg", bottom=True)
137
+ ],
138
+ )
139
+ # TODO : add the filename
140
+ _modal = dbc.Modal(
141
+ children=[
142
+ dbc.ModalHeader(
143
+ style={"padding": "2rem 3rem"},
144
+ children=[html.H6("Warning: Saved local files do not match")],
145
+ ),
146
+ dbc.ModalBody(
147
+ style={"padding": "2em"},
148
+ children=[
149
+ html.P(
150
+ "The data and/or metadata used in the MetaboExperiment file are not the same as the "
151
+ "local ones."
152
+ ),
153
+ html.P(
154
+ "Please restore the correct data and/or metadata if you want "
155
+ "to continue the same experiment. (Full restore)"
156
+ ),
157
+ html.P(
158
+ "Otherwise, you can use the same parameters with new data and/or metadata (Partial restore) "
159
+ "but the sample column name, target column name and classification designs won't be "
160
+ "restored."
161
+ ),
162
+ html.P(
163
+ "If you only want to see the results, it will be available (Load results) but metadata and data "
164
+ "matrix will be reset, as well as the classification designs."
165
+ ),
166
+ html.Div(
167
+ children=[
168
+ dcc.Upload(
169
+ id="upload_datatable_modal",
170
+ children=[
171
+ dbc.Button(
172
+ "Upload Data Matrix",
173
+ id="upload_datatable_modal_button",
174
+ # className="custom_buttons",
175
+ color="outline-primary",
176
+ )
177
+ ],
178
+ ),
179
+ dcc.Loading(
180
+ id="upload_datatable_modal_loading",
181
+ type="dot",
182
+ color="#13BD00",
183
+ children=[
184
+ html.Div(id="upload_datatable_modal_output"),
185
+ ],
186
+ ),
187
+ ],
188
+ style={"display": "flex", "align-items": "center"},
189
+ ),
190
+ html.Div(
191
+ children=[
192
+ dcc.Upload(
193
+ id="upload_metadata_modal",
194
+ children=[
195
+ dbc.Button(
196
+ "Upload Metadata",
197
+ id="upload_metadata_modal_button",
198
+ # className="custom_buttons",
199
+ color="outline-primary",
200
+ )
201
+ ],
202
+ ),
203
+ dcc.Loading(
204
+ id="upload_metadata_modal_loading",
205
+ type="dot",
206
+ color="#13BD00",
207
+ children=[
208
+ html.Div(id="upload_metadata_modal_output"),
209
+ ],
210
+ ),
211
+ ],
212
+ style={"display": "flex", "align-items": "center"},
213
+ ),
214
+ html.Div(
215
+ id="upload_datatable_modal_error_output",
216
+ style={"color": "red"},
217
+ ),
218
+ ],
219
+ ),
220
+ dbc.ModalFooter(
221
+ style={"padding-left": "1em"},
222
+ children=[
223
+ dbc.Button(
224
+ "Close", id="close", className="custom_buttons", n_clicks=0
225
+ ),
226
+ # NO FILES
227
+ dbc.Button(
228
+ "Load results",
229
+ id="loadAnyway",
230
+ className="custom_buttons push",
231
+ n_clicks=0,
232
+ ),
233
+ # require files
234
+ dbc.Button(
235
+ "Partial restore",
236
+ id="partialRestore",
237
+ className="custom_buttons",
238
+ n_clicks=0,
239
+ ),
240
+ # require files
241
+ dbc.Button(
242
+ "Full restore",
243
+ id="fullRestore",
244
+ className="custom_buttons",
245
+ n_clicks=0,
246
+ ),
247
+ ],
248
+ ),
249
+ ],
250
+ id="warning-not-match",
251
+ size="lg",
252
+ is_open=False,
253
+ )
254
+
255
+ _hidden_div = html.Div(id="hidden_div", style={"display": "none"})
256
+
257
+ return dbc.Tab(
258
+ className="global_tab",
259
+ tab_style={"margin-left": "auto"},
260
+ label="Home",
261
+ children=[
262
+ _modal,
263
+ html.Div(
264
+ className="fig_group",
265
+ children=[
266
+ html.Div(
267
+ className="column_content",
268
+ # WARNING !! : _infoFigure is not with the card, it's in a separate column
269
+ children=[
270
+ _docLink,
271
+ _splitsInfo,
272
+ _MLInfo,
273
+ _resultInfo,
274
+ _hidden_div,
275
+ ],
276
+ ),
277
+ html.Div(
278
+ className="column_content",
279
+ children=[
280
+ _loadExpe,
281
+ _infoFigure,
282
+ ],
283
+ ),
284
+ ],
285
+ ),
286
+ ],
287
+ ) # _interpretInfo
288
+
289
+ def _registerCallbacks(self) -> None:
290
+ @self.app.callback(
291
+ [
292
+ Output("upload_datatable_modal_output", "children"),
293
+ Output("upload_datatable_modal_output", "style"),
294
+ ],
295
+ [Input("upload_datatable_modal", "contents")],
296
+ [State("load_expe", "contents")],
297
+ )
298
+ @log_exceptions(self._logger)
299
+ def set_data_matrix_in_modal(contents, dto_contents):
300
+ if contents is not None:
301
+ metabo_experiment_dto = decode_pickle_from_base64(dto_contents)
302
+ if Utils.is_data_the_same(contents, metabo_experiment_dto):
303
+ return "Data matrix uploaded successfully", {"color": "green"}
304
+ else:
305
+ return (
306
+ "Data matrix uploaded but not corresponding to the local one",
307
+ {"color": "yellow"},
308
+ )
309
+ else:
310
+ return dash.no_update, dash.no_update
311
+
312
+ @self.app.callback(
313
+ [
314
+ Output("upload_metadata_modal_output", "children"),
315
+ Output("upload_metadata_modal_output", "style"),
316
+ ],
317
+ [Input("upload_metadata_modal", "contents")],
318
+ [State("load_expe", "contents")],
319
+ )
320
+ @log_exceptions(self._logger)
321
+ def set_metadata_in_modal(contents, dto_contents):
322
+ if contents is not None:
323
+ metabo_experiment_dto = decode_pickle_from_base64(dto_contents)
324
+ if Utils.is_metadata_the_same(contents, metabo_experiment_dto):
325
+ return "Metadata uploaded successfully", {"color": "green"}
326
+ else:
327
+ return "Metadata uploaded but not corresponding to the local one", {
328
+ "color": "yellow"
329
+ }
330
+ else:
331
+ return dash.no_update, dash.no_update
332
+
333
+ @self.app.callback(
334
+ [
335
+ Output("warning-not-match", "is_open"),
336
+ Output("hidden_div", "children"),
337
+ Output("upload_datatable_modal_error_output", "children"),
338
+ ],
339
+ [
340
+ Input("close", "n_clicks"),
341
+ Input("loadAnyway", "n_clicks"),
342
+ Input("partialRestore", "n_clicks"),
343
+ Input("fullRestore", "n_clicks"),
344
+ Input("load_expe", "filename"),
345
+ ],
346
+ [
347
+ State("load_expe", "contents"),
348
+ State("upload_datatable_modal", "contents"),
349
+ State("upload_metadata_modal", "contents"),
350
+ State("upload_datatable_modal", "filename"),
351
+ State("upload_metadata_modal", "filename"),
352
+ ],
353
+ )
354
+ @log_exceptions(self._logger)
355
+ def toggle_modal(
356
+ close,
357
+ load_anyway,
358
+ partial_restore,
359
+ full_restore,
360
+ filename_loaded,
361
+ contents_loaded,
362
+ new_data,
363
+ new_metadata,
364
+ new_data_name,
365
+ new_metadata_name,
366
+ ):
367
+ triggered_id = callback_context.triggered[0]["prop_id"].split(".")[0]
368
+
369
+ if triggered_id == "close":
370
+ return False, dash.no_update
371
+ else:
372
+ if triggered_id == "load_expe":
373
+ metabo_exp_dto = decode_pickle_from_base64(contents_loaded)
374
+ if self.metabo_controller.is_save_safe(metabo_exp_dto):
375
+ self.metabo_controller.full_restore(metabo_exp_dto)
376
+ return (
377
+ False,
378
+ "reload",
379
+ "",
380
+ )
381
+ else:
382
+ return True, dash.no_update, dash.no_update
383
+
384
+ elif triggered_id == "loadAnyway":
385
+ metabo_exp_dto = decode_pickle_from_base64(contents_loaded)
386
+ self.metabo_controller.load_results(metabo_exp_dto)
387
+ return (
388
+ False,
389
+ "",
390
+ "",
391
+ ) # dcc.Location(href="/home", id="someid_doesnt_matter")
392
+
393
+ elif triggered_id == "partialRestore":
394
+ metabo_exp_dto = decode_pickle_from_base64(contents_loaded)
395
+ if new_data and new_metadata:
396
+ try:
397
+ self.metabo_controller.partial_restore(
398
+ metabo_exp_dto,
399
+ new_data_name,
400
+ new_metadata_name,
401
+ data=new_data,
402
+ metadata=new_metadata,
403
+ )
404
+ except ValueError as ve:
405
+ return True, dash.no_update, str(ve)
406
+ return (
407
+ False,
408
+ "",
409
+ "",
410
+ )
411
+ else:
412
+ return (
413
+ True,
414
+ "",
415
+ "You need to upload both data and metadata to do a partial restore",
416
+ )
417
+
418
+ elif triggered_id == "fullRestore":
419
+ metabo_exp_dto = decode_pickle_from_base64(contents_loaded)
420
+ if (
421
+ new_data is not None
422
+ and new_metadata is not None
423
+ and Utils.are_files_corresponding_to_dto(
424
+ new_data, new_metadata, metabo_exp_dto
425
+ )
426
+ ):
427
+ self.metabo_controller.full_restore(metabo_exp_dto)
428
+ return (
429
+ False,
430
+ "",
431
+ "",
432
+ )
433
+ else:
434
+ return (
435
+ True,
436
+ "",
437
+ "You need to restore original data matrix and metadata to do a full restore",
438
+ )
439
+
440
+ return False, dash.no_update, dash.no_update
@@ -0,0 +1,21 @@
1
+ import dash_bootstrap_components as dbc
2
+ from dash import html
3
+
4
+ from .MetaTab import MetaTab
5
+
6
+
7
+ class InterpretTab(MetaTab):
8
+ def getLayout(self) -> dbc.Tab:
9
+ return dbc.Tab(
10
+ className="global_tab",
11
+ # tab_style={"margin-left": "auto"},
12
+ label="Model Interpretation",
13
+ children=[
14
+ html.P(
15
+ "A tab to allow model interpretation with model-agnostic methods."
16
+ )
17
+ ],
18
+ )
19
+
20
+ def _registerCallbacks(self) -> None:
21
+ pass