def test_sinusoidal_comparison(self): a = geometry.CRS("""PROJCS["unnamed", GEOGCS["Unknown datum based upon the custom spheroid", DATUM["Not specified (based on custom spheroid)", SPHEROID["Custom spheroid",6371007.181,0]], PRIMEM["Greenwich",0],UNIT["degree",0.0174532925199433]],PROJECTION["Sinusoidal"], PARAMETER["longitude_of_center",0],PARAMETER["false_easting",0], PARAMETER["false_northing",0],UNIT["Meter",1]]""") b = geometry.CRS("""PROJCS["unnamed",GEOGCS["unnamed ellipse", DATUM["unknown",SPHEROID["unnamed",6371007.181,0]], PRIMEM["Greenwich",0],UNIT["degree",0.0174532925199433]],PROJECTION["Sinusoidal"], PARAMETER["longitude_of_center",0],PARAMETER["false_easting",0], PARAMETER["false_northing",0],UNIT["Meter",1]]""") c = geometry.CRS( '+a=6371007.181 +b=6371007.181 +units=m +y_0=0 +proj=sinu +lon_0=0 +no_defs +x_0=0' ) assert a == b assert a == c assert b == c assert a != epsg4326
def crs(self): """ :rtype: geometry.CRS """ projection = self.metadata.grid_spatial crs = projection.get('spatial_reference', None) if crs: return geometry.CRS(str(crs)) # TODO: really need CRS specified properly in agdc-metadata.yaml if projection['datum'] == 'GDA94': return geometry.CRS('EPSG:283' + str(abs(projection['zone']))) if projection['datum'] == 'WGS84': if projection['zone'][-1] == 'S': return geometry.CRS('EPSG:327' + str(abs(int(projection['zone'][:-1])))) else: return geometry.CRS('EPSG:326' + str(abs(int(projection['zone'][:-1])))) raise RuntimeError('Cant figure out the projection: %s %s' % (projection['datum'], projection['zone']))
def _write_geographical_extents_attributes(nco, extent): geo_extents = extent.to_crs(geometry.CRS("EPSG:4326")) nco.geospatial_bounds = geo_extents.wkt nco.geospatial_bounds_crs = "EPSG:4326" geo_bounds = geo_extents.boundingbox nco.geospatial_lat_min = geo_bounds.bottom nco.geospatial_lat_max = geo_bounds.top nco.geospatial_lat_units = "degrees_north" nco.geospatial_lon_min = geo_bounds.left nco.geospatial_lon_max = geo_bounds.right nco.geospatial_lon_units = "degrees_east"
def test_props(): box1 = geometry.box(10, 10, 30, 30, crs=geometry.CRS('EPSG:4326')) assert box1 assert box1.is_valid assert not box1.is_empty assert box1.area == 400.0 assert box1.boundary.length == 80.0 assert box1.centroid == geometry.point(20, 20, geometry.CRS('EPSG:4326')) triangle = geometry.polygon([(10, 20), (20, 20), (20, 10), (10, 20)], crs=geometry.CRS('EPSG:4326')) assert triangle.envelope == geometry.BoundingBox(10, 10, 20, 20) outer = next(iter(box1)) assert outer.length == 80.0 box1copy = geometry.box(10, 10, 30, 30, crs=geometry.CRS('EPSG:4326')) assert box1 == box1copy assert box1.convex_hull == box1copy # NOTE: this might fail because of point order box2 = geometry.box(20, 10, 40, 30, crs=geometry.CRS('EPSG:4326')) assert box1 != box2
def check_open_with_api(driver_manager, time_slices): from datacube import Datacube dc = Datacube(driver_manager=driver_manager) input_type_name = 'ls5_nbar_albers' input_type = dc.index.products.get_by_name(input_type_name) geobox = geometry.GeoBox(200, 200, Affine(25, 0.0, 638000, 0.0, -25, 6276000), geometry.CRS('EPSG:28355')) observations = dc.find_datasets(product='ls5_nbar_albers', geopolygon=geobox.extent) group_by = query_group_by('time') sources = dc.group_datasets(observations, group_by) data = dc.load_data(sources, geobox, input_type.measurements.values(), driver_manager=driver_manager) assert data.blue.shape == (time_slices, 200, 200)
def open(self) -> Iterator[GeoRasterReader]: """Context manager which returns a :class:`BandDataSource`""" activate_from_config() # check if settings changed and apply new lock = self._lock locked = False if lock is None else lock.acquire(blocking=True) try: _LOG.debug("opening %s", self.filename) with rasterio.open(self.filename, sharing=False) as src: override = False transform = src.transform if transform.is_identity: override = True transform = self.get_transform(src.shape) try: crs = geometry.CRS(_rasterio_crs_wkt(src)) except ValueError: override = True crs = self.get_crs() # The [1.0a1-1.0a8] releases of rasterio had a bug that means it # cannot read multiband data into a numpy array during reprojection # We override it here to force the reading and reprojection into separate steps # TODO: Remove when we no longer care about those versions of rasterio bandnumber = self.get_bandnumber(src) band = rasterio.band(src, bandnumber) nodata = src.nodatavals[band.bidx - 1] if src.nodatavals[ band.bidx - 1] is not None else self.nodata nodata = num2numpy(nodata, band.dtype) if locked: locked = False lock.release() if override: yield OverrideBandDataSource(band, nodata=nodata, crs=crs, transform=transform, lock=lock) else: yield BandDataSource(band, nodata=nodata, lock=lock) except Exception as e: _LOG.error("Error opening source dataset: %s", self.filename) raise e finally: if locked: lock.release()
def test_unary_intersection(): box1 = geometry.box(10, 10, 30, 30, crs=geometry.CRS('EPSG:4326')) box2 = geometry.box(15, 10, 35, 30, crs=geometry.CRS('EPSG:4326')) box3 = geometry.box(20, 10, 40, 30, crs=geometry.CRS('EPSG:4326')) box4 = geometry.box(25, 10, 45, 30, crs=geometry.CRS('EPSG:4326')) box5 = geometry.box(30, 10, 50, 30, crs=geometry.CRS('EPSG:4326')) box6 = geometry.box(35, 10, 55, 30, crs=geometry.CRS('EPSG:4326')) inter1 = geometry.unary_intersection([box1]) assert bool(inter1) assert inter1 == box1 inter2 = geometry.unary_intersection([box1, box2]) assert bool(inter2) assert inter2.area == 300.0 inter3 = geometry.unary_intersection([box1, box2, box3]) assert bool(inter3) assert inter3.area == 200.0 inter4 = geometry.unary_intersection([box1, box2, box3, box4]) assert bool(inter4) assert inter4.area == 100.0 inter5 = geometry.unary_intersection([box1, box2, box3, box4, box5]) assert bool(inter5) assert inter5.type == 'LineString' assert inter5.length == 20.0 inter6 = geometry.unary_intersection([box1, box2, box3, box4, box5, box6]) assert not bool(inter6) assert inter6.is_empty
def test_first_source_is_priority_in_reproject_and_fuse(): crs = geometry.CRS('EPSG:4326') shape = (2, 2) no_data = -1 source1 = FakeDatasetSource([[1, 1], [1, 1]], crs=crs, shape=shape) source2 = FakeDatasetSource([[2, 2], [2, 2]], crs=crs, shape=shape) sources = [source1, source2] output_data = np.full(shape, fill_value=no_data, dtype='int16') reproject_and_fuse(sources, output_data, dst_transform=identity, dst_projection=crs, dst_nodata=no_data) assert (output_data == 1).all()
def test_mixed_result_when_first_source_partially_empty_with_nan_nodata(): crs = geometry.CRS('EPSG:4326') shape = (2, 2) no_data = np.nan source1 = FakeDatasetSource([[1, 1], [no_data, no_data]], crs=crs) source2 = FakeDatasetSource([[2, 2], [2, 2]], crs=crs) sources = [source1, source2] output_data = np.full(shape, fill_value=no_data, dtype='float64') reproject_and_fuse(sources, output_data, dst_transform=identity, dst_projection=crs, dst_nodata=no_data) assert (output_data == [[1, 1], [2, 2]]).all()
def test_ops(): box1 = geometry.box(10, 10, 30, 30, crs=geometry.CRS('EPSG:4326')) box2 = geometry.box(20, 10, 40, 30, crs=geometry.CRS('EPSG:4326')) box4 = geometry.box(40, 10, 60, 30, crs=geometry.CRS('EPSG:4326')) union1 = box1.union(box2) assert union1.area == 600.0 inter1 = box1.intersection(box2) assert bool(inter1) assert inter1.area == 200.0 inter2 = box1.intersection(box4) assert not bool(inter2) assert inter2.is_empty # assert not inter2.is_valid TODO: what's going on here? diff1 = box1.difference(box2) assert diff1.area == 200.0 symdiff1 = box1.symmetric_difference(box2) assert symdiff1.area == 400.0
def main(): with fiona.open('line.shp') as shapes: crs = geometry.CRS(shapes.crs_wkt) first_geometry = next(shapes)['geometry'] line = geometry.Geometry(first_geometry, crs=crs) query = {'time': ('1990-01-01', '1991-01-01'), 'geopolygon': line} dc = datacube.Datacube(app='line-trans-recipe') data = dc.load(product='ls5_nbar_albers', measurements=['red'], **query) trans = transect(data, line, abs(data.affine.a)) trans.red.plot(x='distance', y='time')
def output_geobox(like=None, output_crs=None, resolution=None, align=None, grid_spec=None, load_hints=None, datasets=None, geopolygon=None, **query): """ Configure output geobox from user provided output specs. """ if like is not None: assert output_crs is None, "'like' and 'output_crs' are not supported together" assert resolution is None, "'like' and 'resolution' are not supported together" assert align is None, "'like' and 'align' are not supported together" if isinstance(like, GeoBox): return like return like.geobox if load_hints: if output_crs is None: output_crs = load_hints.get('output_crs', None) if resolution is None: resolution = load_hints.get('resolution', None) if align is None: align = load_hints.get('align', None) if output_crs is not None: if resolution is None: raise ValueError("Must specify 'resolution' when specifying 'output_crs'") crs = geometry.CRS(output_crs) elif grid_spec is not None: # specification from grid_spec crs = grid_spec.crs if resolution is None: resolution = grid_spec.resolution align = align or grid_spec.alignment else: raise ValueError("Product has no default CRS. Must specify 'output_crs' and 'resolution'") # Try figuring out bounds # 1. Explicitly defined with geopolygon # 2. Extracted from x=,y= # 3. Computed from dataset footprints # 4. fail with ValueError if geopolygon is None: geopolygon = query_geopolygon(**query) if geopolygon is None: if datasets is None: raise ValueError("Bounds are not specified") geopolygon = get_bounds(datasets, crs) return geometry.GeoBox.from_geopolygon(geopolygon, resolution, crs, align)
def test_gridworkflow_with_time_depth(): """Test GridWorkflow with time series. Also test `Tile` methods `split` and `split_by_time` """ fakecrs = geometry.CRS("EPSG:4326") grid = 100 # spatial frequency in crs units pixel = 10 # square pixel linear dimension in crs units # if cell(0,0) has lower left corner at grid origin, # and cell indices increase toward upper right, # then this will be cell(1,-2). gridspec = GridSpec(crs=fakecrs, tile_size=(grid, grid), resolution=(-pixel, pixel)) # e.g. product gridspec def make_fake_datasets(num_datasets): start_time = datetime.datetime(2001, 2, 15) delta = datetime.timedelta(days=16) for i in range(num_datasets): fakedataset = MagicMock() fakedataset.extent = geometry.box(left=grid, bottom=-grid, right=2 * grid, top=-2 * grid, crs=fakecrs) fakedataset.center_time = start_time + (delta * i) yield fakedataset fakeindex = PickableMock() fakeindex.datasets.get_field_names.return_value = [ "time" ] # permit query on time fakeindex.datasets.search_eager.return_value = list( make_fake_datasets(100)) # ------ test with time dimension ---- gw = GridWorkflow(fakeindex, gridspec) query = dict(product="fake_product_name") cells = gw.list_cells(**query) for cell_index, cell in cells.items(): # test Tile.split() for label, tile in cell.split("time"): assert tile.shape == (1, 10, 10) # test Tile.split_by_time() for year, year_cell in cell.split_by_time(freq="A"): for t in year_cell.sources.time.values: assert str(t)[:4] == year
def test_output_geobox_fail_paths(): from datacube.api.core import output_geobox gs_nores = GridSpec(crs=geometry.CRS('EPSG:4326'), tile_size=None, resolution=None) with pytest.raises(ValueError): output_geobox() with pytest.raises(ValueError): output_geobox(output_crs='EPSG:4326') # need resolution as well with pytest.raises(ValueError): output_geobox(grid_spec=gs_nores) # GridSpec with missing resolution
def _add_candidate(crs): if crs is None: return if isinstance(crs, str): try: crs_set.add(geometry.CRS(crs)) except geometry.CRSError: warnings.warn(f"Failed to parse CRS: {crs}") elif isinstance(crs, geometry.CRS): # support current bad behaviour of injecting CRS directly into # attributes in example notebooks crs_set.add(crs) else: warnings.warn(f"Ignoring crs attribute of type: {type(crs)}")
def test_read_data_from_outside_file_region(self, make_sample_netcdf, dst_transform): sample_nc, geobox, written_data = make_sample_netcdf source = RasterFileDataSource(sample_nc, 1) dest = np.zeros((200, 1000)) dst_nodata = -999 dst_projection = geometry.CRS('EPSG:3577') dst_resampling = Resampling.nearest # Read exactly the hunk of data that we wrote read_from_source(source, dest, dst_transform, dst_nodata, dst_projection, dst_resampling) assert np.all(dest == -999)
def solar_correct_data(data, dataset): # Apply solar angle correction to the data for a dataset. # See for example http://gsp.humboldt.edu/olm_2015/Courses/GSP_216_Online/lesson4-1/radiometric.html native_x = (dataset.bounds.right + dataset.bounds.left) / 2.0 native_y = (dataset.bounds.top + dataset.bounds.bottom) / 2.0 pt = geometry.point(native_x, native_y, dataset.crs) crs_geo = geometry.CRS("EPSG:4326") geo_pt = pt.to_crs(crs_geo) data_time = dataset.center_time.astimezone(utc) data_lon, data_lat = geo_pt.coords[0] csz = cosine_of_solar_zenith(data_lat, data_lon, data_time) return data / csz
def test_read_from_file_with_missing_crs(no_crs_gdal_path): """ We need to be able to read from data files even when GDAL can't automatically gather all the metdata. The :class:`RasterFileDataSource` is able to override the nodata, CRS and transform attributes if necessary. """ crs = geometry.CRS('EPSG:4326') nodata = -999 transform = Affine(0.01, 0.0, 111.975, 0.0, 0.01, -9.975) data_source = RasterFileDataSource(no_crs_gdal_path, bandnumber=1, nodata=nodata, crs=crs, transform=transform) with data_source.open() as src: dest1 = src.read() assert dest1.shape == (10, 10)
def crs(self) -> Optional[geometry.CRS]: """ Return CRS if available """ projection = self._gs if not projection: return None crs = projection.get('spatial_reference', None) if crs: return geometry.CRS(str(crs)) # Try to infer CRS zone_ = projection.get('zone') datum_ = projection.get('datum') if zone_ and datum_: warnings.warn("Using zone/datum to specify CRS is deprecated", category=DeprecationWarning) try: # TODO: really need CRS specified properly in agdc-metadata.yaml if datum_ == 'GDA94': return geometry.CRS('EPSG:283' + str(abs(zone_))) if datum_ == 'WGS84': if zone_[-1] == 'S': return geometry.CRS('EPSG:327' + str(abs(int(zone_[:-1])))) else: return geometry.CRS('EPSG:326' + str(abs(int(zone_[:-1])))) except geometry.CRSError: # We still return None, as they didn't specify a CRS explicitly... _LOG.warning( "Can't figure out projection: possibly invalid zone (%r) for datum (%r).", zone_, datum_) return None
def tz_for_geometry(geom): crs_geo = geometry.CRS("EPSG:4326") geo_geom = geom.to_crs(crs_geo) centroid = geo_geom.centroid try: return tz_for_coord(centroid.coords[0][0], centroid.coords[0][1]) except NoTimezoneException: pass for pt in geo_geom.boundary.coords: try: return tz_for_coord(pt[0], pt[1]) except NoTimezoneException: pass offset = round(centroid.coords[0][0] / 15.0) return datetime.timezone(datetime.timedelta(hours=offset))
def test_unary_union(): box1 = geometry.box(10, 10, 30, 30, crs=geometry.CRS('EPSG:4326')) box2 = geometry.box(20, 10, 40, 30, crs=geometry.CRS('EPSG:4326')) box3 = geometry.box(30, 10, 50, 30, crs=geometry.CRS('EPSG:4326')) box4 = geometry.box(40, 10, 60, 30, crs=geometry.CRS('EPSG:4326')) union0 = geometry.unary_union([box1]) assert union0 == box1 union1 = geometry.unary_union([box1, box4]) assert union1.type == 'MultiPolygon' assert union1.area == 2.0 * box1.area union2 = geometry.unary_union([box1, box2]) assert union2.type == 'Polygon' assert union2.area == 1.5 * box1.area union3 = geometry.unary_union([box1, box2, box3, box4]) assert union3.type == 'Polygon' assert union3.area == 2.5 * box1.area union4 = geometry.unary_union([union1, box2, box3]) assert union4.type == 'Polygon' assert union4.area == 2.5 * box1.area
def _classify(data): """ performs WOFS classification on an xarray :param xarray data: An xarray of a single granule including bands: blue, green, red, nir, swir1, swir2 :return: xarray water """ logging.info('Classifying dataset') water = classifier.classify(data).to_dataset(dim="water") logging.info('Classification complete') logging.debug(water) water.attrs['crs'] = geometry.CRS(data.attrs['crs']) logging.debug('Set CRS to: %s', data.attrs['crs']) return water
def main(): shape_file = 'my_shape_file.shp' with fiona.open(shape_file) as shapes: crs = geometry.CRS(shapes.crs_wkt) first_geometry = next(iter(shapes))['geometry'] geom = geometry.Geometry(first_geometry, crs=crs) query = {'time': ('1990-01-01', '1991-01-01'), 'geopolygon': geom} dc = datacube.Datacube(app='poly-drill-recipe') data = dc.load(product='ls5_nbar_albers', measurements=['red'], **query) mask = geometry_mask([geom], data.geobox, invert=True) data = data.where(mask) data.red.plot.imshow(col='time', col_wrap=5)
def check_open_with_api(index): from datacube import Datacube dc = Datacube(index=index) input_type_name = 'ls5_nbar_albers' input_type = dc.index.products.get_by_name(input_type_name) geobox = geometry.GeoBox(200, 200, Affine(25, 0.0, 1500000, 0.0, -25, -3900000), geometry.CRS('EPSG:3577')) observations = dc.find_datasets(product='ls5_nbar_albers', geopolygon=geobox.extent) group_by = query_group_by('time') sources = dc.group_datasets(observations, group_by) data = dc.load_data(sources, geobox, input_type.measurements.values()) assert data.blue.shape == (1, 200, 200)
def output_geobox(like=None, output_crs=None, resolution=None, align=None, grid_spec=None, datasets=None, geopolygon=None, **query): """ Configure output geobox from user provided output specs. """ if like is not None: assert output_crs is None, "'like' and 'output_crs' are not supported together" assert resolution is None, "'like' and 'resolution' are not supported together" assert align is None, "'like' and 'align' are not supported together" if isinstance(like, GeoBox): return like return like.geobox if output_crs is not None: # user provided specifications if resolution is None: raise ValueError( "Must specify 'resolution' when specifying 'output_crs'") crs = geometry.CRS(output_crs) else: # specification from grid_spec if grid_spec is None or grid_spec.crs is None: raise ValueError( "Product has no default CRS. Must specify 'output_crs' and 'resolution'" ) crs = grid_spec.crs if resolution is None: if grid_spec.resolution is None: raise ValueError( "Product has no default resolution. Must specify 'resolution'" ) resolution = grid_spec.resolution align = align or grid_spec.alignment if geopolygon is None: geopolygon = query_geopolygon(**query) if geopolygon is None: geopolygon = get_bounds(datasets, crs) return geometry.GeoBox.from_geopolygon(geopolygon, resolution, crs, align)
def test_wrap_dateline_sinusoidal(pts): sinus_crs = geometry.CRS("""PROJCS["unnamed", GEOGCS["Unknown datum based upon the custom spheroid", DATUM["Not specified (based on custom spheroid)", SPHEROID["Custom spheroid",6371007.181,0]], PRIMEM["Greenwich",0],UNIT["degree",0.0174532925199433]], PROJECTION["Sinusoidal"], PARAMETER["longitude_of_center",0], PARAMETER["false_easting",0], PARAMETER["false_northing",0], UNIT["Meter",1]]""") wrap = geometry.polygon(pts, crs=sinus_crs) wrapped = wrap.to_crs(epsg4326) assert wrapped.type == 'Polygon' wrapped = wrap.to_crs(epsg4326, wrapdateline=True) assert wrapped.type == 'MultiPolygon' assert not wrapped.intersects(geometry.line([(0, -90), (0, 90)], crs=epsg4326))
def test_geobox(): points_list = [ [(148.2697, -35.20111), (149.31254, -35.20111), (149.31254, -36.331431), (148.2697, -36.331431)], [(148.2697, 35.20111), (149.31254, 35.20111), (149.31254, 36.331431), (148.2697, 36.331431)], [(-148.2697, 35.20111), (-149.31254, 35.20111), (-149.31254, 36.331431), (-148.2697, 36.331431)], [(-148.2697, -35.20111), (-149.31254, -35.20111), (-149.31254, -36.331431), (-148.2697, -36.331431), (148.2697, -35.20111)], ] for points in points_list: polygon = geometry.polygon(points, crs=geometry.CRS('EPSG:3577')) resolution = (-25, 25) geobox = geometry.GeoBox.from_geopolygon(polygon, resolution) assert abs(resolution[0]) > abs(geobox.extent.boundingbox.left - polygon.boundingbox.left) assert abs(resolution[0]) > abs(geobox.extent.boundingbox.right - polygon.boundingbox.right) assert abs(resolution[1]) > abs(geobox.extent.boundingbox.top - polygon.boundingbox.top) assert abs(resolution[1]) > abs(geobox.extent.boundingbox.bottom - polygon.boundingbox.bottom)
def test_australian_albers_comparison(self): a = geometry.CRS("""PROJCS["GDA94_Australian_Albers",GEOGCS["GCS_GDA_1994", DATUM["Geocentric_Datum_of_Australia_1994",SPHEROID["GRS_1980",6378137,298.257222101]], PRIMEM["Greenwich",0],UNIT["Degree",0.017453292519943295]], PROJECTION["Albers_Conic_Equal_Area"], PARAMETER["standard_parallel_1",-18], PARAMETER["standard_parallel_2",-36], PARAMETER["latitude_of_center",0], PARAMETER["longitude_of_center",132], PARAMETER["false_easting",0], PARAMETER["false_northing",0], UNIT["Meter",1]]""") b = epsg3577 assert a == b assert a != epsg4326
def test_geobox_simple(): from affine import Affine t = geometry.GeoBox(4000, 4000, Affine(0.00025, 0.0, 151.0, 0.0, -0.00025, -29.0), geometry.CRS('EPSG:4326')) expect_lon = np.asarray([151.000125, 151.000375, 151.000625, 151.000875, 151.001125, 151.001375, 151.001625, 151.001875, 151.002125, 151.002375]) expect_lat = np.asarray([-29.000125, -29.000375, -29.000625, -29.000875, -29.001125, -29.001375, -29.001625, -29.001875, -29.002125, -29.002375]) expect_resolution = np.asarray([-0.00025, 0.00025]) assert (np.abs(np.r_[t.resolution] - expect_resolution) < 1e-6).all() assert t.coordinates['latitude'].values.shape == (4000,) assert t.coordinates['longitude'].values.shape == (4000,) assert (np.abs(t.coords['latitude'].values[:10] - expect_lat) < 1e-6).all() assert (np.abs(t.coords['longitude'].values[:10] - expect_lon) < 1e-6).all()
def make_long_SHP_query(shape_file): with fiona.open(shape_file) as shapes: crs = geometry.CRS(shapes.crs_wkt) first_geometry = next(iter(shapes))['geometry'] geom = geometry.Geometry(first_geometry, crs=crs) dc = datacube.Datacube() query = { 'time': ('2013-01-01', '2118-12-31'), 'geopolygon': geom, 'output_crs': 'EPSG:3577', 'resampling': 'bilinear', 'group_by': 'solar_day', } return dc, query, geom