mrio-toolbox 1.1.1__py3-none-any.whl → 1.1.3__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.

Files changed (61) hide show
  1. {mrio_toolbox-1.1.1.dist-info → mrio_toolbox-1.1.3.dist-info}/METADATA +2 -2
  2. mrio_toolbox-1.1.3.dist-info/RECORD +5 -0
  3. mrio_toolbox-1.1.3.dist-info/top_level.txt +1 -0
  4. mrio_toolbox/__init__.py +0 -21
  5. mrio_toolbox/_parts/_Axe.py +0 -539
  6. mrio_toolbox/_parts/_Part.py +0 -1698
  7. mrio_toolbox/_parts/__init__.py +0 -7
  8. mrio_toolbox/_parts/part_operations.py +0 -57
  9. mrio_toolbox/extractors/__init__.py +0 -20
  10. mrio_toolbox/extractors/downloaders.py +0 -36
  11. mrio_toolbox/extractors/emerging/__init__.py +0 -3
  12. mrio_toolbox/extractors/emerging/emerging_extractor.py +0 -117
  13. mrio_toolbox/extractors/eora/__init__.py +0 -3
  14. mrio_toolbox/extractors/eora/eora_extractor.py +0 -132
  15. mrio_toolbox/extractors/exiobase/__init__.py +0 -3
  16. mrio_toolbox/extractors/exiobase/exiobase_extractor.py +0 -270
  17. mrio_toolbox/extractors/extractors.py +0 -79
  18. mrio_toolbox/extractors/figaro/__init__.py +0 -3
  19. mrio_toolbox/extractors/figaro/figaro_downloader.py +0 -280
  20. mrio_toolbox/extractors/figaro/figaro_extractor.py +0 -187
  21. mrio_toolbox/extractors/gloria/__init__.py +0 -3
  22. mrio_toolbox/extractors/gloria/gloria_extractor.py +0 -202
  23. mrio_toolbox/extractors/gtap11/__init__.py +0 -7
  24. mrio_toolbox/extractors/gtap11/extraction/__init__.py +0 -3
  25. mrio_toolbox/extractors/gtap11/extraction/extractor.py +0 -129
  26. mrio_toolbox/extractors/gtap11/extraction/harpy_files/__init__.py +0 -6
  27. mrio_toolbox/extractors/gtap11/extraction/harpy_files/_header_sets.py +0 -279
  28. mrio_toolbox/extractors/gtap11/extraction/harpy_files/har_file.py +0 -262
  29. mrio_toolbox/extractors/gtap11/extraction/harpy_files/har_file_io.py +0 -974
  30. mrio_toolbox/extractors/gtap11/extraction/harpy_files/header_array.py +0 -300
  31. mrio_toolbox/extractors/gtap11/extraction/harpy_files/sl4.py +0 -229
  32. mrio_toolbox/extractors/gtap11/gtap_mrio/__init__.py +0 -6
  33. mrio_toolbox/extractors/gtap11/gtap_mrio/mrio_builder.py +0 -158
  34. mrio_toolbox/extractors/icio/__init__.py +0 -3
  35. mrio_toolbox/extractors/icio/icio_extractor.py +0 -121
  36. mrio_toolbox/extractors/wiod/__init__.py +0 -3
  37. mrio_toolbox/extractors/wiod/wiod_extractor.py +0 -143
  38. mrio_toolbox/mrio.py +0 -899
  39. mrio_toolbox/msm/__init__.py +0 -6
  40. mrio_toolbox/msm/multi_scale_mapping.py +0 -863
  41. mrio_toolbox/utils/__init__.py +0 -3
  42. mrio_toolbox/utils/converters/__init__.py +0 -5
  43. mrio_toolbox/utils/converters/pandas.py +0 -247
  44. mrio_toolbox/utils/converters/xarray.py +0 -130
  45. mrio_toolbox/utils/formatting/__init__.py +0 -0
  46. mrio_toolbox/utils/formatting/formatter.py +0 -528
  47. mrio_toolbox/utils/loaders/__init__.py +0 -7
  48. mrio_toolbox/utils/loaders/_loader.py +0 -312
  49. mrio_toolbox/utils/loaders/_loader_factory.py +0 -96
  50. mrio_toolbox/utils/loaders/_nc_loader.py +0 -184
  51. mrio_toolbox/utils/loaders/_np_loader.py +0 -112
  52. mrio_toolbox/utils/loaders/_pandas_loader.py +0 -128
  53. mrio_toolbox/utils/loaders/_parameter_loader.py +0 -386
  54. mrio_toolbox/utils/savers/__init__.py +0 -11
  55. mrio_toolbox/utils/savers/_path_checker.py +0 -37
  56. mrio_toolbox/utils/savers/_to_folder.py +0 -165
  57. mrio_toolbox/utils/savers/_to_nc.py +0 -60
  58. mrio_toolbox-1.1.1.dist-info/RECORD +0 -59
  59. mrio_toolbox-1.1.1.dist-info/top_level.txt +0 -1
  60. {mrio_toolbox-1.1.1.dist-info → mrio_toolbox-1.1.3.dist-info}/WHEEL +0 -0
  61. {mrio_toolbox-1.1.1.dist-info → mrio_toolbox-1.1.3.dist-info}/licenses/LICENSE +0 -0
mrio_toolbox/mrio.py DELETED
@@ -1,899 +0,0 @@
1
- # -*- coding: utf-8 -*-
2
- """
3
- This module provides the MRIO class.
4
-
5
- Created on Thu Mar 30 10:42:23 2023
6
- @author: beaufils
7
- """
8
-
9
- import os
10
- import numpy as np
11
- import logging
12
- import xarray as xr
13
- import pandas as pd
14
- from mrio_toolbox._parts import Part
15
- from mrio_toolbox.utils import converters
16
- from mrio_toolbox.utils.loaders import make_loader
17
- from mrio_toolbox.utils.savers import save_mrio_to_folder,save_to_nc
18
- from mrio_toolbox.utils.formatting import formatter
19
-
20
- log = logging.getLogger(__name__)
21
-
22
- class MRIO:
23
- """
24
- Representation of an MRIO table
25
-
26
- An MRIO table holds a collection of Parts, each representing a different aspect
27
- of the table (e.g., inter-industry matrix, final demand, satellite accounts, etc).
28
- The MRIO instance allows performing basic operations on the table, such as
29
- loading parts, setting groupings, filtering, aggregating, and saving data.
30
-
31
- Instance variables
32
- ------------------
33
- metadata : dict
34
- Dictionary storing the metadata of the MRIO table.
35
- labels : dict
36
- Labels of the table parts, including:
37
- - List of countries
38
- - List of sectors
39
- groupings : dict
40
- Groupings of the MRIO table. Groupings are used to group labels into
41
- larger categories (e.g., countries into zones, sectors into aggregate
42
- sectors). These groupings are primarily used for visualization or
43
- aggregation purposes.
44
- c : int
45
- Number of countries in the table.
46
- s : int
47
- Number of sectors in the table.
48
- parts : dict of Part objects
49
- Dictionary containing the different parts of the MRIO table.
50
-
51
- Methods
52
- -------
53
- __init__(**kwargs):
54
- Initialize an MRIO instance from a file or explicit parameters.
55
- load_part(update_part=True, standalone=False, **kwargs):
56
- Load a Part object into the MRIO table.
57
- set_groupings(groupings=None):
58
- Set the groupings of the MRIO table.
59
- filter(threshold, fill_value=0):
60
- Filter the MRIO table by removing values below a specified threshold.
61
- add_part(part, name=None, update_part=True):
62
- Add a Part object to the MRIO table.
63
- new_part(data=None, name="part", dimensions=None, fill_value=0.0, **kwargs):
64
- Create a new Part object from data or dimensions.
65
- add_dimensions(dimensions):
66
- Add new dimensions to the MRIO table.
67
- add_labels(new_indices, dimension, fill_value=0.0):
68
- Add items to a label of the MRIO instance.
69
- replace_labels(name, new_labels):
70
- Replace labels for one or more dimensions in all MRIO parts.
71
- rename_dimensions(old_names, new_names):
72
- Rename the names of the dimensions in the MRIO table.
73
- aggregate(on="sectors"):
74
- Aggregate the MRIO table on a given dimension.
75
- has_neg(parts=None):
76
- Check whether some parts of the MRIO table have negative values.
77
- copy():
78
- Create a copy of the MRIO object.
79
- save(file, name=None, extension="npy", overwrite=False, **kwargs):
80
- Save the current MRIO instance to a file or folder.
81
- to_xarray():
82
- Convert the MRIO instance to an xarray Dataset.
83
-
84
- Notes
85
- -----
86
- This class provides a comprehensive interface for working with MRIO tables,
87
- including loading, modifying, and saving data, as well as performing
88
- operations like filtering and aggregation.
89
- """
90
-
91
- def __init__(self,**kwargs):
92
- """
93
- Initialize an MRIO instance.
94
-
95
- There are multiple ways to initialize an MRIO instance:
96
- - From a `.nc` file: Provide the "file" parameter with the path to the file.
97
- - From explicit parameters: Provide the data, labels, and metadata explicitly.
98
- - From a `.yaml` file: Provide the "file" parameter with the path to a `.yaml` file
99
- containing loading instructions.
100
-
101
- If no arguments are provided, an empty MRIO instance is created.
102
-
103
- Parameters
104
- ----------
105
- file : str, optional
106
- Path to the file to load the MRIO table from. If a `.yaml` file is provided,
107
- it is interpreted as loading instructions.
108
- data : dict, xarray.DataArray, xarray.Dataset, or pandas.DataFrame, optional
109
- Data to initialize the MRIO instance. If provided, the instance is created
110
- from this data.
111
- kwargs : dict
112
- Additional parameters for initializing the MRIO instance.
113
-
114
- Raises
115
- ------
116
- ValueError
117
- If the provided data type is not supported for initializing the MRIO instance.
118
-
119
- Notes
120
- -----
121
- The "data" parameter is reserved for setting an MRIO instance from a dictionary.
122
- It is intended for internal use only.
123
- """
124
-
125
- if not kwargs:
126
- #Create an empty MRIO instance
127
- kwargs = {
128
- "data" : dict()
129
- }
130
- if "data" in kwargs:
131
- data = kwargs.pop("data")
132
- if isinstance(data,dict):
133
- log.info("Create MRIO from dict")
134
- self.parts,self.labels,self.metadata,self.groupings = dict(),dict(),dict(),dict()
135
- self.__dict__.update(data)
136
-
137
- for part in self.parts:
138
- self._update_labels(
139
- self.parts[part],
140
- update_part=False
141
- )
142
- self.metadata.update(kwargs)
143
- self.loader = make_loader()
144
- return
145
- if isinstance(data,(xr.DataArray,xr.Dataset)):
146
- if isinstance(data,xr.DataArray):
147
- data = data.to_dataset()
148
- mrio_data,to_load = converters.xarray.make_mrio(data,**kwargs)
149
- self.__init__(data=mrio_data)
150
- for part in to_load:
151
- self.add_part(data[part])
152
- return
153
- if isinstance(data,pd.DataFrame):
154
- self.__init__(data=kwargs)
155
- self.add_part(data)
156
- return
157
- raise ValueError(f"Cannot create an MRIO instance from type: {type(data)}")
158
-
159
-
160
- file = kwargs.pop("file",None)
161
- #Initialize the loader
162
- self.loader = make_loader(file=file,**kwargs)
163
-
164
- #Load basic MRIO data
165
- self.metadata = self.loader.metadata
166
- self.labels = self.loader.labels
167
- self.groupings = self.loader.groupings
168
-
169
- #Initialize the parts
170
- self.parts = dict()
171
- available_parts = self.loader.available_parts(
172
- extension = kwargs.get("extension",None)
173
- )
174
-
175
- to_load = {part:part for part in available_parts}
176
- if "part_settings" in self.loader.__dict__ and bool(self.loader.part_settings):
177
- to_load = dict()
178
- for part in self.loader.part_settings.keys():
179
- to_load[part] = self.loader.part_settings[part].get("file_name",part)
180
-
181
- for part in to_load.keys():
182
- if to_load[part] not in available_parts:
183
- log.warning(f"Part {part} not found in available parts")
184
- continue
185
- kwargs["name"] = part
186
- kwargs["file_name"] = to_load[part]
187
- self.load_part(**kwargs)
188
-
189
- if "countries" in self.labels:
190
- self.c = len(self.labels["countries"])
191
- if "sectors" in self.labels:
192
- self.s = len(self.labels["sectors"])
193
-
194
- def load_part(self,
195
- update_part = True,
196
- standalone=False,
197
- **kwargs):
198
- """
199
- Load a Part object into the MRIO table
200
-
201
- By default, the Part is loaded using the current loader.
202
-
203
- Parameters
204
- ----------
205
- update_part : bool, optional
206
- The groupings and labels of the Part are updated based on the MRIO attributes.
207
- standalone : bool, optional
208
- Whether to load the Part as a standalone object.
209
- The default is False.
210
- kwargs : dict
211
- Additional arguments to pass to the Part loader.
212
- """
213
- name = kwargs.get("name","new_part")
214
- try:
215
- log.debug(f"Try loading part {name} from the current loader")
216
- part = self.loader.load_part(**kwargs)
217
- except FileNotFoundError:
218
- log.info(f"Part {name} not found with the current loader")
219
- log.debug(f"Try resetting the loader")
220
- loader = make_loader(**kwargs)
221
- part = loader.load_part()
222
- part = Part(**part)
223
- if standalone:
224
- return part
225
- log.info(f"Add part {part.name} to MRIO table")
226
- self.add_part(part,update_part=update_part)
227
-
228
- def _update_labels(self,part,update_part=True):
229
- """
230
- Update the labels of the MRIO table with the labels of a Part object
231
-
232
- If all the labels of the Part are already in the MRIO labels,
233
- the method does nothing.
234
- This method is run after adding a new Part to the MRIO table.
235
-
236
- Parameters
237
- ----------
238
- part : Part object
239
- Part object to use for the update.
240
- update_part : bool, optional
241
- If True and the Part labels are not properly set,
242
- tries to update the Part labels based on the MRIO labels.
243
- """
244
- part_labels = part.get_labels()
245
- log.debug(f"Update labels of MRIO table with {part.name}")
246
- for labels in part_labels:
247
- for label in labels.keys():
248
- if isinstance(label,int):
249
- log.debug(f"Skip numerical label in {part.name}")
250
- if update_part:
251
- log.debug(f"Try to update labels of {part.name}")
252
- labels[label] = self._get_labels(
253
- len(labels[label])
254
- )
255
- continue #Skip unkwnown labels
256
- if label not in self.labels.keys():
257
- self.labels[label] = labels[label]
258
- log.info(f"Add label {label} to MRIO table")
259
- if update_part:
260
- part.set_labels(part_labels)
261
-
262
- def _get_labels(self,l):
263
- """
264
- Find the labels fitting an axis with a given shape
265
-
266
- Available labels:
267
-
268
- - countries and sectors
269
- - countries
270
- - zones and sectors
271
- - zones
272
- - sectors
273
-
274
- If no fitting label is found, data are labelled numerically
275
-
276
- Parameters
277
- ----------
278
- l : int
279
- Length of the data dimension.
280
-
281
- Returns
282
- -------
283
- dict of str:list of str
284
- Labels of the axis.
285
-
286
- """
287
- if l==1:
288
- return (["all"])
289
- log.debug("Try to infer label from axis of length "+str(l))
290
- for label in self.labels:
291
- #Look whether a basic label fits the axis
292
- if l == len(self.labels[label]):
293
- log.debug(f"Label {label} fits axis of length {l}")
294
- return {label:self.labels[label]}
295
- for grouping in self.groupings:
296
- #Look whether a grouped label fits the axis
297
- if l == len(self.groupings[grouping]):
298
- log.debug(f"Label {label} fits axis of length {l}")
299
- return {grouping:list(self.groupings[grouping]).keys()}
300
- log.warning("No label found for axis of length "+str(l))
301
- return {0:[i for i in range(l)]}
302
-
303
-
304
- def set_groupings(self,groupings=None):
305
- """Set the groupings of the MRIO table
306
-
307
- Groupings are used to group labels into larger categories
308
- (e.g countries into zones, sectors in aggregate sectors).
309
- Groupings have in principle no impact on the resolution of the table
310
- but can be used for visualization or aggregation purposes.
311
-
312
- Groupings should be disjoint, but this is not enforced.
313
- Nested groupings are not supported.
314
-
315
- Unspecified groupings are set to the identity.
316
- Calling the method without arguments resets the groupings to the identity.
317
-
318
- Parameters
319
- ----------
320
- groupings : dict of dict, optional
321
- Groupings of the MRIO table.
322
- The default is None.
323
- If None, the groupings are set to the identity.
324
- Groupings should be provided as a dict of dict::
325
-
326
- {dimension : {group : [items]}}
327
-
328
- where dimension is the name of the label to group,
329
- group is the name of the group,
330
- and items is a list of items to group.
331
- """
332
- if groupings is None:
333
- groupings = {label:dict() for label in self.labels.keys()}
334
- self.set_groupings(groupings)
335
- for key in groupings.keys():
336
- labels = self.labels[key]
337
- covered = []
338
- for group in list(groupings[key]):
339
- for item in list(groupings[key][group]):
340
- if item not in labels:
341
- log.warning(
342
- f"Item {item} not found in {key} labels"
343
- )
344
- groupings[key][group].remove(item)
345
- else:
346
- covered.append(item)
347
- if len(groupings[key][group]) == 0:
348
- log.warning(f"Group {group} is empty")
349
- groupings[key].pop(group)
350
- for item in labels:
351
- if item not in covered:
352
- groupings[key][item] = [item]
353
- self.groupings[key] = groupings[key]
354
- self._update_groupings()
355
- self.loader.set_groupings(self.groupings)
356
-
357
- def _update_groupings(self):
358
- """
359
- Update the groupings of all Parts of the MRIO instance
360
- """
361
- for part in self.parts.keys():
362
- self.parts[part].update_groupings(self.groupings)
363
- self.groups = {
364
- groups : list(self.groupings[groups].keys()) for groups in self.groupings
365
- } #Save name of groups for each dimension
366
-
367
- def filter(self,threshold,fill_value=0):
368
- """
369
- Filter the MRIO table by removing values below a threshold
370
-
371
- Parameters
372
- ----------
373
- threshold : float
374
- Value below which the values are set to 0.
375
- fill_value : float, optional
376
- Value to use to fill the table if only dimensions are given.
377
-
378
- Returns
379
- -------
380
- None.
381
- """
382
- for part in self.parts.keys():
383
- self.parts[part] = self.parts[part].filter(threshold,fill_value)
384
-
385
- def add_part(self,
386
- part,
387
- name=None,
388
- update_part=True):
389
- """
390
- Add a Part object to the MRIO table
391
-
392
- Parameters
393
- ----------
394
- part : Part object
395
- Part object to add to the MRIO table.
396
- update_part : bool, optional
397
- Whether to update the labels of the Part object.
398
- The default is True.
399
- """
400
- if not isinstance(part,Part):
401
- #Cast the data into a Part object
402
- part=Part(part)
403
- if name is None:
404
- name = part.name
405
- log.info(f"Add part {name} to MRIO table")
406
- self._update_labels(part,update_part)
407
- if update_part:
408
- part.update_groupings(self.groupings)
409
- for metadata in self.metadata:
410
- if metadata not in part.metadata:
411
- part.metadata[metadata] = self.metadata[metadata]
412
- self.parts[name] = part
413
-
414
- def new_part(self,
415
- data=None,
416
- name="part",
417
- dimensions=None,
418
- fill_value=0.0,
419
- **kwargs):
420
- """Cast part data into the corresponding Part Object
421
-
422
- Parameters
423
- ----------
424
- data : np.ndarray, optional
425
- Data to load in the Part. The default is None.
426
- If None, the dimensions argument is used to create an empty Part.
427
- name : str, optional
428
- Name of the Part. The default is "part".
429
- dimensions or labels : list of str, list of ints, str, list of dicts, optional
430
- Labels of the Part.
431
- Either of these formats are accepted:
432
-
433
- - Dictionary of explicit labels for each axis
434
- - List of explicit labels for each axis
435
- - List of existing dimension names
436
-
437
- If None, the labels are inferred from the data shape.
438
- multiplier : str, optional
439
- multiplier of the data. The default is None.
440
- unit : float, optional
441
- Unit of the data. The default is 1.
442
- fill_value : float, optional
443
- Value to use to fill the table if only dimensions are given.
444
-
445
- Returns
446
- -------
447
- Part instance
448
- """
449
- def unpack_dimensions(self,dimensions):
450
- """Unpack the dimensions argument"""
451
- if isinstance(dimensions,dict):
452
- return dimensions
453
- if isinstance(dimensions,str):
454
- #Try to get the dimensions from the current labels or groupings
455
- if dimensions in self.labels.keys():
456
- return {dimensions:self.labels[dimensions]}
457
- if dimensions in self.groupings.keys():
458
- return {dimensions:list(self.groupings[dimensions])}
459
- log.warning(f"Dimension {dimensions} not found in labels or groupings\n"+\
460
- " Available dimensions are "+str(self.labels.keys()))
461
- raise ValueError(f"Invalid dimension {dimensions}")
462
- if isinstance(dimensions,int):
463
- #Try to infer the dimension from the length of the data
464
- return self._get_labels(dimensions)
465
- if isinstance(dimensions,(list,tuple)):
466
- try:
467
- #Try to unpack nested dimensions
468
- output = dict()
469
- for dim in dimensions:
470
- output.update(unpack_dimensions(self,dim))
471
- return output
472
- except ValueError:
473
- #Otherwise assume the labels were given as a list
474
- return {0:dimensions}
475
- raise TypeError(f"Invalid type for dimensions {type(dimensions)}")
476
-
477
- dimensions = kwargs.get("dimensions",dimensions)
478
- if dimensions is None:
479
- dimensions = kwargs.get("labels",None)
480
- if data is None:
481
- #Create a Part from the dimensions only
482
- if dimensions is None:
483
- raise ValueError("No data nor dimensions provided")
484
-
485
- if isinstance(dimensions,(int,str)):
486
- #Ensure dimensions are iterable
487
- dimensions = [dimensions]
488
- labels = []
489
- for dim in dimensions:
490
- labels.append(unpack_dimensions(self,dim))
491
- dims = len(labels)
492
- shape = []
493
- for dim in range(dims):
494
- #Recursively compute the shape of the table
495
- length = 1
496
- for label in labels[dim]:
497
- length *= len(labels[dim][label])
498
- shape.append(length)
499
- data = np.full(shape,fill_value=fill_value)
500
-
501
- elif dimensions is None:
502
- #Infer the dimensions from the data shape
503
- labels = []
504
- for dimension in range(data.ndim):
505
- labels.append(
506
- self._get_labels(data.shape[dimension])
507
- )
508
-
509
- else:
510
- #Reformat the dimensions
511
- labels = []
512
- if isinstance(dimensions,(int,str)):
513
- #Ensure dimensions are iterable
514
- dimensions = [dimensions]
515
- for dim in dimensions:
516
- labels.append(unpack_dimensions(self,dim))
517
-
518
- return Part(data=data,
519
- name=name,
520
- groupings = self.groupings,
521
- labels = labels,
522
- **kwargs)
523
-
524
- def add_dimensions(self,dimensions):
525
- """
526
- Add dimensions to the MRIO table
527
-
528
- Parameters
529
- ----------
530
- dimensions : dict
531
- Description of the dimension to add.
532
- """
533
- for dimension in dimensions.keys():
534
- log.info("Add dimension "+dimension+" to MRIO table")
535
- # check whether the dimension is already in the labels
536
- if dimension in self.labels.keys():
537
- log.info(f"Dimension {dimension} already exists in MRIO labels")
538
- if dimensions[dimension] != self.labels[dimension]:
539
- log.warning(f"There already exist different or differently ordered labels for dimension '{dimension}' in the MRIO labels. "+
540
- "You are now overwriting them which leads to inconsistent labels in the parts of your MRIO table!")
541
-
542
- if isinstance(dimensions[dimension],str):
543
- #For single item dimensions, convert to list
544
- dimensions[dimension] = [dimensions[dimension]]
545
- self.labels[dimension] = dimensions[dimension]
546
-
547
- def check_label_consistency(self):
548
- """
549
- Check whether the labels of of all parts of the MRIO table are consistent.
550
- """
551
-
552
- for part in self.parts.keys():
553
- for key, labels in self.parts[part].labels.items():
554
- if key in self.labels.keys():
555
- if labels != self.labels[key]:
556
- log.warning(f"Labels for dimension'{key}' in part '{part}' are inconsistent with MRIO labels")
557
- return False
558
- else:
559
- log.warning(f"Label {key} not found in MRIO labels")
560
- return False
561
- return True
562
-
563
- def add_labels(self,new_indices,dimension,
564
- fill_value=0.0):
565
- """
566
- Add items to a label of the MRIO instance
567
-
568
- All Parts are updated automatically with the given fill_value
569
-
570
- Parameters
571
- ----------
572
- new_indices : list of str
573
- items to add to the label
574
- dimension : str
575
- name of the labels to which the new indices should be added
576
- fill_value : float, optional
577
- Value to use to fill the newly created label fields in the tables.
578
- """
579
- log.info(f"Add labels {str(new_indices)} to dimension "+dimension)
580
- for part in self.parts.keys():
581
- self.parts[part] = self.parts[part].add_labels(
582
- new_indices,dimension=dimension,
583
- fill_value=fill_value
584
- )
585
- self.labels[dimension] += new_indices
586
- if dimension == "countries":
587
- self.c = len(self.labels[dimension])
588
- if dimension == "sectors":
589
- self.s = len(self.labels[dimension])
590
- if "x" in self.parts.keys():
591
- x = self.x.data
592
- x[x==0] = 1
593
- self.loader.set_labels(self.labels)
594
-
595
- def replace_labels(self,name,new_labels):
596
- """
597
- Replace labels for one or more dimensions in all MRIO parts.
598
-
599
- Parameters
600
- ----------
601
- name : str or list of str
602
- Name of the dimension for which the labels should be replaced
603
- new_labels : list of str or dict of list of str
604
- New labels for given dimension in the labels dictionary.
605
- """
606
- log.info(f"Replace labels for {name}")
607
- if isinstance(name,str):
608
- self._replace_individual_labels(name = name, new_labels = new_labels)
609
- elif isinstance(name,list):
610
- for dimension in name:
611
- if isinstance(new_labels,list):
612
- raise ValueError("You provided multiple dimensions but only one set of new labels.")
613
- elif isinstance(new_labels,dict):
614
- new_labels = new_labels[dimension]
615
- else:
616
- raise TypeError(f"Invalid type for new labels: {type(new_labels)}")
617
- self._replace_individual_labels(dimension,new_labels)
618
-
619
- def _replace_individual_labels(self,name, new_labels): # check for usages and update them
620
- """
621
- Replace labels for one dimension in all MRIO parts.
622
-
623
- Parameters
624
- ----------
625
- name : str
626
- Name of the labels to replace. Usually this is 'countries', 'sectors', 'va_labs' or 'y_labs'
627
- new_labels : list of str
628
- New labels for given name in the label dictionary.
629
- """
630
- log.info(f"Replace labels for {name}")
631
- if name not in self.labels.keys():
632
- log.warning(f"Label {name} is not in MRIO labels and cannot be replaced.")
633
- return
634
- for part in self.parts.keys():
635
- self.parts[part].replace_labels(name, new_labels)
636
- self.loader.set_labels(self.labels)
637
- self.labels[name] = new_labels
638
-
639
- if name in self.groupings.keys():
640
- log.warning("Groupings for all dimensions are reset to identity, because the labels have changed.\n \
641
- Please update the groupings manually if needed.")
642
- self.set_groupings(groupings=None)
643
-
644
- def rename_dimensions(self,old_names,new_names):
645
- """
646
- Rename the names of the dimensions.
647
-
648
- The keys of the label dicts for the MRIO instance are renamed.
649
- The content of the labels and the groupings is conserved.
650
-
651
- Parameters
652
- ----------
653
- old_names : str or list of str
654
- Labels to rename.
655
- new_names : str or list of str
656
- New names for the labels.
657
- """
658
- if isinstance(old_names,str):
659
- old_names = [old_names]
660
- if isinstance(new_names,str):
661
- new_names = [new_names]
662
- for old,new in zip(old_names,new_names):
663
- log.info(f"Rename label {old} to {new}")
664
-
665
- if old in self.labels.keys():
666
- self.labels = {new if key == old else key : value for key, value in self.labels.items()}
667
- else:
668
- log.warning(f"Label {old} is not in MRIO labels and cannot be renamed.")
669
- continue
670
- if old in self.groupings.keys():
671
- self.groupings = {new if key == old else key : value for key, value in self.groupings.items()}
672
- for part in self.parts.keys():
673
- self.parts[part].rename_labels(old,new)
674
-
675
- def reorder_data(self, new_labels):
676
- """
677
- Reorder the data of the MRIO instance based on new labels.
678
-
679
- This method is used to reorder the data of the MRIO instance based on the new labels.
680
- The new labels should be a dictionary with the same keys and items as the old mrio labels
681
- but the keys and items can be in a different order. The data of the part is then reordered
682
- to fit the new labels.
683
-
684
- Parameters
685
- ----------
686
- new_labels : dict
687
- New labels to use for reordering.
688
- """
689
- log.info("Reorder MRIO data with new labels")
690
- old_labels = self.labels
691
- if not isinstance(new_labels,dict):
692
- raise TypeError(f"Invalid type for new labels: {type(new_labels)}. Expected a dict.")
693
- if not set(new_labels.keys()).issubset(set(old_labels.keys())):
694
- raise ValueError("You are trying to reorder data for dimensions that are not present in your MRIO instance")
695
-
696
- for part in self.parts.keys():
697
- new_part_labels = {}
698
- for key, labels in new_labels.items():
699
- if key in self.parts[part].labels.keys():
700
- new_part_labels[key] = labels
701
- self.parts[part].reorder_data(new_part_labels)
702
-
703
- for key in new_labels.keys():
704
- self.replace_labels(key, new_labels[key])
705
-
706
-
707
-
708
- def aggregate(self,on="sectors"):
709
- """Aggregate the MRIO table on a given dimension
710
-
711
- The aggregation is performed by summing the values of the table
712
- for the items that are grouped together.
713
-
714
- Parameters
715
- ----------
716
- on : str, optional
717
- Name of the dimension to aggregate on.
718
- The default is "sectors".
719
-
720
- Returns
721
- -------
722
- None.
723
-
724
- """
725
- if on == "all":
726
- on = list(self.groupings.keys())
727
- if isinstance(on,list):
728
- for item in on:
729
- self.aggregate(item)
730
- return
731
- log.info(f"Aggregate MRIO on {on}")
732
- if on not in self.labels.keys():
733
- raise ValueError(f"Invalid dimension {on}")
734
- if on not in self.groupings.keys():
735
- raise ValueError(f"No groupings defined for dimensions {on}")
736
-
737
- new_groupings = {
738
- item : [item] for item in self.groupings[on]
739
- }
740
- new_labels = [item for item in self.groupings[on]]
741
-
742
- for part in self.parts.keys():
743
- self.parts[part] = self.parts[part].aggregate(on)
744
-
745
- self.groupings[on] = new_groupings
746
- self.labels[on] = new_labels
747
-
748
- if on == "countries":
749
- self.c = len(self.labels[on])
750
- if on == "sectors":
751
- self.s = len(self.labels[on])
752
-
753
- self.loader.set_groupings(self.groupings)
754
- self.loader.set_labels(self.labels)
755
-
756
- def __getattr__(self,name):
757
- selset = [
758
- self.parts,
759
- self.labels,
760
- self.metadata
761
- ]
762
- for sel in selset:
763
- try:
764
- return sel[name]
765
- except:
766
- pass
767
- raise AttributeError(f"Attribute {name} not found")
768
-
769
- def __setattr__(self,name,value):
770
- if isinstance(value,Part):
771
- self.add_part(value,name=name)
772
- elif isinstance(value,np.ndarray):
773
- self.add_part(self.new_part(value,name))
774
- else:
775
- super().__setattr__(name,value)
776
-
777
- def __str__(self):
778
- s = ["MRIO object: "+ ' '.join(self.metadata.values())]
779
- s.append("")
780
- s.append("Parts currently loaded:")
781
- s.append(" " + ", ".join(self.parts.keys()))
782
- return "\n".join(s)
783
-
784
- def has_neg(self,parts=None):
785
- """Check whether some Parts have negative values
786
-
787
- Parameters
788
- ----------
789
- parts : str, list of str or None, optional
790
- List of parts to inspect.
791
- If left empty, all parts are inspected.
792
-
793
- Returns
794
- -------
795
- bool
796
- """
797
- if isinstance(parts,str):
798
- parts = [parts]
799
- elif parts is None:
800
- parts = self.parts.keys()
801
- for part in parts:
802
- if self.parts[part].hasneg():
803
- return True
804
- return False
805
-
806
- def copy(self):
807
- """Create a copy of the MRIO object"""
808
- return MRIO(data=self.__dict__)
809
-
810
- def save(self,
811
- file=None,
812
- name=None,
813
- extension = ".nc",
814
- overwrite=False,
815
- **kwargs):
816
- """
817
- Save the current MRIO instance
818
-
819
- If the path points to a folder, the MRIO parts can be saved as:
820
- - .npy
821
- - .csv
822
- - .txt
823
- - .xlsx
824
-
825
- Labels are saved as .txt files and metadata as a .yaml file.
826
-
827
- Otherwise the MRIO instance is saved as a .nc file.
828
-
829
- Parameters
830
- ----------
831
- file : str
832
- Full path to the file or folder to save the MRIO instance into.
833
- If a file is provided, the extension is used to determine the format.
834
- extension : str, optional
835
- Extension of the file to save the MRIO instance into.
836
- This is only used if the file is a folder.
837
- overwrite : bool, optional
838
- Whether to overwrite the existing file. The default is False.
839
- If False, the version name is iterated until a non-existing
840
- file name is found.
841
- kwargs : dict
842
- Additional arguments to pass to the saver.
843
- """
844
- if file is None:
845
- if file is None:
846
- name = self.metadata.get("name","mrio")
847
- file = name
848
- file_extension = os.path.splitext(file)[1]
849
- if file_extension == "" and extension == ".nc":
850
- file = os.path.join(file+".nc")
851
- file_extension = ".nc"
852
- if file_extension == "":
853
- #If the file is a folder, save in folder
854
- save_mrio_to_folder(
855
- self,
856
- file,
857
- name=name,
858
- extension=extension,
859
- overwrite=overwrite,
860
- **kwargs
861
- )
862
- elif file_extension == ".nc":
863
- #If the file is a .nc, save the tables
864
- save_to_nc(self,file,overwrite,**kwargs)
865
- else:
866
- raise NotImplementedError(f"Cannot save MRIO in {file_extension} format")
867
-
868
- def to_xarray(self):
869
- """
870
- Convert the MRIO instance to an xarray Dataset
871
- """
872
- return converters.xarray.to_DataSet(self)
873
-
874
- def reallocate_negatives(self,**kwargs):
875
- formatter.reallocate_negatives(self,**kwargs)
876
-
877
- def adjust_intermediates(self,**kwargs):
878
- formatter.adjust_intermediates(self,**kwargs)
879
-
880
- def fill_empty_rows(self,**kwargs):
881
- formatter.fill_empty_rows(self,**kwargs)
882
-
883
- def balance_va(self,**kwargs):
884
- formatter.balance_va(self,**kwargs)
885
-
886
- def compute_technical_coefficients(self,**kwargs):
887
- formatter.compute_technical_coefficients(self,**kwargs)
888
-
889
- def compute_leontief(self,**kwargs):
890
- formatter.compute_leontief(self,**kwargs)
891
-
892
- def preprocess(self,**kwargs):
893
- formatter.preprocess(self,**kwargs)
894
-
895
- def rename_part(self,old_name,new_name):
896
- formatter.rename_part(self,old_name,new_name)
897
-
898
- def rename_parts(self,renaming_dict):
899
- formatter.rename_parts(self,renaming_dict)