BUG: explode incorrectly expects unsorted index (#2292)

This commit is contained in:
Martin Fleischmann
2022-01-23 20:04:39 +01:00
committed by GitHub
parent 0ca95d5e76
commit 212cb9c2b5
2 changed files with 116 additions and 30 deletions
+13 -30
View File
@@ -1684,43 +1684,26 @@ individually so that features may have different properties
)
index_parts = True
df_copy = self.copy()
exploded_geom = self.geometry.reset_index(drop=True).explode(index_parts=True)
level_str = f"level_{df_copy.index.nlevels}"
if level_str in df_copy.columns: # GH1393
df_copy = df_copy.rename(columns={level_str: f"__{level_str}"})
if index_parts:
exploded_geom = df_copy.geometry.explode(index_parts=True)
exploded_index = exploded_geom.index
exploded_geom = exploded_geom.reset_index(level=-1, drop=True)
else:
exploded_geom = df_copy.geometry.explode(index_parts=True).reset_index(
level=-1, drop=True
)
exploded_index = exploded_geom.index
df = (
df_copy.drop(df_copy._geometry_column_name, axis=1)
.join(exploded_geom)
.set_geometry(self._geometry_column_name)
.__finalize__(self)
)
df = GeoDataFrame(
self.drop(self._geometry_column_name, axis=1).take(
exploded_geom.index.droplevel(-1)
),
geometry=exploded_geom.values,
).__finalize__(self)
if ignore_index:
df.reset_index(inplace=True, drop=True)
elif index_parts:
# reset to MultiIndex, otherwise df index is only first level of
# exploded GeoSeries index.
df.set_index(exploded_index, inplace=True)
df.index.names = list(self.index.names) + [None]
else:
df.set_index(exploded_index, inplace=True)
df.index.names = self.index.names
if f"__{level_str}" in df.columns:
df = df.rename(columns={f"__{level_str}": level_str})
df = df.set_index(
exploded_geom.index.droplevel(
list(range(exploded_geom.index.nlevels - 1))
),
append=True,
)
return df
+103
View File
@@ -1090,6 +1090,109 @@ class TestGeomMethods:
test_df = df.explode(ignore_index=True, index_parts=True)
assert_frame_equal(test_df, expected_df)
def test_explode_order(self):
df = GeoDataFrame(
{"vals": [1, 2, 3]},
geometry=[MultiPoint([(x, x), (x, 0)]) for x in range(3)],
index=[2, 9, 7],
)
test_df = df.explode(index_parts=True)
expected_index = MultiIndex.from_arrays(
[[2, 2, 9, 9, 7, 7], [0, 1, 0, 1, 0, 1]],
)
expected_geometry = GeoSeries(
[
Point(0, 0),
Point(0, 0),
Point(1, 1),
Point(1, 0),
Point(2, 2),
Point(2, 0),
],
index=expected_index,
)
expected_df = GeoDataFrame(
{"vals": [1, 1, 2, 2, 3, 3]},
geometry=expected_geometry,
index=expected_index,
)
assert_geodataframe_equal(test_df, expected_df)
def test_explode_order_no_multi(self):
df = GeoDataFrame(
{"vals": [1, 2, 3]},
geometry=[Point(0, x) for x in range(3)],
index=[2, 9, 7],
)
test_df = df.explode(index_parts=True)
expected_index = MultiIndex.from_arrays(
[[2, 9, 7], [0, 0, 0]],
)
expected_df = GeoDataFrame(
{"vals": [1, 2, 3]},
geometry=[Point(0, x) for x in range(3)],
index=expected_index,
)
assert_geodataframe_equal(test_df, expected_df)
def test_explode_order_mixed(self):
df = GeoDataFrame(
{"vals": [1, 2, 3]},
geometry=[MultiPoint([(x, x), (x, 0)]) for x in range(2)] + [Point(0, 10)],
index=[2, 9, 7],
)
test_df = df.explode(index_parts=True)
expected_index = MultiIndex.from_arrays(
[[2, 2, 9, 9, 7], [0, 1, 0, 1, 0]],
)
expected_geometry = GeoSeries(
[
Point(0, 0),
Point(0, 0),
Point(1, 1),
Point(1, 0),
Point(0, 10),
],
index=expected_index,
)
expected_df = GeoDataFrame(
{"vals": [1, 1, 2, 2, 3]},
geometry=expected_geometry,
index=expected_index,
)
assert_geodataframe_equal(test_df, expected_df)
def test_explode_duplicated_index(self):
df = GeoDataFrame(
{"vals": [1, 2, 3]},
geometry=[MultiPoint([(x, x), (x, 0)]) for x in range(3)],
index=[1, 1, 2],
)
test_df = df.explode(index_parts=True)
expected_index = MultiIndex.from_arrays(
[[1, 1, 1, 1, 2, 2], [0, 1, 0, 1, 0, 1]],
)
expected_geometry = GeoSeries(
[
Point(0, 0),
Point(0, 0),
Point(1, 1),
Point(1, 0),
Point(2, 2),
Point(2, 0),
],
index=expected_index,
)
expected_df = GeoDataFrame(
{"vals": [1, 1, 2, 2, 3, 3]},
geometry=expected_geometry,
index=expected_index,
)
assert_geodataframe_equal(test_df, expected_df)
#
# Test '&', '|', '^', and '-'
#