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.
Connect to the AρρEEARS API, query the list of available products, submit a point sample request, download the request, become familiar with the AρρEEARS Quality API, and import the results into Python for visualization. AρρEEARS point requests allow users to subset their desired data using latitude/longitude geographic coordinate pairs (points) for a time period of interest, and for specific data layers within data products. AρρEEARS returns the valid data from the parameters defined within the sample request.
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.
# Import packages
import requests as r
import getpass, pprint, time, os, cgi
# Set input directory, change working directory
inDir = 'D:/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
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
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.¶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
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 AρρEEARS
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
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
MCD15A3H.006
.¶prods = ['MCD15A3H.006'] # Start a list for products to be requested, beginning with MCD15A3H.006
prods.append('MOD11A2.006') # Append MOD11A2.006 8 day LST product to the list of products desired
prods # Print list
ProductAndVersion
property. For a list of the layer names only, print the keys from the dictionary below.¶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())
'LST_Day_1km'
to see the information for that layer in the response.¶lst_response['LST_Day_1km'] # Print layer response
layers = [(prods[1],'LST_Day_1km'),(prods[1],'LST_Night_1km')] # Create tupled list linking desired product with desired layers
MCD15A3H.006
product.¶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
lai_response['Lai_500m']['Description'] # Make sure the correct layer is requested
layers.append((prods[0],'Lai_500m')) # Append to tupled list linking desired product with desired layers
prodLayer = []
for l in layers:
prodLayer.append({
"layer": l[1],
"product": l[0]
})
prodLayer
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 request
task_name = input('Enter a Task Name: ') # User-defined name of the task 'NPS Vegetation' used here
task_type = ['point','area'] # Type of task, area or point
startDate = '01-01-2017' # Start of the date range for which to extract data: MM-DD-YYYY
endDate = '12-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
id
and category
properties to further identify your selected coordinates.¶coordinates = [{
"id": "0",
"longitude": "-112.127134",
"latitude": "36.206228",
"category": "Grand Canyon"
}, {
"id": "1",
"longitude": "-112.973760",
"latitude": "37.289327",
"category": "Zion"
}]
task = {
'task_type': task_type[0],
'task_name': task_name,
'params': {
'dates': [
{
'startDate': startDate,
'endDate': endDate
}],
'layers': prodLayer,
'coordinates': coordinates
}
}
pprint.pprint(task)
task
json created above.¶task_response = r.post('{}task'.format(api), json=task, headers=head).json() # Post json to API task service, return response as json
task_response # Print task response
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.¶params = {'limit': 2, 'pretty': True} # Limit API response to 2 most recent entries, return as pretty json
tasks_response = r.get('{}task'.format(api),params = params, headers=head).json() # Query task service setting params & header
tasks_response # Print tasks response
task_response
that was generated when submitting your request, and use the AρρEEARS API status service to check the status of your request.¶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 w/ specific task ID & username
status_response # Print response
# 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'])
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
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
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 # Print dictionary
files
dictionary and a for
loop to automate downloading all of the output files into the output directory.¶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 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))
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.¶params = {'limit': 6, 'pretty': True, 'offset': 20} # Limit 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
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
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
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
# Import Packages
import matplotlib.pyplot as plt
import pandas as pd
import numpy as np
list(files.values()) # List files downloaded
df = pd.read_csv(os.path.join(destDir,'NPS-Vegetation-MOD11A2-006-results.csv')) # Import CSV to a Pandas dataframe
df.columns # Print dataframe column names
lstDay_GC = df['MOD11A2_006_LST_Day_1km'][df.Category == 'Grand Canyon'] # Filter df for the pixel from GC, only keep LST Day 1 km column
dates = df['Date'] # Create list of dates
lst_response.keys() # Print response of product service call from earlier in the tutorial
lst_response['LST_Day_1km'] # Print product information service for the desired layer
lstFill = lst_response['LST_Day_1km']['FillValue'] # Set fill value
units = lst_response['LST_Day_1km']['Units'] # Set units
# Set matplotlib plots inline
%matplotlib inline
plt.style.use("dark_background") # Set default background to black instead of white
fig = plt.figure(1, figsize=(25, 7.5)) # Set the figure size
ax = fig.add_subplot(111) # Create a subplot
ax.plot(lstDay_GC[lstDay_GC!=lstFill], 'k', lw=2.5, color='#1f77b4') # Filter out fill values and plot as blue line
ax.plot(lstDay_GC[lstDay_GC!=lstFill], 'bo', ms=10, color='#1f77b4', alpha = 0.5) # Filter out fill values and plot as blue circle
ax.set_xticks((np.arange(0,len(lstDay_GC)))) # Set the x ticks
ax.set_xticklabels(dates, rotation=45,fontsize=10) # Set the x tick labels
ax.set_yticks((np.arange(250,325, 10))) # Arrange the y ticks
ax.set_yticklabels(np.arange(250,325, 10),fontsize=12,fontweight='bold') # Set the Y tick labels
ax.set_xlabel('Date',fontsize=16,fontweight='bold') # Set x-axis label
ax.set_ylabel("{}({})".format('LST_Day_1km', units),fontsize=16,fontweight='bold') # Set y-axis label
ax.set_title('Time Series',fontsize=20,fontweight='bold'); # Set title
LST_Day_1km
and LST_Night_1km
.¶lstNight_GC = df['MOD11A2_006_LST_Night_1km'][df.Category == 'Grand Canyon'] # Filter df for pixel from GC, only keep LST Night
fig = plt.figure(1, figsize=(25, 7.5)) # Set the figure size
plt.style.use("dark_background") # Set default background to black instead of white
ax = fig.add_subplot(111) # Create a subplot
ax.plot(lstDay_GC[lstDay_GC!=lstFill], 'k', lw=2.5, color='#1f77b4') # Filter out fill values and plot as a blue line
ax.plot(lstNight_GC[lstNight_GC!=lstFill], 'k', lw=2.5, color='#e60000') # Filter out fill values and plot as a red line
ax.legend(('LST_Day_1km', 'LST_Night_1km'),loc='upper left') # Add a legend
ax.plot(lstDay_GC[lstDay_GC!=lstFill], 'bo', ms=10, color='#1f77b4', alpha = 0.5) # Filter out fill values and plot as a blue circle
ax.plot(lstNight_GC[lstNight_GC!=lstFill], 'bo', ms=10, color='#e60000', alpha = 0.5) # Filter out fill values and plot as a red circle
ax.set_xticks((np.arange(0,len(lstDay_GC)))) # Set the x ticks
ax.set_xticklabels(dates, rotation=45,fontsize=10) # Set the x tick labels
ax.set_yticks((np.arange(250,325, 10))) # Arrange the y ticks
ax.set_yticklabels(np.arange(250,325, 10),fontsize=12,fontweight='bold') # Set the Y tick labels
ax.set_xlabel('Date',fontsize=16,fontweight='bold') # Set x-axis label
ax.set_ylabel("{}({})".format('LST_Day_1km', units),fontsize=16,fontweight='bold') # Set y-axis label
ax.set_title('Daytime and Nighttime LST at Grand Canyon NP',fontsize=20,fontweight='bold'); # Set title
matplotlib
.¶lstDay_Z = df['MOD11A2_006_LST_Day_1km'][df.Category == 'Zion'] # Filter for pixel from Zion, only keep LST Day
lstDay_Z[lstDay_Z==lstFill] = np.nan # Set fill values = nan for plotting purposes
lstDay_GC[lstDay_GC==lstFill] = np.nan # Set fill values = nan for plotting purposes
fig = plt.figure(1, figsize=(10, 7.5)) # Set the figure size
plt.style.use("dark_background") # Set default background to black
fig.suptitle('MODIS LST: Grand Canyon vs. Zion National Park, 2017',fontsize=20,fontweight='bold') # Add a title for the plot
ax = fig.add_subplot(111) # Add subplot
ax.set_ylabel("{} {} ({})".format('Grand Canyon:','LST_Day_1km',units),fontsize=16,fontweight='bold') # Set y-axis label
ax.set_xlabel("{} {} ({})".format('Zion:','LST_Day_1km', units),fontsize=16,fontweight='bold') # Set x-axis label
ax.scatter(lstDay_GC, lstDay_Z , alpha=1, c='#1f77b4', edgecolors='none', s=50, label="LST_Day"); # Plot values for both points
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-28-2020
$^{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.