Agro API examples¶
OWM provides an API for Agricultural monitoring that provides soil data, satellite imagery, etc.
The first thing you need to do to get started with it is to create a polygon and store it on the OWM Agro API. PyOWM will give you this new polygon’s ID and you will use it to invoke data queries upon that polygon.
Eg: you can look up satellite imagery, weather data, historical NDVI for that specific polygon.
Read further on to get more details.
OWM website technical reference¶
AgroAPI Manager object¶
In order to do any kind of operations against the OWM Agro API, you need to obtain a pyowm.agro10.agro_manager.AgroManager
instance from the main OWM. You’ll need your API Key for that:
import pyowm
owm = pyowm.OWM('your-API-key')
mgr = owm.agro_manager()
Read on to discover what you can do with it.
Polygon API operations¶
A polygon represents an area on a map upon which you can issue data queries. Each polygon has a unique ID, an optional name and links back to unique OWM ID of the User that owns that polygon. Each polygon has an area that is expressed in acres, but you can also get it in squared kilometers:
pol # this is a pyowm.agro10.polygon.Polygon instance
pol.id # ID
pol.area # in hacres
pol.area_km # in sq kilometers
pol.user_id # owner ID
Each polygon also carries along the pyowm.utils.geo.Polygon
object that represents the geographic polygon and the
pyowm.utils.geo.Point
object that represents the baricentre of the polygon:
geopol = pol.geopolygon # pyowm.utils.geo.Polygon object
point = pol.center # pyowm.utils.geo.Point object
Reading Polygons¶
You can either get all of the Polygons you’ve created on the Agro API or easily get single polygons by specifying their IDs:
list_of_polygons = mgr.get_polygons()
a_polygon = mgr.get_polygon('5abb9fb82c8897000bde3e87')
Creating Polygons¶
Creating polygons is easy: you just need to create a pyowm.utils.geo.Polygon
instance that describes the coordinates
of the polygon you want to create on the Agro API. Then you just need to pass it (along with an optional name) to the
Agro Manager object:
# first create the pyowm.utils.geo.Polygon instance that represents the area (here, a triangle)
from pyowm.utils.geo import Polygon as GeoPolygon
gp = GeoPolygon([[
[-121.1958, 37.6683],
[-121.1779, 37.6687],
[-121.1773, 37.6792],
[-121.1958, 37.6683]]])
# use the Agro Manager to create your polygon on the Agro API
the_new_polygon = mgr.create_polygon(gp, 'my new shiny polygon')
# the new polygon has an ID and a user_id
the_new_polygon.id
the_new_polygon.user_id
You get back a pyowm.agro10.polygon.Polygon
instance and you can use its ID to operate this new polygon on all the
other Agro API methods!
Updating a Polygon¶
Once you’ve created a polygon, you can only change its mnemonic name, as the rest of its parameters cannot be changed by the user. In order to do it:
my_polygon.name # "my new shiny polygon"
my_polygon.name = "changed name"
mgr.update_polygon(my_polygon)
Deleting a Polygon¶
Delete a polygon with
mgr.delete_polygon(my_polygon)
Remember that when you delete a polygon, there is no going back!
Soil data API Operations¶
Once you’ve defined a polygon, you can easily get soil data upon it. Just go with:
soil = mgr.soil_data(polygon)
Soil
is an entity of type pyowm.agro10.soil.Soil
and is basically a wrapper around a Python dict reporting
the basic soil information on that polygon:
soil.polygon_id # str
soil.reference_time(timeformat='unix') # can be: int for UTC Unix time ('unix'),
# ISO8601-formatted str for 'iso' or
# datetime.datetime for 'date'
soil.surface_temp(unit='kelvin') # float (unit can be: 'kelvin', 'celsius' or 'fahrenheit')
soil.ten_cm_temp(unit='kelvin') # float (Kelvins, measured at 10 cm depth) - unit same as for above
soil.moisture # float (m^3/m^3)
Soil data is updated twice a day.
Satellite Imagery API Operations¶
This is the real meat in Agro API: the possibility to obtain satellite imagery right upon your polygons!
Overview¶
Satellite Imagery comes in 3 formats:
- PNG images
- PNG tiles (variable zoom level)
- GeoTIFF images
Tiles can be retrieved by specifying a proper set of tile coordinates (x, y) and a zoom level: please refer to PyOWM’s Map Tiles client documentation for further insights.
When we say that imagery is upon a polygon we mean that the polygon is fully contained in the scene that was acquired by the satellite.
Each image comes with a preset: a preset tells how the acquired scene has been post-processed, eg: image has been put in false colors or image contains values of the Enhanced Vegetation Index (EVI) calculated on the scene
Imagery is provided by the Agro API for different satellites
Images that you retrieve from the Agro API are pyowm.agroapi10.imagery.SatelliteImage
instances, and they contain both
image’s data and metadata.
You can download NDVI images using several color palettes provided by the Agro API, for easier processing on your side.
Operations summary¶
Once you’ve defined a polygon, you can:
- search for available images upon the polygon and taken in a specific time frame. The search can be performed with multiple filters (including: satellite symbol, image type, image preset, min/max resolution, minx/max cloud coverage, …) and returns search results, each one being metadata for a specific image.
- from those metadata, download an image, be it a regular scene or a tile, optionally specifying a color palette for NDVI ones
- if your image has EVI or NDVI presets, you can query for its statistics: these include min/max/median/p25/p75 values for the corresponding index
A concrete example: we want to acquire all NDVI GeoTIFF images acquired by Landsat 8 from July 18, 2017 to October 26, 2017; then we want to get stats for one such image and to save it to a local file.
from pyowm.commons.enums import ImageTypeEnum
from pyowm.agroapi10.enums import SatelliteEnum, PresetEnum
pol_id = '5abb9fb82c8897000bde3e87' # your polygon's ID
acq_from = 1500336000 # 18 July 2017
acq_to = 1508976000 # 26 October 2017
img_type = ImageTypeEnum.GEOTIFF # the image format type
preset = PresetEnum.NDVI # the preset
sat = SatelliteEnum.LANDSAT_8.symbol # the satellite
# the search returns images metadata (in the form of `MetaImage` objects)
results = mgr.search_satellite_imagery(pol_id, acq_from, acq_to, img_type=img_type, preset=preset, None, None, acquired_by=sat)
# download all of the images
satellite_images = [mgr.download_satellite_image(result) for result in results]
# get stats for the first image
sat_img = satellite_images[0]
stats_dict = mgr.stats_for_satellite_image(sat_img)
# ...satellite images can be saved to disk
sat_img.persist('/path/to/my/folder/sat_img.tif')
Let’s see in detail all of the imagery-based operations.
Searching images¶
Search available imagery upon your polygon by specifying at least a mandatory time window, with from and to timestamps expressed as UNIX UTC timestamps:
pol_id = '5abb9fb82c8897000bde3e87' # your polygon's ID
acq_from = 1500336000 # 18 July 2017
acq_to = 1508976000 # 26 October 2017
# the most basic search ever: search all available images upon the polygon in the specified time frame
metaimages_list = mgr.search_satellite_imagery(pol_id, acq_from, acq_to)
What you will get back is actually metadata for the actual imagery, not data.
The function call will return a list of pyowm.agroapi10.imagery.MetaImage
instances, each
one being a bunch of metadata relating to one single satellite image.
Keep these objects, as you will need them in order to download the corresponding satellite images from the Agro API: think of them such as descriptors for the real images.
But let’s get back to search! Search is a parametric affair… you can specify many more filters:
- the image format type (eg. PNG, GEOTIFF)
- the image preset (eg. false color, EVI)
- the satellite that acquired the image (you need to specify its symbol)
- the px/m resolution range for the image (you can specify a minimum value, a maximum value or both of them)
- the % of cloud coverage on the acquired scene (you can specify a minimum value, a maximum value or both of them)
- the % of valid data coverage on the acquired scene (you can specify a minimum value, a maximum value or both of them)
Sky is the limit…
As regards image type, image preset and satellite filters please refer to subsequent sections explaining the supported values.
Examples of search:
from pyowm.commons.enums import ImageTypeEnum
from pyowm.agroapi10.enums import SatelliteEnum, PresetEnum
# search all Landsat 8 images in the specified time frame
results = mgr.search_satellite_imagery(pol_id, acq_from, acq_to, acquired_by=SatelliteEnum.LANDSAT_8.symbol)
# search all GeoTIFF images in the specified time frame
results = mgr.search_satellite_imagery(pol_id, acq_from, acq_to, img_type=ImageTypeEnum.GEOTIFF)
# search all NDVI images acquired by Sentinel 2 in the specified time frame
results = mgr.search_satellite_imagery(pol_id, acq_from, acq_to, acquired_by=SatelliteEnum.SENTINEL_2.symbol,
preset=PresetEnum.NDVI)
# search all PNG images in the specified time frame with a max cloud coverage of 1% and a min valid data coverage of 98%
results = mgr.search_satellite_imagery(pol_id, acq_from, acq_to, img_type=ImageTypeEnum.PNG,
max_cloud_coverage=1, min_valid_data_coverage=98)
# search all true color PNG images in the specified time frame, acquired by Sentinel 2, with a range of metric resolution
# from 4 to 16 px/m, and with at least 90% of valid data coverage
results = mgr.search_satellite_imagery(pol_id, acq_from, acq_to, img_type=ImageTypeEnum.PNG, preset=PresetEnum.TRUE_COLOR,
min_resolution=4, max_resolution=16, min_valid_data_coverage=90)
So, what metadata can be extracted by a MetaImage
object? Here we go:
metaimage.polygon_id # the ID of the polygon upon which the image is taken
metaimage.url # the URL the actual satellite image can be fetched from
metaimage.preset # the satellite image preset
metaimage.image_type # the satellite image format type
metaimage.satellite_name # the name of the satellite that acquired the image
metaimage.acquisition_time('unix') # the timestamp when the image was taken (can be specified using: 'iso', 'unix' and 'date')
metaimage.valid_data_percentage # the percentage of valid data coverage on the image
metaimage.cloud_coverage_percentage # the percentage of cloud coverage on the image
metaimage.sun_azimuth # the sun azimuth angle at scene acquisition time
metaimage.sun_elevation # the sun zenith angle at scene acquisition time
metaimage.stats_url # if the image is EVI or NDVI, this is the URL where index statistics can be retrieved (see further on for details)
Download an image¶
Once you’ve got your metaimages ready, you can download the actual satellite images.
In order to download, you must specify to the Agro API manager object at least the desired metaimage to fetch. If you’re
downloading a tile, you must specify tile coordinates (x, y, and zoom level): these are mandatory, and if you forget
to provide them you’ll get an AssertionError
.
Optionally, you can specify a color palette - but this will be significant only if you’re downloading an image with NDVI preset (otherwise the palette parameter will be safely ignored) - please see further on for reference.
Once download is complete, you’ll get back a pyowm.agroapi10.imagery.SatelliteImage
object (more on this in a while).
Here are some examples:
from pyowm.agroapi10.enums import PaletteEnum
# Download a NDVI image
ndvi_metaimage # metaimage for a NDVI image
bnw_sat_image = mgr.download_satellite_image(ndvi_metaimage, preset=PaletteEnum.BLACK_AND_WHITE)
green_sat_image = mgr.download_satellite_image(ndvi_metaimage, preset=PaletteEnum.GREEN)
# Download a tile
tile_metaimage # metaimage for a tile
tile_image = mgr.download_satellite_image(tile_metaimage, x=2, y=3, zoom=5)
tile_image = mgr.download_satellite_image(tile_metaimage) # AssertionError (x, y and zoom are missing!)
Downloaded satellite images contain both binary image data and and embed the original MetaImage
object describing
image metadata. Furthermore, you can query for the download time of a satellite image, and for its related color palette:
# Get satellite image download time - you can as usual specify: 'iso', 'date' and 'unix' time formats
bnw_sat_image.downloaded_on('iso') # '2017-07-18 14:08:23+00:00'
# Get its palette
bnw_sat_image.palette # '2'
# Get satellite image's data and metadata
bnw_sat_image.data # this returns a `pyowm.commons.image.Image` object or a
# `pyowm.commons.tile.Tile` object depending on the satellite image
metaimage = bnw_sat_image.metadata # this gives a `MetaImage` subtype object
# Use the Metaimage object as usual...
metaimage.polygon_id
metaimage.preset,
metaimage.satellite_name
metaimage.acquisition_time
You can also save satellite images to disk - it’s as easy as:
bnw_sat_image.persist('C:\myfolder\myfile.png')
Querying for NDVI and EVI image stats¶
NDVI and EVI preset images have an extra blessing: you can query for statistics about the image index.
Once you’ve downloaded such satellite images, you can query for stats and get back a data dictionary for each of them:
ndvi_metaimage # metaimage for a NDVI image
# download it
bnw_sat_image = mgr.download_satellite_image(ndvi_metaimage, preset=PaletteEnum.BLACK_AND_WHITE)
# query for stats
stats_dict = mgr.stats_for_satellite_image(bnw_sat_image)
Stats dictionaries contain:
std
: the standard deviation of the indexp25
: the first quartile value of the indexnum
: the number of pixels in the current polygonmin
: the minimum value of the indexmax
: the maximum value of the indexmedian
: the median value of the indexp75
: the third quartile value of the indexmean
: the average value of the index
What if you try to get stats for a non-NDVI or non-EVI image? A ValueError
will be raised!
Supported satellites¶
Supported satellites are provided by the pyowm.agroapi10.enums.SatelliteEnum
enumerator which returns
pyowm.commons.databoxes.Satellite
objects:
from pyowm.agroapi10.enums import SatelliteEnum
sat = SatelliteEnum.SENTINEL_2
sat.name # 'Sentinel-2'
sat.symbol # 's2'
Currently only Landsat 8 and Sentinel 2 satellite imagery is available
Supported presets¶
Supported presets are provided by the pyowm.agroapi10.enums.PresetEnum
enumerator which returns strings, each
one representing an image preset:
from pyowm.agroapi10.enums import PresetEnum
PresetEnum.TRUE_COLOR # 'truecolor'
Currently these are the supported presets: true color, false color, NDVI and EVI
Supported image types¶
Supported image types are provided by the pyowm.commons.databoxes.ImageTypeEnum
enumerator which returns
pyowm.commons.databoxes.ImageType
objects:
from pyowm.agroapi10.enums import ImageTypeEnum
png_type = ImageTypeEnum.PNG
geotiff_type = ImageTypeEnum.GEOTIFF
png_type.name # 'PNG'
png_type.mime_type # 'image/png'
Currently only PNG and GEOTIFF imagery is available
Supported color palettes¶
Supported color palettes are provided by the pyowm.agroapi10.enums.PaletteEnum
enumerator which returns strings,
each one representing a color palette for NDVI images:
from pyowm.agroapi10.enums import PaletteEnum
PaletteEnum.CONTRAST_SHIFTED # '3'
As said, palettes only apply to NDVI images: if you try to specify palettes when downloading images with different presets (eg. false color images), nothing will happen.
The default Agro API color palette is PaletteEnum.GREEN
(which is 1
): if you don’t specify any palette at all when
downloading NDVI images, they will anyway be returned with this palette.
As of today green, black and white and two contrast palettes (one continuous and one continuous but shifted) are supported by the Agro API. Please check the documentation for palettes’ details, including control points.