class TileManager: """ A manager objects that reads OWM map layers tile images . :param API_key: the OWM Weather API key :type API_key: str :param map_layer: the layer for which you want tiles fetched. Allowed map layers are specified by the `pyowm.tiles.enum.MapLayerEnum` enumerator class. :type map_layer: str :param config: the configuration dictionary :type config: dict :returns: a *TileManager* instance :raises: *AssertionError* when no API Key or no map layer is provided, or map layer name is not a string """ def __init__(self, API_key, map_layer, config): assert API_key is not None, 'You must provide a valid API Key' self.API_key = API_key assert map_layer is not None, 'You must provide a valid map layer name' assert isinstance(map_layer, str), 'Map layer name must be a string' self.map_layer = map_layer assert isinstance(config, dict) self.http_client = HttpClient(API_key, config, ROOT_TILE_URL, admits_subdomains=False) def get_tile(self, x, y, zoom): """ Retrieves the tile having the specified coordinates and zoom level :param x: horizontal tile number in OWM tile reference system :type x: int :param y: vertical tile number in OWM tile reference system :type y: int :param zoom: zoom level for the tile :type zoom: int :returns: a `pyowm.tiles.Tile` instance """ status, data = self.http_client.get_png( NAMED_MAP_LAYER_URL % self.map_layer + '/%s/%s/%s.png' % (zoom, x, y), params={'appid': self.API_key}) img = Image(data, ImageTypeEnum.PNG) return Tile(x, y, zoom, self.map_layer, img) def __repr__(self): return "<%s.%s - layer_name=%s>" % (__name__, self.__class__.__name__, self.map_layer)
class TileManager(object): """ A manager objects that reads OWM map layers tile images . :param API_key: the OWM Weather API key :type API_key: str :param map_layer: the layer for which you want tiles fetched. Allowed map layers are specified by the `pyowm.tiles.enum.MapLayerEnum` enumerator class. :type map_layer: str :returns: a *TileManager* instance :raises: *AssertionError* when no API Key or no map layer is provided, or map layer name is not a string """ def __init__(self, API_key, map_layer): assert API_key is not None, 'You must provide a valid API Key' self.API_key = API_key assert map_layer is not None, 'You must provide a valid map layer name' assert isinstance(map_layer, str), 'Map layer name must be a string' self.map_layer = map_layer self.http_client = HttpClient() def get_tile(self, x, y, zoom): """ Retrieves the tile having the specified coordinates and zoom level :param x: horizontal tile number in OWM tile reference system :type x: int :param y: vertical tile number in OWM tile reference system :type y: int :param zoom: zoom level for the tile :type zoom: int :returns: a `pyowm.tiles.Tile` instance """ status, data = self.http_client.get_png( ROOT_TILE_URL % self.map_layer + '/%s/%s/%s.png' % (zoom, x, y), params={'appid': self.API_key}) img = Image(data, ImageTypeEnum.PNG) return Tile(x, y, zoom, self.map_layer, img) def __repr__(self): return "<%s.%s - layer name=%s>" % (__name__, self.__class__.__name__, self.map_layer)
class AgroManager: """ A manager objects that provides a full interface to OWM Agro API. :param API_key: the OWM Weather API key :type API_key: str :param config: the configuration dictionary :type config: dict :returns: an `AgroManager` instance :raises: `AssertionError` when no API Key is provided """ def __init__(self, API_key, config): assert isinstance(API_key, str), 'You must provide a valid API Key' self.API_key = API_key assert isinstance(config, dict) self.http_client = HttpClient(API_key, config, ROOT_AGRO_API) self.geotiff_downloader_http_client = HttpClient( self.API_key, config, ROOT_DOWNLOAD_GEOTIFF_API) self.png_downloader_http_client = HttpClient(self.API_key, config, ROOT_DOWNLOAD_PNG_API) def agro_api_version(self): return AGRO_API_VERSION # POLYGON API subset methods def create_polygon(self, geopolygon, name=None): """ Create a new polygon on the Agro API with the given parameters :param geopolygon: the geopolygon representing the new polygon :type geopolygon: `pyowm.utils.geo.Polygon` instance :param name: optional mnemonic name for the new polygon :type name: str :return: a `pyowm.agro10.polygon.Polygon` instance """ assert geopolygon is not None assert isinstance(geopolygon, GeoPolygon) data = { 'geo_json': { "type": "Feature", "properties": {}, "geometry": geopolygon.to_dict(), } } if name is not None: data['name'] = name status, payload = self.http_client.post( POLYGONS_URI, params={'appid': self.API_key}, data=data, headers={'Content-Type': 'application/json'}) return Polygon.from_dict(payload) def get_polygons(self): """ Retrieves all of the user's polygons registered on the Agro API. :returns: list of `pyowm.agro10.polygon.Polygon` objects """ status, data = self.http_client.get_json( POLYGONS_URI, params={'appid': self.API_key}, headers={'Content-Type': 'application/json'}) return [Polygon.from_dict(item) for item in data] def get_polygon(self, polygon_id): """ Retrieves a named polygon registered on the Agro API. :param id: the ID of the polygon :type id: str :returns: a `pyowm.agro10.polygon.Polygon` object """ status, data = self.http_client.get_json( NAMED_POLYGON_URI % str(polygon_id), params={'appid': self.API_key}, headers={'Content-Type': 'application/json'}) return Polygon.from_dict(data) def update_polygon(self, polygon): """ Updates on the Agro API the Polygon identified by the ID of the provided polygon object. Currently this only changes the mnemonic name of the remote polygon :param polygon: the `pyowm.agro10.polygon.Polygon` object to be updated :type polygon: `pyowm.agro10.polygon.Polygon` instance :returns: `None` if update is successful, an exception otherwise """ assert polygon.id is not None status, _ = self.http_client.put( NAMED_POLYGON_URI % str(polygon.id), params={'appid': self.API_key}, data=dict(name=polygon.name), headers={'Content-Type': 'application/json'}) def delete_polygon(self, polygon): """ Deletes on the Agro API the Polygon identified by the ID of the provided polygon object. :param polygon: the `pyowm.agro10.polygon.Polygon` object to be deleted :type polygon: `pyowm.agro10.polygon.Polygon` instance :returns: `None` if deletion is successful, an exception otherwise """ assert polygon.id is not None status, _ = self.http_client.delete( NAMED_POLYGON_URI % str(polygon.id), params={'appid': self.API_key}, headers={'Content-Type': 'application/json'}) # SOIL API subset methods def soil_data(self, polygon): """ Retrieves the latest soil data on the specified polygon :param polygon: the reference polygon you want soil data for :type polygon: `pyowm.agro10.polygon.Polygon` instance :returns: a `pyowm.agro10.soil.Soil` instance """ assert polygon is not None assert isinstance(polygon, Polygon) polyd = polygon.id status, data = self.http_client.get_json( SOIL_URI, params={ 'appid': self.API_key, 'polyid': polyd }, headers={'Content-Type': 'application/json'}) the_dict = { 'reference_time': data['dt'], 'surface_temp': data['t0'], 'ten_cm_temp': data['t10'], 'moisture': data['moisture'], 'polygon_id': polyd, } return Soil.from_dict(the_dict) # Satellite Imagery subset methods def search_satellite_imagery(self, polygon_id, acquired_from, acquired_to, img_type=None, preset=None, min_resolution=None, max_resolution=None, acquired_by=None, min_cloud_coverage=None, max_cloud_coverage=None, min_valid_data_coverage=None, max_valid_data_coverage=None): """ Searches on the Agro API the metadata for all available satellite images that contain the specified polygon and acquired during the specified time interval; and optionally matching the specified set of filters: - image type (eg. GeoTIF) - image preset (eg. false color, NDVI, ...) - min/max acquisition resolution - acquiring satellite - min/max cloud coverage on acquired scene - min/max valid data coverage on acquired scene :param polygon_id: the ID of the reference polygon :type polygon_id: str :param acquired_from: lower edge of acquisition interval, UNIX timestamp :type acquired_from: int :param acquired_to: upper edge of acquisition interval, UNIX timestamp :type acquired_to: int :param img_type: the desired file format type of the images. Allowed values are given by `pyowm.commons.enums.ImageTypeEnum` :type img_type: `pyowm.commons.databoxes.ImageType` :param preset: the desired preset of the images. Allowed values are given by `pyowm.agroapi10.enums.PresetEnum` :type preset: str :param min_resolution: minimum resolution for images, px/meters :type min_resolution: int :param max_resolution: maximum resolution for images, px/meters :type max_resolution: int :param acquired_by: short symbol of the satellite that acquired the image (eg. "l8") :type acquired_by: str :param min_cloud_coverage: minimum cloud coverage percentage on acquired images :type min_cloud_coverage: int :param max_cloud_coverage: maximum cloud coverage percentage on acquired images :type max_cloud_coverage: int :param min_valid_data_coverage: minimum valid data coverage percentage on acquired images :type min_valid_data_coverage: int :param max_valid_data_coverage: maximum valid data coverage percentage on acquired images :type max_valid_data_coverage: int :return: a list of `pyowm.agro10.imagery.MetaImage` subtypes instances """ assert polygon_id is not None assert acquired_from is not None assert acquired_to is not None assert acquired_from <= acquired_to, 'Start timestamp of acquisition window must come before its end' if min_resolution is not None: assert min_resolution > 0, 'Minimum resolution must be positive' if max_resolution is not None: assert max_resolution > 0, 'Maximum resolution must be positive' if min_resolution is not None and max_resolution is not None: assert min_resolution <= max_resolution, 'Mininum resolution must be lower than maximum resolution' if min_cloud_coverage is not None: assert min_cloud_coverage >= 0, 'Minimum cloud coverage must be non negative' if max_cloud_coverage is not None: assert max_cloud_coverage >= 0, 'Maximum cloud coverage must be non negative' if min_cloud_coverage is not None and max_cloud_coverage is not None: assert min_cloud_coverage <= max_cloud_coverage, 'Minimum cloud coverage must be lower than maximum cloud coverage' if min_valid_data_coverage is not None: assert min_valid_data_coverage >= 0, 'Minimum valid data coverage must be non negative' if max_valid_data_coverage is not None: assert max_valid_data_coverage >= 0, 'Maximum valid data coverage must be non negative' if min_valid_data_coverage is not None and max_valid_data_coverage is not None: assert min_valid_data_coverage <= max_valid_data_coverage, 'Minimum valid data coverage must be lower than maximum valid data coverage' # prepare params params = dict(appid=self.API_key, polyid=polygon_id, start=acquired_from, end=acquired_to) if min_resolution is not None: params['resolution_min'] = min_resolution if max_resolution is not None: params['resolution_max'] = max_resolution if acquired_by is not None: params['type'] = acquired_by if min_cloud_coverage is not None: params['clouds_min'] = min_cloud_coverage if max_cloud_coverage is not None: params['clouds_max'] = max_cloud_coverage if min_valid_data_coverage is not None: params['coverage_min'] = min_valid_data_coverage if max_valid_data_coverage is not None: params['coverage_max'] = max_valid_data_coverage # call API status, data = self.http_client.get_json(SATELLITE_IMAGERY_SEARCH_URI, params=params) result_set = SatelliteImagerySearchResultSet( polygon_id, data, timestamps.now(timeformat='unix')) # further filter by img_type and/or preset (if specified) if img_type is not None and preset is not None: return result_set.with_img_type_and_preset(img_type, preset) elif img_type is not None: return result_set.with_img_type(img_type) elif preset is not None: return result_set.with_preset(preset) else: return result_set.all() def download_satellite_image(self, metaimage, x=None, y=None, zoom=None, palette=None): """ Downloads the satellite image described by the provided metadata. In case the satellite image is a tile, then tile coordinates and zoom must be provided. An optional palette ID can be provided, if supported by the downloaded preset (currently only NDVI is supported) :param metaimage: the satellite image's metadata, in the form of a `MetaImage` subtype instance :type metaimage: a `pyowm.agroapi10.imagery.MetaImage` subtype :param x: x tile coordinate (only needed in case you are downloading a tile image) :type x: int or `None` :param y: y tile coordinate (only needed in case you are downloading a tile image) :type y: int or `None` :param zoom: zoom level (only needed in case you are downloading a tile image) :type zoom: int or `None` :param palette: ID of the color palette of the downloaded images. Values are provided by `pyowm.agroapi10.enums.PaletteEnum` :type palette: str or `None` :return: a `pyowm.agroapi10.imagery.SatelliteImage` instance containing both image's metadata and data """ if palette is not None: assert isinstance(palette, str) params = dict(paletteid=palette) else: palette = PaletteEnum.GREEN params = {} # polygon PNG if isinstance(metaimage, MetaPNGImage): prepared_url = metaimage.url status, data = self.png_downloader_http_client.get_png( prepared_url, params=params) img = Image(data, metaimage.image_type) return SatelliteImage( metaimage, img, downloaded_on=timestamps.now(timeformat='unix'), palette=palette) # GeoTIF elif isinstance(metaimage, MetaGeoTiffImage): prepared_url = metaimage.url status, data = self.geotiff_downloader_http_client.get_geotiff( prepared_url, params=params) img = Image(data, metaimage.image_type) return SatelliteImage( metaimage, img, downloaded_on=timestamps.now(timeformat='unix'), palette=palette) # tile PNG elif isinstance(metaimage, MetaTile): assert x is not None assert y is not None assert zoom is not None prepared_url = self._fill_url(metaimage.url, x, y, zoom) status, data = self.http_client.get_png(prepared_url, params=params) img = Image(data, metaimage.image_type) tile = Tile(x, y, zoom, None, img) return SatelliteImage( metaimage, tile, downloaded_on=timestamps.now(timeformat='unix'), palette=palette) else: raise ValueError("Cannot download: unsupported MetaImage subtype") def stats_for_satellite_image(self, metaimage): """ Retrieves statistics for the satellite image described by the provided metadata. This is currently only supported 'EVI' and 'NDVI' presets :param metaimage: the satellite image's metadata, in the form of a `MetaImage` subtype instance :type metaimage: a `pyowm.agroapi10.imagery.MetaImage` subtype :return: dict """ if metaimage.preset not in [PresetEnum.EVI, PresetEnum.NDVI]: raise ValueError("Unsupported image preset: should be EVI or NDVI") if metaimage.stats_url is None: raise ValueError("URL for image statistics is not defined") status, data = self.http_client.get_json(metaimage.stats_url, params={}) return data # Utilities def _fill_url(self, url_template, x, y, zoom): return url_template.replace('{x}', str(x)).replace('{y}', str(y)).replace( '{z}', str(zoom)) def __repr__(self): return '<%s.%s>' % (__name__, self.__class__.__name__)
class AgroManager(object): """ A manager objects that provides a full interface to OWM Agro API. :param API_key: the OWM Weather API key :type API_key: str :returns: an `AgroManager` instance :raises: `AssertionError` when no API Key is provided """ def __init__(self, API_key): assert API_key is not None, 'You must provide a valid API Key' self.API_key = API_key self.http_client = HttpClient() def agro_api_version(self): return AGRO_API_VERSION # POLYGON API subset methods def create_polygon(self, geopolygon, name=None): """ Create a new polygon on the Agro API with the given parameters :param geopolygon: the geopolygon representing the new polygon :type geopolygon: `pyowm.utils.geo.Polygon` instance :param name: optional mnemonic name for the new polygon :type name: str :return: a `pyowm.agro10.polygon.Polygon` instance """ assert geopolygon is not None assert isinstance(geopolygon, GeoPolygon) data = dict() data['geo_json'] = { "type": "Feature", "properties": {}, "geometry": geopolygon.as_dict() } if name is not None: data['name'] = name status, payload = self.http_client.post( POLYGONS_URI, params={'appid': self.API_key}, data=data, headers={'Content-Type': 'application/json'}) return Polygon.from_dict(payload) def get_polygons(self): """ Retrieves all of the user's polygons registered on the Agro API. :returns: list of `pyowm.agro10.polygon.Polygon` objects """ status, data = self.http_client.get_json( POLYGONS_URI, params={'appid': self.API_key}, headers={'Content-Type': 'application/json'}) return [Polygon.from_dict(item) for item in data] def get_polygon(self, polygon_id): """ Retrieves a named polygon registered on the Agro API. :param id: the ID of the polygon :type id: str :returns: a `pyowm.agro10.polygon.Polygon` object """ status, data = self.http_client.get_json( NAMED_POLYGON_URI % str(polygon_id), params={'appid': self.API_key}, headers={'Content-Type': 'application/json'}) return Polygon.from_dict(data) def update_polygon(self, polygon): """ Updates on the Agro API the Polygon identified by the ID of the provided polygon object. Currently this only changes the mnemonic name of the remote polygon :param polygon: the `pyowm.agro10.polygon.Polygon` object to be updated :type polygon: `pyowm.agro10.polygon.Polygon` instance :returns: `None` if update is successful, an exception otherwise """ assert polygon.id is not None status, _ = self.http_client.put( NAMED_POLYGON_URI % str(polygon.id), params={'appid': self.API_key}, data=dict(name=polygon.name), headers={'Content-Type': 'application/json'}) def delete_polygon(self, polygon): """ Deletes on the Agro API the Polygon identified by the ID of the provided polygon object. :param polygon: the `pyowm.agro10.polygon.Polygon` object to be deleted :type polygon: `pyowm.agro10.polygon.Polygon` instance :returns: `None` if deletion is successful, an exception otherwise """ assert polygon.id is not None status, _ = self.http_client.delete( NAMED_POLYGON_URI % str(polygon.id), params={'appid': self.API_key}, headers={'Content-Type': 'application/json'}) # SOIL API subset methods def soil_data(self, polygon): """ Retrieves the latest soil data on the specified polygon :param polygon: the reference polygon you want soil data for :type polygon: `pyowm.agro10.polygon.Polygon` instance :returns: a `pyowm.agro10.soil.Soil` instance """ assert polygon is not None assert isinstance(polygon, Polygon) polyd = polygon.id status, data = self.http_client.get_json( SOIL_URI, params={'appid': self.API_key, 'polyid': polyd}, headers={'Content-Type': 'application/json'}) the_dict = dict() the_dict['reference_time'] = data['dt'] the_dict['surface_temp'] = data['t0'] the_dict['ten_cm_temp'] = data['t10'] the_dict['moisture'] = data['moisture'] the_dict['polygon_id'] = polyd return Soil.from_dict(the_dict) # Satellite Imagery subset methods def search_satellite_imagery(self, polygon_id, acquired_from, acquired_to, img_type=None, preset=None, min_resolution=None, max_resolution=None, acquired_by=None, min_cloud_coverage=None, max_cloud_coverage=None, min_valid_data_coverage=None, max_valid_data_coverage=None): """ Searches on the Agro API the metadata for all available satellite images that contain the specified polygon and acquired during the specified time interval; and optionally matching the specified set of filters: - image type (eg. GeoTIF) - image preset (eg. false color, NDVI, ...) - min/max acquisition resolution - acquiring satellite - min/max cloud coverage on acquired scene - min/max valid data coverage on acquired scene :param polygon_id: the ID of the reference polygon :type polygon_id: str :param acquired_from: lower edge of acquisition interval, UNIX timestamp :type acquired_from: int :param acquired_to: upper edge of acquisition interval, UNIX timestamp :type acquired_to: int :param img_type: the desired file format type of the images. Allowed values are given by `pyowm.commons.enums.ImageTypeEnum` :type img_type: `pyowm.commons.databoxes.ImageType` :param preset: the desired preset of the images. Allowed values are given by `pyowm.agroapi10.enums.PresetEnum` :type preset: str :param min_resolution: minimum resolution for images, px/meters :type min_resolution: int :param max_resolution: maximum resolution for images, px/meters :type max_resolution: int :param acquired_by: short symbol of the satellite that acquired the image (eg. "l8") :type acquired_by: str :param min_cloud_coverage: minimum cloud coverage percentage on acquired images :type min_cloud_coverage: int :param max_cloud_coverage: maximum cloud coverage percentage on acquired images :type max_cloud_coverage: int :param min_valid_data_coverage: minimum valid data coverage percentage on acquired images :type min_valid_data_coverage: int :param max_valid_data_coverage: maximum valid data coverage percentage on acquired images :type max_valid_data_coverage: int :return: a list of `pyowm.agro10.imagery.MetaImage` subtypes instances """ assert polygon_id is not None assert acquired_from is not None assert acquired_to is not None assert acquired_from <= acquired_to, 'Start timestamp of acquisition window must come before its end' if min_resolution is not None: assert min_resolution > 0, 'Minimum resolution must be positive' if max_resolution is not None: assert max_resolution > 0, 'Maximum resolution must be positive' if min_resolution is not None and max_resolution is not None: assert min_resolution <= max_resolution, 'Mininum resolution must be lower than maximum resolution' if min_cloud_coverage is not None: assert min_cloud_coverage >= 0, 'Minimum cloud coverage must be non negative' if max_cloud_coverage is not None: assert max_cloud_coverage >= 0, 'Maximum cloud coverage must be non negative' if min_cloud_coverage is not None and max_cloud_coverage is not None: assert min_cloud_coverage <= max_cloud_coverage, 'Minimum cloud coverage must be lower than maximum cloud coverage' if min_valid_data_coverage is not None: assert min_valid_data_coverage >= 0, 'Minimum valid data coverage must be non negative' if max_valid_data_coverage is not None: assert max_valid_data_coverage >= 0, 'Maximum valid data coverage must be non negative' if min_valid_data_coverage is not None and max_valid_data_coverage is not None: assert min_valid_data_coverage <= max_valid_data_coverage, 'Minimum valid data coverage must be lower than maximum valid data coverage' # prepare params params = dict(appid=self.API_key, polyid=polygon_id, start=acquired_from, end=acquired_to) if min_resolution is not None: params['resolution_min'] = min_resolution if max_resolution is not None: params['resolution_max'] = max_resolution if acquired_by is not None: params['type'] = acquired_by if min_cloud_coverage is not None: params['clouds_min'] = min_cloud_coverage if max_cloud_coverage is not None: params['clouds_max'] = max_cloud_coverage if min_valid_data_coverage is not None: params['coverage_min'] = min_valid_data_coverage if max_valid_data_coverage is not None: params['coverage_max'] = max_valid_data_coverage # call API status, data = self.http_client.get_json(SATELLITE_IMAGERY_SEARCH_URI, params=params) result_set = SatelliteImagerySearchResultSet(polygon_id, data, timeutils.now(timeformat='unix')) # further filter by img_type and/or preset (if specified) if img_type is not None and preset is not None: return result_set.with_img_type_and_preset(img_type, preset) elif img_type is not None: return result_set.with_img_type(img_type) elif preset is not None: return result_set.with_preset(preset) else: return result_set.all() def download_satellite_image(self, metaimage, x=None, y=None, zoom=None, palette=None): """ Downloads the satellite image described by the provided metadata. In case the satellite image is a tile, then tile coordinates and zoom must be provided. An optional palette ID can be provided, if supported by the downloaded preset (currently only NDVI is supported) :param metaimage: the satellite image's metadata, in the form of a `MetaImage` subtype instance :type metaimage: a `pyowm.agroapi10.imagery.MetaImage` subtype :param x: x tile coordinate (only needed in case you are downloading a tile image) :type x: int or `None` :param y: y tile coordinate (only needed in case you are downloading a tile image) :type y: int or `None` :param zoom: zoom level (only needed in case you are downloading a tile image) :type zoom: int or `None` :param palette: ID of the color palette of the downloaded images. Values are provided by `pyowm.agroapi10.enums.PaletteEnum` :type palette: str or `None` :return: a `pyowm.agroapi10.imagery.SatelliteImage` instance containing both image's metadata and data """ if palette is not None: assert isinstance(palette, str) params = dict(paletteid=palette) else: palette = PaletteEnum.GREEN params = dict() # polygon PNG if isinstance(metaimage, MetaPNGImage): prepared_url = metaimage.url status, data = self.http_client.get_png( prepared_url, params=params) img = Image(data, metaimage.image_type) return SatelliteImage(metaimage, img, downloaded_on=timeutils.now(timeformat='unix'), palette=palette) # GeoTIF elif isinstance(metaimage, MetaGeoTiffImage): prepared_url = metaimage.url status, data = self.http_client.get_geotiff( prepared_url, params=params) img = Image(data, metaimage.image_type) return SatelliteImage(metaimage, img, downloaded_on=timeutils.now(timeformat='unix'), palette=palette) # tile PNG elif isinstance(metaimage, MetaTile): assert x is not None assert y is not None assert zoom is not None prepared_url = self._fill_url(metaimage.url, x, y, zoom) status, data = self.http_client.get_png( prepared_url, params=params) img = Image(data, metaimage.image_type) tile = Tile(x, y, zoom, None, img) return SatelliteImage(metaimage, tile, downloaded_on=timeutils.now(timeformat='unix'), palette=palette) else: raise ValueError("Cannot download: unsupported MetaImage subtype") def stats_for_satellite_image(self, metaimage): """ Retrieves statistics for the satellite image described by the provided metadata. This is currently only supported 'EVI' and 'NDVI' presets :param metaimage: the satellite image's metadata, in the form of a `MetaImage` subtype instance :type metaimage: a `pyowm.agroapi10.imagery.MetaImage` subtype :return: dict """ if metaimage.preset != PresetEnum.EVI and metaimage.preset != PresetEnum.NDVI: raise ValueError("Unsupported image preset: should be EVI or NDVI") if metaimage.stats_url is None: raise ValueError("URL for image statistics is not defined") status, data = self.http_client.get_json(metaimage.stats_url, params={}) return data # Utilities def _fill_url(self, url_template, x, y, zoom): return url_template.replace('{x}', str(x)).replace('{y}', str(y)).replace('{z}', str(zoom)) def __repr__(self): return '<%s.%s>' % (__name__, self.__class__.__name__)