Search code examples
gisgoogle-earth-enginesatellite-image

How to calculate SAVI with MODIS in Google Earth Engine (Getting Error: Image.select: Pattern 'B2' did not match any bands.)


I am trying to calculate SAVI vegetation index using MODIS data. But I am getting an error showing:

Image.select: Pattern 'B2' did not match any bands.

Code:

countries = ee.FeatureCollection("USDOS/LSIB_SIMPLE/2017")
canada = countries.filter(ee.Filter.eq("country_na", "Canada"))
image = ee.ImageCollection("MODIS/061/MOD09A1")\
            .filterDate('2017-01-01','2017-12-31')\
            .filter(ee.Filter.lt('CLOUDY_PIXEL_PERCENTAGE',10))\
            .filterBounds(canada)\
            .median()\
            .clip(canada)

savi = image.expression(
    '1.5*((NIR-RED)/(NIR+RED+0.5))',{
        'NIR':image.select('B2'),
        'RED':image.select('B1')
    }).rename('savi')

saviVis = {'min':0.0, 'max':1, 'palette':['yellow', 'green']}
Map = geemap.Map()
Map.addLayer(savi, saviVis, 'SAVI')
Map

Why am I getting this error? Isn't B1 designated to Red and B2 to NIR?


Solution

  • The general thing to do when you hit this type of problem is to start examining the dataset for what is actually there — how many images are you matching, what properties and bands those images have, etc. I found two problems:

    1. Your filter criteria matched zero images. Therefore the collection is empty, and therefore the median() image from that collection has no bands at all. (You can check this by putting the collection in a variable and printing the size() of it.) You will need to adjust the criteria.

      It seems that the main reason they didn't match is that the images in MODIS/061/MOD09A1 do not have a CLOUDY_PIXEL_PERCENTAGE property.

    2. The band names for MODIS/061/MOD09A1 are not B1, B2, ... but sur_refl_b01, sur_refl_b02 and so on. You can see this with the Inspector in the Earth Engine Code Editor, or on the dataset description page.

    Perhaps you were working from information about a different dataset?

    With the two problems above fixed, your code produces some results. This is the (JS) version I produced while testing (Code Editor link):

    var countries = ee.FeatureCollection("USDOS/LSIB_SIMPLE/2017");
    var canada = countries.filter(ee.Filter.eq("country_na", "Canada"));
    var images = ee.ImageCollection("MODIS/061/MOD09A1")
                .filterDate('2017-01-01','2017-12-31')
                // .filter(ee.Filter.lt('CLOUDY_PIXEL_PERCENTAGE',10))
                .filterBounds(canada);
    // print(images);
    var image = images.median().clip(canada);
    
    Map.addLayer(canada);
    Map.addLayer(image);
    
    var savi = image.expression(
        '1.5*((NIR-RED)/(NIR+RED+0.5))',{
            'NIR':image.select('sur_refl_b02'),
            'RED':image.select('sur_refl_b01')
        }).rename('savi');
    
    var saviVis = {'min':0.0, 'max':1, 'palette':['yellow', 'green']};
    Map.addLayer(savi, saviVis, 'SAVI')