Open In Colab

2. Image clipping with VIIRS-DNB (5 min)

Satellite data, which often comes structured as a GeoTIFF if you recall from Data overview (10 min), can cover large areas geospatially. It’s not always required to work with the entire file, in fact, it’s often preferred to work only with a smaller Area Of Interest (AOI).

In this tutorial, we’re going to show how you can clip a particular satellite raster file to a specific AOI, including a geometry from a geopolitical boundary. We’ll also apply this clipping to an entire ImageCollection.

For this exercise, we’ll work with the VIIRS-DNB data.

Our tasks in this exercise:

  1. Get a monthly VIIRS-DNB composite and clip to a Geometry (a buffer around a point)

  2. Clip the image to the geometry of the state of California.

  3. Clip all the images in the VIIRS-DNB stray-light corrected image collection to the state of California

2.1. Get and clip a VIIRS-DNB monthly composite

For this exercise, we’ll look at the VIIRS-DNB monthly composite for December 2019.

2.1.1. Initialize map, get image and add as layer

# reminder that if you are installing libraries in a Google Colab instance you will be prompted to restart your kernal

try:
    import geemap, ee
except ModuleNotFoundError:
    if 'google.colab' in str(get_ipython()):
        print("package not found, installing w/ pip in Google Colab...")
        !pip install geemap
    else:
        print("package not found, installing w/ conda...")
        !conda install mamba -c conda-forge -y
        !mamba install geemap -c conda-forge -y
    import geemap, ee
try:
        ee.Initialize()
except Exception as e:
        ee.Authenticate()
        ee.Initialize()

# get December image, we're using the "avg_rad" band
viirs2019_12 = ee.ImageCollection("NOAA/VIIRS/DNB/MONTHLY_V1/VCMSLCFG").filterDate("2019-12-01","2019-12-31").select('avg_rad').median()


# initialize our map
map1 = geemap.Map()
map1.add_basemap('SATELLITE')
map1.addLayer(viirs2019_12, {}, "VIIRS-DNB Dec 2019")

map1.addLayerControl()
map1

2.2. Clip our image to an area around Los Angeles, CA

We’ll create a circular AOI using the ee.Geometry.Point method at lon: -118.2541, lat: 34.0469 (downtown LA) and then create a 200,000 meter (200 km) buffer around that.

lat = 34.0469
lon = -118.2541
aoi = ee.Geometry.Point([lon, lat]).buffer(200000);

Now, let’s clip our VIIRS image to our AOI and add that as a layer by passing our aoi object to the .clip() function, like this:

viirs2019_12_clipped = viirs2019_12.clip(aoi)

map2 = geemap.Map(center=[lat, lon],zoom=7)
map2.add_basemap('SATELLITE')
map2.addLayer(viirs2019_12_clipped, {}, "VIIRS-DNB- Greater LA Dec 2019")
map2.addLayerControl()
map2

Now we can focus our attention (for analysis or visualization) on just the area around greater LA.

2.3. Clip an image to a geopolitical boundary: State of California

We arbitrarily chose a lat/lon point and buffer to clip our image around, but in geospatial analysis, we’re often called to focus on particular geopolitical boundaries.

One example might be to use the shapefile of a country or sub-national boundary to clip our image.

2.3.1. Importing shapefiles with geemap

Importing shapefiles is very easy to do with geemap. It’s as simple as:

ee_object = geemap.shp_to_ee(<pathtomyshapefile>)

…which you can now add to your map object:

Map.addLayer(ee_object, {}, 'Layer name')

So if you had a shapefile, say for the state of California, you could import that as just shown, get the geomtry of the shapefile (i.e. by selecting the geometry field) and then clip your image to that geometry, just like we did with aoi earlier).

Conveniently, Google Earth Engine actually has geometries for US States as a native FeatureCollection so we dont need to get those. These are based on the US Census TIGER files from 2016 and are located in GEE at TIGER/2016/States

We’ll retrieve the geometry for the state of California:

aoi_CA = ee.FeatureCollection('TIGER/2016/States').filter(ee.Filter.eq('NAME', 'California'))

Now, just as with our previous AOI, we can clip our VIIRS Dec 2019 composite image to the entire state of California.

viirs2019_12_ca = viirs2019_12.clip(aoi_CA)

map3 = geemap.Map(center=[lat, lon],zoom=5)
map3.add_basemap('SATELLITE')
map3.addLayer(viirs2019_12_ca, {}, "VIIRS-DNB- California Dec 2019")
map3.addLayerControl()
map3

2.4. Clip an entire ImageCollection to the State of California

So far, we’ve just clipped the December 2019 VIIRS-DNB composite, but we can easily apply this geometry clipping to an entire Image Collection. This would help if we wanted to create time series analysis of our focus area.

2.4.1. ImageCollection map

Here’s it’s necessary to learn about the .map() function of ImageCollections, which as the name suggests, maps a given function each image in the collection, with some constraints as you can read here.

Previously, we passed our geometry (e.g. aoi_CA) to the .clip() function to clip a single image. We can map a function that does this to our entire ImageCollection in Python by first defining a simple function that clips a single image to our specific AOI (California).

# get the entire VIIRS-DNB selection -- still only selecting the "avg_rad" band
viirsDNB = ee.ImageCollection("NOAA/VIIRS/DNB/MONTHLY_V1/VCMSLCFG").select('avg_rad')

# here's a function that uses the CA aoi to clip an image
def clip_func(x):
    return x.clip(aoi_CA)

# for simple functions in Python, we can also use the "lambda" convention
# this is identical to what we just defined above 
# and is nice and compact for vectorizing functions on arrays and images, etc.
clip_func = lambda x: x.clip(aoi_CA)

# in fact, by using lambda, we dont need to define this "clip_func" function at all
# we can write it directly in our "map" function, like this:
viirs_CA = viirsDNB.map(lambda x: x.clip(aoi_CA))

Now we can query this image collection for any date or series of dates to visualize layers.

Let’s look at June of 2015 and June 2020, for instance:

viirs_CA_2015_06 = viirs_CA.filterDate('2015-06-01','2015-06-30').median()
viirs_CA_2019_06 = viirs_CA.filterDate('2019-06-01','2019-06-30').median()

map4 = geemap.Map(center=[lat, lon],zoom=5)
map4.add_basemap('SATELLITE')
map4.addLayer(viirs_CA_2015_06, {}, "VIIRS-DNB- California June 2015")
map4.addLayer(viirs_CA_2019_06, {}, "VIIRS-DNB- California June 2019")
map4.addLayerControl()
map4

2.4.2. Annual composite

We could also get an annual composite of California for all of 2019, by reducing our image collection (through the .median() function.

viirs_CA_2019 = viirs_CA.filterDate('2019-01-01','2019-12-31').median()

map5 = geemap.Map(center=[lat, lon],zoom=5)
map5.add_basemap('SATELLITE')
map5.addLayer(viirs_CA_2019, {}, "VIIRS-DNB- California 2019 (median)")
map5.addLayerControl()
map5

You can also get the the difference (i.e. change) in nighttime lights by subtracting images – and much more. We’ll cover operations like that in following exercises, but now you know how to clip an image to a specific geometry.

2.5. References: