Skip Navigation

MODIS

AIforEarth EarthObservation NASA SatelliteImagery USGS

Satellite imagery from the Moderate Resolution Imaging Spectroradiometer (MODIS).

MODIS provides Earth observation data in a wide spectral range, from 1999 to the present. The MODIS satellites image the Earth every one to two days, though individual products derived from MODIS data may have lower temporal resolutions. MODIS is administered by the National Aeronautics and Space Administration (NASA) and the US Geological Survey (USGS). We currently mirror the MCD43A4 (500m-resolution global daily surface reflectance) product on Azure dating back to 2000, and we will be on-boarding select additional MODIS products.

Storage resources

Data are stored in blobs in the East US data center, in the following blob container:

https://modissa.blob.core.windows.net/modis

Within that container, data are organized according to:

[product]/[htile]/[vtile]/[daynum]/[filename]

product is the MODIS product name; currently MCD43A4 is available on Azure.

htile and vtile refer to tile numbers in the MODIS sinusoidal grid system. The notebook available under “Data Access” demonstrates one way to map latitude and longitude into this grid system.

daynum is a four-digit year plus a three-digit day of year (from 001 to 365), e.g. 2019001 represents January 1, 2019.

…for example, the folder:

MCD43A4/00/08/2019010

…contains images from Jan 10, 2019.

Images are stored in GeoTIFF format, with one image per MODIS channel. The mapping from channels to spectral bands is product-specific; for MCD43A4, mappings are available here.

As per that document, spectral band 1 corresponds channel 7 for MCD43A4, so in the above directory, the file:

MCD43A4.A2019001.h00v08.006.2019010201703.hdf_07.tiff

…contains information from spectral band 1.

We also provide a read-only SAS (shared access signature) token to allow access to MODIS data via, e.g., BlobFuse, which allows you to mount blob containers as drives:

st=2019-07-26T22%3A24%3A15Z&se=2032-07-27T22%3A24%3A00Z&sp=rl&sv=2018-03-28&sr=c&sig=ENT24qUY%2BlxL93XMykFQwfq4ctHDPLmYPDaaAn7YI3Q%3D

Mounting instructions for Linux are here.

MODIS data can consume hundreds of terabytes, so large-scale processing is best performed in the East US Azure data center, where the images are stored. If you are using MODIS data for environmental science applications, consider applying for an AI for Earth grant to support your compute requirements.

Index

We will be releasing a complete inventory of MODIS images available on Azure in the coming weeks.

Contact

For questions about this dataset, contact aiforearthdatasets@microsoft.com.

Notices

MICROSOFT PROVIDES AZURE OPEN DATASETS ON AN “AS IS” BASIS. MICROSOFT MAKES NO WARRANTIES, EXPRESS OR IMPLIED, GUARANTEES OR CONDITIONS WITH RESPECT TO YOUR USE OF THE DATASETS. TO THE EXTENT PERMITTED UNDER YOUR LOCAL LAW, MICROSOFT DISCLAIMS ALL LIABILITY FOR ANY DAMAGES OR LOSSES, INCLUDING DIRECT, CONSEQUENTIAL, SPECIAL, INDIRECT, INCIDENTAL OR PUNITIVE, RESULTING FROM YOUR USE OF THE DATASETS.

This dataset is provided under the original terms that Microsoft received source data. The dataset may include data sourced from Microsoft.

Access

Available inWhen to use
Azure Notebooks

Quickly explore the dataset with Jupyter notebooks hosted on Azure or your local machine.

Select your preferred service:

Azure Notebooks

Azure Notebooks

Package: Language: Python

Demo notebook for accessing MODIS data on Azure

This notebook provides an example of accessing MODIS data from blob storage on Azure, including (1) finding the MODIS tile corresponding to a lat/lon coordinate, (2) retrieving that tile from blob storage, and (3) displaying that tile using the rasterio library.

This notebook uses the MODIS surface reflectance product as an example, but data structure and access will be the same for other MODIS product.

MODIS data are stored in the East US data center, so this notebook will run most efficiently on Azure compute located in East US. We recommend that substantial computation depending on MODIS data also be situated in East US. You don't want to download hundreds of terabytes to your laptop! If you are using MODIS data for environmental science applications, consider applying for an AI for Earth grant to support your compute requirements.

Imports and environment

In [3]:
import os
import tempfile
import numpy as np
import shutil
import urllib

import matplotlib.pyplot as plt
import rasterio
from azure.storage.blob import BlockBlobService

# Storage locations are documented at http://aka.ms/ai4edata-modis
modis_blob_root = 'http://modissa.blob.core.windows.net/modis'
modis_container_name = 'modis'
modis_account_name = 'modissa'

modis_temp_path = os.path.join(tempfile.gettempdir(),'modis')
os.makedirs(modis_temp_path,exist_ok=True)

# This file is provided by NASA; it indicates the lat/lon extents of each
# MODIS tile.
#
# The file originally comes from:
#
# https://modis-land.gsfc.nasa.gov/pdf/sn_bound_10deg.txt
modis_tile_extents_url = modis_blob_root + '/sn_bound_10deg.txt'

# Read-only shared access signature (SAS) URL for the MODIS container
modis_sas_url = 'st=2019-07-26T17%3A21%3A46Z&se=2029-07-27T17%3A21%3A00Z&sp=rl&sv=2018-03-28&sr=c&sig=1NpBV6P8SIibRcelWZyLCpIh4KFiqEzOipjKU5ZIRrQ%3D'

# Load this file into a table, where each row is (v,h,lonmin,lonmax,latmin,latmax)
modis_tile_extents = np.genfromtxt(modis_tile_extents_url,
                     skip_header = 7, 
                     skip_footer = 3)

modis_blob_service = BlockBlobService(account_name=modis_account_name,sas_token=modis_sas_url)
                                
%matplotlib inline

Functions

In [4]:
def lat_lon_to_modis_tiles(lat,lon):
    """
    Get the modis tile indices (h,v) for a given lat/lon
    
    https://www.earthdatascience.org/tutorials/convert-modis-tile-to-lat-lon/
    """
    
    found_matching_tile = False
    i = 0
    while(not found_matching_tile):
        found_matching_tile = lat >= modis_tile_extents[i, 4] \ 
        and lat <= modis_tile_extents[i, 5] \
        and lon >= modis_tile_extents[i, 2] and lon <= modis_tile_extents[i, 3]
        i += 1
        
    v = int(modis_tile_extents[i-1, 0])
    h = int(modis_tile_extents[i-1, 1])
    
    return h,v


def list_blobs_in_folder(container_name,folder_name):
    """
    List all blobs in a virtual folder in an Azure blob container
    """
    
    files = []
    generator = modis_blob_service.list_blobs(modis_container_name, prefix=folder_name, delimiter="")
    for blob in generator:
        files.append(blob.name)
    return files
        
    
def list_tiff_blobs_in_folder(container_name,folder_name):
    """"
    List .tiff files in a folder
    """
    
    files = list_blobs_in_folder(container_name,folder_name)
    files = [fn for fn in files if fn.endswith('.tiff')]
    return files
             

def download_url(url, destination_filename):
    """
    Utility function for downloading a URL to a local file
    """
    
    print('Downloading file {}'.format(os.path.basename(url)),end='')
    urllib.request.urlretrieve(url, destination_filename)  
    assert(os.path.isfile(destination_filename))
    nBytes = os.path.getsize(destination_filename)
    print('...done, {} bytes.'.format(nBytes))
    

def download_url_to_temp_file(url):
    fn = os.path.join(modis_temp_path,next(tempfile._get_candidate_names()))
    download_url(url,fn)
    return fn

Access and plot a MODIS tile

In [5]:
# Files are stored according to:
#
# http://modissa.blob.core.windows.net/[product]/[htile]/[vtile]/[year][day]/filename

# Surface reflectance
product = 'MCD43A4'

# Let's look at the tile containing Chicago, IL, on May 15, 2019 (day of year 135)
h,v = lat_lon_to_modis_tiles(41.881832,-87.623177)
daynum = '2019135'
folder = product + '/' + '{:0>2d}/{:0>2d}'.format(h,v) + '/' + daynum

# Find all .tiff files from this tile on this day, one file per channel
files = list_tiff_blobs_in_folder(modis_container_name,folder)

norm_value = 4000

# Channel 7 in a MCD43A4 file corresponds to MODIS band 1.  
#
# Let's map bands 1, 4, and 3 (channels 7,10,9) to RGB.
channels = [7,10,9]
image_data = []
for ifn in channels:
    remote_fn = files[ifn]
    url = modis_blob_root + '/' + remote_fn
    fn = download_url_to_temp_file(url)
    raster = rasterio.open(fn,'r')
    band_array = raster.read(1)
    raster.close()
    band_array = band_array / norm_value
    image_data.append(band_array)
rgb = np.dstack((image_data[0],image_data[1],image_data[2]))
np.clip(rgb,0,1,rgb)
plt.imshow(rgb)
Downloading file MCD43A4.A2019135.h11v04.006.2019149220457.hdf_08.tiff...done, 11546274 bytes.
Downloading file MCD43A4.A2019135.h11v04.006.2019149220457.hdf_11.tiff...done, 11546274 bytes.
Downloading file MCD43A4.A2019135.h11v04.006.2019149220457.hdf_10.tiff...done, 11546274 bytes.
Out[5]:
<matplotlib.image.AxesImage at 0x1f8f82ca710>

Clean up temporary files

In [6]:
shutil.rmtree(modis_temp_path)