In [1]:
# Install the development version of the earthpy package
# !pip install git+https://github.com/earthlab/earthpy@apppears
In [2]:
import getpass
import json
import os
import pathlib
from glob import glob
import matplotlib.pyplot as plt

# Library to work with tabular data
import pandas as pd

# Library to work with vector data
import geopandas as gpd

import earthpy.appeears as eaapp
import hvplot.pandas
import hvplot.xarray
import rioxarray as rxr
import xarray as xr
In [3]:
abuja_dir = os.path.join(pathlib.Path.home(), 'abuja-data')
# Make the data directory
os.makedirs(abuja_dir, exist_ok=True)

abuja_dir
Out[3]:
'/home/jovyan/abuja-data'
In [4]:
# Define url to Nigeria .shp
nigeria_url = "https://open.africa/dataset/83582021-d8f7-4bfd-928f-e9c6c8cb1247/resource/372a616a-66cc-41f7-ac91-d8af8f23bc2b/download/nigeria-lgas.zip"

# Open Nigeria .shp using geopandas
nigeria_gdf = gpd.read_file(nigeria_url)
nigeria_gdf
Out[4]:
STATE LGA AREA PERIMETER LONGITUDE LATITUDE FULL_NAME geometry
0 Sokoto Gada 1193.977 170.095 None None None POLYGON ((5.53632 13.88793, 5.53480 13.88488, ...
1 Sokoto Illela 1298.423 174.726 None None None POLYGON ((5.53632 13.88793, 5.54517 13.88419, ...
2 Sokoto Tangaza 2460.715 209.702 None None None POLYGON ((4.85548 13.76724, 4.86189 13.78085, ...
3 Borno Abadam 2430.515 288.957 None None None POLYGON ((12.83189 13.39871, 12.83397 13.40439...
4 Lake Lake chad 5225.912 497.039 None None None POLYGON ((13.48608 13.30821, 13.48296 13.31344...
... ... ... ... ... ... ... ... ...
770 Delta Isoko North 485.467 169.369 None None None MULTIPOLYGON (((6.31996 5.63341, 6.32003 5.633...
771 Niger Lavun 3951.431 424.153 None None None MULTIPOLYGON (((6.12188 9.09441, 6.12001 9.094...
772 Yobe Bade 817.260 216.207 None None None MULTIPOLYGON (((11.01052 12.80457, 11.00747 12...
773 Zamfara Maru 7795.261 536.500 None None None MULTIPOLYGON (((6.43894 12.41104, 6.43609 12.4...
774 Akwa Ibom Oron 81.472 57.846 None None None POLYGON ((8.22063 4.84473, 8.23405 4.82974, 8....

775 rows × 8 columns

In [8]:
print(nigeria_gdf.columns)
Index(['STATE', 'LGA', 'AREA', 'PERIMETER', 'LONGITUDE', 'LATITUDE',
       'FULL_NAME', 'geometry'],
      dtype='object')
In [14]:
# SEARCH FOR STATE IN DATA FRAME.
search_state = 'Abuja'  # Note: Use capital letters if the column is in capital letters

# Check if the state exists in the specified column
if search_state in nigeria_gdf['STATE'].values:
    print(f"{search_state} exists in the GeoDataFrame.")
else:
    print(f"{search_state} does not exist in the GeoDataFrame.")
Abuja exists in the GeoDataFrame.
In [16]:
# Select out Abuja
Abuja = nigeria_gdf[nigeria_gdf["STATE"]=="Abuja"]
Abuja
Out[16]:
STATE LGA AREA PERIMETER LONGITUDE LATITUDE FULL_NAME geometry
300 Abuja Bwari 818.909 153.605 None None None POLYGON ((7.62143 9.30766, 7.62241 9.30840, 7....
307 Abuja Gwagwalada 967.762 129.429 None None None POLYGON ((7.12020 9.12689, 7.12679 9.11870, 7....
308 Abuja Abaji 1002.453 257.578 None None None POLYGON ((6.96319 9.23240, 6.96163 9.23123, 6....
314 Abuja Abuja Municipal 1585.320 206.501 None None None POLYGON ((7.17027 9.09925, 7.17036 9.09829, 7....
329 Abuja Kwali 1299.111 151.853 None None None POLYGON ((7.05974 8.89200, 7.06064 8.89094, 7....
331 Abuja Kuje 1708.466 217.281 None None None POLYGON ((7.07285 8.90097, 7.08316 8.90024, 7....
In [17]:
# Display Interactive map of state, In this case (Abuja)
Abuja.explore()
Out[17]:
Make this Notebook Trusted to load map: File -> Trust Notebook
In [21]:
# Select Gwagwalada
Gwagwalada = Abuja[Abuja["LGA"] == 'Gwagwalada']
Gwagwalada
Out[21]:
STATE LGA AREA PERIMETER LONGITUDE LATITUDE FULL_NAME geometry
307 Abuja Gwagwalada 967.762 129.429 None None None POLYGON ((7.12020 9.12689, 7.12679 9.11870, 7....
In [22]:
# Display Gwagwalada Map
Gwagwalada.explore()
Out[22]:
Make this Notebook Trusted to load map: File -> Trust Notebook
In [23]:
# Initialize AppeearsDownloader for MODIS NDVI data
ndvi_downloader = eaapp.AppeearsDownloader(
    download_key='abuja-ndvi',
    ea_dir=abuja_dir,
    product='MOD13Q1.061',
    layer='_250m_16_days_NDVI',
    start_date="07-01",
    end_date="07-31",
    recurring=True,
    year_range=[2015, 2020],
    polygon= Gwagwalada
)

ndvi_downloader.download_files(cache=True)
In [24]:
# Get a list of NDVI tif file paths
abuja_paths = sorted(glob(os.path.join(abuja_dir, 'abuja-ndvi', '*', '*NDVI*.tif')))
len(abuja_paths)
Out[24]:
18
In [27]:
scale_factor = 10000
doy_start = -19
doy_end = -12
In [28]:
abuja_das = []
for abuja_path in abuja_paths:
    # Get date from file name
    doy = abuja_path [doy_start:doy_end]
    date = pd.to_datetime(doy, format='%Y%j')

    # Open dataset
    da = rxr.open_rasterio(abuja_path, masked=True).squeeze()

    # Add date dimension and clean up metadata
    da = da.assign_coords({'date': date})
    da = da.expand_dims({'date': 1})
    da.name = 'NDVI'

    # Multiple by scale factor
    da = da / scale_factor

    # Prepare for concatenation
    abuja_das.append(da)

len(abuja_das)
Out[28]:
18
In [29]:
abuja_da = xr.combine_by_coords(abuja_das, coords=['date'])
abuja_da
Out[29]:
<xarray.Dataset>
Dimensions:      (x: 165, y: 167, date: 18)
Coordinates:
    band         int64 1
  * x            (x) float64 6.824 6.826 6.828 6.83 ... 7.159 7.161 7.164 7.166
  * y            (y) float64 9.236 9.234 9.232 9.23 ... 8.897 8.895 8.893 8.891
    spatial_ref  int64 0
  * date         (date) datetime64[ns] 2015-06-26 2015-07-12 ... 2020-07-27
Data variables:
    NDVI         (date, y, x) float32 0.5796 0.5933 0.5727 ... 0.6463 0.6531
xarray.Dataset
    • x: 165
    • y: 167
    • date: 18
    • band
      ()
      int64
      1
      array(1)
    • x
      (x)
      float64
      6.824 6.826 6.828 ... 7.164 7.166
      array([6.823958, 6.826042, 6.828125, 6.830208, 6.832292, 6.834375, 6.836458,
             6.838542, 6.840625, 6.842708, 6.844792, 6.846875, 6.848958, 6.851042,
             6.853125, 6.855208, 6.857292, 6.859375, 6.861458, 6.863542, 6.865625,
             6.867708, 6.869792, 6.871875, 6.873958, 6.876042, 6.878125, 6.880208,
             6.882292, 6.884375, 6.886458, 6.888542, 6.890625, 6.892708, 6.894792,
             6.896875, 6.898958, 6.901042, 6.903125, 6.905208, 6.907292, 6.909375,
             6.911458, 6.913542, 6.915625, 6.917708, 6.919792, 6.921875, 6.923958,
             6.926042, 6.928125, 6.930208, 6.932292, 6.934375, 6.936458, 6.938542,
             6.940625, 6.942708, 6.944792, 6.946875, 6.948958, 6.951042, 6.953125,
             6.955208, 6.957292, 6.959375, 6.961458, 6.963542, 6.965625, 6.967708,
             6.969792, 6.971875, 6.973958, 6.976042, 6.978125, 6.980208, 6.982292,
             6.984375, 6.986458, 6.988542, 6.990625, 6.992708, 6.994792, 6.996875,
             6.998958, 7.001042, 7.003125, 7.005208, 7.007292, 7.009375, 7.011458,
             7.013542, 7.015625, 7.017708, 7.019792, 7.021875, 7.023958, 7.026042,
             7.028125, 7.030208, 7.032292, 7.034375, 7.036458, 7.038542, 7.040625,
             7.042708, 7.044792, 7.046875, 7.048958, 7.051042, 7.053125, 7.055208,
             7.057292, 7.059375, 7.061458, 7.063542, 7.065625, 7.067708, 7.069792,
             7.071875, 7.073958, 7.076042, 7.078125, 7.080208, 7.082292, 7.084375,
             7.086458, 7.088542, 7.090625, 7.092708, 7.094792, 7.096875, 7.098958,
             7.101042, 7.103125, 7.105208, 7.107292, 7.109375, 7.111458, 7.113542,
             7.115625, 7.117708, 7.119792, 7.121875, 7.123958, 7.126042, 7.128125,
             7.130208, 7.132292, 7.134375, 7.136458, 7.138542, 7.140625, 7.142708,
             7.144792, 7.146875, 7.148958, 7.151042, 7.153125, 7.155208, 7.157292,
             7.159375, 7.161458, 7.163542, 7.165625])
    • y
      (y)
      float64
      9.236 9.234 9.232 ... 8.893 8.891
      array([9.236458, 9.234375, 9.232292, 9.230208, 9.228125, 9.226042, 9.223958,
             9.221875, 9.219792, 9.217708, 9.215625, 9.213542, 9.211458, 9.209375,
             9.207292, 9.205208, 9.203125, 9.201042, 9.198958, 9.196875, 9.194792,
             9.192708, 9.190625, 9.188542, 9.186458, 9.184375, 9.182292, 9.180208,
             9.178125, 9.176042, 9.173958, 9.171875, 9.169792, 9.167708, 9.165625,
             9.163542, 9.161458, 9.159375, 9.157292, 9.155208, 9.153125, 9.151042,
             9.148958, 9.146875, 9.144792, 9.142708, 9.140625, 9.138542, 9.136458,
             9.134375, 9.132292, 9.130208, 9.128125, 9.126042, 9.123958, 9.121875,
             9.119792, 9.117708, 9.115625, 9.113542, 9.111458, 9.109375, 9.107292,
             9.105208, 9.103125, 9.101042, 9.098958, 9.096875, 9.094792, 9.092708,
             9.090625, 9.088542, 9.086458, 9.084375, 9.082292, 9.080208, 9.078125,
             9.076042, 9.073958, 9.071875, 9.069792, 9.067708, 9.065625, 9.063542,
             9.061458, 9.059375, 9.057292, 9.055208, 9.053125, 9.051042, 9.048958,
             9.046875, 9.044792, 9.042708, 9.040625, 9.038542, 9.036458, 9.034375,
             9.032292, 9.030208, 9.028125, 9.026042, 9.023958, 9.021875, 9.019792,
             9.017708, 9.015625, 9.013542, 9.011458, 9.009375, 9.007292, 9.005208,
             9.003125, 9.001042, 8.998958, 8.996875, 8.994792, 8.992708, 8.990625,
             8.988542, 8.986458, 8.984375, 8.982292, 8.980208, 8.978125, 8.976042,
             8.973958, 8.971875, 8.969792, 8.967708, 8.965625, 8.963542, 8.961458,
             8.959375, 8.957292, 8.955208, 8.953125, 8.951042, 8.948958, 8.946875,
             8.944792, 8.942708, 8.940625, 8.938542, 8.936458, 8.934375, 8.932292,
             8.930208, 8.928125, 8.926042, 8.923958, 8.921875, 8.919792, 8.917708,
             8.915625, 8.913542, 8.911458, 8.909375, 8.907292, 8.905208, 8.903125,
             8.901042, 8.898958, 8.896875, 8.894792, 8.892708, 8.890625])
    • spatial_ref
      ()
      int64
      0
      crs_wkt :
      GEOGCS["WGS 84",DATUM["WGS_1984",SPHEROID["WGS 84",6378137,298.257223563,AUTHORITY["EPSG","7030"]],AUTHORITY["EPSG","6326"]],PRIMEM["Greenwich",0,AUTHORITY["EPSG","8901"]],UNIT["degree",0.0174532925199433,AUTHORITY["EPSG","9122"]],AXIS["Latitude",NORTH],AXIS["Longitude",EAST],AUTHORITY["EPSG","4326"]]
      semi_major_axis :
      6378137.0
      semi_minor_axis :
      6356752.314245179
      inverse_flattening :
      298.257223563
      reference_ellipsoid_name :
      WGS 84
      longitude_of_prime_meridian :
      0.0
      prime_meridian_name :
      Greenwich
      geographic_crs_name :
      WGS 84
      horizontal_datum_name :
      World Geodetic System 1984
      grid_mapping_name :
      latitude_longitude
      spatial_ref :
      GEOGCS["WGS 84",DATUM["WGS_1984",SPHEROID["WGS 84",6378137,298.257223563,AUTHORITY["EPSG","7030"]],AUTHORITY["EPSG","6326"]],PRIMEM["Greenwich",0,AUTHORITY["EPSG","8901"]],UNIT["degree",0.0174532925199433,AUTHORITY["EPSG","9122"]],AXIS["Latitude",NORTH],AXIS["Longitude",EAST],AUTHORITY["EPSG","4326"]]
      GeoTransform :
      6.822916666055434 0.0020833333331466974 0.0 9.237499999172456 0.0 -0.0020833333331466974
      array(0)
    • date
      (date)
      datetime64[ns]
      2015-06-26 ... 2020-07-27
      array(['2015-06-26T00:00:00.000000000', '2015-07-12T00:00:00.000000000',
             '2015-07-28T00:00:00.000000000', '2016-06-25T00:00:00.000000000',
             '2016-07-11T00:00:00.000000000', '2016-07-27T00:00:00.000000000',
             '2017-06-26T00:00:00.000000000', '2017-07-12T00:00:00.000000000',
             '2017-07-28T00:00:00.000000000', '2018-06-26T00:00:00.000000000',
             '2018-07-12T00:00:00.000000000', '2018-07-28T00:00:00.000000000',
             '2019-06-26T00:00:00.000000000', '2019-07-12T00:00:00.000000000',
             '2019-07-28T00:00:00.000000000', '2020-06-25T00:00:00.000000000',
             '2020-07-11T00:00:00.000000000', '2020-07-27T00:00:00.000000000'],
            dtype='datetime64[ns]')
    • NDVI
      (date, y, x)
      float32
      0.5796 0.5933 ... 0.6463 0.6531
      array([[[0.5796, 0.5933, 0.5727, ..., 0.4792, 0.4792, 0.4863],
              [0.4863, 0.557 , 0.2871, ..., 0.5017, 0.4617, 0.4617],
              [0.5733, 0.31  , 0.2896, ..., 0.3291, 0.3291, 0.4617],
              ...,
              [0.6557, 0.6557, 0.6883, ..., 0.5928, 0.6592, 0.7034],
              [0.6823, 0.7237, 0.7237, ..., 0.6534, 0.6342, 0.6391],
              [0.4703, 0.4703, 0.7237, ..., 0.6839, 0.6342, 0.6391]],
      
             [[0.3585, 0.4728, 0.4728, ..., 0.6084, 0.5556, 0.5556],
              [0.2919, 0.3978, 0.3872, ..., 0.6084, 0.5354, 0.5354],
              [0.2482, 0.3978, 0.3565, ..., 0.73  , 0.5452, 0.4544],
              ...,
              [0.1006, 0.09  , 0.6895, ..., 0.5015, 0.5246, 0.5098],
              [0.1006, 0.09  , 0.6895, ..., 0.268 , 0.2073, 0.2829],
              [0.8596, 0.8779, 0.8779, ..., 0.2676, 0.2676, 0.2814]],
      
             [[0.3011, 0.3011, 0.3111, ..., 0.0974, 0.089 , 0.1308],
              [0.2715, 0.2364, 0.2364, ..., 0.0962, 0.0915, 0.1338],
              [0.237 , 0.2209, 0.2209, ..., 0.1277, 0.1382, 0.1338],
              ...,
      ...
              [0.4607, 0.4607, 0.3711, ..., 0.4332, 0.5082, 0.5295],
              [0.4607, 0.4607, 0.3711, ..., 0.3829, 0.4571, 0.5295],
              [0.2937, 0.2278, 0.4524, ..., 0.4896, 0.4571, 0.3327]],
      
             [[0.5516, 0.5674, 0.5377, ..., 0.2019, 0.1376, 0.105 ],
              [0.6154, 0.5691, 0.4732, ..., 0.2019, 0.1651, 0.105 ],
              [0.4165, 0.2704, 0.206 , ..., 0.2235, 0.1988, 0.1988],
              ...,
              [0.2695, 0.5224, 0.1691, ..., 0.191 , 0.191 , 0.1599],
              [0.2695, 0.2695, 0.1691, ..., 0.2169, 0.2169, 0.2849],
              [0.4338, 0.5767, 0.5767, ..., 0.3376, 0.3481, 0.2787]],
      
             [[0.683 , 0.6689, 0.7116, ..., 0.6772, 0.6548, 0.6476],
              [0.683 , 0.6941, 0.6941, ..., 0.7129, 0.6492, 0.6044],
              [0.7102, 0.7048, 0.551 , ..., 0.7125, 0.6724, 0.4667],
              ...,
              [0.5185, 0.5092, 0.507 , ..., 0.6278, 0.5765, 0.6533],
              [0.6613, 0.633 , 0.606 , ..., 0.6022, 0.561 , 0.596 ],
              [0.6625, 0.6428, 0.6564, ..., 0.6259, 0.6463, 0.6531]]],
            dtype=float32)
    • x
      PandasIndex
      PandasIndex(Index([6.8239583327220075,  6.826041666055154,  6.828124999388301,
              6.830208332721448,  6.832291666054594,  6.834374999387741,
              6.836458332720888,  6.838541666054034,  6.840624999387181,
              6.842708332720328,
             ...
              7.146874999359746,  7.148958332692892,  7.151041666026039,
              7.153124999359186,  7.155208332692332,  7.157291666025479,
              7.159374999358626, 7.1614583326917725,  7.163541666024919,
              7.165624999358066],
            dtype='float64', name='x', length=165))
    • y
      PandasIndex
      PandasIndex(Index([9.236458332505883, 9.234374999172736,  9.23229166583959,
             9.230208332506443, 9.228124999173296,  9.22604166584015,
             9.223958332507003, 9.221874999173856,  9.21979166584071,
             9.217708332507563,
             ...
             8.909374999201852, 8.907291665868705, 8.905208332535558,
             8.903124999202412, 8.901041665869265, 8.898958332536118,
             8.896874999202971, 8.894791665869825, 8.892708332536678,
             8.890624999203531],
            dtype='float64', name='y', length=167))
    • date
      PandasIndex
      PandasIndex(DatetimeIndex(['2015-06-26', '2015-07-12', '2015-07-28', '2016-06-25',
                     '2016-07-11', '2016-07-27', '2017-06-26', '2017-07-12',
                     '2017-07-28', '2018-06-26', '2018-07-12', '2018-07-28',
                     '2019-06-26', '2019-07-12', '2019-07-28', '2020-06-25',
                     '2020-07-11', '2020-07-27'],
                    dtype='datetime64[ns]', name='date', freq=None))
In [30]:
# Compute the difference in NDVI before and after the fire
abuja_diff = (
    abuja_da
        .sel(date=slice('2017', '2020'))
        .mean('date')
        .NDVI 
   - abuja_da
        .sel(date=slice('2015', '2017'))
        .mean('date')
        .NDVI
)
In [32]:
# Plot the difference
fig, ax = plt.subplots()

abuja_diff.plot(x='x', y='y', cmap='PiYG', robust=True, ax=ax)
Gwagwalada.plot(edgecolor='black', color='none', ax=ax)
plt.show()
No description has been provided for this image
In [33]:
Gwagwalada_out_gdf = (
    gpd.GeoDataFrame(geometry=Gwagwalada.envelope)
    .overlay(Gwagwalada, how='difference'))
Gwagwalada_out_gdf
Out[33]:
geometry
0 MULTIPOLYGON (((6.82315 8.88978, 6.82315 9.109...
In [34]:
# Clip data to both inside and outside the boundary
ndvi_abuja_da = abuja_da.rio.clip(Gwagwalada.geometry, from_disk=True)
ndvi_abuja_out_da = abuja_da.rio.clip(Gwagwalada_out_gdf.geometry, from_disk=True)
In [35]:
# Compute mean annual July NDVI
jul_ndvi_abuja_df = (
    ndvi_abuja_da
    .groupby(ndvi_abuja_da.date.dt.year)
    .mean(...)
    .NDVI.to_dataframe())
jul_ndvi_abuja_out_df = (
    ndvi_abuja_out_da
    .groupby(ndvi_abuja_out_da.date.dt.year)
    .mean(...)
    .NDVI.to_dataframe())

# Plot inside and outside the reservation
abuja_jul_ndvi_df = (
    jul_ndvi_abuja_df[['NDVI']]
    .join(
        jul_ndvi_abuja_out_df[['NDVI']], 
        lsuffix=' Inside Gwagwalada', rsuffix=' Outside Gwagwalada')
)
In [36]:
# Plot difference inside and outside the reservation
abuja_jul_ndvi_df.plot(
    title='NDVI before and after 2017; Gwagwalada, Abuja, Nigeria')
Out[36]:
<Axes: title={'center': 'NDVI before and after 2017; Gwagwalada, Abuja, Nigeria'}, xlabel='year'>
No description has been provided for this image