def test_rasterization_function(): sq1 = GeoFeature( GeoVector.from_bounds(xmin=0, ymin=2, xmax=1, ymax=3, crs=WGS84_CRS), {'value': 1.0} ) sq2 = GeoFeature( GeoVector.from_bounds(xmin=1, ymin=0, xmax=3, ymax=2, crs=WGS84_CRS), {'value': 2.0} ) fc = FeatureCollection([sq1, sq2]) def func(feat): return feat['value'] expected_image = np.ma.masked_array( [[ [1.0, 0.0, 0.0], [0.0, 2.0, 2.0], [0.0, 2.0, 2.0] ]], [ [False, True, True], [True, False, False], [True, False, False], ] ) result = fc.rasterize(1.0, fill_value=func, crs=WGS84_CRS, dtype=np.float32) assert_array_equal(result.image.mask, expected_image.mask) assert_array_equal(result.image.data, expected_image.data)
def test_groupby_agg_returns_expected_result(): fc = FeatureCollection([ GeoFeature(GeoVector(Point(3, 3)), { 'prop1': 'a', 'b': 1 }), GeoFeature(GeoVector(Point(1, 1)), { 'prop1': 'a', 'b': 2 }), GeoFeature(GeoVector(Point(2, 2)), { 'prop1': 'b', 'b': 3 }) ]) def first(collection): return collection[0] expected_result = FeatureCollection([ GeoFeature(GeoVector(Point(3, 3)), {'b': 1}), GeoFeature(GeoVector(Point(2, 2)), {'b': 3}) ]) assert list(fc.groupby('prop1')['b'].agg(first)) == expected_result
def test_rasterization_of_line_has_correct_pixel_width(resolution): xmax, ymax = 11, 5 pixels_width = 1 line = GeoFeature.from_shape( LineString([(xmax / 2, 0), (xmax / 2, ymax * 4 / 5)])) roi = GeoVector.from_bounds(xmin=0, ymin=0, xmax=xmax, ymax=ymax, crs=DEFAULT_CRS) fc = FeatureCollection([line]) expected_image = np.zeros( (int(ymax // resolution), int(xmax // resolution)), dtype=np.uint8) expected_image[int(1 // resolution):, expected_image.shape[1] // 2] = 1 expected_affine = Affine(resolution, 0.0, 0.0, 0.0, -resolution, 5.0) expected_crs = DEFAULT_CRS expected_result = GeoRaster2(expected_image, expected_affine, expected_crs, nodata=0) result = fc.rasterize(resolution, polygonize_width=pixels_width, crs=DEFAULT_CRS, bounds=roi) assert result == expected_result
def test_rasterization_of_line_simple(): resolution = 1 pixels_width = 1 line = GeoFeature.from_shape(LineString([(2.5, 0), (2.5, 3)])) roi = GeoVector.from_bounds(xmin=0, ymin=0, xmax=5, ymax=5, crs=DEFAULT_CRS) fc = FeatureCollection([line]) expected_image = np.zeros((5, 5), dtype=np.uint8) expected_image[2:, 2] = 1 expected_affine = Affine(1.0, 0.0, 0.0, 0.0, -1.0, 5.0) expected_crs = DEFAULT_CRS expected_result = GeoRaster2(expected_image, expected_affine, expected_crs, nodata=0) result = fc.rasterize(resolution, polygonize_width=pixels_width, crs=DEFAULT_CRS, bounds=roi) assert result == expected_result
def test_rasterization_raise_error_for_too_big_image(): shape = Polygon([(0, 0), (1, 0), (1, -1), (0, -1)]) fcol = FeatureCollection([GeoFeature(GeoVector(shape), {})]) with pytest.raises(ScaleError) as excinfo: fcol.rasterize(1e-50) assert "Scale is too fine, increase it for a smaller image" in excinfo.exconly()
def test_feature_collection_schema_of_empty_set(): fc = FeatureCollection([]) assert fc.schema == {"geometry": None, "properties": {}} with tempfile.NamedTemporaryFile(suffix=".json") as target: fc.save(target.name) fc2 = FileCollection.open(target.name) assert fc == fc2
def test_get_tile_merge_tiles(tile): raster1_path = './tests/data/raster/overlap1.tif' raster2_path = './tests/data/raster/overlap2.tif' raster1 = GeoRaster2.open(raster1_path) raster2 = GeoRaster2.open(raster2_path) features = [ GeoFeature(raster1.footprint().reproject(new_crs=WGS84_CRS), {'raster_url': raster1_path, 'created': datetime.now()}), GeoFeature(raster2.footprint().reproject(new_crs=WGS84_CRS), {'raster_url': raster2_path, 'created': datetime.now()}), ] fc = FeatureCollection(features) bounds = mercantile.xy_bounds(*tile) eroi = GeoVector.from_bounds(xmin=bounds.left, xmax=bounds.right, ymin=bounds.bottom, ymax=bounds.top, crs=WEB_MERCATOR_CRS) expected_tile = merge_all([raster1.get_tile(*tile), raster2.get_tile(*tile)], roi=eroi) merged = fc.get_tile(*tile, sort_by='created') if merged is not None: assert merged == expected_tile else: assert expected_tile.image.mask.all() assert (expected_tile.image.data == 0).all()
def test_groupby_can_extract_property(): fc = FeatureCollection([ GeoFeature(GeoVector(Point(3, 3)), { 'prop1': 'a', 'b': 1 }), GeoFeature(GeoVector(Point(1, 1)), { 'prop1': 'a', 'b': 2 }), GeoFeature(GeoVector(Point(2, 2)), { 'prop1': 'b', 'b': 3 }) ]) expected_groups = [ ('a', FeatureCollection([ GeoFeature(GeoVector(Point(3, 3)), {'b': 1}), GeoFeature(GeoVector(Point(1, 1)), {'b': 2}), ])), ('b', FeatureCollection([GeoFeature(GeoVector(Point(2, 2)), {'b': 3})])) ] assert list(fc.groupby('prop1')['b']) == expected_groups
def test_get_values(): fc = FeatureCollection([ GeoFeature(GeoVector(Point(0, 0)), {'prop1': 1}), GeoFeature(GeoVector(Point(0, 0)), {'prop1': 2}), GeoFeature(GeoVector(Point(0, 0)), {'prop1': 3}), GeoFeature(GeoVector(Point(0, 0)), {'prop2': 1}), ]) assert list(fc.get_values('prop1')) == [1, 2, 3, None]
def test_feature_collection_to_record_from_record(): num_features = 3 gen_features = (GeoFeature.from_shape( Polygon([(0 + d_x, 0), (0 + d_x, 1), (1 + d_x, 1), (1 + d_x, 0)])) for d_x in range(num_features)) fc = FeatureCollection(gen_features) assert mapping(fc) == mapping( FeatureCollection.from_record(fc.to_record(WGS84_CRS), WGS84_CRS))
def test_groupby_has_proper_groups(): gfa1 = GeoFeature(GeoVector(Point(3, 3)), {'prop1': 'a'}) gfa2 = GeoFeature(GeoVector(Point(1, 1)), {'prop1': 'a'}) gfb1 = GeoFeature(GeoVector(Point(2, 2)), {'prop1': 'b'}) fc = FeatureCollection([gfa1, gfa2, gfb1]) expected_groups = [('a', FeatureCollection([gfa1, gfa2])), ('b', FeatureCollection([gfb1]))] assert list(fc.groupby('prop1')) == expected_groups
def test_featurecollection_save_has_no_side_effects(): fc = FeatureCollection([ GeoFeature(GeoVector(Point(0, 0)), {'attr1': 1}), GeoFeature(GeoVector(Point(0, 0)), {'attr2': 1}) ]) with tempfile.NamedTemporaryFile(suffix=".json") as fp: fc.save(fp.name) assert fc[0].attributes == {'attr1': 1} assert fc[1].attributes == {'attr2': 1}
def test_collection_add(): gv1 = GeoVector.from_bounds(xmin=0, ymin=0, xmax=2, ymax=1) gv2 = GeoVector.from_bounds(xmin=1, ymin=0, xmax=3, ymax=1) gv3 = GeoVector.from_bounds(xmin=2, ymin=0, xmax=4, ymax=1) gv4 = GeoVector.from_bounds(xmin=3, ymin=0, xmax=5, ymax=1) assert (gv1 + gv2) == FeatureCollection.from_geovectors([gv1, gv2]) assert (gv1 + gv2 + gv3) == FeatureCollection.from_geovectors( [gv1, gv2, gv3]) assert (((gv1 + gv2) + (gv3 + gv4)) == (gv1 + gv2 + gv3 + gv4) == FeatureCollection.from_geovectors([gv1, gv2, gv3, gv4]))
def test_feature_collection_filter_returns_proper_elements(): num_features = 3 gen_features = (GeoFeature.from_shape( Polygon([(0 + d_x, 0), (0 + d_x, 1), (1 + d_x, 1), (1 + d_x, 0)])) for d_x in range(num_features)) filter_gv = GeoVector(Point(1.5, 0.5)) fcol = FeatureCollection(gen_features) res = fcol.filter(intersects=filter_gv) assert len(list(res)) == 1
def test_groupby_with_dissolve(): fc = FeatureCollection([ GeoFeature(GeoVector.from_bounds(xmin=0, ymin=0, xmax=2, ymax=1, crs=DEFAULT_CRS), {'prop1': 'a', 'b': 1}), GeoFeature(GeoVector.from_bounds(xmin=1, ymin=0, xmax=3, ymax=1, crs=DEFAULT_CRS), {'prop1': 'a', 'b': 2}), GeoFeature(GeoVector.from_bounds(xmin=0, ymin=0, xmax=2, ymax=1, crs=DEFAULT_CRS), {'prop1': 'b', 'b': 3}), ]) expected_result = FeatureCollection([ GeoFeature(GeoVector.from_bounds(xmin=0, ymin=0, xmax=3, ymax=1, crs=DEFAULT_CRS), {'b': 3}), GeoFeature(GeoVector.from_bounds(xmin=0, ymin=0, xmax=2, ymax=1, crs=DEFAULT_CRS), {'b': 3}), ]) assert fc.dissolve('prop1', sum) == fc.groupby('prop1').agg(partial(dissolve, aggfunc=sum)) == expected_result
def test_rasterization_function_raises_error_if_no_dtype_is_given(): sq1 = GeoFeature( GeoVector.from_bounds(xmin=0, ymin=2, xmax=1, ymax=3, crs=WGS84_CRS), {'value': 1.0}) sq2 = GeoFeature( GeoVector.from_bounds(xmin=1, ymin=0, xmax=3, ymax=2, crs=WGS84_CRS), {'value': 2.0}) fc = FeatureCollection([sq1, sq2]) with pytest.raises(ValueError) as excinfo: fc.rasterize(1.0, fill_value=lambda x: 1, crs=WGS84_CRS) assert "dtype must be specified for multivalue rasterization" in excinfo.exconly( )
def test_sort(): fc = FeatureCollection([ GeoFeature(GeoVector(Point(3, 3)), {'prop1': 3}), GeoFeature(GeoVector(Point(1, 1)), {'prop1': 1}), GeoFeature(GeoVector(Point(2, 2)), {'prop1': 2}) ]) expected_fc = FeatureCollection([ GeoFeature(GeoVector(Point(1, 1)), {'prop1': 1}), GeoFeature(GeoVector(Point(2, 2)), {'prop1': 2}), GeoFeature(GeoVector(Point(3, 3)), {'prop1': 3}) ]) assert fc.sort("prop1") == expected_fc
def test_featurecollection_apply_multiple_statements(): fc = fc_generator(5) new_fc = fc.apply(prop1=3) new_fc_2 = new_fc.apply(prop2=lambda f: f['prop1'] + 2, prop3='aaa') assert new_fc_2 == FeatureCollection([GeoFeature(feat.geometry, {'prop1': 3, 'prop2': 5, 'prop3': 'aaa'}) for feat in fc])
def test_feature_collection_with_invalid_schema(): fc = FileCollection.open("tests/data/vector/bsas_barrios_lla.geojson") schema = fc.schema.copy() schema["properties"] = {} with pytest.raises(ValueError) as exception: fc2 = FeatureCollection(list(fc), schema=schema) assert exception.message.startswith("Record does not match collection schema")
def test_feature_collection_from_rasters(): rasters_list = [ GeoRaster2.open("./tests/data/raster/overlap1.tif"), GeoRaster2.open("./tests/data/raster/overlap2.tif") ] fc = FeatureCollection.from_georasters(rasters_list) assert fc.is_rasters_collection()
def test_featurecollection_schema_for_property_types_with_none_values(): fc = FeatureCollection([ GeoFeature(GeoVector(Point(0, 0)), { 'prop1': None, 'prop2': 1.0, 'prop3': 'A' }), GeoFeature(GeoVector(Point(0, 0)), { 'prop1': 2, 'prop2': None, 'prop3': 'B' }), GeoFeature(GeoVector(Point(0, 0)), { 'prop1': 3, 'prop2': 3.0, 'prop3': None }) ]) expected_schema = { 'geometry': 'Point', 'properties': { 'prop1': 'int', 'prop2': 'float', 'prop3': 'str' } } assert fc.schema == expected_schema
def test_featurecollection_apply_on_rasters_collection(): rasters_list = [ GeoRaster2.open("./tests/data/raster/overlap1.tif"), GeoRaster2.open("./tests/data/raster/overlap2.tif") ] fc = FeatureCollection.from_georasters(rasters_list) new_fc = fc.apply(prop1=3) assert new_fc.is_rasters_collection()
def fc_generator(num_features): gen_features = ( GeoFeature.from_shape( Polygon([(0 + d_x, 0), (0 + d_x, 1), (1 + d_x, 1), (1 + d_x, 0)]) ) for d_x in range(num_features) ) return FeatureCollection(gen_features)
def test_rasterization_has_expected_affine_and_crs(): shape = Polygon([(0, 0), (1, 0), (1, -1), (0, -1)]) crs = CRS({'init': 'epsg:32631'}) fcol = FeatureCollection([GeoFeature(GeoVector(shape, crs), {})]) expected_affine = ~Affine(1.0, 0.0, 0.0, 0.0, -1.0, 0.0) georaster = fcol.rasterize(1, crs=crs) assert georaster.crs == crs assert georaster.affine.a == pytest.approx(expected_affine.a) assert georaster.affine.b == pytest.approx(expected_affine.b, abs=1e-10) assert georaster.affine.c == pytest.approx(expected_affine.c, abs=1e-10) assert georaster.affine.d == pytest.approx(expected_affine.d, abs=1e-10) assert georaster.affine.e == pytest.approx(expected_affine.e) assert georaster.affine.f == pytest.approx(expected_affine.f, abs=1e-10)
def test_featurecollection_property_names_includes_all(): fc = FeatureCollection([ GeoFeature(GeoVector(Point(0, 0)), {'prop1': 1}), GeoFeature(GeoVector(Point(0, 0)), {'prop2': 1}) ]) expected_property_names = ['prop1', 'prop2'] assert sorted(fc.property_names) == expected_property_names
def test_featurecollection_map(): fc = fc_generator(5) def func(feat): return GeoFeature(feat.geometry, {'attr1': 1}) new_fc = fc.map(func) assert new_fc == FeatureCollection([func(feat) for feat in fc])
def test_featurecollection_attribute_names_includes_all(): fc = FeatureCollection([ GeoFeature(GeoVector(Point(0, 0)), {'attr1': 1}), GeoFeature(GeoVector(Point(0, 0)), {'attr2': 1}) ]) expected_attribute_names = ['attr1', 'attr2'] assert sorted(fc.attribute_names) == expected_attribute_names
def test_featurecollection_schema_raises_error_for_heterogeneous_property_types(): fc = FeatureCollection([ GeoFeature(GeoVector(Point(0, 0)), {'prop1': 1}), GeoFeature(GeoVector(Point(0, 0)), {'prop1': 1.0}) ]) with pytest.raises(FeatureCollectionIOError) as excinfo: fc.schema assert "Cannot generate a schema for a heterogeneous FeatureCollection. " in excinfo.exconly()
def test_featurecollection_schema_raises_error_for_heterogeneous_types(): fc = FeatureCollection.from_geovectors([ GeoVector(Polygon.from_bounds(0, 0, 1, 1)), GeoVector(Point(0, 0)) ]) with pytest.raises(FeatureCollectionIOError) as excinfo: fc.schema assert "Cannot generate a schema for a heterogeneous FeatureCollection. " in excinfo.exconly()
def test_convex_hull_and_envelope(): fc = FeatureCollection.from_geovectors([ GeoVector.from_bounds(xmin=0, ymin=0, xmax=1, ymax=1), GeoVector.from_bounds(xmin=1, ymin=0, xmax=2, ymax=1), GeoVector.from_bounds(xmin=1, ymin=1, xmax=2, ymax=2), ]) expected_convex_hull = GeoVector(Polygon([(0, 0), (2, 0), (2, 2), (1, 2), (0, 1), (0, 0)])) expected_envelope = GeoVector.from_bounds(xmin=0, ymin=0, xmax=2, ymax=2) assert fc.convex_hull.equals(expected_convex_hull) assert fc.envelope.equals(expected_envelope)