Skip to content

Commit

Permalink
Geojson ids option (#220)
Browse files Browse the repository at this point in the history
  • Loading branch information
Mr-Ixolate authored May 6, 2024
1 parent 5af019c commit 025c0e6
Show file tree
Hide file tree
Showing 5 changed files with 78 additions and 5 deletions.
31 changes: 31 additions & 0 deletions tests/test_extract.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import json
import pytest
from topojson.core.extract import Extract
from shapely import geometry
import geopandas
Expand Down Expand Up @@ -469,6 +470,36 @@ def test_extract_keep_properties():
assert topo["objects"]["feature_1"]["properties"]["name"]["def"] == "ghi"


def test_extract_geojson_keep_index():
feat_1 = Feature(
id="custom_index",
geometry=Polygon([[[0, 0], [1, 0], [1, 1], [0, 1], [0, 0]]]),
)
feat_2 = Feature(
geometry=Polygon([[[1, 0], [2, 0], [2, 1], [1, 1], [1, 0]]]),
)
data = FeatureCollection([feat_1, feat_2])
topo = Extract(data).to_dict()
objects = topo["objects"]

assert bool(objects.get("custom_index")) == True
assert bool(objects.get("feature_1")) == True


def test_extract_geojson_keep_index_duplicates():
feat_1 = Feature(
id="duplicate_id",
geometry=Polygon([[[0, 0], [1, 0], [1, 1], [0, 1], [0, 0]]]),
)
feat_2 = Feature(
id="duplicate_id",
geometry=Polygon([[[1, 0], [2, 0], [2, 1], [1, 1], [1, 0]]]),
)
data = FeatureCollection([feat_1,feat_2])
with pytest.raises(IndexError):
Extract(data)


# why cannot load geojson file using json module?
def test_extract_read_geojson_from_json_dict():
with open("tests/files_geojson/naturalearth_lowres.geojson") as f:
Expand Down
24 changes: 22 additions & 2 deletions tests/test_topology.py
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ def test_topology_winding_order_TopoOptions():
topo = topojson.Topology(data, winding_order="CW_CCW").to_dict(options=True)

assert len(topo["objects"]) == 1
assert len(topo["options"]) == 11
assert len(topo["options"]) == 12


# test winding order using kwarg variables
Expand All @@ -106,7 +106,7 @@ def test_topology_winding_order_kwarg_vars():
topo = topojson.Topology(data, winding_order="CW_CCW").to_dict(options=True)

assert len(topo["objects"]) == 1
assert len(topo["options"]) == 11
assert len(topo["options"]) == 12


def test_topology_computing_topology():
Expand Down Expand Up @@ -699,3 +699,23 @@ def test_topology_write_multiple_object_json_dict():
topo_dict = topo.to_dict()

assert len(topo_dict["objects"]) == 2

def test_topology_ignore_index_true_geojson():

from geojson import Feature, FeatureCollection, Polygon
feat_1 = Feature(
id="duplicate_id",
geometry=Polygon([[[0, 0], [1, 0], [1, 1], [0, 1], [0, 0]]]),
)
feat_2 = Feature(
id="duplicate_id",
geometry=Polygon([[[1, 0], [2, 0], [2, 1], [1, 1], [1, 0]]]),
)
fc = FeatureCollection([feat_1,feat_2])

# Using ignore_index to use default feature ids.
topo = topojson.Topology(fc, ignore_index=True).to_dict(options=True)
geom = topo["objects"]["data"]["geometries"]

index = [obj["id"] for obj in geom]
assert index == ["feature_0","feature_1"]
16 changes: 13 additions & 3 deletions topojson/core/extract.py
Original file line number Diff line number Diff line change
Expand Up @@ -460,9 +460,19 @@ def _extract_featurecollection(self, geom):

if feature["type"] == "GeometryCollection":
feature_dict["geometries"] = feature["geometry"]["geometries"]
data[
"feature_{}".format(str(idx).zfill(zfill_value))
] = feature_dict # feature

if self.options.ignore_index or not feature.get("id"):
data[
"feature_{}".format(str(idx).zfill(zfill_value))
] = feature_dict
else:
data[feature.get("id")] = feature_dict # feature

# check for overwritten duplicate keys
if len(data) < len(obj["features"]):
msg = "index in data duplicated, use `ignore_index=True` to overwrite index"
raise IndexError(msg)

# new data dictionary is created, throw the geometries back to main()
self._is_single = False
self._extractor(data)
Expand Down
6 changes: 6 additions & 0 deletions topojson/core/topology.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,11 @@ class Topology(Hashmap):
case it is required to provide a list of the referenced `object_name` in
combination with an equal length list of `data` objects.
Default is a single object named `data`.
ignore_index : bool
If set to true existing ids/indexes of geojson FeatureCollections will be
ignored and overwritten. Otherwise features with ids will use their existing one.
If indexes are not ignored and a duplicate id exists an exception will be raised.
Default is false.
"""

def __init__(
Expand All @@ -114,6 +119,7 @@ def __init__(
simplify_algorithm="dp",
winding_order="CW_CCW",
object_name="data",
ignore_index=False,
):
options = TopoOptions(locals())

Expand Down
6 changes: 6 additions & 0 deletions topojson/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ def __init__(
simplify_algorithm="dp",
winding_order=None,
object_name="data",
ignore_index=False,
):
# get all arguments
arguments = locals()
Expand Down Expand Up @@ -91,6 +92,11 @@ def __init__(
else:
self.object_name = ["data"]

if "ignore_index" in arguments:
self.ignore_index = arguments["ignore_index"]
else:
self.ignore_index = False

def __repr__(self):
return "TopoOptions(\n {}\n)".format(pprint.pformat(self.__dict__))

Expand Down

0 comments on commit 025c0e6

Please sign in to comment.