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_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_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_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_delegated_predicates(predicate_name): feature_1 = GeoFeature.from_shape(Polygon([(0, 0), (1, 0), (1, 1), (0, 1)])) feature_2 = GeoFeature.from_shape( Polygon([(0.5, 0), (1.5, 0), (1.5, 1), (0.5, 1)])) assert (getattr(feature_1, predicate_name)(feature_2) == getattr( feature_1.geometry, predicate_name)(feature_2.geometry))
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_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_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_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_geofeature_copy_with_updates_properties(request): feature = GeoFeature(GeoVector(Point(0, 0)), OrderedDict([('prop1', 1), ('prop2', '2')])) new_properties = OrderedDict([('prop2', 1), ('prop3', '2')]) feature_copy = feature.copy_with(properties=new_properties) assert feature != feature_copy assert feature.geometry == feature_copy.geometry assert id(feature.geometry) != id(feature_copy.geometry) assert feature_copy.properties == {'prop1': 1, 'prop2': 1, 'prop3': '2'}
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_geofeature_copy_with(request): feature = GeoFeature( GeoVector(Point(0, 0)), OrderedDict([('prop1', 1), ('prop2', '2'), ('prop3', datetime(2018, 4, 25, 11, 18))])) feature_copy = feature.copy_with() assert feature == feature_copy assert id(feature.geometry) != id(feature_copy.geometry) assert id(feature.properties) != id(feature_copy.properties)
def validate(self): """ if schema exists we run shape file validation code of fiona by trying to save to in MemoryFile """ if self._schema is not None: with MemoryFile() as memfile: with memfile.open(driver="ESRI Shapefile", schema=self.schema) as target: for _item in self._results: # getting rid of the assets that don't behave well becasue of in memroy rasters item = GeoFeature(_item.geometry, _item.properties) target.write(item.to_record(item.crs))
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_geofeature_from_record_for_a_record_with_raster(raster, request): raster = request.getfixturevalue(raster) properties = OrderedDict([('prop1', 1), ('prop2', '2'), ('prop3', datetime(2018, 4, 25, 11, 18))]) feature = GeoFeature.from_raster(raster, properties=properties) feature2 = GeoFeature.from_record(feature.to_record(feature.crs), feature.crs) assert feature.raster() == feature2.raster() assert feature.geometry == feature2.geometry assert feature2.to_record(feature2.crs)['properties'] == feature.to_record( feature.crs)['properties'] assert feature2.crs == feature2.raster().crs
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_geofeature_equality_checks_geometry_and_properties( geometry, properties): ref_geometry = GeoVector(Polygon([(0, 0), (1, 0), (1, 1), (0, 1)])) ref_properties = {'property_1': 1} feature1 = GeoFeature(ref_geometry, ref_properties) feature2 = GeoFeature(geometry, properties) if geometry == ref_geometry and properties == ref_properties: assert feature1 == feature2 else: assert feature1 != feature2
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_featurecollection_schema_treat_unsupported_property_types_as_str(): fc = FeatureCollection([ GeoFeature(GeoVector(Point(0, 0)), {'prop1': bool(0), 'prop2': date(2018, 5, 19)}), GeoFeature(GeoVector(Point(0, 0)), {'prop1': bool(1), 'prop2': date(2018, 5, 20)}) ]) expected_schema = { 'geometry': 'Point', 'properties': { 'prop1': 'str', 'prop2': 'str' } } assert fc.schema == expected_schema
def test_feature_collection_with_dates_serializes_correctly(): # "For Shapefiles, however, the only possible field type is 'date' as 'datetime' and 'time' are not available." # https://github.com/Toblerity/Fiona/pull/130 # See also: https://github.com/Toblerity/Fiona/issues/572 schema = { 'geometry': 'Point', 'properties': OrderedDict([ ('prop_date', 'date'), ]), } expected_attributes = { 'prop_date': date(2018, 4, 23), } feature = GeoFeature(GeoVector(Point(0, 0)), expected_attributes) with tempfile.TemporaryDirectory() as path: file_path = os.path.join(path, "test_dates.shp") with fiona.open(file_path, mode='w', driver="ESRI Shapefile", schema=schema, crs=feature.crs) as sink: sink.write(mapping(feature)) fc = FileCollection.open(file_path) assert fc.schema == schema assert fc[0].geometry == feature.geometry assert fc[0].attributes == expected_attributes
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_delegated_unary_predicates(predicate_name): feature = GeoFeature( GeoVector(Polygon([(0, 0), (1, 0), (1, 1), (0, 1)])), {} ) assert getattr(feature, predicate_name) == getattr(feature.geometry, predicate_name)
def test_geofeature_str(): expected_geovector = GeoVector(Point(0.0, 0.0)) expected_attributes = {'attribute_1': 1} res = GeoFeature(expected_geovector, expected_attributes) assert str(res) == "GeoFeature(Point, {'attribute_1': 1})"
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_geofeature_str(): expected_geovector = GeoVector(Point(0.0, 0.0)) expected_properties = {'property_1': 1} res = GeoFeature(expected_geovector, expected_properties) assert str(res) == "GeoFeature(Point, {'property_1': 1})"
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_delegated_properties(property_name): feature = GeoFeature( GeoVector(Point(0, 10)), {} ) assert getattr(feature, property_name) == getattr(feature.geometry, property_name)
def _adapt_feature_before_write(self, feature): new_properties = feature.properties.copy() for key in self.property_names: new_properties.setdefault(key, None) new_geometry = feature.geometry.reproject(self.crs) return GeoFeature(new_geometry, new_properties)
def __add__(self, other): if isinstance(other, GeoVector): other = GeoFeature(other, {}) if isinstance(other, GeoFeature): other = [other] return FeatureCollection([feat for feat in chain(self, other)])