Getting Started with the AρρEEARS API: Submitting and Downloading an Area Request

This tutorial demonstrates how to use Python to connect to the AρρEEARS API

The Application for Extracting and Exploring Analysis Ready Samples (AρρEEARS) offers a simple and efficient way to access and transform geospatial data from a variety of federal data archives in an easy-to-use web application interface. AρρEEARS enables users to subset geospatial data spatially, temporally, and by band/layer for point and area samples. AρρEEARS returns not only the requested data, but also the associated quality values, and offers interactive visualizations with summary statistics in the web interface. The AρρEEARS API offers users programmatic access to all features available in AρρEEARS, with the exception of visualizations. The API features are demonstrated in this notebook.


Example: Submit an area request using a U.S. National Park boundary as the region of interest for extracting elevation, vegetation and land surface temperature data

Connect to the AρρEEARS API, query the list of available products, submit an area sample request, download the request, become familiar with the AρρEEARS Quality API, and import the results into Python for visualization. AρρEEARS area sample requests allow users to subset their desired data by spatial area via vector polygons (shapefiles or GeoJSONs). Users can also reproject and reformat the output data. AρρEEARS returns the valid data from the parameters defined within the sample request.

Data Used in the Example:

  • Data layers:
    • NASA MeaSUREs Shuttle Radar Topography Mission (SRTM) Version 3 Digital Elevation Model
    • Combined MODIS Leaf Area Index (LAI)
    • Terra MODIS Land Surface Temperature
      • MOD11A2.006, 1000m, 8 day: 'LST_Day_1km', 'LST_Night_1km'

Topics Covered:

  1. Getting Started
    1a. Enable Access to the API
    1b. Set Up the Working Environment
    1c. Login [Login]
  2. Query Available Products [Product API]
    2a. Search and Explore Available Products [List Products]
    2b. Search and Explore Available Layers [List Layers]
  3. Submit an Area Request [Tasks]
    3a. Import a Shapefile
    3b. Search and Explore Available Projections [Spatial API]
    3c. Compile a JSON [Task Object]
    3d. Submit a Task Request [Submit Task]
    3e. Retrieve Task Status [Retrieve Task]
  4. Download a Request [Bundle API]
    4a. Explore Files in Request Output [List Files]
    4b. Download Files in a Request (Automation) [Download File]
  5. Explore AρρEEARS Quality Service [Quality API]
    5a. List Quality Layers [List Quality Layers]
    5b. Show Quality Values [List Quality Values]
    5c. Decode Quality Values [Decode Quality Values]
  6. BONUS: Import Request Output and Visualize
    6a. Import a GeoTIFF
    6b. Plot a GeoTIFF

Dependencies:


AρρEEARS Information:

To access AρρEEARS, visit: https://lpdaacsvc.cr.usgs.gov/appeears/

For comprehensive documentation of the full functionality of the AρρEEARS API, please see the AρρEEARS API Documentation

Throughout the tutorial, specific sections of the API documentation can be accessed by clicking on the bracketed [] links in the section headings.


Files Used in this Tutorial:

Source Code used to Generate this Tutorial:


1. Getting Started

NOTE: If this is your first time using the AρρEEARS API, you must first enable API access by following the instructions provided below.


1a. Enable Access to the API

AρρEEARS API access requires the same NASA Earthdata Login as the AρρEEARS user interface. In addition to having a valid NASA Earthdata Login account, the API feature must be enabled for the user within AρρEEARS.

To enable access to the AρρEEARS API, navigate to the AρρEEARS website. Click the Sign In button in the top right portion of the AρρEEARS landing page screen.

AppEEARS Sign In

Once you are signed in, click the Manage User icon in the top right portion of the AρρEEARS landing page screen and select Settings.

Manage User -> Settings

Select the Enable API box to gain access to the AρρEEARS API.

Enable API Access


1b. Set Up the Working Environment

Next, import the required packages, set the input/working directory, and create an output directory for the results.

In [1]:
# Import packages
import requests as r
import getpass, pprint, time, os, cgi, json
import geopandas as gpd

If you are missing any of the packages above, download them in order to use the full functionality of this tutorial.

In [2]:
# Set input directory, change working directory
inDir = 'C:/appeears-api-getting-started/'           # IMPORTANT: Update to reflect directory on your OS
os.chdir(inDir)                                      # Change to working directory
api = 'https://lpdaacsvc.cr.usgs.gov/appeears/api/'  # Set the AρρEEARS API to a variable

If you plan to execute this tutorial on your own OS, `inDir` above needs to be changed.


1c. Login [Login]

To submit a request, you must first login to the AρρEEARS API. Use the getpass package to enter your NASA Earthdata login Username and Password. When prompted after executing the code block below, enter your username followed by your password.

In [3]:
user = getpass.getpass(prompt = 'Enter NASA Earthdata Login Username: ')      # Input NASA Earthdata Login Username
password = getpass.getpass(prompt = 'Enter NASA Earthdata Login Password: ')  # Input NASA Earthdata Login Password

Use the requests package to post your username and password. A successful login will provide you with a token to be used later in this tutorial to submit a request. For more information or if you are experiencing difficulties, please see the API Documentation.

In [4]:
token_response = r.post('{}login'.format(api), auth=(user, password)).json() # Insert API URL, call login service, provide credentials & return json
del user, password                                                           # Remove user and password information
token_response                                                               # Print response
Out[4]:
{'expiration': '2018-04-20T19:09:30Z',
 'token': 'qAuEjsZX7bR0uym1b5h5_PHO81bROfAneJ0nfOwVeS9H61aZBZVmbRbM99vrfV_ND7iByiCJSKyGTCEWD9FZow',
 'token_type': 'Bearer'}

Above, you should see a Bearer token. Notice that this token will expire approximately 48 hours after being acquired.


2. Query Available Products [Product API]

2a. Search and Explore Available Products [List Products]

The product API provides details about all of the products and layers available in AρρEEARS. Below, call the product API to list all of the products available in AρρEEARS.

In [5]:
product_response = r.get('{}product'.format(api)).json()                         # request all products in the product service
print('AρρEEARS currently supports {} products.'.format(len(product_response)))  # Print no. products available in AppEEARS
AρρEEARS currently supports 87 products.

Next, create a dictionary indexed by product name, making it easier to query a specific product.

In [6]:
products = {p['ProductAndVersion']: p for p in product_response} # Create a dictionary indexed by product name & version
products['MCD15A3H.006']                                         # Print information for MCD15A3H.006 LAI/FPAR Product
Out[6]:
{'Available': True,
 'DOI': '10.5067/MODIS/MCD15A3H.006',
 'Deleted': False,
 'Description': 'Leaf Area Index (LAI) and Fractional Photosynthetically Active Radiation (FPAR)',
 'DocLink': 'https://doi.org/10.5067/MODIS/MCD15A3H.006',
 'Platform': 'Combined MODIS',
 'Product': 'MCD15A3H',
 'ProductAndVersion': 'MCD15A3H.006',
 'RasterType': 'Tile',
 'Resolution': '500m',
 'Source': 'LP DAAC',
 'TemporalExtentEnd': 'Present',
 'TemporalExtentStart': '2002-07-04',
 'TemporalGranularity': '4 day',
 'Version': '006'}

The product service provides many useful details, including if a product is currently available in AρρEEARS, a description, and information on the spatial and temporal resolution.

Below, make a list of all product+version names, and search for products containing Leaf Area Index in their description.

In [7]:
prodNames = {p['ProductAndVersion'] for p in product_response} # Make list of all products (including version)
for p in prodNames:                                            # Make for loop to search list of products 'Description' for a keyword                
    if 'Leaf Area Index' in products[p]['Description']:
        pprint.pprint(products[p])                             # Print info for each product containing LAI in its description
{'Available': True,
 'DOI': '10.5067/MODIS/MOD15A2H.006',
 'Deleted': False,
 'Description': 'Leaf Area Index (LAI) and Fractional Photosynthetically '
                'Active Radiation (FPAR)',
 'DocLink': 'https://doi.org/10.5067/MODIS/MOD15A2H.006',
 'Platform': 'Terra MODIS',
 'Product': 'MOD15A2H',
 'ProductAndVersion': 'MOD15A2H.006',
 'RasterType': 'Tile',
 'Resolution': '500m',
 'Source': 'LP DAAC',
 'TemporalExtentEnd': 'Present',
 'TemporalExtentStart': '2000-02-18',
 'TemporalGranularity': '8 day',
 'Version': '006'}
{'Available': True,
 'DOI': '10.5067/MODIS/MYD15A2H.006',
 'Deleted': False,
 'Description': 'Leaf Area Index (LAI) and Fractional Photosynthetically '
                'Active Radiation (FPAR)',
 'DocLink': 'https://doi.org/10.5067/MODIS/MYD15A2H.006',
 'Platform': 'Aqua MODIS',
 'Product': 'MYD15A2H',
 'ProductAndVersion': 'MYD15A2H.006',
 'RasterType': 'Tile',
 'Resolution': '500m',
 'Source': 'LP DAAC',
 'TemporalExtentEnd': 'Present',
 'TemporalExtentStart': '2002-07-04',
 'TemporalGranularity': '8 day',
 'Version': '006'}
{'Available': True,
 'DOI': '10.5067/MODIS/MCD15A2H.006',
 'Deleted': False,
 'Description': 'Leaf Area Index (LAI) and Fractional Photosynthetically '
                'Active Radiation (FPAR)',
 'DocLink': 'https://doi.org/10.5067/MODIS/MCD15A2H.006',
 'Platform': 'Combined MODIS',
 'Product': 'MCD15A2H',
 'ProductAndVersion': 'MCD15A2H.006',
 'RasterType': 'Tile',
 'Resolution': '500m',
 'Source': 'LP DAAC',
 'TemporalExtentEnd': 'Present',
 'TemporalExtentStart': '2002-07-04',
 'TemporalGranularity': '8 day',
 'Version': '006'}
{'Available': True,
 'DOI': '10.5067/MODIS/MCD15A3H.006',
 'Deleted': False,
 'Description': 'Leaf Area Index (LAI) and Fractional Photosynthetically '
                'Active Radiation (FPAR)',
 'DocLink': 'https://doi.org/10.5067/MODIS/MCD15A3H.006',
 'Platform': 'Combined MODIS',
 'Product': 'MCD15A3H',
 'ProductAndVersion': 'MCD15A3H.006',
 'RasterType': 'Tile',
 'Resolution': '500m',
 'Source': 'LP DAAC',
 'TemporalExtentEnd': 'Present',
 'TemporalExtentStart': '2002-07-04',
 'TemporalGranularity': '4 day',
 'Version': '006'}

Using the info above, start a list of desired products by using the highest temporal resolution LAI product, MCD15A3H.006.

In [8]:
prods = ['MCD15A3H.006']     # Start a list for products to be requested, beginning with MCD15A3H.006
prods.append('MOD11A2.006')  # Append the MOD11A2.006 8 day LST product to the list of products desired
prods.append('SRTMGL1.003')  # Append the SRTMGL1.003 product to the list of products desired
prods                        # Print list
Out[8]:
['MCD15A3H.006', 'MOD11A2.006', 'SRTMGL1.003']

2b. Search and Explore Available Layers [List Layers]

The product API allows you to call all of the layers available for a given product. Each product is referenced by its ProductAndVersion property. For a list of the layer names only, print the keys from the dictionary below.

In [9]:
lst_response = r.get('{}product/{}'.format(api, prods[1])).json()  # Request layers for the 2nd product (index 1) in the list: MOD11A2.006
list(lst_response.keys())
Out[9]:
['Clear_sky_days',
 'Clear_sky_nights',
 'Day_view_angl',
 'Day_view_time',
 'Emis_31',
 'Emis_32',
 'LST_Day_1km',
 'LST_Night_1km',
 'Night_view_angl',
 'Night_view_time',
 'QC_Day',
 'QC_Night']

Use the dictionary key 'LST_Day_1km' to see the information for that layer in the response.

In [10]:
lst_response['LST_Day_1km'] # Print layer response
Out[10]:
{'AddOffset': 0.0,
 'Available': True,
 'DataType': 'float32',
 'Description': 'Day Land Surface Temperature',
 'Dimensions': ['time', 'YDim', 'XDim'],
 'FillValue': 0,
 'Layer': 'LST_Day_1km',
 'OrigDataType': 'uint16',
 'OrigValidMax': 65535,
 'OrigValidMin': 7500,
 'QualityLayers': "['QC_Day']",
 'QualityProductAndVersion': 'MOD11A2.006',
 'ScaleFactor': 0.02,
 'Units': 'Kelvin',
 'ValidMax': 1310.699951,
 'ValidMin': 150.0,
 'XSize': 1200,
 'YSize': 1200}

AρρEEARS also allows subsetting data spectrally (by band). Create a tupled list with product name and specific layers desired.

In [11]:
layers = [(prods[1],'LST_Day_1km'),(prods[1],'LST_Night_1km')]  # Create tupled list linking desired product with desired layers

Next, request the layers for the MCD15A3H.006 product.

In [12]:
lai_response = r.get('{}product/{}'.format(api, prods[0])).json()  # Request layers for the 1st product (index 0) in the list: MCD15A3H.006
list(lai_response.keys())                                          # Print the LAI layer names
Out[12]:
['FparExtra_QC',
 'FparLai_QC',
 'FparStdDev_500m',
 'Fpar_500m',
 'LaiStdDev_500m',
 'Lai_500m']
In [13]:
lai_response['Lai_500m']['Description']  # Make sure the correct layer is requested
Out[13]:
'Leaf area index'

Above, Lai_500m is the desired layer within the MCD15A3h.006 product.

Next, append Lai_500m to the tupled list of desired product/layers.

In [14]:
layers.append((prods[0],'Lai_500m')) # Append to tupled list linking desired product with desired layers

Thirdly, request the layers for the SRTMGL1.003 product.

In [15]:
dem_response = r.get('{}product/{}'.format(api, prods[2])).json()  # Request layers for the 3rd product (index 2) in the list: SRTMGL1.003
list(dem_response.keys())                                          # Print the SRTM DEM layer names 
Out[15]:
['Band1']

Finally, append Band1 to the tupled list of desired products/layers.

In [16]:
layers.append((prods[2],'Band1')) # Append to tupled list linking desired product with desired layers

Below, take the tupled list (layers) and create a list of dictionaries to store each layer+product combination. This will make it easier to insert into the json file used to submit a request in Section 3.

In [17]:
prodLayer = []
for l in layers:
    prodLayer.append({
            "layer": l[1],
            "product": l[0]
          })
prodLayer
Out[17]:
[{'layer': 'LST_Day_1km', 'product': 'MOD11A2.006'},
 {'layer': 'LST_Night_1km', 'product': 'MOD11A2.006'},
 {'layer': 'Lai_500m', 'product': 'MCD15A3H.006'},
 {'layer': 'Band1', 'product': 'SRTMGL1.003'}]

3. Submit an Area Request [Tasks]

The Submit task API call provides a way to submit a new request to be processed. It can accept data via JSON, query string, or a combination of both. In the example below, compile a json and submit a request. Tasks in AρρEEARS correspond to each request associated with your user account. Therefore, each of the calls to this service requires an authentication token (see Section 1c.), which is stored in a header below.

In [18]:
token = token_response['token']                      # Save login token to a variable
head = {'Authorization': 'Bearer {}'.format(token)}  # Create a header to store token information, needed to submit a request

3a. Import a Shapefile

In this section, begin by importing a shapefile using the geopandas package. The shapefile is publically available for download from the NPS website.

In [19]:
nps = gpd.read_file('{}nps_boundary.shp'.format(inDir + os.sep)) # Read in shapefile as dataframe using geopandas
print(nps.head())                                                # Print first few lines of dataframe
  UNIT_CODE                                          GIS_Notes  \
0      AMME  LEGACY: contact allen_mccoy@nps.gov for additi...   
1      EBLA  LEGACY: contact allen_mccoy@nps.gov for additi...   
2      LARO  LEGACY: contact allen_mccoy@nps.gov for additi...   
3      LEWI  LEGACY: contact allen_mccoy@nps.gov for additi...   
4      OLYM  LEGACY: contact allen_mccoy@nps.gov for additi...   

                                    UNIT_NAME   DATE_EDIT STATE REGION  \
0                      American Memorial Park  2015-04-22    MP     PW   
1  Ebey's Landing National Historical Reserve  2015-04-22    WA     PW   
2     Lake Roosevelt National Recreation Area  2015-04-22    WA     PW   
3    Lewis and Clark National Historical Park  2015-04-22    WA     PW   
4                       Olympic National Park  2015-04-22    WA     PW   

   GNIS_ID                    UNIT_TYPE CREATED_BY METADATA  \
0  1879026                         Park     Legacy            
1  1888910  National Historical Reserve     Legacy            
2  1531834     National Recreation Area     Legacy            
3  2055170     National Historical Park     Legacy            
4  1530459                National Park     Legacy            

                 PARKNAME                                           geometry  
0  American Memorial Park  POLYGON ((145.723496788 15.22246183000004, 145...  
1          Ebey's Landing  POLYGON ((-122.6528982094848 48.25378514027204...  
2          Lake Roosevelt  (POLYGON ((-118.4520020926864 47.8421348958409...  
3         Lewis and Clark  (POLYGON ((-124.0749506444566 46.3022812330924...  
4                 Olympic  (POLYGON ((-124.3806127629999 47.6020991240000...  

Below, query the geopandas dataframe for the national park that you are interested in using for your region of interest, here Grand Canyon National Park.

In [20]:
nps_gc = nps[nps['UNIT_NAME']=='Grand Canyon National Park'].to_json() # Extract Grand Canyon NP and set to variable
nps_gc = json.loads(nps_gc)                                            # Convert to json format

3b. Search and Explore Available Projections [Spatial API]

The spatial API provides some helper services used to support submitting area task requests. The call below will retrieve the list of supported projections in AρρEEARS.

In [21]:
projections = r.get('{}spatial/proj'.format(api)).json()  # Call to spatial API, return projs as json
projections                                               # Print projections and information
Out[21]:
[{'Available': True,
  'Datum': '',
  'Description': 'Native Projection',
  'EPSG': '',
  'GridMapping': '',
  'Name': 'native',
  'Proj4': '',
  'Units': ''},
 {'Available': True,
  'Datum': 'wgs84',
  'Description': 'Geographic',
  'EPSG': 4326.0,
  'GridMapping': 'latitude_longitude',
  'Name': 'geographic',
  'Proj4': '+proj=longlat +datum=WGS84 +no_defs',
  'Units': 'degrees'},
 {'Available': True,
  'Datum': '',
  'Description': 'MODIS Sinusoidal',
  'EPSG': '',
  'GridMapping': 'sinusoidal',
  'Name': 'sinu_modis',
  'Proj4': '+proj=sinu +lon_0=0 +x_0=0 +y_0=0 +a=6371007.181 +b=6371007.181 +units=m +no_defs',
  'Units': 'meters'},
 {'Available': True,
  'Datum': 'wgs84',
  'Description': 'WELD Albers Equal Area Alaska',
  'EPSG': '',
  'GridMapping': 'albers_conical_equal_area',
  'Name': 'albers_weld_alaska',
  'Proj4': '+proj=aea +lat_1=55 +lat_2=65 +lat_0=50 +lon_0=-154 +x_0=0 +y_0=0 +datum=WGS84 +units=m +no_defs',
  'Units': 'meters'},
 {'Available': True,
  'Datum': 'wgs84',
  'Description': 'WELD Albers Equal Area CONUS',
  'EPSG': '',
  'GridMapping': 'albers_conical_equal_area',
  'Name': 'albers_weld_conus',
  'Proj4': '+proj=aea +lat_1=29.5 +lat_2=45.5 +lat_0=23 +lon_0=-96 +x_0=0 +y_0=0 +datum=WGS84 +units=m +no_defs',
  'Units': 'meters'},
 {'Available': True,
  'Datum': 'wgs84',
  'Description': 'EASE-Grid 2.0 Global',
  'EPSG': 6933.0,
  'GridMapping': 'lambert_azimuthal_equal_area',
  'Name': 'easegrid_2_global',
  'Proj4': '+proj=cea +lon_0=0 +lat_ts=30 +x_0=0 +y_0=0 +datum=WGS84 +units=m +no_defs',
  'Units': 'meters'},
 {'Available': True,
  'Datum': 'wgs84',
  'Description': 'EASE-Grid 2.0 Northern Hemisphere',
  'EPSG': 6931.0,
  'GridMapping': 'lambert_azimuthal_equal_area',
  'Name': 'easegrid_2_north',
  'Proj4': '+proj=laea +lat_0=90 +lon_0=0 +x_0=0 +y_0=0 +datum=WGS84 +units=m +no_defs',
  'Units': 'meters'}]

Create a dictionary of projections with projection Name as the keys.

In [22]:
projs = {}                                  # Create an empty dictionary
for p in projections: projs[p['Name']] = p  # Fill dictionary with `Name` as keys
list(projs.keys())                          # Print dictionary keys
Out[22]:
['native',
 'geographic',
 'sinu_modis',
 'albers_weld_alaska',
 'albers_weld_conus',
 'easegrid_2_global',
 'easegrid_2_north']
In [23]:
projs['geographic']
Out[23]:
{'Available': True,
 'Datum': 'wgs84',
 'Description': 'Geographic',
 'EPSG': 4326.0,
 'GridMapping': 'latitude_longitude',
 'Name': 'geographic',
 'Proj4': '+proj=longlat +datum=WGS84 +no_defs',
 'Units': 'degrees'}

3c. Compile a JSON [Task Object]

In this section, begin by setting up the information needed to compile an acceptable json for submitting an AρρEEARS area request. For detailed information on required json parameters, see the API Documentation.

In [24]:
task_name = input('Enter a Task Name: ') # User-defined name of the task: 'NPS Vegetation Area' used in example
In [25]:
task_type = ['point','area']        # Type of task, area or point
proj = projs['geographic']['Name']  # Set output projection 
outFormat = ['geotiff', 'netcdf4']  # Set output file format type
startDate = '07-01-2017'            # Start of the date range for which to extract data: MM-DD-YYYY
endDate = '07-31-2017'              # End of the date range for which to extract data: MM-DD-YYYY
recurring = False                   # Specify True for a recurring date range
#yearRange = [2000,2016]            # if recurring = True, set yearRange, change start/end date to MM-DD

Below, compile the JSON to be submitted as an area request. Notice that nps_gc is inserted from the shapefile transformed to a json via the geopandas and json packages above in section 3a.

In [26]:
task = {
    'task_type': task_type[1],
    'task_name': task_name,
    'params': {
         'dates': [
         {
             'startDate': startDate,
             'endDate': endDate
         }],
         'layers': prodLayer,
         'output': {
                 'format': {
                         'type': outFormat[0]}, 
                         'projection': proj},
         'geo': nps_gc,
    }
}

3d. Submit a Task Request [Submit Task]

Below, post a call to the API task service, using the task json created above.

In [27]:
task_response = r.post('{}task'.format(api), json=task, headers=head).json()  # Post json to the API task service, return response as json
task_response                                                                 # Print task response
Out[27]:
{'status': 'pending', 'task_id': '5ab03e68-9096-4c3d-a4b8-e35542129a1d'}

3e. Retrieve Task Status [Retrieve Task]

This API call will list all of the requests associated with your user account, automatically sorted by date descending with the most recent requests listed first.

The AρρEEARS API contains some helpful formatting resources. Below, limit the API response to 2 entries and set pretty to True to format the response as an organized json, making it easier to read. Additional information on AρρEEARS API pagination and formatting can be found in the API documentation.

In [28]:
params = {'limit': 2, 'pretty': True} # Limit API response to 2 most recent entries, return as pretty json
In [29]:
tasks_response = r.get('{}task'.format(api), params=params, headers=head).json() # Query task service, setting params and header 
tasks_response                                                                   # Print tasks response
Out[29]:
[{'api_version': 'v1',
  'created': '2018-04-19T14:32:10.629000',
  'error': None,
  'expires_on': None,
  'params': {'dates': [{'endDate': '07-31-2017', 'startDate': '07-01-2017'}],
   'layers': [{'layer': 'LST_Day_1km', 'product': 'MOD11A2.006'},
    {'layer': 'LST_Night_1km', 'product': 'MOD11A2.006'},
    {'layer': 'Lai_500m', 'product': 'MCD15A3H.006'},
    {'layer': 'Band1', 'product': 'SRTMGL1.003'}]},
  'retry_at': None,
  'status': 'processing',
  'svc_version': '2.7',
  'task_id': '5ab03e68-9096-4c3d-a4b8-e35542129a1d',
  'task_name': 'NPS Vegetation Area',
  'task_type': 'area',
  'updated': '2018-04-19T14:32:11.869000',
  'user_id': 'lpdaac2018@gmail.com',
  'web_version': None},
 {'api_version': 'v1',
  'attempts': 1,
  'created': '2018-04-19T13:39:47.099000',
  'error': None,
  'expires_on': None,
  'params': {'dates': [{'endDate': '07-31-2017', 'startDate': '07-01-2017'}],
   'layers': [{'layer': 'LST_Day_1km', 'product': 'MOD11A2.006'},
    {'layer': 'LST_Night_1km', 'product': 'MOD11A2.006'},
    {'layer': 'Lai_500m', 'product': 'MCD15A3H.006'},
    {'layer': 'Band1', 'product': 'SRTMGL1.003'}]},
  'retry_at': None,
  'status': 'done',
  'svc_version': '2.7',
  'task_id': 'c97e3b68-2168-4fe5-b554-cd11ff03ff37',
  'task_name': 'NPS Vegetation Area',
  'task_type': 'area',
  'updated': '2018-04-19T13:41:13.727000',
  'user_id': 'lpdaac2018@gmail.com',
  'web_version': None}]

Next, take the task id returned from the task_response that was generated when submitting your request, and use the AρρEEARS API status service to check the status of your request.

In [30]:
task_id = task_response['task_id']                                               # Set task id from request submission
status_response = r.get('{}status/{}'.format(api, task_id), headers=head).json() # Call status service with specific task ID & user credentials
status_response                                                        
Out[30]:
{'progress': {'details': [{'desc': 'Initializing',
    'pct_complete': 100,
    'step': 1},
   {'desc': 'Downloading', 'pct_complete': 100, 'step': 2},
   {'desc': 'Generating Files', 'pct_complete': 16, 'step': 3},
   {'desc': 'Extracting Stats', 'pct_complete': 0, 'step': 4},
   {'desc': 'Finalizing', 'pct_complete': 0, 'step': 5}],
  'summary': 51},
 'status_id': '85042422-cb86-4ef3-8e57-bdecab1a4f83',
 'status_type': 'task',
 'task_id': '5ab03e68-9096-4c3d-a4b8-e35542129a1d',
 'updated': '2018-04-19T14:32:47.043000',
 'user_id': 'lpdaac2018@gmail.com'}

Above, if your request is still processing, you can find information on the status of how close it is to completing.

Below, call the task service for your request every 20 seconds to check the status of your request.

In [31]:
# Ping API until request is complete, then continue to Section 4
starttime = time.time()
while r.get('{}task/{}'.format(api, task_id), headers=head).json()['status'] != 'done':
    print(r.get('{}task/{}'.format(api, task_id), headers=head).json()['status'])
    time.sleep(20.0 - ((time.time() - starttime) % 20.0))
print(r.get('{}task/{}'.format(api, task_id), headers=head).json()['status'])
processing
processing
done
done

4. Download a Request [Bundle API]

Before downloading the request output, set up an output directory to store the output files, and examine the files contained in the request output.

In [32]:
destDir = os.path.join(inDir, task_name)                # Set up output directory using input directory and task name
if not os.path.exists(destDir):os.makedirs(destDir)     # Create the output directory

4a. Explore Files in Request Output [List Files]

The bundle API provides information about completed tasks. For any completed task, a bundle can be queried to return the files contained as a part of the task request. Below, call the bundle API and return all of the output files.

In [33]:
bundle = r.get('{}bundle/{}'.format(api,task_id)).json()  # Call API and return bundle contents for the task_id as json
bundle                                                    # Print bundle contents
Out[33]:
{'bundle_type': 'area',
 'created': '2018-04-19T14:34:43.582000',
 'files': [{'file_id': '90b38902-53d3-49c4-8f5b-992534d33c30',
   'file_name': 'MCD15A3H.006_2017182_to_2017212/MCD15A3H.006_Lai_500m_doy2017185_aid0001.tif',
   'file_size': 22314,
   'file_type': 'tif',
   'sha256': '6df26e6faec2a6246fb119058e9241e51907a8c33f419331a39becf133bd8ae8'},
  {'file_id': 'ced62b05-5c6e-4cc8-91eb-7baa3d3516f4',
   'file_name': 'MCD15A3H.006_2017182_to_2017212/MCD15A3H.006_Lai_500m_doy2017189_aid0001.tif',
   'file_size': 22624,
   'file_type': 'tif',
   'sha256': 'a665cb8c97eb6d6e4b451dcad9858062714d4c22db7e484c4c0ae98ff81ce965'},
  {'file_id': '9e89e081-0f61-4031-88af-07e6ed17ea57',
   'file_name': 'MCD15A3H.006_2017182_to_2017212/MCD15A3H.006_Lai_500m_doy2017193_aid0001.tif',
   'file_size': 22818,
   'file_type': 'tif',
   'sha256': '13906ebee165a560b1821bdaa081c2174097bc97d5c556fcb3bafe05cd54c0b7'},
  {'file_id': '79ec947e-e9bd-4898-89f0-c643bbc72c6a',
   'file_name': 'MCD15A3H.006_2017182_to_2017212/MCD15A3H.006_Lai_500m_doy2017197_aid0001.tif',
   'file_size': 23069,
   'file_type': 'tif',
   'sha256': '59df354309a73574562df0e5ead34a7549565b31e000bb0e8ed8bc4981a5ad14'},
  {'file_id': '466cbe55-585b-4e9e-b52f-089b2c267ed2',
   'file_name': 'MCD15A3H.006_2017182_to_2017212/MCD15A3H.006_Lai_500m_doy2017201_aid0001.tif',
   'file_size': 23314,
   'file_type': 'tif',
   'sha256': 'f72ee626d840d795950c5b9030371147945cd478de96ac456478f0b37a7dac21'},
  {'file_id': '20520875-c158-4c96-967e-32c09784e6c6',
   'file_name': 'MCD15A3H.006_2017182_to_2017212/MCD15A3H.006_Lai_500m_doy2017205_aid0001.tif',
   'file_size': 22221,
   'file_type': 'tif',
   'sha256': '65fb870cd949359868773b8634faa648270efd6ac6c25c83ae05336704b79f3b'},
  {'file_id': '2cb2fdf4-f5c7-4f4e-97c1-543fe8ac5b81',
   'file_name': 'MCD15A3H.006_2017182_to_2017212/MCD15A3H.006_Lai_500m_doy2017209_aid0001.tif',
   'file_size': 22321,
   'file_type': 'tif',
   'sha256': '0df8bd82af14de440e504fa96ebab98f25661afc179e1b2bd219767993a74bb0'},
  {'file_id': '472efd46-c218-43c1-8580-5a04cf2027f7',
   'file_name': 'MCD15A3H.006_2017182_to_2017212/MCD15A3H.006_FparLai_QC_doy2017185_aid0001.tif',
   'file_size': 16447,
   'file_type': 'tif',
   'sha256': '1da8f49cef70bb14b55a07d576a22004976053031bc4ae4456a6346d29c62fd7'},
  {'file_id': '90d11971-a02e-4fdb-84b4-d4d638b67df9',
   'file_name': 'MCD15A3H.006_2017182_to_2017212/MCD15A3H.006_FparLai_QC_doy2017189_aid0001.tif',
   'file_size': 16522,
   'file_type': 'tif',
   'sha256': '72beefc0d66a9465ba729d1607478937b40a26427bd98c45aaab4eb51b55ef20'},
  {'file_id': 'f0c11af2-b02e-4883-b3d9-144704e7bb2b',
   'file_name': 'MCD15A3H.006_2017182_to_2017212/MCD15A3H.006_FparLai_QC_doy2017193_aid0001.tif',
   'file_size': 17247,
   'file_type': 'tif',
   'sha256': 'b10673628d9b7114321170ab94d3ba049b64b8761ccef67dbbf09ca47287fca1'},
  {'file_id': '3b2d5834-a9f7-44c6-9700-3aada7c579ea',
   'file_name': 'MCD15A3H.006_2017182_to_2017212/MCD15A3H.006_FparLai_QC_doy2017197_aid0001.tif',
   'file_size': 15325,
   'file_type': 'tif',
   'sha256': 'd665c49bdb399c7d0138c94c2ad5eb0256ea268f472e40674bcfdbd6afe887f1'},
  {'file_id': 'a5270a27-f29b-4ddf-9787-73ac1cbe6b69',
   'file_name': 'MCD15A3H.006_2017182_to_2017212/MCD15A3H.006_FparLai_QC_doy2017201_aid0001.tif',
   'file_size': 18111,
   'file_type': 'tif',
   'sha256': 'e648f2063d44eef8055ec5ecbe2f0ca2a814c628d4a1139de3cdbe0ae0f783c6'},
  {'file_id': '9b4dba8a-8038-41cf-a72c-d226dc589ca9',
   'file_name': 'MCD15A3H.006_2017182_to_2017212/MCD15A3H.006_FparLai_QC_doy2017205_aid0001.tif',
   'file_size': 17631,
   'file_type': 'tif',
   'sha256': '534aabc4214fe7aa5c281a02cb4e9f1d009be792468a1df6a6e9de2ecb8f6308'},
  {'file_id': 'ce9a91a2-0115-46ae-a16d-d26199542fbf',
   'file_name': 'MCD15A3H.006_2017182_to_2017212/MCD15A3H.006_FparLai_QC_doy2017209_aid0001.tif',
   'file_size': 19351,
   'file_type': 'tif',
   'sha256': '3d0f25ccd2fecfd4e172154f00e27e52a8615bc2317ced28de706c7d2849ed9a'},
  {'file_id': '51d666d8-1a62-4a2e-b312-ab30349f18a0',
   'file_name': 'MOD11A2.006_2017182_to_2017212/MOD11A2.006_LST_Day_1km_doy2017185_aid0001.tif',
   'file_size': 20726,
   'file_type': 'tif',
   'sha256': '9c0be4389829214e976783ca06a14c86fcee05ea70fcbeac60e9ca06d2c3db96'},
  {'file_id': '2332a9e6-1d00-4162-a870-d136d39245fc',
   'file_name': 'MOD11A2.006_2017182_to_2017212/MOD11A2.006_LST_Day_1km_doy2017193_aid0001.tif',
   'file_size': 20906,
   'file_type': 'tif',
   'sha256': '98754a517c21b7dba405303056df845f4875e8ed8714a26154cf61317e705b8a'},
  {'file_id': '9391cd86-9c58-4837-8b61-cd9db3634e91',
   'file_name': 'MOD11A2.006_2017182_to_2017212/MOD11A2.006_LST_Day_1km_doy2017201_aid0001.tif',
   'file_size': 21006,
   'file_type': 'tif',
   'sha256': '02df614606c5f819a75eaca59edf6966a2220a039f79a8dbf3cd0fe6dc817847'},
  {'file_id': 'a51bc12d-f81d-490a-b1d3-f0f42b5a3506',
   'file_name': 'MOD11A2.006_2017182_to_2017212/MOD11A2.006_LST_Day_1km_doy2017209_aid0001.tif',
   'file_size': 21055,
   'file_type': 'tif',
   'sha256': 'fb1bcc64f24aee0782c1e13e20709d668837671a0c169bb709c12c780fe7a883'},
  {'file_id': '0ad89106-888f-47c3-b338-ed35612373e1',
   'file_name': 'MOD11A2.006_2017182_to_2017212/MOD11A2.006_LST_Night_1km_doy2017185_aid0001.tif',
   'file_size': 20944,
   'file_type': 'tif',
   'sha256': 'b5c1cb64119c64dfa4eca104f76d33e4206025b9e869462d3a389c3969ff90ec'},
  {'file_id': 'c85a4f58-2f42-4453-9d79-58abda51e87f',
   'file_name': 'MOD11A2.006_2017182_to_2017212/MOD11A2.006_LST_Night_1km_doy2017193_aid0001.tif',
   'file_size': 20894,
   'file_type': 'tif',
   'sha256': 'f0fc737755f379c7c3426cb6ecffec7daa47128b58789d97199b3b6fcad6bb44'},
  {'file_id': 'fccca1b0-8302-4794-b2a6-e219440ba790',
   'file_name': 'MOD11A2.006_2017182_to_2017212/MOD11A2.006_LST_Night_1km_doy2017201_aid0001.tif',
   'file_size': 20753,
   'file_type': 'tif',
   'sha256': 'abebe9f6d18d12f9e398f981889de6dac2cbbd1eb4ac5e65eee027e72a134d31'},
  {'file_id': 'c96cfb13-8cb0-4635-a710-31406e70a1aa',
   'file_name': 'MOD11A2.006_2017182_to_2017212/MOD11A2.006_LST_Night_1km_doy2017209_aid0001.tif',
   'file_size': 20740,
   'file_type': 'tif',
   'sha256': 'dc46df8bf9e9280d775aa3616b87b84d9568fe95ef0b60788774a0dc1731d628'},
  {'file_id': '425949c7-001d-4259-991b-748fc6fdd3e4',
   'file_name': 'MOD11A2.006_2017182_to_2017212/MOD11A2.006_QC_Day_doy2017185_aid0001.tif',
   'file_size': 4167,
   'file_type': 'tif',
   'sha256': 'fd51d505ea5ad3e151852579f57f3dbcac2f6dd6ad70143937699899a251babd'},
  {'file_id': '0641bff4-b261-4d02-bbb7-77e8a2690685',
   'file_name': 'MOD11A2.006_2017182_to_2017212/MOD11A2.006_QC_Day_doy2017193_aid0001.tif',
   'file_size': 3780,
   'file_type': 'tif',
   'sha256': '938c62a176b134229f0ee116e6d4f3489a781a53bcd47843117b2e7793dcfeeb'},
  {'file_id': 'e0541de2-f55f-494a-9a0f-fa1571ee2777',
   'file_name': 'MOD11A2.006_2017182_to_2017212/MOD11A2.006_QC_Day_doy2017201_aid0001.tif',
   'file_size': 4260,
   'file_type': 'tif',
   'sha256': '3d83c6eefd76ddbe114aede0c5db08906f0ec2f01eba8b0bf0b497104616f82b'},
  {'file_id': '18e3ad78-25c6-4b8f-a26c-f8f40fe26b40',
   'file_name': 'MOD11A2.006_2017182_to_2017212/MOD11A2.006_QC_Day_doy2017209_aid0001.tif',
   'file_size': 4399,
   'file_type': 'tif',
   'sha256': 'd13eac0cd473af8a9d8042b2713c590390cb5de0ff97daeea15b1a4e910bcff6'},
  {'file_id': 'a057c0fe-8f05-4ab0-a39a-0cf64887460b',
   'file_name': 'MOD11A2.006_2017182_to_2017212/MOD11A2.006_QC_Night_doy2017185_aid0001.tif',
   'file_size': 3474,
   'file_type': 'tif',
   'sha256': '74cb18c9fa57c02d54688cc2476fc9aedb4d1212676f69f972fad44593975bb5'},
  {'file_id': 'cbf1259c-08c0-4957-88be-fbe9268345fc',
   'file_name': 'MOD11A2.006_2017182_to_2017212/MOD11A2.006_QC_Night_doy2017193_aid0001.tif',
   'file_size': 4059,
   'file_type': 'tif',
   'sha256': '12dafc4573b5c5463a87db4a2372233a3d6e65ef5951c03bb4f9b80a817ef7be'},
  {'file_id': '0c9c6a4f-aeed-429e-bc30-6a803d5dce9f',
   'file_name': 'MOD11A2.006_2017182_to_2017212/MOD11A2.006_QC_Night_doy2017201_aid0001.tif',
   'file_size': 4086,
   'file_type': 'tif',
   'sha256': '8e02bba546cf4c36b803dab5828fb17b80bf2122961c3d867c8f79c2547394ce'},
  {'file_id': 'f45cb774-9d8c-4676-8afd-70a406be371e',
   'file_name': 'MOD11A2.006_2017182_to_2017212/MOD11A2.006_QC_Night_doy2017209_aid0001.tif',
   'file_size': 4261,
   'file_type': 'tif',
   'sha256': 'a5eaa02b02f5f8684fef1fc63a292c0a980f2361bd188a544e63dd5467235edf'},
  {'file_id': '652bbdca-495e-4d03-9b44-37187606b089',
   'file_name': 'SRTMGL1.003_2017182_to_2017212/SRTMGL1.003_Band1_doy2000042_aid0001.tif',
   'file_size': 13874640,
   'file_type': 'tif',
   'sha256': 'cd847b565dc838fa9563c82b6c4f9252ded8a5d0baed4c861649e77bfca763d3'},
  {'file_id': 'd8694e31-0e23-419e-8873-0a475bf6f4c2',
   'file_name': 'SRTMGL1N.003_2017182_to_2017212/SRTMGL1N.003_Band1_doy2000042_aid0001.tif',
   'file_size': 2390131,
   'file_type': 'tif',
   'sha256': '70ec677f35b9d2d08f87050af995e5019d016df9bbfe7f5ec5569c308eda375a'},
  {'file_id': '4d59d92c-2a72-48d6-92a8-06408760f509',
   'file_name': 'MCD15A3H-006-FparLai-QC-lookup.csv',
   'file_size': 3939,
   'file_type': 'csv',
   'sha256': '2262ee6f69834f4ad0c5ac36a2122ee84518844983aa85d0f416bc4ea04af2f3'},
  {'file_id': '82bbb5fc-81ee-4bc6-aef1-c38dbc0039e8',
   'file_name': 'MOD11A2-006-QC-Day-lookup.csv',
   'file_size': 516,
   'file_type': 'csv',
   'sha256': '67d369219e0835b556cbf67b20f97b1554f886835c758c8302e9d13610ace36c'},
  {'file_id': '54e95aa3-cdfb-462b-9b1c-f38433348005',
   'file_name': 'MOD11A2-006-QC-Night-lookup.csv',
   'file_size': 631,
   'file_type': 'csv',
   'sha256': '84265a384dcc629d7e4d37b1b92c784c396bfdd8211d2b030b21840621dbf211'},
  {'file_id': 'c4bffc6b-4ae0-4c05-bd01-66b56272b802',
   'file_name': 'SRTMGL1N-003-Band1-lookup.csv',
   'file_size': 1534,
   'file_type': 'csv',
   'sha256': '906d1c5662fba410feb6721e0065a662decbaad87e0379935c0938aa9f27317e'},
  {'file_id': '3d9fd1a2-0889-4092-8624-da7c458d3292',
   'file_name': 'MCD15A3H-006-FparLai-QC-Statistics-QA.csv',
   'file_size': 767,
   'file_type': 'csv',
   'sha256': 'bce048196c5b52ab20bbbd413316849e63cc504a44b566502390103ee69aea41'},
  {'file_id': 'f645c9f0-d78c-41bd-b9e4-d090a7c397f5',
   'file_name': 'MOD11A2-006-QC-Day-Statistics-QA.csv',
   'file_size': 245,
   'file_type': 'csv',
   'sha256': 'f2f8674fd2c69469d0c6832e760dbad530233ee0a0eedd73adbe8d874e9d3e9a'},
  {'file_id': '40d70eb7-7f11-4939-b88c-25ee7e543378',
   'file_name': 'MOD11A2-006-QC-Night-Statistics-QA.csv',
   'file_size': 268,
   'file_type': 'csv',
   'sha256': '32c62684e06bfd1f3e012567427863dd51388a63dec74eae29efa503684a6740'},
  {'file_id': 'd35c4e8e-500d-4b65-9475-6322398bf1c0',
   'file_name': 'SRTMGL1N-003-Band1-Statistics-QA.csv',
   'file_size': 546,
   'file_type': 'csv',
   'sha256': 'b8d34e627d6a6a5286c9524a1560e5648490003040f706240000d031a32869ac'},
  {'file_id': '8373241c-8ed2-4a5e-aeb1-df3a35387aac',
   'file_name': 'MCD15A3H-006-Statistics.csv',
   'file_size': 1113,
   'file_type': 'csv',
   'sha256': 'ecb036c2e7ad9c3f5485c4b1e748b9afca75de07bedf8c2cdfbbcf5f3adc46d5'},
  {'file_id': 'af85254a-2d3b-4b64-a064-5aa1241ba2d9',
   'file_name': 'MOD11A2-006-Statistics.csv',
   'file_size': 1521,
   'file_type': 'csv',
   'sha256': '82dcac4dfaf6fe3f05a9067422be390bdf36f6ebb437ca4ff4ef1b7096d8c896'},
  {'file_id': '10c4aca8-e32d-40fd-bad9-1cf3035ca641',
   'file_name': 'SRTMGL1-003-Statistics.csv',
   'file_size': 320,
   'file_type': 'csv',
   'sha256': '54fa76cee411fd221697f63ea7ebd8146507b36e13b7ae56ee2f50a015caa77c'},
  {'file_id': 'a45c879a-5aa7-405c-85b0-3fbf193d12a1',
   'file_name': 'NPS-Vegetation-Area-granule-list.txt',
   'file_size': 4046,
   'file_type': 'txt',
   'sha256': '27a7fe9ccc12f5d898e8604cc8d5721bf034a1daa0bb194289e032865e8cfc82'},
  {'file_id': 'ca722bcc-5e69-4892-b147-34815f75ca45',
   'file_name': 'NPS-Vegetation-Area-request.json',
   'file_size': 13613955,
   'file_type': 'json',
   'sha256': 'a702ec36e83aadb307f1278f302692205989fab7ee87c75f3a9be68564e94e5e'},
  {'file_id': '19557597-f5c1-4a31-94e1-cdaf29997b9d',
   'file_name': 'NPS-Vegetation-Area-MCD15A3H-006-metadata.xml',
   'file_size': 21326,
   'file_type': 'xml',
   'sha256': '58cd4c563a65cf40bac88a9567f2664ef0878e55ed82f71c48e5cf012acf606f'},
  {'file_id': '1a36ed71-d9ef-4918-95fb-60424014f5cb',
   'file_name': 'NPS-Vegetation-Area-MOD11A2-006-metadata.xml',
   'file_size': 21291,
   'file_type': 'xml',
   'sha256': 'bd86d03212b1380c4b29b4364255dc48e9559d4967111be3032ea9588686d399'},
  {'file_id': '631a22d7-1eae-4b93-8065-fcc180edc42e',
   'file_name': 'NPS-Vegetation-Area-SRTMGL1-003-metadata.xml',
   'file_size': 21266,
   'file_type': 'xml',
   'sha256': '96e9ea603bcd52215903cb0b4358210305a16049d2cfd36c25a51d9e53c083bf'},
  {'file_id': '18d5efbf-51da-4ba2-9dd0-65d9c1932803',
   'file_name': 'README.txt',
   'file_size': 15680,
   'file_type': 'txt',
   'sha256': '9bd05acfa6ddecd2317a841e46bf4704e5f6c9c1b7a5782da65a7ee08e379309'}],
 'task_id': '5ab03e68-9096-4c3d-a4b8-e35542129a1d',
 'updated': '2018-04-19T14:33:32.406000'}

4b. Download Files in a Request (Automation) [Download File]

Now, use the contents of the bundle to select the file name and id and store as a dictionary.

In [34]:
files = {}                                                       # Create empty dictionary
for f in bundle['files']: files[f['file_id']] = f['file_name']   # Fill dictionary with file_id as keys and file_name as values
files    
Out[34]:
{'0641bff4-b261-4d02-bbb7-77e8a2690685': 'MOD11A2.006_2017182_to_2017212/MOD11A2.006_QC_Day_doy2017193_aid0001.tif',
 '0ad89106-888f-47c3-b338-ed35612373e1': 'MOD11A2.006_2017182_to_2017212/MOD11A2.006_LST_Night_1km_doy2017185_aid0001.tif',
 '0c9c6a4f-aeed-429e-bc30-6a803d5dce9f': 'MOD11A2.006_2017182_to_2017212/MOD11A2.006_QC_Night_doy2017201_aid0001.tif',
 '10c4aca8-e32d-40fd-bad9-1cf3035ca641': 'SRTMGL1-003-Statistics.csv',
 '18d5efbf-51da-4ba2-9dd0-65d9c1932803': 'README.txt',
 '18e3ad78-25c6-4b8f-a26c-f8f40fe26b40': 'MOD11A2.006_2017182_to_2017212/MOD11A2.006_QC_Day_doy2017209_aid0001.tif',
 '19557597-f5c1-4a31-94e1-cdaf29997b9d': 'NPS-Vegetation-Area-MCD15A3H-006-metadata.xml',
 '1a36ed71-d9ef-4918-95fb-60424014f5cb': 'NPS-Vegetation-Area-MOD11A2-006-metadata.xml',
 '20520875-c158-4c96-967e-32c09784e6c6': 'MCD15A3H.006_2017182_to_2017212/MCD15A3H.006_Lai_500m_doy2017205_aid0001.tif',
 '2332a9e6-1d00-4162-a870-d136d39245fc': 'MOD11A2.006_2017182_to_2017212/MOD11A2.006_LST_Day_1km_doy2017193_aid0001.tif',
 '2cb2fdf4-f5c7-4f4e-97c1-543fe8ac5b81': 'MCD15A3H.006_2017182_to_2017212/MCD15A3H.006_Lai_500m_doy2017209_aid0001.tif',
 '3b2d5834-a9f7-44c6-9700-3aada7c579ea': 'MCD15A3H.006_2017182_to_2017212/MCD15A3H.006_FparLai_QC_doy2017197_aid0001.tif',
 '3d9fd1a2-0889-4092-8624-da7c458d3292': 'MCD15A3H-006-FparLai-QC-Statistics-QA.csv',
 '40d70eb7-7f11-4939-b88c-25ee7e543378': 'MOD11A2-006-QC-Night-Statistics-QA.csv',
 '425949c7-001d-4259-991b-748fc6fdd3e4': 'MOD11A2.006_2017182_to_2017212/MOD11A2.006_QC_Day_doy2017185_aid0001.tif',
 '466cbe55-585b-4e9e-b52f-089b2c267ed2': 'MCD15A3H.006_2017182_to_2017212/MCD15A3H.006_Lai_500m_doy2017201_aid0001.tif',
 '472efd46-c218-43c1-8580-5a04cf2027f7': 'MCD15A3H.006_2017182_to_2017212/MCD15A3H.006_FparLai_QC_doy2017185_aid0001.tif',
 '4d59d92c-2a72-48d6-92a8-06408760f509': 'MCD15A3H-006-FparLai-QC-lookup.csv',
 '51d666d8-1a62-4a2e-b312-ab30349f18a0': 'MOD11A2.006_2017182_to_2017212/MOD11A2.006_LST_Day_1km_doy2017185_aid0001.tif',
 '54e95aa3-cdfb-462b-9b1c-f38433348005': 'MOD11A2-006-QC-Night-lookup.csv',
 '631a22d7-1eae-4b93-8065-fcc180edc42e': 'NPS-Vegetation-Area-SRTMGL1-003-metadata.xml',
 '652bbdca-495e-4d03-9b44-37187606b089': 'SRTMGL1.003_2017182_to_2017212/SRTMGL1.003_Band1_doy2000042_aid0001.tif',
 '79ec947e-e9bd-4898-89f0-c643bbc72c6a': 'MCD15A3H.006_2017182_to_2017212/MCD15A3H.006_Lai_500m_doy2017197_aid0001.tif',
 '82bbb5fc-81ee-4bc6-aef1-c38dbc0039e8': 'MOD11A2-006-QC-Day-lookup.csv',
 '8373241c-8ed2-4a5e-aeb1-df3a35387aac': 'MCD15A3H-006-Statistics.csv',
 '90b38902-53d3-49c4-8f5b-992534d33c30': 'MCD15A3H.006_2017182_to_2017212/MCD15A3H.006_Lai_500m_doy2017185_aid0001.tif',
 '90d11971-a02e-4fdb-84b4-d4d638b67df9': 'MCD15A3H.006_2017182_to_2017212/MCD15A3H.006_FparLai_QC_doy2017189_aid0001.tif',
 '9391cd86-9c58-4837-8b61-cd9db3634e91': 'MOD11A2.006_2017182_to_2017212/MOD11A2.006_LST_Day_1km_doy2017201_aid0001.tif',
 '9b4dba8a-8038-41cf-a72c-d226dc589ca9': 'MCD15A3H.006_2017182_to_2017212/MCD15A3H.006_FparLai_QC_doy2017205_aid0001.tif',
 '9e89e081-0f61-4031-88af-07e6ed17ea57': 'MCD15A3H.006_2017182_to_2017212/MCD15A3H.006_Lai_500m_doy2017193_aid0001.tif',
 'a057c0fe-8f05-4ab0-a39a-0cf64887460b': 'MOD11A2.006_2017182_to_2017212/MOD11A2.006_QC_Night_doy2017185_aid0001.tif',
 'a45c879a-5aa7-405c-85b0-3fbf193d12a1': 'NPS-Vegetation-Area-granule-list.txt',
 'a51bc12d-f81d-490a-b1d3-f0f42b5a3506': 'MOD11A2.006_2017182_to_2017212/MOD11A2.006_LST_Day_1km_doy2017209_aid0001.tif',
 'a5270a27-f29b-4ddf-9787-73ac1cbe6b69': 'MCD15A3H.006_2017182_to_2017212/MCD15A3H.006_FparLai_QC_doy2017201_aid0001.tif',
 'af85254a-2d3b-4b64-a064-5aa1241ba2d9': 'MOD11A2-006-Statistics.csv',
 'c4bffc6b-4ae0-4c05-bd01-66b56272b802': 'SRTMGL1N-003-Band1-lookup.csv',
 'c85a4f58-2f42-4453-9d79-58abda51e87f': 'MOD11A2.006_2017182_to_2017212/MOD11A2.006_LST_Night_1km_doy2017193_aid0001.tif',
 'c96cfb13-8cb0-4635-a710-31406e70a1aa': 'MOD11A2.006_2017182_to_2017212/MOD11A2.006_LST_Night_1km_doy2017209_aid0001.tif',
 'ca722bcc-5e69-4892-b147-34815f75ca45': 'NPS-Vegetation-Area-request.json',
 'cbf1259c-08c0-4957-88be-fbe9268345fc': 'MOD11A2.006_2017182_to_2017212/MOD11A2.006_QC_Night_doy2017193_aid0001.tif',
 'ce9a91a2-0115-46ae-a16d-d26199542fbf': 'MCD15A3H.006_2017182_to_2017212/MCD15A3H.006_FparLai_QC_doy2017209_aid0001.tif',
 'ced62b05-5c6e-4cc8-91eb-7baa3d3516f4': 'MCD15A3H.006_2017182_to_2017212/MCD15A3H.006_Lai_500m_doy2017189_aid0001.tif',
 'd35c4e8e-500d-4b65-9475-6322398bf1c0': 'SRTMGL1N-003-Band1-Statistics-QA.csv',
 'd8694e31-0e23-419e-8873-0a475bf6f4c2': 'SRTMGL1N.003_2017182_to_2017212/SRTMGL1N.003_Band1_doy2000042_aid0001.tif',
 'e0541de2-f55f-494a-9a0f-fa1571ee2777': 'MOD11A2.006_2017182_to_2017212/MOD11A2.006_QC_Day_doy2017201_aid0001.tif',
 'f0c11af2-b02e-4883-b3d9-144704e7bb2b': 'MCD15A3H.006_2017182_to_2017212/MCD15A3H.006_FparLai_QC_doy2017193_aid0001.tif',
 'f45cb774-9d8c-4676-8afd-70a406be371e': 'MOD11A2.006_2017182_to_2017212/MOD11A2.006_QC_Night_doy2017209_aid0001.tif',
 'f645c9f0-d78c-41bd-b9e4-d090a7c397f5': 'MOD11A2-006-QC-Day-Statistics-QA.csv',
 'fccca1b0-8302-4794-b2a6-e219440ba790': 'MOD11A2.006_2017182_to_2017212/MOD11A2.006_LST_Night_1km_doy2017201_aid0001.tif'}

Use the files dictionary and a for loop to automate downloading all of the output files into the output directory.

In [35]:
for f in files:
    dl = r.get('{}bundle/{}/{}'.format(api, task_id, f), stream=True)                                # Get a stream to the bundle file
    filename = os.path.basename(cgi.parse_header(dl.headers['Content-Disposition'])[1]['filename'])  # Parse the name from Content-Disposition header 
    filepath = os.path.join(destDir, filename)                                                       # Create output file path
    with open(filepath, 'wb') as f:                                                                  # Write file to dest dir
        for data in dl.iter_content(chunk_size=8192): f.write(data) 
print('Downloaded files can be found at: {}'.format(destDir))
Downloaded files can be found at: C:/Users/ckrehbiel/Documents/appeears-api-getting-started/NPS Vegetation Area

5. Explore AρρEEARS Quality Service [Quality API]

The quality API provides quality details about all of the data products available in AρρEEARS. Below are examples of how to query the quality API for listing quality products, layers, and values. The final example (Section 5c.) demonstrates how AρρEEARS quality services can be leveraged to decode pertinent quality values for your data.

First, reset pagination to include offset which allows you to set the number of results to skip before starting to return entries. Next, make a call to list all of the data product layers and the associated quality product and layer information.

In [36]:
params = {'limit': 6, 'pretty': True, 'offset': 20}                     # Limit response to 6 entries, start w/ 20th entry, return pretty json
quality_response = r.get('{}quality'.format(api), params=params).json() # Call quality API using pagination and return json
quality_response                                                        # Print response
Out[36]:
[{'Layer': 'Fpar_500m',
  'ProductAndVersion': 'MCD15A2H.006',
  'QualityLayers': ['FparLai_QC'],
  'QualityProductAndVersion': 'MCD15A2H.006'},
 {'Layer': 'Lai_500m',
  'ProductAndVersion': 'MCD15A2H.006',
  'QualityLayers': ['FparLai_QC'],
  'QualityProductAndVersion': 'MCD15A2H.006'},
 {'Layer': 'Fpar_1km',
  'ProductAndVersion': 'MCD15A3.005',
  'QualityLayers': ['FparLai_QC'],
  'QualityProductAndVersion': 'MCD15A3.005'},
 {'Layer': 'Lai_1km',
  'ProductAndVersion': 'MCD15A3.005',
  'QualityLayers': ['FparLai_QC'],
  'QualityProductAndVersion': 'MCD15A3.005'},
 {'Layer': 'Fpar_500m',
  'ProductAndVersion': 'MCD15A3H.006',
  'QualityLayers': ['FparLai_QC'],
  'QualityProductAndVersion': 'MCD15A3H.006'},
 {'Layer': 'Lai_500m',
  'ProductAndVersion': 'MCD15A3H.006',
  'QualityLayers': ['FparLai_QC'],
  'QualityProductAndVersion': 'MCD15A3H.006'}]

5a. List Quality Layers [List Quality Layers]

This API call will list all of the quality layer information for a product.

In [37]:
product = 'MCD15A3H.006'                                        # Product used in the example
ql_response = r.get('{}quality/{}'.format(api,product)).json()  # Call API to retrieve quality layers for selected product
ql_response                                                     # Print response
Out[37]:
[{'Layer': 'Fpar_500m',
  'ProductAndVersion': 'MCD15A3H.006',
  'QualityLayers': ['FparLai_QC'],
  'QualityProductAndVersion': 'MCD15A3H.006'},
 {'Layer': 'Lai_500m',
  'ProductAndVersion': 'MCD15A3H.006',
  'QualityLayers': ['FparLai_QC'],
  'QualityProductAndVersion': 'MCD15A3H.006'}]

5b. Show Quality Values [List Quality Values]

This API call will list all of the values for a given quality layer.

In [38]:
qlayer = ql_response[1]['QualityLayers'][0]                                # Set quality layer from ql_response for 'Lai_500m'
qv_response = r.get('{}quality/{}/{}'.format(api, product, qlayer)).json() # Call API for list of bit-word quality values
qv_response                                                                # Print response
Out[38]:
[{'Acceptable': True,
  'Description': 'Good quality (main algorithm with or without saturation)',
  'Name': 'MODLAND',
  'ProductAndVersion': 'MCD15A3H.006',
  'QualityLayer': 'FparLai_QC',
  'Value': 0},
 {'Acceptable': False,
  'Description': 'Other Quality (back-up algorithm or fill values)',
  'Name': 'MODLAND',
  'ProductAndVersion': 'MCD15A3H.006',
  'QualityLayer': 'FparLai_QC',
  'Value': 1},
 {'Acceptable': None,
  'Description': 'Terra',
  'Name': 'Sensor',
  'ProductAndVersion': 'MCD15A3H.006',
  'QualityLayer': 'FparLai_QC',
  'Value': 0},
 {'Acceptable': None,
  'Description': 'Aqua',
  'Name': 'Sensor',
  'ProductAndVersion': 'MCD15A3H.006',
  'QualityLayer': 'FparLai_QC',
  'Value': 1},
 {'Acceptable': None,
  'Description': 'Detectors apparently fine for up to 50% of channels 1, 2',
  'Name': 'DeadDetector',
  'ProductAndVersion': 'MCD15A3H.006',
  'QualityLayer': 'FparLai_QC',
  'Value': 0},
 {'Acceptable': None,
  'Description': 'Dead detectors caused >50% adjacent detector retrieval',
  'Name': 'DeadDetector',
  'ProductAndVersion': 'MCD15A3H.006',
  'QualityLayer': 'FparLai_QC',
  'Value': 1},
 {'Acceptable': None,
  'Description': 'Significant clouds NOT present (clear)',
  'Name': 'CloudState',
  'ProductAndVersion': 'MCD15A3H.006',
  'QualityLayer': 'FparLai_QC',
  'Value': 0},
 {'Acceptable': None,
  'Description': 'Significant clouds WERE present',
  'Name': 'CloudState',
  'ProductAndVersion': 'MCD15A3H.006',
  'QualityLayer': 'FparLai_QC',
  'Value': 1},
 {'Acceptable': None,
  'Description': 'Mixed cloud present in pixel',
  'Name': 'CloudState',
  'ProductAndVersion': 'MCD15A3H.006',
  'QualityLayer': 'FparLai_QC',
  'Value': 2},
 {'Acceptable': None,
  'Description': 'Cloud state not defined, assumed clear',
  'Name': 'CloudState',
  'ProductAndVersion': 'MCD15A3H.006',
  'QualityLayer': 'FparLai_QC',
  'Value': 3},
 {'Acceptable': None,
  'Description': 'Main (RT) method used, best result possible (no saturation)',
  'Name': 'SCF_QC',
  'ProductAndVersion': 'MCD15A3H.006',
  'QualityLayer': 'FparLai_QC',
  'Value': 0},
 {'Acceptable': None,
  'Description': 'Main (RT) method used with saturation. Good, very usable',
  'Name': 'SCF_QC',
  'ProductAndVersion': 'MCD15A3H.006',
  'QualityLayer': 'FparLai_QC',
  'Value': 1},
 {'Acceptable': None,
  'Description': 'Main (RT) method failed due to bad geometry, empirical algorithm used',
  'Name': 'SCF_QC',
  'ProductAndVersion': 'MCD15A3H.006',
  'QualityLayer': 'FparLai_QC',
  'Value': 2},
 {'Acceptable': None,
  'Description': 'Main (RT) method failed due to problems other than geometry, empirical algorithm used',
  'Name': 'SCF_QC',
  'ProductAndVersion': 'MCD15A3H.006',
  'QualityLayer': 'FparLai_QC',
  'Value': 3},
 {'Acceptable': None,
  'Description': "Pixel not produced at all, value couldn't be retrieved (possible reasons: bad L1B data, unusable MOD09GA data)",
  'Name': 'SCF_QC',
  'ProductAndVersion': 'MCD15A3H.006',
  'QualityLayer': 'FparLai_QC',
  'Value': 4}]

5c. Decode Quality Values [Decode Quality Values]

This API call will decode the bits for a given quality value.

In [39]:
val = 1                                                                            # Set a specific value
q_response = r.get('{}quality/{}/{}/{}'.format(api, product, qlayer, val)).json()  # Call quality API for specific value
q_response                                                                         # Print response
Out[39]:
{'Binary Representation': '0b00000001',
 'CloudState': {'bits': '0b00',
  'description': 'Significant clouds NOT present (clear)'},
 'DeadDetector': {'bits': '0b0',
  'description': 'Detectors apparently fine for up to 50% of channels 1, 2'},
 'MODLAND': {'bits': '0b1',
  'description': 'Other Quality (back-up algorithm or fill values)'},
 'SCF_QC': {'bits': '0b000',
  'description': 'Main (RT) method used, best result possible (no saturation)'},
 'Sensor': {'bits': '0b0', 'description': 'Terra'}}

6. BONUS: Import Request Output and Visualize

Here, import one of the output GeoTIFFs and show some basic visualizations using the matplotlib package.

In [40]:
# Import packages
import matplotlib.pyplot as plt
import numpy as np
from osgeo import gdal
list(files.values())  # List files downloaded
Out[40]:
['MCD15A3H.006_2017182_to_2017212/MCD15A3H.006_Lai_500m_doy2017185_aid0001.tif',
 'MCD15A3H.006_2017182_to_2017212/MCD15A3H.006_Lai_500m_doy2017189_aid0001.tif',
 'MCD15A3H.006_2017182_to_2017212/MCD15A3H.006_Lai_500m_doy2017193_aid0001.tif',
 'MCD15A3H.006_2017182_to_2017212/MCD15A3H.006_Lai_500m_doy2017197_aid0001.tif',
 'MCD15A3H.006_2017182_to_2017212/MCD15A3H.006_Lai_500m_doy2017201_aid0001.tif',
 'MCD15A3H.006_2017182_to_2017212/MCD15A3H.006_Lai_500m_doy2017205_aid0001.tif',
 'MCD15A3H.006_2017182_to_2017212/MCD15A3H.006_Lai_500m_doy2017209_aid0001.tif',
 'MCD15A3H.006_2017182_to_2017212/MCD15A3H.006_FparLai_QC_doy2017185_aid0001.tif',
 'MCD15A3H.006_2017182_to_2017212/MCD15A3H.006_FparLai_QC_doy2017189_aid0001.tif',
 'MCD15A3H.006_2017182_to_2017212/MCD15A3H.006_FparLai_QC_doy2017193_aid0001.tif',
 'MCD15A3H.006_2017182_to_2017212/MCD15A3H.006_FparLai_QC_doy2017197_aid0001.tif',
 'MCD15A3H.006_2017182_to_2017212/MCD15A3H.006_FparLai_QC_doy2017201_aid0001.tif',
 'MCD15A3H.006_2017182_to_2017212/MCD15A3H.006_FparLai_QC_doy2017205_aid0001.tif',
 'MCD15A3H.006_2017182_to_2017212/MCD15A3H.006_FparLai_QC_doy2017209_aid0001.tif',
 'MOD11A2.006_2017182_to_2017212/MOD11A2.006_LST_Day_1km_doy2017185_aid0001.tif',
 'MOD11A2.006_2017182_to_2017212/MOD11A2.006_LST_Day_1km_doy2017193_aid0001.tif',
 'MOD11A2.006_2017182_to_2017212/MOD11A2.006_LST_Day_1km_doy2017201_aid0001.tif',
 'MOD11A2.006_2017182_to_2017212/MOD11A2.006_LST_Day_1km_doy2017209_aid0001.tif',
 'MOD11A2.006_2017182_to_2017212/MOD11A2.006_LST_Night_1km_doy2017185_aid0001.tif',
 'MOD11A2.006_2017182_to_2017212/MOD11A2.006_LST_Night_1km_doy2017193_aid0001.tif',
 'MOD11A2.006_2017182_to_2017212/MOD11A2.006_LST_Night_1km_doy2017201_aid0001.tif',
 'MOD11A2.006_2017182_to_2017212/MOD11A2.006_LST_Night_1km_doy2017209_aid0001.tif',
 'MOD11A2.006_2017182_to_2017212/MOD11A2.006_QC_Day_doy2017185_aid0001.tif',
 'MOD11A2.006_2017182_to_2017212/MOD11A2.006_QC_Day_doy2017193_aid0001.tif',
 'MOD11A2.006_2017182_to_2017212/MOD11A2.006_QC_Day_doy2017201_aid0001.tif',
 'MOD11A2.006_2017182_to_2017212/MOD11A2.006_QC_Day_doy2017209_aid0001.tif',
 'MOD11A2.006_2017182_to_2017212/MOD11A2.006_QC_Night_doy2017185_aid0001.tif',
 'MOD11A2.006_2017182_to_2017212/MOD11A2.006_QC_Night_doy2017193_aid0001.tif',
 'MOD11A2.006_2017182_to_2017212/MOD11A2.006_QC_Night_doy2017201_aid0001.tif',
 'MOD11A2.006_2017182_to_2017212/MOD11A2.006_QC_Night_doy2017209_aid0001.tif',
 'SRTMGL1.003_2017182_to_2017212/SRTMGL1.003_Band1_doy2000042_aid0001.tif',
 'SRTMGL1N.003_2017182_to_2017212/SRTMGL1N.003_Band1_doy2000042_aid0001.tif',
 'MCD15A3H-006-FparLai-QC-lookup.csv',
 'MOD11A2-006-QC-Day-lookup.csv',
 'MOD11A2-006-QC-Night-lookup.csv',
 'SRTMGL1N-003-Band1-lookup.csv',
 'MCD15A3H-006-FparLai-QC-Statistics-QA.csv',
 'MOD11A2-006-QC-Day-Statistics-QA.csv',
 'MOD11A2-006-QC-Night-Statistics-QA.csv',
 'SRTMGL1N-003-Band1-Statistics-QA.csv',
 'MCD15A3H-006-Statistics.csv',
 'MOD11A2-006-Statistics.csv',
 'SRTMGL1-003-Statistics.csv',
 'NPS-Vegetation-Area-granule-list.txt',
 'NPS-Vegetation-Area-request.json',
 'NPS-Vegetation-Area-MCD15A3H-006-metadata.xml',
 'NPS-Vegetation-Area-MOD11A2-006-metadata.xml',
 'NPS-Vegetation-Area-SRTMGL1-003-metadata.xml',
 'README.txt']

6a. Import a GeoTIFF

To perform the next step below, you will need to have GDAL installed on your OS. Open the GeoTIFF file for the SRTM DEM, and read in as an array.

In [41]:
dem = gdal.Open(destDir + '/SRTMGL1.003_Band1_doy2000042_aid0001.tif' ) # Read file in
demBand = dem.GetRasterBand(1)                                          # Read the band (layer)
demData = demBand.ReadAsArray().astype('float')                         # Import band as an array with type float

Next, query the metadata for the fill value, and set fill value equal to nan.

In [42]:
demFill = demBand.GetNoDataValue()            # Returns fill value
demData[demData == demFill] = np.nan          # Set fill value to nan

6b. Plot a GeoTIFF

In this section, begin by highlighting the functionality of the matplotlib plotting package.

In [43]:
# Set matplotlib plots inline
%matplotlib inline 

First, make a basic plot of the DEM data.

In [44]:
plt.imshow(demData);  # Visualize a basic plot of the DEM data

Next, add some additional parameters to the plot.

In [45]:
fig = plt.figure(figsize = (10,7.5))  # Set the figure size (x,y)
plt.axis('off')                       # Remove the axes' values
ax = fig.add_subplot(111)             

# Plot the array, using a colormap and setting a custom linear stretch based on the min/max Elevation values
plt.imshow(demData, vmin = np.nanmin(demData), vmax = np.nanmax(demData), cmap = 'terrain');

Finally, add important map items including a legend and title.

In [46]:
plt.style.use("dark_background")                                                       # Default to a black background
fig2 = plt.figure(figsize=(10,7.5))                                                    # Set the figure size
plt.axis('off')                                                                        # Remove the axes' values
ax1 = fig2.add_subplot(111)                                                            # Make a subplot
fig2.subplots_adjust(top=3.8)                                                          # Adjust spacing
ax1.set_title('SRTM DEM: Grand Canyon NP',fontsize=15,fontweight='bold',color='white') # Add title

# Plot the masked data, using a colormap and setting a custom linear stretch based on the min/max DEM values
im = plt.imshow(demData, vmin = np.nanmin(demData), vmax = np.nanmax(demData), cmap = 'terrain');

cb = plt.colorbar(im, orientation='horizontal', fraction=0.047, pad=0.004, shrink=0.6) # Add a colormap legend
cb.set_label(label='Elevation (m)', color = 'white')                                   # Set Label and color
cb.outline.set_edgecolor('white')                                                      # Set edge color

This example can provide a template to use for your own research workflows. Leveraging the AρρEEARS API for searching, extracting, and formatting analysis ready data, and importing it directly into Python means that you can keep your entire research workflow in a single software program, from start to finish.


Contact Information

Material written by Cole Krehbiel$^{1}$

Contact: LPDAAC@usgs.gov
Voice: +1-605-594-6116
Organization: Land Processes Distributed Active Archive Center (LP DAAC)
Website: https://lpdaac.usgs.gov/
Date last modified: 04-19-2018

$^{1}$Innovate! Inc., contractor to the U.S. Geological Survey, Earth Resources Observation and Science (EROS) Center, Sioux Falls, South Dakota, 57198-001, USA. Work performed under USGS contract G15PD00467 for LP DAAC$^{2}$.

$^{2}$LP DAAC Work performed under NASA contract NNG14HH33I.