mirror of
https://github.com/wassname/geopandas.git
synced 2026-09-24 13:30:40 +08:00
ENH: Make the id property in to_json optional (#1637)
* Make the id property in to_json optional As discussed in #390, the id property in geojson generated with to_json may not be all that meaningful (frequently just an arbitrary row number in a dataframe). The option to disable writing ids without meaning is given here with a new argument `drop_id`, set to `False` by default. * Add to_json tests when only geometry column * Fix linting error * Improved docstring on drop_id option * Fix merge conflict leftover * Set id key first in iterfeatures * Update geopandas/geodataframe.py * Update geopandas/geodataframe.py Co-authored-by: Martin Fleischmann <martin@martinfleischmann.net> Co-authored-by: Joris Van den Bossche <jorisvandenbossche@gmail.com>
This commit is contained in:
co-authored by
Martin Fleischmann
Joris Van den Bossche
parent
8bc5c30afd
commit
56fd62f010
+38
-19
@@ -658,7 +658,7 @@ class GeoDataFrame(GeoPandasBase, DataFrame):
|
||||
|
||||
return df
|
||||
|
||||
def to_json(self, na="null", show_bbox=False, **kwargs):
|
||||
def to_json(self, na="null", show_bbox=False, drop_id=False, **kwargs):
|
||||
"""
|
||||
Returns a GeoJSON representation of the ``GeoDataFrame`` as a string.
|
||||
|
||||
@@ -669,6 +669,10 @@ class GeoDataFrame(GeoPandasBase, DataFrame):
|
||||
See below.
|
||||
show_bbox : bool, optional, default: False
|
||||
Include bbox (bounds) in the geojson
|
||||
drop_id : bool, default: False
|
||||
Whether to retain the index of the GeoDataFrame as the id property
|
||||
in the generated GeoJSON. Default is False, but may want True
|
||||
if the index is just arbitrary row numbers.
|
||||
|
||||
Notes
|
||||
-----
|
||||
@@ -707,7 +711,9 @@ class GeoDataFrame(GeoPandasBase, DataFrame):
|
||||
GeoDataFrame.to_file : write GeoDataFrame to file
|
||||
|
||||
"""
|
||||
return json.dumps(self._to_geo(na=na, show_bbox=show_bbox), **kwargs)
|
||||
return json.dumps(
|
||||
self._to_geo(na=na, show_bbox=show_bbox, drop_id=drop_id), **kwargs
|
||||
)
|
||||
|
||||
@property
|
||||
def __geo_interface__(self):
|
||||
@@ -740,24 +746,29 @@ box': (2.0, 1.0, 2.0, 1.0)}], 'bbox': (1.0, 1.0, 2.0, 2.0)}
|
||||
|
||||
|
||||
"""
|
||||
return self._to_geo(na="null", show_bbox=True)
|
||||
return self._to_geo(na="null", show_bbox=True, drop_id=False)
|
||||
|
||||
def iterfeatures(self, na="null", show_bbox=False):
|
||||
def iterfeatures(self, na="null", show_bbox=False, drop_id=False):
|
||||
"""
|
||||
Returns an iterator that yields feature dictionaries that comply with
|
||||
__geo_interface__
|
||||
|
||||
Parameters
|
||||
----------
|
||||
na : {'null', 'drop', 'keep'}, default 'null'
|
||||
na : str, optional
|
||||
Options are {'null', 'drop', 'keep'}, default 'null'.
|
||||
Indicates how to output missing (NaN) values in the GeoDataFrame
|
||||
* null: ouput the missing entries as JSON null
|
||||
* drop: remove the property from the feature. This applies to
|
||||
each feature individually so that features may have
|
||||
different properties
|
||||
* keep: output the missing entries as NaN
|
||||
|
||||
show_bbox : include bbox (bounds) in the geojson. default False
|
||||
show_bbox : bool, optional
|
||||
Include bbox (bounds) in the geojson. Default False.
|
||||
drop_id : bool, default: False
|
||||
Whether to retain the index of the GeoDataFrame as the id property
|
||||
in the generated GeoJSON. Default is False, but may want True
|
||||
if the index is just arbitrary row numbers.
|
||||
|
||||
Examples
|
||||
--------
|
||||
@@ -805,27 +816,35 @@ box': (2.0, 1.0, 2.0, 1.0)}], 'bbox': (1.0, 1.0, 2.0, 2.0)}
|
||||
else:
|
||||
properties_items = {k: v for k, v in zip(properties_cols, row)}
|
||||
|
||||
feature = {
|
||||
"id": str(ids[i]),
|
||||
"type": "Feature",
|
||||
"properties": properties_items,
|
||||
"geometry": mapping(geom) if geom else None,
|
||||
}
|
||||
if drop_id:
|
||||
feature = {}
|
||||
else:
|
||||
feature = {"id": str(ids[i])}
|
||||
|
||||
feature["type"] = "Feature"
|
||||
feature["properties"] = properties_items
|
||||
feature["geometry"] = mapping(geom) if geom else None
|
||||
|
||||
if show_bbox:
|
||||
feature["bbox"] = geom.bounds if geom else None
|
||||
|
||||
yield feature
|
||||
|
||||
else:
|
||||
for fid, geom in zip(ids, geometries):
|
||||
feature = {
|
||||
"id": str(fid),
|
||||
"type": "Feature",
|
||||
"properties": {},
|
||||
"geometry": mapping(geom) if geom else None,
|
||||
}
|
||||
|
||||
if drop_id:
|
||||
feature = {}
|
||||
else:
|
||||
feature = {"id": str(fid)}
|
||||
|
||||
feature["type"] = "Feature"
|
||||
feature["properties"] = {}
|
||||
feature["geometry"] = mapping(geom) if geom else None
|
||||
|
||||
if show_bbox:
|
||||
feature["bbox"] = geom.bounds if geom else None
|
||||
|
||||
yield feature
|
||||
|
||||
def _to_geo(self, **kwargs):
|
||||
|
||||
@@ -365,6 +365,7 @@ class TestDataFrame:
|
||||
data = json.loads(text)
|
||||
assert data["type"] == "FeatureCollection"
|
||||
assert len(data["features"]) == 5
|
||||
assert "id" in data["features"][0].keys()
|
||||
|
||||
def test_to_json_geom_col(self):
|
||||
df = self.df.copy()
|
||||
@@ -377,6 +378,12 @@ class TestDataFrame:
|
||||
assert data["type"] == "FeatureCollection"
|
||||
assert len(data["features"]) == 5
|
||||
|
||||
def test_to_json_only_geom_column(self):
|
||||
text = self.df[["geometry"]].to_json()
|
||||
data = json.loads(text)
|
||||
assert len(data["features"]) == 5
|
||||
assert "id" in data["features"][0].keys()
|
||||
|
||||
def test_to_json_na(self):
|
||||
# Set a value as nan and make sure it's written
|
||||
self.df.loc[self.df["BoroName"] == "Queens", "Shape_Area"] = np.nan
|
||||
@@ -436,6 +443,20 @@ class TestDataFrame:
|
||||
assert np.isnan(props["Shape_Leng"])
|
||||
assert "Shape_Area" in props
|
||||
|
||||
def test_to_json_drop_id(self):
|
||||
text = self.df.to_json(drop_id=True)
|
||||
data = json.loads(text)
|
||||
assert len(data["features"]) == 5
|
||||
for f in data["features"]:
|
||||
assert "id" not in f.keys()
|
||||
|
||||
def test_to_json_drop_id_only_geom_column(self):
|
||||
text = self.df[["geometry"]].to_json(drop_id=True)
|
||||
data = json.loads(text)
|
||||
assert len(data["features"]) == 5
|
||||
for f in data["features"]:
|
||||
assert "id" not in f.keys()
|
||||
|
||||
def test_copy(self):
|
||||
df2 = self.df.copy()
|
||||
assert type(df2) is GeoDataFrame
|
||||
|
||||
Reference in New Issue
Block a user