mrio-toolbox 1.0.0__py3-none-any.whl → 1.1.1__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.
Potentially problematic release.
This version of mrio-toolbox might be problematic. Click here for more details.
- mrio_toolbox/__init__.py +18 -2
- mrio_toolbox/_parts/_Axe.py +95 -37
- mrio_toolbox/_parts/_Part.py +264 -70
- mrio_toolbox/_parts/__init__.py +4 -0
- mrio_toolbox/_parts/part_operations.py +24 -17
- mrio_toolbox/extractors/__init__.py +20 -0
- mrio_toolbox/extractors/downloaders.py +36 -0
- mrio_toolbox/extractors/emerging/__init__.py +3 -0
- mrio_toolbox/extractors/emerging/emerging_extractor.py +117 -0
- mrio_toolbox/extractors/eora/__init__.py +3 -0
- mrio_toolbox/extractors/eora/eora_extractor.py +132 -0
- mrio_toolbox/extractors/exiobase/__init__.py +3 -0
- mrio_toolbox/extractors/exiobase/exiobase_extractor.py +270 -0
- mrio_toolbox/extractors/extractors.py +79 -0
- mrio_toolbox/extractors/figaro/__init__.py +3 -0
- mrio_toolbox/extractors/figaro/figaro_downloader.py +280 -0
- mrio_toolbox/extractors/figaro/figaro_extractor.py +187 -0
- mrio_toolbox/extractors/gloria/__init__.py +3 -0
- mrio_toolbox/extractors/gloria/gloria_extractor.py +202 -0
- mrio_toolbox/extractors/gtap11/__init__.py +7 -0
- mrio_toolbox/extractors/gtap11/extraction/__init__.py +3 -0
- mrio_toolbox/extractors/gtap11/extraction/extractor.py +129 -0
- mrio_toolbox/extractors/gtap11/extraction/harpy_files/__init__.py +6 -0
- mrio_toolbox/extractors/gtap11/extraction/harpy_files/_header_sets.py +279 -0
- mrio_toolbox/extractors/gtap11/extraction/harpy_files/har_file.py +262 -0
- mrio_toolbox/extractors/gtap11/extraction/harpy_files/har_file_io.py +974 -0
- mrio_toolbox/extractors/gtap11/extraction/harpy_files/header_array.py +300 -0
- mrio_toolbox/extractors/gtap11/extraction/harpy_files/sl4.py +229 -0
- mrio_toolbox/extractors/gtap11/gtap_mrio/__init__.py +6 -0
- mrio_toolbox/extractors/gtap11/gtap_mrio/mrio_builder.py +158 -0
- mrio_toolbox/extractors/icio/__init__.py +3 -0
- mrio_toolbox/extractors/icio/icio_extractor.py +121 -0
- mrio_toolbox/extractors/wiod/__init__.py +3 -0
- mrio_toolbox/extractors/wiod/wiod_extractor.py +143 -0
- mrio_toolbox/mrio.py +254 -94
- mrio_toolbox/msm/__init__.py +6 -0
- mrio_toolbox/msm/multi_scale_mapping.py +863 -0
- mrio_toolbox/utils/__init__.py +3 -0
- mrio_toolbox/utils/converters/__init__.py +3 -0
- mrio_toolbox/utils/converters/pandas.py +8 -6
- mrio_toolbox/utils/converters/xarray.py +2 -13
- mrio_toolbox/utils/formatting/__init__.py +0 -0
- mrio_toolbox/utils/formatting/formatter.py +528 -0
- mrio_toolbox/utils/loaders/__init__.py +4 -0
- mrio_toolbox/utils/loaders/_loader.py +60 -4
- mrio_toolbox/utils/loaders/_loader_factory.py +22 -1
- mrio_toolbox/utils/loaders/_nc_loader.py +37 -1
- mrio_toolbox/utils/loaders/_pandas_loader.py +29 -3
- mrio_toolbox/utils/loaders/_parameter_loader.py +61 -16
- mrio_toolbox/utils/savers/__init__.py +3 -0
- mrio_toolbox/utils/savers/_path_checker.py +25 -7
- mrio_toolbox/utils/savers/_to_folder.py +6 -1
- mrio_toolbox/utils/savers/_to_nc.py +26 -18
- {mrio_toolbox-1.0.0.dist-info → mrio_toolbox-1.1.1.dist-info}/METADATA +10 -6
- mrio_toolbox-1.1.1.dist-info/RECORD +59 -0
- {mrio_toolbox-1.0.0.dist-info → mrio_toolbox-1.1.1.dist-info}/WHEEL +1 -1
- mrio_toolbox-1.0.0.dist-info/RECORD +0 -26
- {mrio_toolbox-1.0.0.dist-info → mrio_toolbox-1.1.1.dist-info/licenses}/LICENSE +0 -0
- {mrio_toolbox-1.0.0.dist-info → mrio_toolbox-1.1.1.dist-info}/top_level.txt +0 -0
mrio_toolbox/_parts/_Part.py
CHANGED
|
@@ -10,6 +10,7 @@ import itertools
|
|
|
10
10
|
import numpy as np
|
|
11
11
|
import pandas as pd
|
|
12
12
|
import xarray as xr
|
|
13
|
+
import copy
|
|
13
14
|
from mrio_toolbox._parts._Axe import Axe
|
|
14
15
|
import logging
|
|
15
16
|
from mrio_toolbox.utils import converters
|
|
@@ -26,46 +27,151 @@ def load_part(
|
|
|
26
27
|
return Part(**loader.load_part(**kwargs))
|
|
27
28
|
|
|
28
29
|
class Part:
|
|
30
|
+
"""
|
|
31
|
+
Representation of an MRIO Part object.
|
|
32
|
+
|
|
33
|
+
MRIO Parts are the basic building blocks of the MRIO toolbox. A Part is
|
|
34
|
+
built from a numpy array and a set of Axes, corresponding to the dimensions
|
|
35
|
+
of the array. The Axes hold the labels of the Part in the different
|
|
36
|
+
dimensions and are used to perform advanced indexing and operations on the Part.
|
|
37
|
+
|
|
38
|
+
Axes support multi-level indexing and groupings.
|
|
39
|
+
|
|
40
|
+
Instance variables
|
|
41
|
+
------------------
|
|
42
|
+
data : numpy.ndarray
|
|
43
|
+
Numerical data of the Part.
|
|
44
|
+
axes : list of Axe instances
|
|
45
|
+
Axes corresponding to the dimensions of the Part.
|
|
46
|
+
groupings : dict
|
|
47
|
+
Groupings of the labels of the Part, for each label defined.
|
|
48
|
+
metadata : dict
|
|
49
|
+
Additional metadata of the Part (e.g., path, name, multiplier, unit).
|
|
50
|
+
name : str
|
|
51
|
+
Name of the Part.
|
|
52
|
+
ndim : int
|
|
53
|
+
Number of dimensions of the Part.
|
|
54
|
+
shape : tuple
|
|
55
|
+
Shape of the Part.
|
|
56
|
+
|
|
57
|
+
Methods
|
|
58
|
+
-------
|
|
59
|
+
__init__(data=None, labels=None, axes=None, **kwargs):
|
|
60
|
+
Initialize a Part object.
|
|
61
|
+
alias(**kwargs):
|
|
62
|
+
Create a new Part with modified parameters.
|
|
63
|
+
fix_dims(skip_labels=False, skip_data=False):
|
|
64
|
+
Align the number of axes with the number of dimensions.
|
|
65
|
+
get(*args, aspart=True, squeeze=False):
|
|
66
|
+
Extract data from the Part object.
|
|
67
|
+
setter(value, *args):
|
|
68
|
+
Change the value of a data selection.
|
|
69
|
+
develop(axis=None, on=None, squeeze=True):
|
|
70
|
+
Reshape a Part to avoid double labels.
|
|
71
|
+
reformat(new_dimensions):
|
|
72
|
+
Reshape a Part to match a new dimensions combination.
|
|
73
|
+
combine_axes(start=0, end=None, in_place=False):
|
|
74
|
+
Combine axes of a Part into a single one.
|
|
75
|
+
swap_axes(axis1, axis2):
|
|
76
|
+
Swap two axes of a Part.
|
|
77
|
+
swap_ax_levels(axis, dim1, dim2):
|
|
78
|
+
Swap two levels of an axis.
|
|
79
|
+
flatten(invert=False):
|
|
80
|
+
Flatten a 2D Part into a 1D Part.
|
|
81
|
+
squeeze():
|
|
82
|
+
Remove dimensions of length 1 from the Part.
|
|
83
|
+
expand_dims(axis, copy=None):
|
|
84
|
+
Add dimensions to a Part instance.
|
|
85
|
+
copy():
|
|
86
|
+
Return a copy of the current Part object.
|
|
87
|
+
extraction(dimensions, labels=["all"], on_groupings=True, domestic_only=False, axis="all"):
|
|
88
|
+
Set labels over dimension(s) to 0.
|
|
89
|
+
leontief_inversion():
|
|
90
|
+
Compute the Leontief inverse of a square Part.
|
|
91
|
+
update_groupings(groupings, ax=None):
|
|
92
|
+
Update the groupings of the current Part object.
|
|
93
|
+
aggregate(on="countries", axis=None):
|
|
94
|
+
Aggregate dimensions along one or several axes.
|
|
95
|
+
aggregate_on(on, axis):
|
|
96
|
+
Aggregate a Part along a given axis.
|
|
97
|
+
get_labels(axis=None):
|
|
98
|
+
Returns a list with the labels of the axes as dictionaries.
|
|
99
|
+
list_labels():
|
|
100
|
+
List the labels of the Part.
|
|
101
|
+
get_dimensions(axis=None):
|
|
102
|
+
Return the list of dimensions of the Part.
|
|
103
|
+
rename_labels(old, new):
|
|
104
|
+
Rename some labels of the Part.
|
|
105
|
+
replace_labels(name, labels, axis=None):
|
|
106
|
+
Update a label of the Part.
|
|
107
|
+
set_labels(labels, axis=None):
|
|
108
|
+
Change the labels of the Part.
|
|
109
|
+
add_labels(labels, dimension=None, axes=None, fill_value=0):
|
|
110
|
+
Add indices to one or multiple Part axes.
|
|
111
|
+
expand(axis=None, over="countries"):
|
|
112
|
+
Expand an axis of the Part.
|
|
113
|
+
issquare():
|
|
114
|
+
Check whether the Part is square.
|
|
115
|
+
hasneg():
|
|
116
|
+
Check whether the Part has negative elements.
|
|
117
|
+
hasax(name=None):
|
|
118
|
+
Return the dimensions along which a Part has given labels.
|
|
119
|
+
sum(axis=None, on=None, keepdims=False):
|
|
120
|
+
Sum the Part along one or several axes or on a given dimension.
|
|
121
|
+
save(file=None, name=None, extension=".npy", overwrite=False, include_labels=False, write_instructions=False, **kwargs):
|
|
122
|
+
Save the Part object to a file.
|
|
123
|
+
to_pandas():
|
|
124
|
+
Return the current Part object as a Pandas DataFrame.
|
|
125
|
+
to_xarray():
|
|
126
|
+
Save the Part object to an xarray DataArray.
|
|
127
|
+
mean(axis=None):
|
|
128
|
+
Compute the mean of the Part along a given axis.
|
|
129
|
+
min(axis=None):
|
|
130
|
+
Compute the minimum value of the Part along a given axis.
|
|
131
|
+
max(axis=None):
|
|
132
|
+
Compute the maximum value of the Part along a given axis.
|
|
133
|
+
mul(a, propagate_labels=True):
|
|
134
|
+
Perform matrix multiplication between Parts with label propagation.
|
|
135
|
+
filter(threshold, fill_value=0):
|
|
136
|
+
Set to 0 the values below a given threshold.
|
|
137
|
+
diag():
|
|
138
|
+
Create a diagonal Part from a 1D Part or extract the diagonal of a 2D Part.
|
|
139
|
+
transpose():
|
|
140
|
+
Transpose the Part object.
|
|
141
|
+
"""
|
|
142
|
+
|
|
29
143
|
def __init__(self,data=None,
|
|
30
144
|
labels=None,
|
|
31
145
|
axes=None,
|
|
32
146
|
**kwargs):
|
|
33
|
-
"""
|
|
34
|
-
|
|
35
|
-
MRIO Parts are the basic building blocks of the MRIO toolbox.
|
|
36
|
-
A Part is built from a numpy array and a set of Axes,
|
|
37
|
-
corresponding to the dimensions of the array.
|
|
38
|
-
The Axes hold the labels of the Part in the different dimensions
|
|
39
|
-
and are used to perform advanced indexing and operations on the Part.
|
|
40
|
-
|
|
41
|
-
Axes support multi-level indexing and groupings.
|
|
147
|
+
"""
|
|
148
|
+
Initialize a Part object.
|
|
42
149
|
|
|
43
150
|
Parameters
|
|
44
151
|
----------
|
|
45
|
-
data : numpy
|
|
46
|
-
Numerical data of the
|
|
47
|
-
|
|
48
|
-
with a shape matching the axes.
|
|
49
|
-
groupings : dict of label level : dict
|
|
50
|
-
Groupings of the labels of the Part, for each label defined.
|
|
51
|
-
The groupings are passed to the Axe objects.
|
|
152
|
+
data : numpy.ndarray, optional
|
|
153
|
+
Numerical data of the Part. If not provided, a Part filled with
|
|
154
|
+
zeros (or another fill value) is created based on the shape of the axes.
|
|
52
155
|
labels : list of str or dict, optional
|
|
53
|
-
Labels
|
|
54
|
-
|
|
55
|
-
of the part
|
|
56
|
-
The lower level correspond to the dict of labels for each axe.
|
|
57
|
-
Remember that an Axe can have different levels of labels.
|
|
156
|
+
Labels for the axes. If provided, the labels define the structure
|
|
157
|
+
of the axes. If not provided, axes are created based on the data.
|
|
58
158
|
axes : list of Axe instances, optional
|
|
59
|
-
Custom Axes for the Part.
|
|
60
|
-
|
|
159
|
+
Custom Axes for the Part. If not provided, axes are created from
|
|
160
|
+
the labels or inferred from the data.
|
|
61
161
|
kwargs : dict
|
|
62
|
-
Additional metadata
|
|
63
|
-
(e.g. path, name, multiplier, unit...)
|
|
162
|
+
Additional metadata for the Part (e.g., path, name, multiplier, unit).
|
|
64
163
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
164
|
+
Raises
|
|
165
|
+
------
|
|
166
|
+
ValueError
|
|
167
|
+
If the length of the labels does not match the data dimensions.
|
|
168
|
+
TypeError
|
|
169
|
+
If the provided labels are of an unsupported type.
|
|
68
170
|
|
|
171
|
+
Notes
|
|
172
|
+
-----
|
|
173
|
+
If both `data` and `axes` are not provided, the method creates an
|
|
174
|
+
empty Part with default axes and zero-filled data.
|
|
69
175
|
"""
|
|
70
176
|
|
|
71
177
|
if data is not None:
|
|
@@ -128,6 +234,7 @@ class Part:
|
|
|
128
234
|
new_dims[-1].append(dim)
|
|
129
235
|
|
|
130
236
|
if new_dims != self.get_dimensions():
|
|
237
|
+
|
|
131
238
|
log.info("Reformat the Part")
|
|
132
239
|
new_part = self.reformat(new_dims)
|
|
133
240
|
self.data = new_part.data
|
|
@@ -257,13 +364,15 @@ class Part:
|
|
|
257
364
|
|
|
258
365
|
|
|
259
366
|
def __getitem__(self,args):
|
|
260
|
-
if isinstance(args,str) or isinstance(args,int) or isinstance(args,np.integer):
|
|
367
|
+
if isinstance(args,str) or isinstance(args,int) or isinstance(args,np.integer) or isinstance(args,dict):
|
|
261
368
|
args = (args,)
|
|
262
369
|
return self.get(*args)
|
|
263
370
|
|
|
264
371
|
def __setitem__(self,args,value):
|
|
265
372
|
if isinstance(value,Part):
|
|
266
373
|
value = value.data
|
|
374
|
+
if isinstance(args,str) or isinstance(args,int) or isinstance(args,np.integer) or isinstance(args,dict):
|
|
375
|
+
args = (args,)
|
|
267
376
|
self.setter(value,*args)
|
|
268
377
|
|
|
269
378
|
def setter(self,value,*args):
|
|
@@ -319,7 +428,6 @@ class Part:
|
|
|
319
428
|
Returns
|
|
320
429
|
-------
|
|
321
430
|
New Part object or numpy object
|
|
322
|
-
|
|
323
431
|
"""
|
|
324
432
|
sels = []
|
|
325
433
|
axes = []
|
|
@@ -379,12 +487,11 @@ class Part:
|
|
|
379
487
|
squeeze : bool, optional
|
|
380
488
|
Whether to remove dimensions of length 1.
|
|
381
489
|
The default is True.
|
|
382
|
-
|
|
490
|
+
|
|
383
491
|
Returns
|
|
384
492
|
-------
|
|
385
|
-
Part object
|
|
386
|
-
|
|
387
|
-
|
|
493
|
+
Developped Part : Part object
|
|
494
|
+
The developed part
|
|
388
495
|
"""
|
|
389
496
|
if isinstance(on,str):
|
|
390
497
|
on = [on]
|
|
@@ -414,6 +521,7 @@ class Part:
|
|
|
414
521
|
"This operation is not yet supported."
|
|
415
522
|
)
|
|
416
523
|
#If the order of the dimensions is unchanged, we can simply reshape
|
|
524
|
+
|
|
417
525
|
shape = [len(ax) for ax in axes]
|
|
418
526
|
data = self.data.reshape(shape)
|
|
419
527
|
if squeeze:
|
|
@@ -423,35 +531,42 @@ class Part:
|
|
|
423
531
|
return Part(data=data,name=f"developped_{self.name}",
|
|
424
532
|
groupings=self.groupings,axes=axes)
|
|
425
533
|
|
|
426
|
-
def reformat(self,new_dimensions):
|
|
534
|
+
def reformat(self, new_dimensions):
|
|
427
535
|
"""
|
|
428
|
-
Reshape a Part to match a new dimensions combination
|
|
536
|
+
Reshape a Part to match a new dimensions combination.
|
|
429
537
|
|
|
430
538
|
Equivalent to a combination of the develop and combine_axes methods.
|
|
431
539
|
|
|
432
540
|
This only works for contiguous dimensions in the current Part,
|
|
433
541
|
without overlapping dimensions.
|
|
434
|
-
For example, if the Part has dimensions:
|
|
435
|
-
[["countries"],["sectors"],["sectors"]]
|
|
436
|
-
The following is allowed:
|
|
437
|
-
[["countries","sectors"],["sectors"]]
|
|
438
|
-
The following is not allowed:
|
|
439
|
-
[["countries"],["sectors","sectors"]]
|
|
440
|
-
[["sectors"],["countries","sectors"]]
|
|
441
|
-
[["sectors","countries"],["sectors"]]
|
|
442
542
|
|
|
443
543
|
Parameters
|
|
444
544
|
----------
|
|
445
|
-
|
|
446
|
-
|
|
545
|
+
new_dimensions : list of list of str
|
|
546
|
+
Target dimensions to reshape into.
|
|
447
547
|
|
|
448
548
|
Returns
|
|
449
549
|
-------
|
|
450
|
-
data : numpy
|
|
451
|
-
Reshaped data
|
|
452
|
-
axes : list of Axe
|
|
453
|
-
Reshaped axes
|
|
550
|
+
data : numpy.ndarray
|
|
551
|
+
Reshaped data.
|
|
552
|
+
axes : list of Axe
|
|
553
|
+
Reshaped axes.
|
|
554
|
+
|
|
555
|
+
Examples
|
|
556
|
+
--------
|
|
557
|
+
If the Part has dimensions::
|
|
558
|
+
|
|
559
|
+
[["countries"], ["sectors"], ["sectors"]]
|
|
560
|
+
|
|
561
|
+
The following is allowed::
|
|
454
562
|
|
|
563
|
+
[["countries", "sectors"], ["sectors"]]
|
|
564
|
+
|
|
565
|
+
The following is not allowed::
|
|
566
|
+
|
|
567
|
+
[["countries"], ["sectors", "sectors"]]
|
|
568
|
+
[["sectors"], ["countries", "sectors"]]
|
|
569
|
+
[["sectors", "countries"], ["sectors"]]
|
|
455
570
|
"""
|
|
456
571
|
return part_operations.reformat(self,new_dimensions)
|
|
457
572
|
|
|
@@ -661,14 +776,6 @@ class Part:
|
|
|
661
776
|
dimensions = [dimensions]
|
|
662
777
|
if isinstance(labels,str) and labels!="all":
|
|
663
778
|
labels = [labels]
|
|
664
|
-
if len(labels) != len(dimensions):
|
|
665
|
-
if len(dimensions)==1:
|
|
666
|
-
#If only one dimension is passed, we broadcast the labels
|
|
667
|
-
labels = [labels]
|
|
668
|
-
else:
|
|
669
|
-
#Raise an error for ambiguous cases
|
|
670
|
-
log.critical("Number of dimensions and labels do not match for extraction")
|
|
671
|
-
raise ValueError("Number of dimensions and labels do not match for extraction")
|
|
672
779
|
if isinstance(dimensions,dict):
|
|
673
780
|
to_select = dimensions
|
|
674
781
|
labels = list(to_select.values())
|
|
@@ -677,14 +784,30 @@ class Part:
|
|
|
677
784
|
to_select = dict()
|
|
678
785
|
for dim,label in zip(dimensions,labels):
|
|
679
786
|
to_select[dim] = label
|
|
787
|
+
if len(labels) != len(dimensions):
|
|
788
|
+
if len(dimensions)==1:
|
|
789
|
+
#If only one dimension is passed, we broadcast the labels
|
|
790
|
+
labels = [labels]
|
|
791
|
+
else:
|
|
792
|
+
#Raise an error for ambiguous cases
|
|
793
|
+
log.critical("Number of dimensions and labels do not match for extraction")
|
|
794
|
+
raise ValueError("Number of dimensions and labels do not match for extraction")
|
|
680
795
|
|
|
681
796
|
allowed = []
|
|
682
797
|
for i,ax in enumerate(self.axes):
|
|
683
798
|
if all(dimension in ax.dimensions for dimension in dimensions):
|
|
684
799
|
allowed.append(i)
|
|
685
800
|
if len(allowed) == 0:
|
|
686
|
-
|
|
687
|
-
|
|
801
|
+
if len(dimensions) == 1:
|
|
802
|
+
log.critical("No axis found for extraction on "+str(dimensions))
|
|
803
|
+
raise ValueError("No axis found for extraction on "+str(dimensions))
|
|
804
|
+
log.info(f"No axis found for simultaneous extractions on {dimensions}")
|
|
805
|
+
log.info(f"Try successive extractions on {dimensions}")
|
|
806
|
+
for dim,label in zip(dimensions,labels):
|
|
807
|
+
self.extraction(dim,label,
|
|
808
|
+
on_groupings=on_groupings,
|
|
809
|
+
domestic_only=domestic_only,
|
|
810
|
+
axis=axis)
|
|
688
811
|
if axis == "all":
|
|
689
812
|
log.info(f"Extract {to_select} on axes "+ str(allowed))
|
|
690
813
|
axis = allowed
|
|
@@ -820,7 +943,7 @@ class Part:
|
|
|
820
943
|
|
|
821
944
|
if isinstance(on,list):
|
|
822
945
|
for item in on:
|
|
823
|
-
self = self.aggregate(axis
|
|
946
|
+
self = self.aggregate(on = item, axis=axis)
|
|
824
947
|
return self
|
|
825
948
|
if on not in self.groupings.keys():
|
|
826
949
|
raise ValueError(f"No groupings defined for dimensions {on}")
|
|
@@ -871,8 +994,8 @@ class Part:
|
|
|
871
994
|
|
|
872
995
|
output = Part(axes=new_axis)
|
|
873
996
|
idsum = new_axis[axis].dimensions.index(on) #Index of the dimension to sum on
|
|
874
|
-
ref_dev = self.develop(axis)
|
|
875
|
-
new_dev = output.develop(axis)
|
|
997
|
+
ref_dev = self.develop(axis, squeeze=False)
|
|
998
|
+
new_dev = output.develop(axis,squeeze=False)
|
|
876
999
|
selector = ["all"]*ref_dev.ndim
|
|
877
1000
|
for label in new_labels[on]:
|
|
878
1001
|
selector[axis+idsum] = label
|
|
@@ -887,8 +1010,9 @@ class Part:
|
|
|
887
1010
|
|
|
888
1011
|
def get_labels(self,axis=None):
|
|
889
1012
|
"""
|
|
890
|
-
Returns the
|
|
891
|
-
|
|
1013
|
+
Returns a list with the labels of each axis
|
|
1014
|
+
of the part in a the dictionary.
|
|
1015
|
+
|
|
892
1016
|
Parameters
|
|
893
1017
|
----------
|
|
894
1018
|
axis : int or list of int, optional
|
|
@@ -1035,12 +1159,12 @@ class Part:
|
|
|
1035
1159
|
Value used to initialize the new Part
|
|
1036
1160
|
|
|
1037
1161
|
Returns
|
|
1038
|
-
|
|
1162
|
+
-------
|
|
1039
1163
|
Part instance
|
|
1040
1164
|
Part instance with the additional ax indices.
|
|
1041
1165
|
|
|
1042
1166
|
Raise
|
|
1043
|
-
|
|
1167
|
+
-----
|
|
1044
1168
|
ValueError
|
|
1045
1169
|
A Value Error is raised if neither the axes nor the
|
|
1046
1170
|
ref_set arguments are set.
|
|
@@ -1073,6 +1197,67 @@ class Part:
|
|
|
1073
1197
|
output[sel] = self.data
|
|
1074
1198
|
return output
|
|
1075
1199
|
|
|
1200
|
+
def reorder_data(self,new_labels):
|
|
1201
|
+
"""
|
|
1202
|
+
Reorder the data of the Part according to new labels.
|
|
1203
|
+
|
|
1204
|
+
Parameters
|
|
1205
|
+
----------
|
|
1206
|
+
new_labels : dict
|
|
1207
|
+
New labels for the axes.
|
|
1208
|
+
The keys are the dimensions, the values are the labels.
|
|
1209
|
+
|
|
1210
|
+
Raises
|
|
1211
|
+
------
|
|
1212
|
+
ValueError
|
|
1213
|
+
If the new labels do not match the current axes.
|
|
1214
|
+
"""
|
|
1215
|
+
|
|
1216
|
+
if not isinstance(new_labels,dict):
|
|
1217
|
+
raise ValueError("New labels should be a dictionary")
|
|
1218
|
+
|
|
1219
|
+
|
|
1220
|
+
|
|
1221
|
+
sels = []
|
|
1222
|
+
for axis in self.axes:
|
|
1223
|
+
old_labels = axis.labels
|
|
1224
|
+
if not set(new_labels.keys()).issubset(set(old_labels.keys())):
|
|
1225
|
+
sels.append(axis.get("all"))
|
|
1226
|
+
continue
|
|
1227
|
+
for key in new_labels.keys():
|
|
1228
|
+
set_old = set(old_labels[key])
|
|
1229
|
+
set_new = set(new_labels[key])
|
|
1230
|
+
if not set_old.issubset(set_new):
|
|
1231
|
+
raise ValueError(f"The new labels provided for dimension '{key}' is not a superset of the old labels. " +
|
|
1232
|
+
f"Old labels: {old_labels[key]}, new labels: {new_labels[key]}. "
|
|
1233
|
+
"If you want to rename the labels of this dimensions, use the method 'replace_labels() before reordering the data")
|
|
1234
|
+
|
|
1235
|
+
|
|
1236
|
+
ax_label_dict = {}
|
|
1237
|
+
for key in old_labels.keys():
|
|
1238
|
+
if key in new_labels.keys():
|
|
1239
|
+
ax_label_dict[key] = new_labels[key]
|
|
1240
|
+
for lab in new_labels[key]:
|
|
1241
|
+
if lab not in old_labels[key]:
|
|
1242
|
+
# If the label is not in the list, remove it
|
|
1243
|
+
ax_label_dict[key].remove(lab)
|
|
1244
|
+
else:
|
|
1245
|
+
ax_label_dict[key] = old_labels[key]
|
|
1246
|
+
|
|
1247
|
+
sels.append(axis.get(ax_label_dict))
|
|
1248
|
+
|
|
1249
|
+
if len(sels) == 0:
|
|
1250
|
+
raise ValueError(f"None of the dimensions provided in the new labels dict {new_labels.keys()} are present "+
|
|
1251
|
+
f"in the labels of part '{self.name}', which only contains the dimensions {self.get_dimensions()}")
|
|
1252
|
+
|
|
1253
|
+
#Execute the selection
|
|
1254
|
+
self.data = self.data[np.ix_(*sels)]
|
|
1255
|
+
|
|
1256
|
+
# Update the axes with the new labels
|
|
1257
|
+
for dim in new_labels.keys():
|
|
1258
|
+
self.replace_labels(name = dim, labels = new_labels[dim])
|
|
1259
|
+
|
|
1260
|
+
|
|
1076
1261
|
def expand(self,axis=None,over="countries"):
|
|
1077
1262
|
"""
|
|
1078
1263
|
Expand an axis of the Part
|
|
@@ -1212,10 +1397,13 @@ class Part:
|
|
|
1212
1397
|
raise ValueError(f"Cannot sum on {on} as it is not a dimension of axis {axis}")
|
|
1213
1398
|
if ax.levels == 1:
|
|
1214
1399
|
#If the axis has a single level, this is a simple sum
|
|
1400
|
+
axes = self.axes.copy()
|
|
1401
|
+
if not keepdims:
|
|
1402
|
+
del axes[axis]
|
|
1215
1403
|
return self.alias(
|
|
1216
1404
|
data = self.data.sum(axis,keepdims=keepdims),
|
|
1217
1405
|
name=f"{self.name}_sum_{axis}",
|
|
1218
|
-
axes =
|
|
1406
|
+
axes = axes
|
|
1219
1407
|
)
|
|
1220
1408
|
#Otherwise, sum on the relevant levels
|
|
1221
1409
|
idsum = ax.dimensions.index(on) #Index of the dimension to sum on
|
|
@@ -1280,7 +1468,7 @@ class Part:
|
|
|
1280
1468
|
if path is None:
|
|
1281
1469
|
raise FileNotFoundError("No path specified for saving the Part")
|
|
1282
1470
|
if extension == ".nc":
|
|
1283
|
-
path = os.path.join(path,name)
|
|
1471
|
+
path = os.path.join(path,name+extension)
|
|
1284
1472
|
save_to_nc(self,path,overwrite,
|
|
1285
1473
|
write_instructions=write_instructions,
|
|
1286
1474
|
**kwargs)
|
|
@@ -1385,10 +1573,16 @@ class Part:
|
|
|
1385
1573
|
|
|
1386
1574
|
def diag(self):
|
|
1387
1575
|
if self.ndim == 1:
|
|
1576
|
+
log.info("Diagonalize a 1D part")
|
|
1388
1577
|
return self.alias(data=np.diag(self.data),
|
|
1389
1578
|
name=f"diag_{self.name}",
|
|
1390
1579
|
axes = self.axes*2)
|
|
1391
|
-
|
|
1580
|
+
try:
|
|
1581
|
+
log.info("The part has too many dimensions: try to diagonalize the squeezed part")
|
|
1582
|
+
return self.squeeze().diag()
|
|
1583
|
+
except:
|
|
1584
|
+
raise ValueError("Cannot diagonalize a part with more than 2 dimensions")
|
|
1585
|
+
|
|
1392
1586
|
def __add__(self,a):
|
|
1393
1587
|
if isinstance(a,Part):
|
|
1394
1588
|
name = a.name
|
mrio_toolbox/_parts/__init__.py
CHANGED
|
@@ -9,42 +9,49 @@ at a later point.
|
|
|
9
9
|
|
|
10
10
|
def reformat(part,new_dimensions):
|
|
11
11
|
"""
|
|
12
|
-
Reshape a Part to match a new dimensions combination
|
|
12
|
+
Reshape a Part to match a new dimensions combination.
|
|
13
13
|
|
|
14
14
|
Equivalent to a combination of the develop and combine_axes methods.
|
|
15
15
|
|
|
16
16
|
This only works for contiguous dimensions in the current Part,
|
|
17
17
|
without overlapping dimensions.
|
|
18
|
-
For example, if the Part has dimensions:
|
|
19
|
-
[["countries"],["sectors"],["sectors"]]
|
|
20
|
-
The following is allowed:
|
|
21
|
-
[["countries","sectors"],["sectors"]]
|
|
22
|
-
The following is not allowed:
|
|
23
|
-
[["countries"],["sectors","sectors"]]
|
|
24
|
-
[["sectors"],["countries","sectors"]]
|
|
25
|
-
[["sectors","countries"],["sectors"]]
|
|
26
18
|
|
|
27
19
|
Parameters
|
|
28
20
|
----------
|
|
29
|
-
|
|
30
|
-
|
|
21
|
+
new_dimensions : list of list of str
|
|
22
|
+
Target dimensions to reshape into.
|
|
31
23
|
|
|
32
24
|
Returns
|
|
33
25
|
-------
|
|
34
|
-
data : numpy
|
|
35
|
-
Reshaped data
|
|
36
|
-
axes : list of Axe
|
|
37
|
-
Reshaped axes
|
|
26
|
+
data : numpy.ndarray
|
|
27
|
+
Reshaped data.
|
|
28
|
+
axes : list of Axe
|
|
29
|
+
Reshaped axes.
|
|
38
30
|
|
|
31
|
+
Examples
|
|
32
|
+
--------
|
|
33
|
+
If the Part has dimensions::
|
|
34
|
+
|
|
35
|
+
[["countries"], ["sectors"], ["sectors"]]
|
|
36
|
+
|
|
37
|
+
The following is allowed::
|
|
38
|
+
|
|
39
|
+
[["countries", "sectors"], ["sectors"]]
|
|
40
|
+
|
|
41
|
+
The following is not allowed::
|
|
42
|
+
|
|
43
|
+
[["countries"], ["sectors", "sectors"]]
|
|
44
|
+
[["sectors"], ["countries", "sectors"]]
|
|
45
|
+
[["sectors", "countries"], ["sectors"]]
|
|
39
46
|
"""
|
|
40
47
|
def formatting_iteration(part,new_dimensions):
|
|
41
48
|
if part.get_dimensions() == new_dimensions:
|
|
42
49
|
return part
|
|
43
50
|
for i,dim in enumerate(part.get_dimensions()):
|
|
44
51
|
if dim != new_dimensions[i]:
|
|
45
|
-
part = part.combine_axes(i,i+len(new_dimensions)-1)
|
|
52
|
+
part = part.combine_axes(i,i+len(new_dimensions[i])-1)
|
|
46
53
|
return formatting_iteration(part,new_dimensions)
|
|
47
|
-
developed = part.develop()
|
|
54
|
+
developed = part.develop(squeeze = False)
|
|
48
55
|
return formatting_iteration(developed,new_dimensions)
|
|
49
56
|
|
|
50
57
|
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"""
|
|
2
|
+
This module provides functions to extract raw MRIO data from various providers.
|
|
3
|
+
Given the raw data files, it allows to build an MRIO object to be used with this library.
|
|
4
|
+
"""
|
|
5
|
+
from .extractors import *
|
|
6
|
+
from .downloaders import *
|
|
7
|
+
|
|
8
|
+
__all__ = [
|
|
9
|
+
"extract_MRIO",
|
|
10
|
+
"extract_eora",
|
|
11
|
+
"extract_gloria",
|
|
12
|
+
"extract_wiod",
|
|
13
|
+
"extract_exiobase",
|
|
14
|
+
"extract_figaro",
|
|
15
|
+
"extract_emerging",
|
|
16
|
+
"extract_gtap",
|
|
17
|
+
"extract_icio",
|
|
18
|
+
"download_MRIO",
|
|
19
|
+
"download_figaro"
|
|
20
|
+
]
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Module for extracting and converting data from various sources.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import logging as log
|
|
6
|
+
log = log.getLogger(__name__)
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def download_MRIO(table,year,destination,**kwargs):
|
|
10
|
+
"""
|
|
11
|
+
Downloads the MRIO from the internet and saves it to the specified destination.
|
|
12
|
+
|
|
13
|
+
Specific downloaders are called based on the table name.
|
|
14
|
+
Refer to the individual downloader functions for more details.
|
|
15
|
+
|
|
16
|
+
Parameters
|
|
17
|
+
----------
|
|
18
|
+
table : str
|
|
19
|
+
Name of the MRIO table to extract. Currently supported:
|
|
20
|
+
|
|
21
|
+
- 'figaro': Downloading FIGARO data.
|
|
22
|
+
|
|
23
|
+
year : str
|
|
24
|
+
Year of the data to extract.
|
|
25
|
+
destination : path-like
|
|
26
|
+
Path to the destination directory where the NetCDF file will be saved.
|
|
27
|
+
**kwargs : dict
|
|
28
|
+
Additional keyword arguments specific to the extractor function.
|
|
29
|
+
For example, `extended` for WIOD extraction to specify if extended data should be included.
|
|
30
|
+
"""
|
|
31
|
+
log.info(f"Download MRIO data for table '{table}' for year {year} to the folder {destination}")
|
|
32
|
+
if table == 'figaro':
|
|
33
|
+
from mrio_toolbox.extractors.figaro.figaro_downloader import download_figaro
|
|
34
|
+
download_figaro(year, destination, **kwargs)
|
|
35
|
+
else:
|
|
36
|
+
raise ValueError(f"Downloader for table '{table}' is not implemented yet. Currently supported: 'figaro'.")
|