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.
- SankeyExcelParser/__init__.py +0 -0
- SankeyExcelParser/io_excel.py +1867 -0
- SankeyExcelParser/io_excel_constants.py +811 -0
- SankeyExcelParser/sankey.py +3138 -0
- SankeyExcelParser/sankey_utils/__init__.py +0 -0
- SankeyExcelParser/sankey_utils/data.py +1118 -0
- SankeyExcelParser/sankey_utils/excel_source.py +31 -0
- SankeyExcelParser/sankey_utils/flux.py +344 -0
- SankeyExcelParser/sankey_utils/functions.py +278 -0
- SankeyExcelParser/sankey_utils/node.py +340 -0
- SankeyExcelParser/sankey_utils/protos/__init__.py +0 -0
- SankeyExcelParser/sankey_utils/protos/flux.py +84 -0
- SankeyExcelParser/sankey_utils/protos/node.py +386 -0
- SankeyExcelParser/sankey_utils/protos/sankey_object.py +135 -0
- SankeyExcelParser/sankey_utils/protos/tag_group.py +95 -0
- SankeyExcelParser/sankey_utils/sankey_object.py +165 -0
- SankeyExcelParser/sankey_utils/table_object.py +37 -0
- SankeyExcelParser/sankey_utils/tag.py +95 -0
- SankeyExcelParser/sankey_utils/tag_group.py +206 -0
- SankeyExcelParser/su_trace.py +239 -0
- SankeyExcelParser/tests/integration/__init__.py +0 -0
- SankeyExcelParser/tests/integration/test_base.py +356 -0
- SankeyExcelParser/tests/integration/test_run_check_input.py +100 -0
- SankeyExcelParser/tests/integration/test_run_conversions.py +96 -0
- SankeyExcelParser/tests/integration/test_run_load_input.py +94 -0
- SankeyExcelParser/tests/unit/__init__.py +0 -0
- SankeyExcelParser-1.0.0b0.data/scripts/run_parse_and_write_excel.py +155 -0
- SankeyExcelParser-1.0.0b0.data/scripts/run_parse_excel.py +115 -0
- SankeyExcelParser-1.0.0b0.dist-info/METADATA +113 -0
- SankeyExcelParser-1.0.0b0.dist-info/RECORD +32 -0
- SankeyExcelParser-1.0.0b0.dist-info/WHEEL +5 -0
- 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
|