From f8e50aa6b64b0cc0f0baca403fab8803a17aaa85 Mon Sep 17 00:00:00 2001
From: Philip Hackstock
Date: Tue, 24 May 2022 09:59:24 +0200
Subject: [PATCH] Fix/concat (#665)
* Add index transfer to concat
* Add test for non-standard concat
* Add details to concat docstring
* Apply suggestions from code review
Co-authored-by: Daniel Huppmann
Co-authored-by: Daniel Huppmann
---
pyam/core.py | 8 +++++++-
tests/test_feature_append_concat.py | 32 +++++++++++++++++++++++++++++
2 files changed, 39 insertions(+), 1 deletion(-)
diff --git a/pyam/core.py b/pyam/core.py
index 55a86af0d..cb958c9f1 100755
--- a/pyam/core.py
+++ b/pyam/core.py
@@ -2793,6 +2793,8 @@ def concat(objs, ignore_meta_conflict=False, **kwargs):
The *meta* attributes are merged only for those objects of *objs* that are passed
as :class:`IamDataFrame` instances.
+ The :attr:`dimensions` and :attr:`index` names of all elements of *dfs* must be
+ identical. The returned IamDataFrame inherits the dimensions and index names.
"""
if not islistable(objs) or isinstance(objs, pd.DataFrame):
raise TypeError(f"'{objs.__class__.__name__}' object is not iterable")
@@ -2844,7 +2846,11 @@ def as_iamdataframe(df):
)
# return as new IamDataFrame, this will verify integrity as part of `__init__()`
- return IamDataFrame(pd.concat(ret_data, verify_integrity=False), meta=ret_meta)
+ return IamDataFrame(
+ pd.concat(ret_data, verify_integrity=False),
+ meta=ret_meta,
+ index=ret_meta.index.names,
+ )
def read_datapackage(path, data="data", meta="meta"):
diff --git a/tests/test_feature_append_concat.py b/tests/test_feature_append_concat.py
index 0e030ec0e..0ea0f90cb 100644
--- a/tests/test_feature_append_concat.py
+++ b/tests/test_feature_append_concat.py
@@ -104,6 +104,38 @@ def test_concat(test_df, reverse, iterable):
npt.assert_array_equal(ts.iloc[2].values, ts.iloc[3].values)
+def test_concat_non_default_index():
+ # Test that merging two IamDataFrames with identical, non-standard index dimensions
+ # preserves the index.
+
+ df1 = IamDataFrame(
+ pd.DataFrame(
+ [["model_a", "scenario_a", "region_a", "variable_a", "unit", 1, 1]],
+ columns=IAMC_IDX + ["version", 2005],
+ ),
+ index=META_IDX + ["version"],
+ )
+ df2 = IamDataFrame(
+ pd.DataFrame(
+ [["model_a", "scenario_a", "region_a", "variable_a", "unit", 2, 2]],
+ columns=IAMC_IDX + ["version", 2005],
+ ),
+ index=META_IDX + ["version"],
+ )
+ exp = IamDataFrame(
+ pd.DataFrame(
+ [
+ ["model_a", "scenario_a", "region_a", "variable_a", "unit", 1, 1],
+ ["model_a", "scenario_a", "region_a", "variable_a", "unit", 2, 2],
+ ],
+ columns=IAMC_IDX + ["version", 2005],
+ ),
+ index=META_IDX + ["version"],
+ )
+
+ assert_iamframe_equal(exp, concat([df1, df2]))
+
+
@pytest.mark.parametrize("reverse", (False, True))
def test_concat_with_pd_dataframe(test_df, reverse):
other = test_df.filter(scenario="scen_b").rename({"scenario": {"scen_b": "scen_c"}})