def serialize(self, value, jsonapi_format=False): return shapely_to_geojson(value)
def paged_search(self, products=None, sat_ids=None, date="acquired", place=None, geom=None, start_datetime=None, end_datetime=None, cloud_fraction=None, cloud_fraction_0=None, fill_fraction=None, storage_state=None, q=None, limit=100, fields=None, dltile=None, sort_field=None, sort_order="asc", randomize=None, continuation_token=None, **kwargs): """ Execute a metadata query in a paged manner, with up to 10,000 items per page. Most clients should use :py:func:`features` instead, which batch searches into smaller requests and handles the paging for you. :param list(str) products: Product Identifier(s). :param list(str) sat_ids: Satellite identifier(s). :param str date: The date field to use for search (default is `acquired`). :param str place: A slug identifier to be used as a region of interest. :param str geom: A GeoJSON or WKT region of interest or a Shapely shape object. :param str start_datetime: Desired starting timestamp, in any common format. :param str end_datetime: Desired ending timestamp, in any common format. :param float cloud_fraction: Maximum cloud fraction, calculated by data provider. :param float cloud_fraction_0: Maximum cloud fraction, calculated by cloud mask pixels. :param float fill_fraction: Minimum scene fill fraction, calculated as valid/total pixels. :param str storage_state: Filter results based on `storage_state` value. Allowed values are `"available"`, `"remote"`, or `None`, which returns all results regardless of `storage_state` value. :param ~descarteslabs.common.property_filtering.filtering.Expression q: Expression for filtering the results. See :py:attr:`~descarteslabs.client.services.metadata.properties`. :param int limit: Maximum number of items per page to return. :param list(str) fields: Properties to return. :param str dltile: A dltile key used to specify the search geometry, an alternative to the ``geom`` argument. :param str sort_field: Property to sort on. :param str sort_order: Order of sort. :param bool randomize: Randomize the results. You may also use an `int` or `str` as an explicit seed. :param str continuation_token: None for new query, or the `properties.continuation_token` value from the returned FeatureCollection from a previous invocation of this method to page through a large result set. :return: GeoJSON ``FeatureCollection`` containing at most `limit` features. :rtype: DotDict """ check_deprecated_kwargs( kwargs, { "product": "products", "const_id": "const_ids", "sat_id": "sat_ids", "start_time": "start_datetime", "end_time": "end_datetime", "offset": None, }, ) if place: places = Places() places.auth = self.auth shape = places.shape(place, geom="low") geom = json.dumps(shape["geometry"]) if dltile is not None: if isinstance(dltile, string_types): dltile = self._raster.dltile(dltile) if isinstance(dltile, dict): geom = dltile["geometry"] if isinstance(geom, dict): geom = json.dumps(geom) kwargs.update({"date": date, "limit": limit}) if sat_ids: if isinstance(sat_ids, string_types): sat_ids = [sat_ids] kwargs["sat_ids"] = sat_ids if products: if isinstance(products, string_types): products = [products] kwargs["products"] = products if geom: geom = shapely_to_geojson(geom) kwargs["geom"] = geom if start_datetime: kwargs["start_datetime"] = start_datetime if end_datetime: kwargs["end_datetime"] = end_datetime if cloud_fraction is not None: kwargs["cloud_fraction"] = cloud_fraction if cloud_fraction_0 is not None: kwargs["cloud_fraction_0"] = cloud_fraction_0 if fill_fraction is not None: kwargs["fill_fraction"] = fill_fraction if storage_state: kwargs["storage_state"] = storage_state if fields is not None: kwargs["fields"] = fields if q is not None: if not isinstance(q, list): q = [q] kwargs["query_expr"] = AndExpression(q).serialize() if sort_field is not None: kwargs["sort_field"] = sort_field if sort_order is not None: kwargs["sort_order"] = sort_order if randomize is not None: kwargs["random_seed"] = randomize if continuation_token is not None: kwargs["continuation_token"] = continuation_token r = self.session.post("/search", json=kwargs) fc = {"type": "FeatureCollection", "features": r.json()} if "x-continuation-token" in r.headers: fc["properties"] = { "continuation_token": r.headers["x-continuation-token"] } return DotDict(fc)
def summary(self, products=None, sat_ids=None, date="acquired", interval=None, place=None, geom=None, start_datetime=None, end_datetime=None, cloud_fraction=None, cloud_fraction_0=None, fill_fraction=None, storage_state=None, q=None, pixels=None, dltile=None, **kwargs): """Get a summary of the results for the specified spatio-temporal query. :param list(str) products: Product identifier(s). :param list(str) sat_ids: Satellite identifier(s). :param str date: The date field to use for search (e.g. `acquired`). :param str interval: Part of the date to aggregate over (e.g. `day`). The list of possibilites is: * ``year`` or ``y`` * ``quarter`` * ``month`` or ``M`` * ``week`` or ``q`` * ``day`` or ``d`` * ``hour`` or ``h`` * ``minute`` or ``m`` * ``product`` :param str place: A slug identifier to be used as a region of interest. :param str geom: A GeoJSON or WKT region of interest or a Shapely shape object. :param str start_datetime: Desired starting timestamp, in any common format. :param str end_datetime: Desired ending timestamp, in any common format. :param float cloud_fraction: Maximum cloud fraction, calculated by data provider. :param float cloud_fraction_0: Maximum cloud fraction, calculated by cloud mask pixels. :param float fill_fraction: Minimum scene fill fraction, calculated as valid/total pixels. :param str storage_state: Filter results based on `storage_state` value. Allowed values are `"available"`, `"remote"`, or `None`, which returns all results regardless of `storage_state` value. :param ~descarteslabs.common.property_filtering.filtering.Expression q: Expression for filtering the results. See :py:attr:`~descarteslabs.client.services.metadata.properties`. :param bool pixels: Whether to include pixel counts in summary calculations. :param str dltile: A dltile key used to specify the search geometry, an alternative to the ``geom`` argument. :return: Dictionary containing summary of products that match query. Empty products list if no matching products found. :rtype: DotDict Example:: >>> from descarteslabs.client.services import Metadata >>> iowa_geom = { ... "coordinates": [[ ... [-96.498997, 42.560832], ... [-95.765645, 40.585208], ... [-91.729115, 40.61364], ... [-91.391613, 40.384038], ... [-90.952233, 40.954047], ... [-91.04589, 41.414085], ... [-90.343228, 41.587833], ... [-90.140613, 41.995999], ... [-91.065059, 42.751338], ... [-91.217706, 43.50055], ... [-96.599191, 43.500456], ... [-96.498997, 42.560832] ... ]], ... "type": "Polygon" ... } >>> Metadata().summary(geom=iowa_geom, ... products=['landsat:LC08:PRE:TOAR'], ... start_datetime='2016-07-06', ... end_datetime='2016-07-07', ... interval='hour', ... pixels=True) { 'bytes': 93298309, 'count': 1, 'items': [ { 'bytes': 93298309, 'count': 1, 'date': '2016-07-06T16:00:00.000Z', 'pixels': 250508160, 'timestamp': 1467820800 } ], 'pixels': 250508160, 'products': ['landsat:LC08:PRE:TOAR'] } """ check_deprecated_kwargs( kwargs, { "product": "products", "const_id": "const_ids", "sat_id": "sat_ids", "start_time": "start_datetime", "end_time": "end_datetime", "part": "interval", }, ) if place: places = Places() places.auth = self.auth shape = places.shape(place, geom="low") geom = json.dumps(shape["geometry"]) if dltile is not None: if isinstance(dltile, string_types): dltile = self._raster.dltile(dltile) if isinstance(dltile, dict): geom = dltile["geometry"] if isinstance(geom, dict): geom = json.dumps(geom) if sat_ids: if isinstance(sat_ids, string_types): sat_ids = [sat_ids] kwargs["sat_ids"] = sat_ids if products: if isinstance(products, string_types): products = [products] kwargs["products"] = products if date: kwargs["date"] = date if interval: kwargs["interval"] = interval if geom: geom = shapely_to_geojson(geom) kwargs["geom"] = geom if start_datetime: kwargs["start_datetime"] = start_datetime if end_datetime: kwargs["end_datetime"] = end_datetime if cloud_fraction is not None: kwargs["cloud_fraction"] = cloud_fraction if cloud_fraction_0 is not None: kwargs["cloud_fraction_0"] = cloud_fraction_0 if fill_fraction is not None: kwargs["fill_fraction"] = fill_fraction if q is not None: if not isinstance(q, list): q = [q] kwargs["query_expr"] = AndExpression(q).serialize() if pixels: kwargs["pixels"] = pixels if storage_state: kwargs["storage_state"] = storage_state r = self.session.post("/summary", json=kwargs) return DotDict(r.json())
def dltiles_from_shape(self, resolution, tilesize, pad, shape): """ Return a feature collection of DLTile GeoJSONs that intersect a GeoJSON geometry ``shape`` or a Shapely shape object. :param float resolution: Resolution of DLTile :param int tilesize: Number of valid pixels per DLTile :param int pad: Number of ghost pixels per DLTile (overlap among tiles) :param str shape: A GeoJSON geometry specifying a shape over which to intersect DLTiles :return: GeoJSON FeatureCollection of intersecting DLTile geometries. :rtype: DotDict :raises descarteslabs.client.exceptions.BadRequestError: if the given parameters would generate too many tiles - use :meth:`Raster.iter_dltiles_from_shape` to iterate over more Example:: >>> from descarteslabs.client.services import Raster >>> iowa_geom = { ... "coordinates": [[ ... [-96.498997, 42.560832], ... [-95.765645, 40.585208], ... [-91.729115, 40.61364], ... [-91.391613, 40.384038], ... [-90.952233, 40.954047], ... [-91.04589, 41.414085], ... [-90.343228, 41.587833], ... [-90.140613, 41.995999], ... [-91.065059, 42.751338], ... [-91.217706, 43.50055], ... [-96.599191, 43.500456], ... [-96.498997, 42.560832] ... ]], ... "type": "Polygon" ... } >>> tiles = Raster().dltiles_from_shape(30.0, 2048, 16, iowa_geom) >>> tiles['features'][0] { 'geometry': { 'coordinates': [ [ [-96.81264975325402, 41.045203319986356], [-96.07101667769108, 41.02873098016475], [-96.04576296033223, 41.59007261142797], [-96.79377566762066, 41.6068715494603...], ... ] ], 'type': 'Polygon' }, 'properties': { 'cs_code': 'EPSG:32614', 'geotrans': [ 683840.0, 30.0, 0, 4608480.0, ... ], 'key': '2048:16:30.0:14:3:74', 'outputBounds': [683840.0, 4546080.0, 746240.0, 4608480.0], 'pad': 16, 'proj4': '+proj=utm +zone=14 +datum=WGS84 +units=m +no_defs ', 'resolution': 30.0, 'ti': 3, 'tilesize': 2048, 'tj': 74, 'wkt': 'PROJCS["WGS 84 / UTM zone 14N",GEOGCS["WGS...Northing",NORTH],AUTHORITY["EPSG","32614"]]', 'zone': 14 }, 'type': 'Feature' } """ shape = shapely_to_geojson(shape) return DotDict( type="FeatureCollection", features=list( self.iter_dltiles_from_shape(resolution, tilesize, pad, shape) ), )
def iter_dltiles_from_shape(self, resolution, tilesize, pad, shape, maxtiles=None): """ Iterates over all DLTiles as GeoJSONs features that intersect the GeoJSON geometry ``shape`` or Shapely shape object. :param float resolution: Resolution of DLTile :param int tilesize: Number of valid pixels per DLTile :param int pad: Number of ghost pixels per DLTile (overlap among tiles) :param str shape: A GeoJSON geometry or Shapely shape specifying a shape over which to intersect DLTiles. :return: An iterator over GeoJSON features representing intersecting DLTiles :rtype: generator(DotDict) Example:: >>> iowa_geom = { ... "coordinates": [[ ... [-96.498997, 42.560832], ... [-95.765645, 40.585208], ... [-91.729115, 40.61364], ... [-91.391613, 40.384038], ... [-90.952233, 40.954047], ... [-91.04589, 41.414085], ... [-90.343228, 41.587833], ... [-90.140613, 41.995999], ... [-91.065059, 42.751338], ... [-91.217706, 43.50055], ... [-96.599191, 43.500456], ... [-96.498997, 42.560832] ... ]], ... "type": "Polygon" ... } >>> next(Raster().iter_dltiles_from_shape(30.0, 2048, 16, iowa_geom)) { 'geometry': { 'coordinates': [ [ [-96.81264975325402, 41.045203319986356], [-96.07101667769108, 41.02873098016475], [-96.04576296033223, 41.59007261142797], [-96.79377566762066, 41.6068715494603...], ... ] ], 'type': 'Polygon' }, 'properties': { 'cs_code': 'EPSG:32614', 'geotrans': [ 683840.0, 30.0, 0, 4608480.0, ... ], 'key': '2048:16:30.0:14:3:74', 'outputBounds': [683840.0, 4546080.0, 746240.0, 4608480.0], 'pad': 16, 'proj4': '+proj=utm +zone=14 +datum=WGS84 +units=m +no_defs ', 'resolution': 30.0, 'ti': 3, 'tilesize': 2048, 'tj': 74, 'wkt': 'PROJCS["WGS 84 / UTM zone 14N",GEOGCS["WGS...Northing",NORTH],AUTHORITY["EPSG","32614"]]', 'zone': 14 }, 'type': 'Feature' } """ if maxtiles is not None: warnings.warn( "The maxtiles argument is deprecated and will be removed in a future " "release.", FutureWarning, ) shape = shapely_to_geojson(shape) shape = as_json_string(shape) params = { "resolution": resolution, "tilesize": tilesize, "pad": pad, "shape": shape, "maxtiles": 5000, } while True: r = self.session.post("/dlkeys/from_shape", json=params) fc = DotDict(r.json()) for t in fc.features: yield t iterstate = fc.get("iterstate", None) if iterstate: params["start_zone"] = iterstate.start_zone params["start_ti"] = iterstate.start_ti params["start_tj"] = iterstate.start_tj else: break
def test_serialize_geometry(self): i = Image(name="myimage", product_id="p1", geometry=self.geometry) assert shapely_to_geojson(i.geometry) == i.serialize()["geometry"]