mirror of
https://github.com/wassname/geopandas.git
synced 2026-09-13 12:30:29 +08:00
BUG: pd.concat(axis=0) can override crs information (#2067)
This commit is contained in:
+2
-1
@@ -28,7 +28,8 @@ Deprecations and compatibility notes:
|
||||
Bug fixes:
|
||||
- Accessing `gdf.geometry` where the active geometry column is missing, and a column named `"geometry"` is present
|
||||
will now raise an `AttributeError`, rather than returning `gdf["geometry"]` (#2575)
|
||||
|
||||
- Combining GeoSeries/GeoDataFrames with ``pandas.concat`` will no longer silently
|
||||
override CRS information if not all inputs have the same CRS (#2056).
|
||||
|
||||
Version 0.11.1 (July 24, 2022)
|
||||
------------------------------
|
||||
|
||||
+24
-1
@@ -1317,7 +1317,7 @@ class GeometryArray(ExtensionArray):
|
||||
ExtensionArray
|
||||
"""
|
||||
data = np.concatenate([ga.data for ga in to_concat])
|
||||
return GeometryArray(data, crs=to_concat[0].crs)
|
||||
return GeometryArray(data, crs=_get_common_crs(to_concat))
|
||||
|
||||
def _reduce(self, name, skipna=True, **kwargs):
|
||||
# including the base class version here (that raises by default)
|
||||
@@ -1388,3 +1388,26 @@ class GeometryArray(ExtensionArray):
|
||||
else:
|
||||
return False
|
||||
return (self == item).any()
|
||||
|
||||
|
||||
def _get_common_crs(arr_seq):
|
||||
|
||||
crs_set = {arr.crs for arr in arr_seq}
|
||||
crs_not_none = [crs for crs in crs_set if crs is not None]
|
||||
names = [crs.name for crs in crs_not_none]
|
||||
|
||||
if len(crs_not_none) == 0:
|
||||
return None
|
||||
if len(crs_not_none) == 1:
|
||||
if len(crs_set) != 1:
|
||||
warnings.warn(
|
||||
"CRS not set for some of the concatenation inputs. "
|
||||
f"Setting output's CRS as {names[0]} "
|
||||
"(the single non-null crs provided)."
|
||||
)
|
||||
return crs_not_none[0]
|
||||
|
||||
raise ValueError(
|
||||
f"Cannot determine common CRS for concatenation inputs, got {names}. "
|
||||
"Use `to_crs()` to transform geometries to the same CRS before merging."
|
||||
)
|
||||
|
||||
@@ -54,11 +54,6 @@ class TestMerging:
|
||||
self._check_metadata(res)
|
||||
exp = GeoDataFrame(pd.concat([pd.DataFrame(self.gdf), pd.DataFrame(self.gdf)]))
|
||||
assert_geodataframe_equal(exp, res)
|
||||
# check metadata comes from first gdf
|
||||
res4 = pd.concat([self.gdf.set_crs("epsg:4326"), self.gdf], axis=0)
|
||||
# Note: this behaviour potentially does not make sense. If geom cols are
|
||||
# concatenated but have different CRS, then the CRS will be overridden.
|
||||
self._check_metadata(res4, crs="epsg:4326")
|
||||
|
||||
# series
|
||||
res = pd.concat([self.gdf.geometry, self.gdf.geometry])
|
||||
@@ -66,6 +61,48 @@ class TestMerging:
|
||||
assert isinstance(res, GeoSeries)
|
||||
assert isinstance(res.geometry, GeoSeries)
|
||||
|
||||
def test_concat_axis0_crs(self):
|
||||
|
||||
# CRS not set for both GeoDataFrame
|
||||
res = pd.concat([self.gdf, self.gdf])
|
||||
self._check_metadata(res)
|
||||
|
||||
# CRS set for both GeoDataFrame, same CRS
|
||||
res1 = pd.concat([self.gdf.set_crs("epsg:4326"), self.gdf.set_crs("epsg:4326")])
|
||||
self._check_metadata(res1, crs="epsg:4326")
|
||||
|
||||
# CRS not set for one GeoDataFrame, but set for the other GeoDataFrame
|
||||
with pytest.warns(
|
||||
UserWarning, match=r"CRS not set for some of the concatenation inputs.*"
|
||||
):
|
||||
res2 = pd.concat([self.gdf, self.gdf.set_crs("epsg:4326")])
|
||||
self._check_metadata(res2, crs="epsg:4326")
|
||||
|
||||
# CRS set for both GeoDataFrame, different CRS
|
||||
with pytest.raises(
|
||||
ValueError, match=r"Cannot determine common CRS for concatenation inputs.*"
|
||||
):
|
||||
pd.concat([self.gdf.set_crs("epsg:4326"), self.gdf.set_crs("epsg:4327")])
|
||||
|
||||
# CRS not set for one GeoDataFrame, but set for the other GeoDataFrames,
|
||||
# same CRS
|
||||
with pytest.warns(
|
||||
UserWarning, match=r"CRS not set for some of the concatenation inputs.*"
|
||||
):
|
||||
res3 = pd.concat(
|
||||
[self.gdf, self.gdf.set_crs("epsg:4326"), self.gdf.set_crs("epsg:4326")]
|
||||
)
|
||||
self._check_metadata(res3, crs="epsg:4326")
|
||||
|
||||
# CRS not set for one GeoDataFrame, but set for the other GeoDataFrames,
|
||||
# different CRS
|
||||
with pytest.raises(
|
||||
ValueError, match=r"Cannot determine common CRS for concatenation inputs.*"
|
||||
):
|
||||
pd.concat(
|
||||
[self.gdf, self.gdf.set_crs("epsg:4326"), self.gdf.set_crs("epsg:4327")]
|
||||
)
|
||||
|
||||
def test_concat_axis1(self):
|
||||
|
||||
res = pd.concat([self.gdf, self.df], axis=1)
|
||||
|
||||
Reference in New Issue
Block a user