SankeyExcelParser 1.0.0b0__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 (32) hide show
  1. SankeyExcelParser/__init__.py +0 -0
  2. SankeyExcelParser/io_excel.py +1867 -0
  3. SankeyExcelParser/io_excel_constants.py +811 -0
  4. SankeyExcelParser/sankey.py +3138 -0
  5. SankeyExcelParser/sankey_utils/__init__.py +0 -0
  6. SankeyExcelParser/sankey_utils/data.py +1118 -0
  7. SankeyExcelParser/sankey_utils/excel_source.py +31 -0
  8. SankeyExcelParser/sankey_utils/flux.py +344 -0
  9. SankeyExcelParser/sankey_utils/functions.py +278 -0
  10. SankeyExcelParser/sankey_utils/node.py +340 -0
  11. SankeyExcelParser/sankey_utils/protos/__init__.py +0 -0
  12. SankeyExcelParser/sankey_utils/protos/flux.py +84 -0
  13. SankeyExcelParser/sankey_utils/protos/node.py +386 -0
  14. SankeyExcelParser/sankey_utils/protos/sankey_object.py +135 -0
  15. SankeyExcelParser/sankey_utils/protos/tag_group.py +95 -0
  16. SankeyExcelParser/sankey_utils/sankey_object.py +165 -0
  17. SankeyExcelParser/sankey_utils/table_object.py +37 -0
  18. SankeyExcelParser/sankey_utils/tag.py +95 -0
  19. SankeyExcelParser/sankey_utils/tag_group.py +206 -0
  20. SankeyExcelParser/su_trace.py +239 -0
  21. SankeyExcelParser/tests/integration/__init__.py +0 -0
  22. SankeyExcelParser/tests/integration/test_base.py +356 -0
  23. SankeyExcelParser/tests/integration/test_run_check_input.py +100 -0
  24. SankeyExcelParser/tests/integration/test_run_conversions.py +96 -0
  25. SankeyExcelParser/tests/integration/test_run_load_input.py +94 -0
  26. SankeyExcelParser/tests/unit/__init__.py +0 -0
  27. SankeyExcelParser-1.0.0b0.data/scripts/run_parse_and_write_excel.py +155 -0
  28. SankeyExcelParser-1.0.0b0.data/scripts/run_parse_excel.py +115 -0
  29. SankeyExcelParser-1.0.0b0.dist-info/METADATA +113 -0
  30. SankeyExcelParser-1.0.0b0.dist-info/RECORD +32 -0
  31. SankeyExcelParser-1.0.0b0.dist-info/WHEEL +5 -0
  32. SankeyExcelParser-1.0.0b0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,1118 @@
1
+ """
2
+ Author : Vincent LE DOZE
3
+ Date : 31/05/23
4
+
5
+ This file contains descriptions for Data class
6
+
7
+ """
8
+
9
+ # Local modules -----------------------------------------------------
10
+ from SankeyExcelParser.sankey_utils.sankey_object import SankeyObject
11
+ from SankeyExcelParser.sankey_utils.protos.flux import _ProtoFlux
12
+ import SankeyExcelParser.io_excel_constants as CONST
13
+
14
+
15
+ # CLASS ----------------------------------------------------------------------------
16
+ class ProtoData(object):
17
+ """
18
+ Define Data simple object.
19
+
20
+ Parameters
21
+ ----------
22
+ :param natural_unit: Unité naturelle de reference pour la donnée.
23
+ :type natural_unit: str
24
+
25
+ :param factor: Facteur de conversion
26
+ :type factor: float
27
+
28
+ :param source: source de la donnée.
29
+ :type source: str
30
+
31
+ :param hypothesis: Descriptions des hypothèes de données
32
+ :type hypothesis: str
33
+ """
34
+
35
+ def __init__(
36
+ self,
37
+ **kwargs
38
+ ):
39
+ # Attributes
40
+ self._natural_unit = None
41
+ self._factor = None
42
+ self._source = None
43
+ self._hypothesis = None
44
+ self.update(**kwargs)
45
+
46
+ def update(
47
+ self,
48
+ **kwargs
49
+ ):
50
+ for key, value in kwargs.items():
51
+ setattr(self, key, value)
52
+
53
+ def _set_as_int(
54
+ self,
55
+ key,
56
+ value
57
+ ):
58
+ # None case
59
+ if value is None:
60
+ setattr(self, key, None)
61
+ return
62
+ # Real affectation
63
+ try:
64
+ value_as_int = int(value)
65
+ setattr(self, key, value_as_int)
66
+ except Exception:
67
+ pass
68
+
69
+ def _set_as_float(
70
+ self,
71
+ key,
72
+ value
73
+ ):
74
+ # None case
75
+ if value is None:
76
+ setattr(self, key, None)
77
+ return
78
+ # Real affectation
79
+ try:
80
+ value_as_float = float(value)
81
+ # NAN protection
82
+ if (value_as_float != value_as_float):
83
+ return
84
+ setattr(self, key, value_as_float)
85
+ except Exception:
86
+ pass
87
+
88
+ def _get_as_round_value(
89
+ self,
90
+ key,
91
+ digits
92
+ ):
93
+ try:
94
+ return round(getattr(self, key), digits)
95
+ except Exception:
96
+ return getattr(self, key)
97
+
98
+ def _set_as_str(
99
+ self,
100
+ key,
101
+ value
102
+ ):
103
+ # None case
104
+ if value is None:
105
+ setattr(self, key, None)
106
+ return
107
+ # Real affectation
108
+ try:
109
+ value_as_str = str(value)
110
+ setattr(self, key, value_as_str)
111
+ except Exception:
112
+ pass
113
+
114
+ @property
115
+ def natural_unit(self):
116
+ return self._natural_unit
117
+
118
+ @natural_unit.setter
119
+ def natural_unit(self, _):
120
+ self._set_as_str('_natural_unit', _)
121
+
122
+ @property
123
+ def factor(self):
124
+ return self._factor
125
+
126
+ @factor.setter
127
+ def factor(self, _):
128
+ self._set_as_float('_factor', _)
129
+
130
+ @property
131
+ def source(self):
132
+ return self._source
133
+
134
+ @source.setter
135
+ def source(self, _):
136
+ self._set_as_str('_source', _)
137
+
138
+ @property
139
+ def hypothesis(self):
140
+ return self._hypothesis
141
+
142
+ @hypothesis.setter
143
+ def hypothesis(self, _):
144
+ self._set_as_str('_hypothesis', _)
145
+
146
+
147
+ class DataMinMax(ProtoData):
148
+ """
149
+ Define Data constraint object.
150
+ Inherits from ProtoData.
151
+
152
+ Parameters
153
+ ----------
154
+ :param reference: Reference of the object on that the min max applies to.
155
+ :param reference: Flux | Data
156
+
157
+ :param min_val: Value that reference value must be superior to
158
+ :type min_val: float
159
+
160
+ :param min_quantity: Quantity that reference value must be superior to
161
+ :type min_quantity: float
162
+
163
+ :param max_val: Value that reference value must be inferior to
164
+ :type max_val: float
165
+
166
+ :param max_quantity: Quantity that reference value must be inferior to
167
+ :type max_quantity: float
168
+ """
169
+ def __init__(
170
+ self,
171
+ reference,
172
+ **kwargs
173
+ ):
174
+ # Attributes
175
+ self._reference = reference
176
+ self._min_val = None
177
+ self._min_quantity = None
178
+ self._max_val = None
179
+ self._max_quantity = None
180
+ # Init parent attributes
181
+ ProtoData.__init__(self)
182
+ # Update initial values
183
+ self.update(**kwargs)
184
+
185
+ @property
186
+ def min_val(self):
187
+ return self._min_val
188
+
189
+ @min_val.setter
190
+ def min_val(self, _):
191
+ self._set_as_float('_min_val', _)
192
+
193
+ @property
194
+ def min_quantity(self):
195
+ return self._min_quantity
196
+
197
+ @min_quantity.setter
198
+ def min_quantity(self, _):
199
+ self._set_as_float('_min_quantity', _)
200
+
201
+ @property
202
+ def max_val(self):
203
+ return self._max_val
204
+
205
+ @max_val.setter
206
+ def max_val(self, _):
207
+ self._set_as_float('_max_val', _)
208
+
209
+ @property
210
+ def max_quantity(self):
211
+ return self._max_quantity
212
+
213
+ @max_quantity.setter
214
+ def max_quantity(self, _):
215
+ self._set_as_float('_max_quantity', _)
216
+
217
+ def update_table(
218
+ self,
219
+ columns_datataggs_names: list,
220
+ columns_fluxtaggs_names: list,
221
+ extra_infos_names: list,
222
+ table: list
223
+ ):
224
+ """
225
+ Update a panda table with this data infos.
226
+ The columns are organized as :
227
+
228
+ 2. Origin
229
+ 3. Destination
230
+ 4. All data tags (multiple columns) : for each column we have the respective tags or None
231
+ 5. All flux tags (multiple columns) : for each column we have the respective tags or None
232
+ 6. Min value
233
+ 7. Max value
234
+ 8. Min Quantity
235
+ 9. Max quantity
236
+ 10. Natural unit
237
+ 11. Factor
238
+ 12. Sources
239
+ 13. Hypothesis
240
+ 14. All remaining extra infos (if present, multiple columns)
241
+
242
+ Parameters
243
+ ----------
244
+ :param columns_datataggs_names: List of tag groups for data tags columns
245
+ :type columns_datataggs_names: list[str] | list[TagGroup]
246
+
247
+ :param columns_fluxtaggs_names: List of tag groups for flux tags columns
248
+ :type columns_fluxtaggs_names: list[str] | list[TagGroup]
249
+
250
+ :param extra_infos_names: List of extra infos to search for extra infos columns
251
+ :type extra_infos_names: list[str]
252
+
253
+ :param table: Table (2D-list) where all infos will be added
254
+ :type table: list (modified)
255
+
256
+ """
257
+ # Only for data with value
258
+ if (self._min_val is None) and \
259
+ (self._min_quantity is None) and \
260
+ (self._max_val is None) and \
261
+ (self._max_quantity is None):
262
+ return
263
+ # Create table line with corresponding data
264
+ line = [
265
+ self._reference.orig.name,
266
+ self._reference.dest.name]
267
+ # Get tags
268
+ line += self._reference.get_tags_from_taggroups(
269
+ columns_datataggs_names, return_names_instead_of_refs=True)
270
+ line += self._reference.get_tags_from_taggroups(
271
+ columns_fluxtaggs_names, return_names_instead_of_refs=True)
272
+ # Create table line with corresponding data
273
+ line += [
274
+ self._min_val,
275
+ self._max_val,
276
+ self._min_quantity,
277
+ self._max_quantity,
278
+ self._natural_unit,
279
+ self._factor,
280
+ self._source,
281
+ self._hypothesis]
282
+ # Add extra info cols if needed
283
+ for extra_info_name in extra_infos_names:
284
+ if extra_info_name in self._reference.extra_infos.keys():
285
+ line.append(self._reference.extra_infos[extra_info_name])
286
+ else:
287
+ line.append(None)
288
+ # We can add it directly in the table
289
+ table.append(line)
290
+
291
+
292
+ class DataConstraint(ProtoData):
293
+ """
294
+ Define Data constraint object.
295
+
296
+ Parameters
297
+ ----------
298
+ :param reference: Reference of the object on that the constraint applies to.
299
+ :param reference: Flux | Data
300
+
301
+ :param eq: Value that reference value must be equal to
302
+ :type eq: float
303
+
304
+ :param ineq_inf: Value that reference value must be superior to
305
+ :type ineq_inf: float
306
+
307
+ :param ineq_sup: Value that reference value must be inferior to
308
+ :type ineq_sup: float
309
+
310
+ :param traduction: What the constraint value mean for the reference.
311
+ :type traduction: str
312
+ """
313
+ def __init__(
314
+ self,
315
+ id,
316
+ reference,
317
+ **kwargs
318
+ ):
319
+ # Attributes
320
+ self._id = -1
321
+ self._set_as_int('_id', id)
322
+ self._reference = reference
323
+ self._eq = None
324
+ self._ineq_inf = None
325
+ self._ineq_sup = None
326
+ self._traduction = None
327
+ # Init parent attributes
328
+ ProtoData.__init__(self)
329
+ # Update initial values
330
+ self.update(**kwargs)
331
+
332
+ @property
333
+ def id(self):
334
+ return self._id
335
+
336
+ @property
337
+ def reference(self):
338
+ return self._reference
339
+
340
+ @property
341
+ def eq(self):
342
+ return self._eq
343
+
344
+ @eq.setter
345
+ def eq(self, _):
346
+ self._set_as_float('_eq', _)
347
+
348
+ @property
349
+ def ineq_inf(self):
350
+ return self._ineq_inf
351
+
352
+ @ineq_inf.setter
353
+ def ineq_inf(self, _):
354
+ self._set_as_float('_ineq_inf', _)
355
+
356
+ @property
357
+ def ineq_sup(self):
358
+ return self._ineq_sup
359
+
360
+ @ineq_sup.setter
361
+ def ineq_sup(self, _):
362
+ self._set_as_float('_ineq_sup', _)
363
+
364
+ @property
365
+ def traduction(self):
366
+ return self._traduction
367
+
368
+ @traduction.setter
369
+ def traduction(self, _):
370
+ self._set_as_str('_traduction', _)
371
+
372
+ def update_table(
373
+ self,
374
+ columns_datataggs_names: list,
375
+ columns_fluxtaggs_names: list,
376
+ extra_infos_names: list,
377
+ table: list
378
+ ):
379
+ """
380
+ Update a panda table with this data infos.
381
+ The columns are organized as :
382
+
383
+ 1. Id
384
+ 2. Origin
385
+ 3. Destination
386
+ 4. All data tags (multiple columns) : for each column we have the respective tags or None
387
+ 5. All flux tags (multiple columns) : for each column we have the respective tags or None
388
+ 6. Eq
389
+ 7. Ineq inf
390
+ 8. Ineq sup
391
+ 9. traduction
392
+ 10. source
393
+ 11. hypothesis
394
+ 12. All remaining extra infos (if present, multiple columns)
395
+
396
+
397
+ Parameters
398
+ ----------
399
+ :param columns_datataggs_names: List of tag groups for data tags columns
400
+ :type columns_datataggs_names: list[str] | list[TagGroup]
401
+
402
+ :param columns_fluxtaggs_names: List of tag groups for flux tags columns
403
+ :type columns_fluxtaggs_names: list[str] | list[TagGroup]
404
+
405
+ :param extra_infos_names: List of extra infos to search for extra infos columns
406
+ :type extra_infos_names: list[str]
407
+
408
+ :param table: Table (2D-list) where all infos will be added
409
+ :type table: list[list] (modified)
410
+
411
+ """
412
+ # Only for data with value
413
+ if (self._eq is None) and \
414
+ (self._ineq_inf is None) and \
415
+ (self._ineq_sup is None):
416
+ return
417
+ # Create table line with corresponding data
418
+ line = [
419
+ self._id,
420
+ self._reference.orig.name,
421
+ self._reference.dest.name]
422
+ # Get tags
423
+ line += self._reference.get_tags_from_taggroups(
424
+ columns_datataggs_names, return_names_instead_of_refs=True)
425
+ line += self._reference.get_tags_from_taggroups(
426
+ columns_fluxtaggs_names, return_names_instead_of_refs=True)
427
+ # Create table line with corresponding data
428
+ line += [
429
+ self._eq,
430
+ self._ineq_inf,
431
+ self._ineq_sup,
432
+ self._traduction,
433
+ self._source,
434
+ self._hypothesis]
435
+ # Add extra info cols if needed
436
+ for extra_info_name in extra_infos_names:
437
+ if extra_info_name in self._reference.extra_infos.keys():
438
+ line.append(self._reference.extra_infos[extra_info_name])
439
+ else:
440
+ line.append(None)
441
+ # We can add it directly in the table
442
+ table.append(line)
443
+
444
+ def get_as_dict(self):
445
+ # Init output
446
+ output = {}
447
+ # Get values
448
+ output['reference'] = {}
449
+ if isinstance(self._reference, _ProtoFlux):
450
+ output['reference']['orig'] = self.reference.orig.name
451
+ output['reference']['dest'] = self.reference.dest.name
452
+ if isinstance(self._reference, Data):
453
+ output['reference']['orig'] = self.reference.flux.orig.name
454
+ output['reference']['dest'] = self.reference.flux.dest.name
455
+ output['tags'] = [
456
+ [_.group.name, _.name]
457
+ for _ in self.reference.tags]
458
+ output['eq'] = self.eq
459
+ output['ineq_inf'] = self.ineq_inf
460
+ output['ineq_suo'] = self.ineq_sup
461
+ return output
462
+
463
+
464
+ class Data(ProtoData, SankeyObject):
465
+ """
466
+ Define Data object.
467
+ Inherits from `ProtoData` and `SankeyObject`
468
+
469
+ Parameters
470
+ ----------
471
+ :param flux: Flux associé à la donnée.
472
+ :type flux: Flux
473
+
474
+ :param tags: list of tags associated to the data
475
+ :type tags: list
476
+
477
+ :param sigma: Ecart type (Incertitude de la donnée).
478
+ L'incertitude porte sur les données. \
479
+ Elle est soit renseignée par la source et recopiée ici, \
480
+ soit renseignée de manière arbitraire par la personne faisant \
481
+ l'AFM en fonction de la confiance dans les données présentées \
482
+ par la source, selon la méthodologie décrite dans la première \
483
+ feuille de cet Excel.
484
+ :type sigma: float
485
+
486
+ :param min: Borne inférieure de la valeur possible de la donnée. \
487
+ Valeur obligatoire pour réaliser l'AFM.
488
+ :type min: DataMinMax
489
+
490
+ :param max: Borne supérieur de la valeur possible de la donnée. \
491
+ Valeur obligatoire pour réaliser l'AFM.
492
+ :type max: DataMinMax
493
+
494
+ :param constraints: TODO
495
+ :type constraints: dict
496
+
497
+ :param alterego: If data, then alterego is the associated result and vice-versa
498
+ :type alterego: Data
499
+ """
500
+
501
+ def __init__(
502
+ self,
503
+ **kwargs
504
+ ):
505
+ # Data values attributes
506
+ self._value = None
507
+ self._quantity = None
508
+ # Flux attribute
509
+ self._flux = None
510
+ # Uncertainty attributes
511
+ self._sigma = None
512
+ self._min_max = DataMinMax(self)
513
+ # Reconcilliation attributes
514
+ self._constraints = {}
515
+ self._alterego = None
516
+ self._analysis_vector = []
517
+ # Init super constructor
518
+ ProtoData.__init__(self)
519
+ SankeyObject.__init__(self)
520
+ # Update all present attributes
521
+ self.update(**kwargs)
522
+
523
+ def update_unknown_only(
524
+ self,
525
+ **kwargs
526
+ ):
527
+ for key, value in kwargs.items():
528
+ if getattr(self, key) is None:
529
+ setattr(self, key, value)
530
+
531
+ @property
532
+ def value(self):
533
+ return self._value
534
+
535
+ @value.setter
536
+ def value(self, _):
537
+ self._set_as_float('_value', _)
538
+
539
+ def value_rounded(self, _):
540
+ return self._get_as_round_value('_value', _)
541
+
542
+ @property
543
+ def quantity(self):
544
+ return self._quantity
545
+
546
+ @quantity.setter
547
+ def quantity(self, _):
548
+ self._set_as_float('_quantity', _)
549
+
550
+ def quantity_rounded(self, _):
551
+ return self._get_as_round_value('_quantity', _)
552
+
553
+ @property
554
+ def flux(self):
555
+ return self._flux
556
+
557
+ @flux.setter
558
+ def flux(self, _):
559
+ # None case
560
+ if _ is None:
561
+ self._flux = None
562
+ return
563
+ # Real affectation
564
+ if isinstance(_, _ProtoFlux):
565
+ self._flux = _
566
+
567
+ @property
568
+ def orig(self):
569
+ return self.flux.orig
570
+
571
+ @property
572
+ def dest(self):
573
+ return self.flux.dest
574
+
575
+ @property
576
+ def natural_unit(self):
577
+ if (self._natural_unit is None) and (self._flux is not None):
578
+ return self._flux.natural_unit
579
+ return self._natural_unit
580
+
581
+ @natural_unit.setter
582
+ def natural_unit(self, _):
583
+ self._set_as_str('_natural_unit', _)
584
+
585
+ def natural_unit_rounded(self, _):
586
+ return self._get_as_round_value('_natural_unit', _)
587
+
588
+ @property
589
+ def factor(self):
590
+ if (self._factor is None) and (self._flux is not None):
591
+ return self._flux.factor
592
+ return self._factor
593
+
594
+ @factor.setter
595
+ def factor(self, _):
596
+ self._set_as_float('_factor', _)
597
+
598
+ def factor_rounded(self, _):
599
+ return self._get_as_round_value('_factor', _)
600
+
601
+ @property
602
+ def sigma(self):
603
+ if (self._sigma is not None):
604
+ return self._sigma
605
+ if (self._value is not None):
606
+ return self._value*CONST.DEFAULT_SIGMA_RELATIVE
607
+ return None
608
+
609
+ @sigma.setter
610
+ def sigma(self, _):
611
+ self._set_as_float('_sigma', _)
612
+
613
+ def sigma_rounded(self, _):
614
+ return self._get_as_round_value('_sigma', _)
615
+
616
+ @property
617
+ def sigma_relative(self):
618
+ if (self._value is not None):
619
+ if (self._sigma is not None):
620
+ if abs(self._value) > 0.0:
621
+ return self._sigma/self._value
622
+ else:
623
+ return self._sigma
624
+ return None
625
+
626
+ @sigma_relative.setter
627
+ def sigma_relative(self, _):
628
+ if _ is None:
629
+ _ = CONST.DEFAULT_SIGMA_RELATIVE
630
+ try:
631
+ self._set_as_float('_sigma', self._value*_)
632
+ except Exception:
633
+ pass
634
+
635
+ def sigma_relative_rounded(self, _):
636
+ return self._get_as_round_value('sigma_relative', _)
637
+
638
+ @property
639
+ def sigma_percent(self):
640
+ if (self._value is not None):
641
+ if (self._sigma is not None):
642
+ if abs(self._value) > 0.0:
643
+ return (self._sigma/self._value)*100.0
644
+ else:
645
+ return self._sigma*100.0
646
+ return None
647
+
648
+ @sigma_percent.setter
649
+ def sigma_percent(self, _):
650
+ if _ is None:
651
+ _ = CONST.DEFAULT_SIGMA_PERCENT
652
+ try:
653
+ self._set_as_float('_sigma', _*self._value/100.0)
654
+ except Exception:
655
+ pass
656
+
657
+ @property
658
+ def min_max(self):
659
+ return self._min_max
660
+
661
+ @property
662
+ def min_val(self):
663
+ return self._min_max.min_val
664
+
665
+ @min_val.setter
666
+ def min_val(self, _):
667
+ self._min_max.min_val = _
668
+
669
+ @property
670
+ def max_val(self):
671
+ return self._min_max.max_val
672
+
673
+ @max_val.setter
674
+ def max_val(self, _):
675
+ self._min_max.max_val = _
676
+
677
+ @property
678
+ def constraints(self):
679
+ return self._constraints
680
+
681
+ def add_constraint(self, id_constraint, **kwargs):
682
+ # Create a new piece of constraint
683
+ constraint = DataConstraint(id_constraint, self, **kwargs)
684
+ # Update constraint for given id
685
+ if id_constraint in self._constraints.keys():
686
+ self._constraints[id_constraint].append(constraint)
687
+ else:
688
+ self._constraints[id_constraint] = [constraint]
689
+ # Return constraint
690
+ return constraint
691
+
692
+ @property
693
+ def alterego(self):
694
+ return self._alterego
695
+
696
+ @alterego.setter
697
+ def alterego(self, _):
698
+ if self._alterego is None:
699
+ if isinstance(_, Data):
700
+ self._alterego = _
701
+ _.alterego = self
702
+ else:
703
+ # Reset alterego link
704
+ if _ is None:
705
+ old_alterego = self._alterego
706
+ self._alterego = None
707
+ old_alterego.altergo = None
708
+
709
+ @property
710
+ def analysis_vector(self):
711
+ # Protection with copy
712
+ return self._analysis_vector.copy()
713
+
714
+ @analysis_vector.setter
715
+ def analysis_vector(self, _):
716
+ if isinstance(_, list):
717
+ self._analysis_vector = _
718
+
719
+ def update_table(
720
+ self,
721
+ columns_datataggs_names: list,
722
+ columns_fluxtaggs_names: list,
723
+ extra_infos_names: list,
724
+ table: list,
725
+ rounding_digits: int = 2,
726
+ as_result: bool = False,
727
+ table_for_analysis: list = None
728
+ ):
729
+ """
730
+ Update a panda table with this data infos.
731
+
732
+ Parameters
733
+ ----------
734
+ :param columns_datataggs_names: List of tag groups for data tags columns
735
+ :type columns_datataggs_names: list[str] | list[TagGroup]
736
+
737
+ :param columns_fluxtaggs_names: List of tag groups for flux tags columns
738
+ :type columns_fluxtaggs_names: list[str] | list[TagGroup]
739
+
740
+ :param extra_infos_names: List of extra infos to search for extra infos columns
741
+ :type extra_infos_names: list[str]
742
+
743
+ :param table: Table (2D-list) where all infos will be added
744
+ :type table: list[list] (modified)
745
+
746
+ :param rounding_digits: Rounding precision for floating values
747
+ :type rounding digits: int (default=2)
748
+
749
+ :param as_result: Table columns are differents if data is a result.
750
+ :type as_result: bool (default=False)
751
+
752
+ :param table_for_analysis: Table (2D-list) analysis can be updated if data is result
753
+ :type table_for_analysis: list[list] (default=None)
754
+ """
755
+ if as_result is True:
756
+ # Result table
757
+ self._update_results_table(
758
+ columns_datataggs_names,
759
+ columns_fluxtaggs_names,
760
+ table,
761
+ rounding_digits=rounding_digits)
762
+ # Analysis table if needed
763
+ if table_for_analysis is not None:
764
+ self._update_analysis_table(
765
+ columns_datataggs_names,
766
+ columns_fluxtaggs_names,
767
+ table_for_analysis,
768
+ rounding_digits=rounding_digits)
769
+ else:
770
+ self._update_data_table(
771
+ columns_datataggs_names,
772
+ columns_fluxtaggs_names,
773
+ extra_infos_names,
774
+ table,
775
+ rounding_digits=rounding_digits)
776
+
777
+ def _update_data_table(
778
+ self,
779
+ columns_datataggs_names: list,
780
+ columns_fluxtaggs_names: list,
781
+ extra_infos_names: list,
782
+ table: list,
783
+ rounding_digits: int = 2
784
+ ):
785
+ """
786
+ Update a panda table with this data infos.
787
+ The columns are organized as :
788
+
789
+ 1. Origin
790
+ 2. Destination
791
+ 3. All data tags (multiple columns) : for each column we have the respective tags or None
792
+ 4. All flux tags (multiple columns) : for each column we have the respective tags or None
793
+ 5. Value
794
+ 6. Quantity
795
+ 7. Natural unit
796
+ 8. factor
797
+ 9. Sigma relative to value
798
+ 10. source
799
+ 11. hypothesis
800
+ 12. All remaining extra infos (if present, multiple columns)
801
+
802
+ Parameters
803
+ ----------
804
+ :param columns_datataggs_names: List of tag groups for data tags columns
805
+ :type columns_datataggs_names: list[str] | list[TagGroup]
806
+
807
+ :param columns_fluxtaggs_names: List of tag groups for flux tags columns
808
+ :type columns_fluxtaggs_names: list[str] | list[TagGroup]
809
+
810
+ :param extra_infos_names: List of extra infos to search for extra infos columns
811
+ :type extra_infos_names: list[str]
812
+
813
+ :param table: Table (2D-list) where all infos will be added
814
+ :type table: list[list] (modified)
815
+
816
+ """
817
+ # Write only if we have something to write
818
+ if (self.value is None) & (self.quantity is None):
819
+ return
820
+ # Create table line with corresponding data
821
+ line = [
822
+ self.orig.name,
823
+ self.dest.name]
824
+ # Get tags
825
+ line += self.get_tags_from_taggroups(
826
+ columns_datataggs_names, return_names_instead_of_refs=True)
827
+ line += self.get_tags_from_taggroups(
828
+ columns_fluxtaggs_names, return_names_instead_of_refs=True)
829
+ # Create table line with corresponding data
830
+ line += [
831
+ self.value_rounded(rounding_digits),
832
+ self.quantity_rounded(rounding_digits),
833
+ self.natural_unit,
834
+ self.factor_rounded(rounding_digits),
835
+ self.sigma_relative_rounded(rounding_digits),
836
+ self.source,
837
+ self.hypothesis]
838
+ # Add extra info cols if needed
839
+ for extra_info_name in extra_infos_names:
840
+ if extra_info_name in self.extra_infos.keys():
841
+ line.append(self.extra_infos[extra_info_name])
842
+ else:
843
+ line.append(None)
844
+ # We can add it directly in the table
845
+ table.append(line)
846
+
847
+ def _update_results_table(
848
+ self,
849
+ columns_datataggs_names: list,
850
+ columns_fluxtaggs_names: list,
851
+ table: list,
852
+ rounding_digits: int = 2
853
+ ):
854
+ """
855
+ Update a panda table with this data infos.
856
+ The columns are organized as :
857
+
858
+ 1. Origin
859
+ 2. Destination
860
+ 3. All data tags (multiple columns) : for each column we have the respective tags or None
861
+ 4. All flux tags (multiple columns) : for each column we have the respective tags or None
862
+ 5. Value
863
+ 6. Free min
864
+ 7. Free max
865
+
866
+ Parameters
867
+ ----------
868
+ :param columns_datataggs_names: List of tag groups for data tags columns
869
+ :type columns_datataggs_names: list[str] | list[TagGroup]
870
+
871
+ :param columns_fluxtaggs_names: List of tag groups for flux tags columns
872
+ :type columns_fluxtaggs_names: list[str] | list[TagGroup]
873
+
874
+ :param table: Table (2D-list) where all infos will be added
875
+ :type table: list[list] (modified)
876
+
877
+ """
878
+ # Create table line with corresponding data
879
+ line = [
880
+ self.orig.name,
881
+ self.dest.name]
882
+ # Get tags
883
+ line += self.get_tags_from_taggroups(
884
+ columns_datataggs_names, return_names_instead_of_refs=True)
885
+ line += self.get_tags_from_taggroups(
886
+ columns_fluxtaggs_names, return_names_instead_of_refs=True)
887
+ # Create table line with corresponding data
888
+ line += [
889
+ self.value_rounded(rounding_digits),
890
+ self.min_val,
891
+ self.max_val]
892
+ # We can add it directly in the table
893
+ table.append(line)
894
+
895
+ def _update_analysis_table(
896
+ self,
897
+ columns_datataggs_names: list,
898
+ columns_fluxtaggs_names: list,
899
+ table: list,
900
+ rounding_digits: int = 2
901
+ ):
902
+ """
903
+ Update a panda table with this data infos.
904
+ The columns are organized as :
905
+
906
+ 1. Origin
907
+ 2. Destination
908
+ 3. All data tags (multiple columns) : for each column we have the respective tags or None
909
+ 4. All flux tags (multiple columns) : for each column we have the respective tags or None
910
+ 5. Result Value
911
+ 6. Result Free min
912
+ 7. Result Free max
913
+ 8. Input Value
914
+ 9. Input Sigma
915
+ 10. Input relative Sigma (percent)
916
+ 11. Input min value
917
+ 12. Input max value
918
+ 13. Relative difference between Input and Result (relative to Input Sigma)
919
+ 14. Result classification = (Mesurée / Redondandes / Determinable / Indeterminable (libre))
920
+ 15+. Ai Matrix (if asked) = Liste de lignes dans lesquelles la donnée est
921
+ impliquée dans la matrice de contrainte.
922
+
923
+ Parameters
924
+ ----------
925
+ :param columns_datataggs_names: List of tag groups for data tags columns
926
+ :type columns_datataggs_names: list[str] | list[TagGroup]
927
+
928
+ :param columns_fluxtaggs_names: List of tag groups for flux tags columns
929
+ :type columns_fluxtaggs_names: list[str] | list[TagGroup]
930
+
931
+ :param table: Table (2D-list) where all infos will be added
932
+ :type table: list[list] (modified)
933
+
934
+ """
935
+ # Only if we have something to put inside
936
+ if (len(self._analysis_vector) > 0):
937
+ # Create table line with corresponding data
938
+ line = [
939
+ self.orig.name,
940
+ self.dest.name]
941
+ # Get tags
942
+ line += self.get_tags_from_taggroups(
943
+ columns_datataggs_names, return_names_instead_of_refs=True)
944
+ line += self.get_tags_from_taggroups(
945
+ columns_fluxtaggs_names, return_names_instead_of_refs=True)
946
+ # Create table line with corresponding result data
947
+ line += [
948
+ self.value_rounded(rounding_digits),
949
+ self.min_val,
950
+ self.max_val]
951
+ # Create table line with corresponding analysis data
952
+ line += [
953
+ round(_, rounding_digits)
954
+ if isinstance(_, float)
955
+ else _
956
+ for _ in self._analysis_vector]
957
+ # We can add it directly in the table
958
+ table.append(line)
959
+
960
+ def get_as_dict(self):
961
+ # Init output
962
+ output = {}
963
+ # Get values
964
+ output['value'] = self.value
965
+ output['tags'] = [
966
+ [_.group.name, _.name] for _ in self.tags]
967
+ try:
968
+ output['alterego'] = self.alterego.value
969
+ except Exception:
970
+ pass
971
+ return output
972
+
973
+ def __repr__(self):
974
+ s = '{}'.format(self._value)
975
+ for tag in self._tags:
976
+ s += ' | {}'.format(tag)
977
+ return s
978
+
979
+
980
+ def MCData(SankeyObject):
981
+ """
982
+ Define a MonteCarlo Data object.
983
+ Inherits from `SankeyObject`
984
+
985
+ Parameters
986
+ ----------
987
+ :param flux: Flux associé à la donnée.
988
+ :type flux: Flux
989
+
990
+ :param tags: list of tags associated to the data
991
+ :type tags: list
992
+
993
+ :param starting_data: Input data
994
+ :type starting_data: Data
995
+
996
+ :param result_data: Output data
997
+ :type result_data: Data
998
+ """
999
+
1000
+ def __init__(
1001
+ self,
1002
+ **kwargs
1003
+ ):
1004
+ # Flux attribute
1005
+ self._flux = None
1006
+ # Input and output data
1007
+ self._starting_data = None
1008
+ self._result_data = None
1009
+ # Probalities and histogrammes
1010
+ self._probas = {}
1011
+ self._hists = {}
1012
+ # Update all present attributes
1013
+ self.update(**kwargs)
1014
+
1015
+ def update(
1016
+ self,
1017
+ **kwargs
1018
+ ):
1019
+ for key, value in kwargs.items():
1020
+ setattr(self, key, value)
1021
+
1022
+ @property
1023
+ def flux(self):
1024
+ return self._flux
1025
+
1026
+ @flux.setter
1027
+ def flux(self, _):
1028
+ # None case
1029
+ if _ is None:
1030
+ self._flux = None
1031
+ return
1032
+ # Real affectation
1033
+ if isinstance(_, _ProtoFlux):
1034
+ self._flux = _
1035
+
1036
+ @property
1037
+ def starting_data(self):
1038
+ return self._starting_data
1039
+
1040
+ @starting_data.setter
1041
+ def starting_data(self, _):
1042
+ # None case
1043
+ if _ is None:
1044
+ self._starting_data = None
1045
+ return
1046
+ # Real affectation
1047
+ if isinstance(_, Data):
1048
+ self._starting_data = _
1049
+
1050
+ @property
1051
+ def result_data(self):
1052
+ return self._result_data
1053
+
1054
+ @result_data.setter
1055
+ def result_data(self, _):
1056
+ # None case
1057
+ if _ is None:
1058
+ self._result_data = None
1059
+ return
1060
+ # Real affectation
1061
+ if isinstance(_, Data):
1062
+ self._result_data = _
1063
+
1064
+ @property
1065
+ def min(self):
1066
+ return self._result_data.min_val
1067
+
1068
+ @min.setter
1069
+ def min(self, _):
1070
+ self._result_data.min_val = _
1071
+
1072
+ @property
1073
+ def max(self):
1074
+ return self._result_data.max_val
1075
+
1076
+ @max.setter
1077
+ def max(self, _):
1078
+ self._result_data.max_val = _
1079
+
1080
+ def add_proba(self, _key, _value):
1081
+ if (_key is not None):
1082
+ try:
1083
+ value = float(_value)
1084
+ key = str(_key)
1085
+ # NAN protection
1086
+ if (value == value):
1087
+ self._probas[key] = value
1088
+ except Exception:
1089
+ pass
1090
+
1091
+ def get_proba(self, _key):
1092
+ if (_key is not None):
1093
+ try:
1094
+ key = str(_key)
1095
+ return self._probas[key]
1096
+ except Exception:
1097
+ pass
1098
+ return None
1099
+
1100
+ def add_hist(self, _key, _value):
1101
+ if (_key is not None):
1102
+ try:
1103
+ value = float(_value)
1104
+ key = str(_key)
1105
+ # NAN protection
1106
+ if (value == value):
1107
+ self._hists[key] = value
1108
+ except Exception:
1109
+ pass
1110
+
1111
+ def get_hist(self, _key):
1112
+ if (_key is not None):
1113
+ try:
1114
+ key = str(_key)
1115
+ return self._hists[key]
1116
+ except Exception:
1117
+ pass
1118
+ return None