Interactive Session: Complementing anthropogenic GHG emissions with natural GHG emissions and fluxes

About the Data

Methane (CH₄) emissions from vegetated wetlands are estimated to be the largest natural source of methane in the global CH₄ budget, contributing to roughly one third of the total of natural and anthropogenic emissions. Wetland CH₄ is produced by microbes breaking down organic matter in the oxygen deprived environment of inundated soils. Due to limited data availability, the details of the role of wetland CH₄ emissions have thus far been underrepresented. Using the Earth Observation SIMulator version (LPJ-EOSIM) of the Lund-Potsdam-Jena Dynamic Global Vegetation Model (LPJ-DGVM) global CH₄ emissions from wetlands are estimated at 0.5 x 0.5 degree spatial resolution. By simulating wetland extent and using characteristics of inundated areas, such as wetland soil moisture, temperature, and carbon content, the model provides estimates of CH₄ quantities emitted into the atmosphere. The LPJ-EOSIM Wetland Methane Emissions dataset consists of global daily and monthly model estimates of terrestrial wetland methane emissions from 1990 to the present, with data added every two months. The monthly dataset is computed by summing the daily data for each month. The estimates are regularly used in conjunction with NASA’s Goddard Earth Observing System (GEOS) model to simulate the impact of wetlands and other methane sources on atmospheric methane concentrations, to compare against satellite and airborne data, and to improve understanding and prediction of wetland emissions. This is a new version and replaces the LPJ-wsl dataset previously available in the GHG Center.

Requirements

  • Set up Python Environment - See setup_instructions.md in the /setup/ folder

Learning Objectives

  • How to use U.S. GHG Center STAC Catalog to access Wetland Methane Emissions, LPJ-wsl Model data
  • How to use earthaccess to find MERRA-2 data
  • How to visualize datasets using folium and perform zonal statistics
  • How to plot time series for MERRA-2 variables and Wetland Methane Emissions, LPJ-wsl Model and analyze the results

Approach

  1. Identify available dates and temporal frequency of observations for the given collection using the GHGC API /stacendpoint. The collection processed in this notebook is the Wetland Methane Emissions, LPJ-wsl Model data product
  2. Pass the STAC item into the raster API /stac/tilejson.json endpoint
  3. Access the MERRA-2 data for different variables (precipitation rate, surface soil moisture)
  4. Define the spatial region of interest
  5. Using plugins from folium to visualize two tiles (side-by-side), allowing time point comparison
  6. After the visualization, perform zonal statistics for a given polygon
  7. Plot monthly time series for LPJ-wetland emission and different MERRA-2 dataset and analyze them

Data

  1. Monthly LPJ Wetland CH4 Emissions (US GHG Center STAC)

Setup

Import the required Python libraries by running the next cell.

# import earthaccess
import os
import json
import requests
import pandas as pd
import geopandas as gpd
os.environ['USE_PYGEOS'] = '0'
import folium
import folium.plugins
import seaborn as sns
import glob
import numpy as np
import netCDF4 as nc
import matplotlib.pyplot as plt
import branca.colormap as cm
from folium import TileLayer 
from pystac_client import Client 
from datetime import datetime
import stackstac
import xarray as xr
import rioxarray as rxr
import surfaceAreaGrid
from cartopy import crs as ccrs
import cartopy.feature as cf

Querying the STAC API

Search for the LPJ Wetland Methane Emissions Data using the Raster API and its STAC collection name!

# Provide STAC and RASTER API endpoints
STAC_API_URL = "http://earth.gov/ghgcenter/api/stac"
RASTER_API_URL = "https://earth.gov/ghgcenter/api/raster"

# Please use the collection name similar to the one used in STAC collection
# Name of the collection for wetland methane monthly emissions 
collection_name = "lpjeosim-wetlandch4-monthgrid-v1"
# Fetching the collection from STAC collections using appropriate endpoint
# Using the Client module of pystac_client

catalog = Client.open(STAC_API_URL)

# Pick the collection
# Select GRA2PES collection: browse item_assets, spatial and temporal extent
collection = catalog.get_collection(collection_name)
collection

Here we are examining the contents of our collection under summaries. We notice the data is available from January 1980 to May 2021. By looking at dashboard: time density, we can see that these observations are collected monthly.

# Get items from this collection, examine temporal extent of each
items = list(collection.get_items())
print(f"Found {len(items)} items in {collection_name} collection.")
Found 417 items in lpjeosim-wetlandch4-monthgrid-v1 collection.
# Examining the first item in the collection
# Keep in mind that a list starts from 0, 1, 2,... therefore ‘[0]’ is referring to the first item in the list/collection 
items[0]

Define the Spatial Area of Interest

For this example, our spatial area of interest (AOI) will be a region in the state of Louisiana (LA). The state of Louisiana encompasses a diverse range of non-tidal and tidal freshwater wetlands including palustrine, lacustrine, riverine, estuarine, and marine wetlands. These ecosystems cover roughly one-third of the state according to the U.S. Fish and Wildlife Service, making Louisiana an ideal site for monitoring the natural source of methane emissions.

Our AOI is defined by a polygon, and there are several methods for defining our polygon - here we read in a GEOJSON created by using geojson.io. If you want to look at data over a different region, try drawing your own AOI and dropping the GEOJSON into this directory!

We also include an example of how to read geospatial information from a shapefile.

# We'll use geopandas to read our GEOJSON, which defines a polygon over our AOI.
louisiana_aoi = gpd.read_file('./louisiana.geojson')
## Method #2 of defining a polygon - using a shapefile!
## An individual shapefile has a .shp extension,
## but comes packaged with several supplemental files, typically in .zip format.
## Here we have unpacked the contents of a .zip from the Census Bureau
## in data/cb_2018_us_state_20m
## We'll use geopandas to read the .shp file found there and isolate Louisiana.
## Uncomment the next two lines to use the shapefile!
# 
#gdf = gpd.read_file('./data/cb_2018_us_state_20m/cb_2018_us_state_20m.shp')
#louisiana_aoi = gdf[gdf['NAME'] == 'Louisiana']

Opening and Exploring Wetland Methane Emissions Data Using the Raster API

Let’s visualize methane emissions on an interactive map using folium.

items[0].properties
{'end_datetime': '2024-09-30T00:00:00+00:00',
 'start_datetime': '2024-09-01T00:00:00+00:00',
 'datetime': None}
# To access the year value from each item more easily, 
# this will let us query more explicitly by year and month (e.g., 2020-02)
items = {item.properties["start_datetime"][:7]: item for item in items} 


# Set the asset value to the appropriate parameter 
asset_name = 'ensemble-mean-ch4-wetlands-emissions'

Visualizing CH₄ Emissions

# Select colormap
color_map = "magma"
# Set the minimum and maximum values to provide our upper and lower bounds
rescale_values = {'max': 0.000000001, 'min': 0.0}


new_date1, new_date2, new_date3 = '2021-05', '2021-06','2021-07'
# Reading the tiles from raster api
tile_date_1 = requests.get(
    f"{RASTER_API_URL}/collections/{items[new_date1].collection_id}/items/{items[new_date1].id}/tilejson.json?"
    f"&assets={asset_name}"
    f"&color_formula=gamma+r+1.05&colormap_name={color_map}"
    f"&rescale={rescale_values['min']},{rescale_values['max']}",
).json()
tile_date_1


tile_date_2 = requests.get(
    f"{RASTER_API_URL}/collections/{items[new_date2].collection_id}/items/{items[new_date2].id}/tilejson.json?"
    f"&assets={asset_name}"
    f"&color_formula=gamma+r+1.05&colormap_name={color_map}"
    f"&rescale={rescale_values['min']},{rescale_values['max']}",
).json()
tile_date_2


tile_date_3 = requests.get(
    f"{RASTER_API_URL}/collections/{items[new_date3].collection_id}/items/{items[new_date3].id}/tilejson.json?"
    f"&assets={asset_name}"
    f"&color_formula=gamma+r+1.05&colormap_name={color_map}"
    f"&rescale={rescale_values['min']},{rescale_values['max']}",
).json()
tile_date_3


# Interactive visulaization 
map_ = folium.Map(location=(30,-90), zoom_start=5)

# May 2021
tile1 = TileLayer(
    tiles=tile_date_1["tiles"][0],
    attr="GHG",
    name=new_date1
)
tile1.add_to(map_)

# June 2021
tile2 = TileLayer(
    tiles=tile_date_2["tiles"][0],
    attr="GHG",
    name=new_date2
)
tile2.add_to(map_)

# July 2021
tile3 = TileLayer(
    tiles=tile_date_3["tiles"][0],
    attr="GHG",
    name=new_date3
)
tile3.add_to(map_)

folium.GeoJson(louisiana_aoi, name="louisiana, USA").add_to(map_)
folium.LayerControl(collapsed=False,position='bottomleft').add_to(map_)

# Add legend
colormap = cm.LinearColormap(colors = ['#2c115f','#721f81','#b73779','#f1605d','#feb078'], vmin = 0, vmax = 0.000000003 )
colormap.caption = 'kg CH₄/m²/s'

svg_style = '<style>svg#legend {font-size: 14px; background-color: white;}</style>'
map_.get_root().header.add_child(folium.Element(svg_style))
map_.add_child(colormap)


# Visualizing the map
map_
Make this Notebook Trusted to load map: File -> Trust Notebook

Click through the layers of this map to see how wetland emissions ramp up over the course of the wet season!

Generate Statistics and Time Series for Methane Emissions in 2020 and 2021

# You can change the years here to look at whichever consecutive two years you want.
years = [2020,2021]
items = catalog.search(
    collections=[collection_name],  # Specify the collection
    datetime=f"{years[0]}-01-01/{years[1]}-12-31",
    limit=24
)
items_2020_2021 = items.items()
# The bounding box should be passed to the geojson param as a geojson Feature or FeatureCollection
# The following function generates statistics for the assigned parameter 
def generate_stats(item, geojson):
    result = requests.post(
        f"{RASTER_API_URL}/cog/statistics",
        params={"url": item["assets"]["ensemble-mean-ch4-wetlands-emissions"]["href"], "dst-crs": "+proj=cea"},
        json=json.loads(geojson.to_json())["features"][0],
    ).json()
    return {
        **result["properties"],
        "datetime": item["properties"]["start_datetime"],
    }
# Generate the stats for the data

stats = [generate_stats(item.to_dict(), louisiana_aoi) for item in items_2020_2021]
stats
[{'statistics': {'b1': {'min': 0.0,
    'max': 2.5330124109324004e-10,
    'mean': 9.19302689528223e-11,
    'count': 50.7400016784668,
    'sum': 4.6645420859192654e-09,
    'std': 5.961293826978086e-11,
    'median': 1.0525500609981364e-10,
    'majority': 0.0,
    'minority': 2.2488163674977413e-12,
    'unique': 62.0,
    'histogram': [[16.0, 5.0, 8.0, 8.0, 11.0, 10.0, 7.0, 2.0, 1.0, 1.0],
     [0.0,
      2.5330123415434613e-11,
      5.0660246830869227e-11,
      7.599036677685689e-11,
      1.0132049366173845e-10,
      1.2665062054662002e-10,
      1.5198073355371378e-10,
      1.7731086043859534e-10,
      2.026409873234769e-10,
      2.2797111420835847e-10,
      2.5330124109324004e-10]],
    'valid_percent': 62.73,
    'masked_pixels': 41.0,
    'valid_pixels': 69.0,
    'percentile_2': 0.0,
    'percentile_98': 2.2315847780784992e-10}},
  'datetime': '2021-12-01T00:00:00+00:00'},
 {'statistics': {'b1': {'min': 0.0,
    'max': 1.9719920141270109e-10,
    'mean': 7.804688145762739e-11,
    'count': 50.7400016784668,
    'sum': 3.960098915456456e-09,
    'std': 5.3807522484790133e-11,
    'median': 8.573550897006399e-11,
    'majority': 0.0,
    'minority': 1.43457294654592e-12,
    'unique': 62.0,
    'histogram': [[15.0, 7.0, 8.0, 5.0, 12.0, 7.0, 6.0, 5.0, 2.0, 2.0],
     [0.0,
      1.971992014127011e-11,
      3.943984028254022e-11,
      5.915976042381033e-11,
      7.887968056508043e-11,
      9.859960070635054e-11,
      1.1831952084762065e-10,
      1.3803944098889076e-10,
      1.5775936113016087e-10,
      1.7747928127143098e-10,
      1.9719920141270109e-10]],
    'valid_percent': 62.73,
    'masked_pixels': 41.0,
    'valid_pixels': 69.0,
    'percentile_2': 0.0,
    'percentile_98': 1.9495059733198872e-10}},
  'datetime': '2021-11-01T00:00:00+00:00'},
 {'statistics': {'b1': {'min': 0.0,
    'max': 5.43883327264183e-10,
    'mean': 2.3125538983759242e-10,
    'count': 50.7400016784668,
    'sum': 1.1733899185628616e-08,
    'std': 1.7068861513688473e-10,
    'median': 2.5294608074766245e-10,
    'majority': 0.0,
    'minority': 2.577651850646512e-12,
    'unique': 62.0,
    'histogram': [[15.0, 10.0, 7.0, 7.0, 4.0, 8.0, 4.0, 5.0, 4.0, 5.0],
     [0.0,
      5.438833411419708e-11,
      1.0877666822839416e-10,
      1.6316500928148514e-10,
      2.1755333645678832e-10,
      2.719416636320915e-10,
      3.263300185629703e-10,
      3.8071834573827346e-10,
      4.3510667291357663e-10,
      4.894950000888798e-10,
      5.43883327264183e-10]],
    'valid_percent': 62.73,
    'masked_pixels': 41.0,
    'valid_pixels': 69.0,
    'percentile_2': 0.0,
    'percentile_98': 5.435277783405468e-10}},
  'datetime': '2021-10-01T00:00:00+00:00'},
 {'statistics': {'b1': {'min': 0.0,
    'max': 9.205272655243846e-10,
    'mean': 3.299917838983646e-10,
    'count': 50.7400016784668,
    'sum': 1.6743783248784894e-08,
    'std': 2.5976790639845377e-10,
    'median': 3.156697403472464e-10,
    'majority': 0.0,
    'minority': 3.2837877382563274e-12,
    'unique': 62.0,
    'histogram': [[18.0, 13.0, 3.0, 9.0, 9.0, 5.0, 6.0, 1.0, 2.0, 3.0],
     [0.0,
      9.205272655243846e-11,
      1.8410545310487691e-10,
      2.7615817965731537e-10,
      3.6821090620975383e-10,
      4.602636327621923e-10,
      5.523163593146307e-10,
      6.443691136226448e-10,
      7.364218124195077e-10,
      8.284745112163705e-10,
      9.205272655243846e-10]],
    'valid_percent': 62.73,
    'masked_pixels': 41.0,
    'valid_pixels': 69.0,
    'percentile_2': 0.0,
    'percentile_98': 8.539197682289057e-10}},
  'datetime': '2021-09-01T00:00:00+00:00'},
 {'statistics': {'b1': {'min': 0.0,
    'max': 8.733219147849525e-10,
    'mean': 3.5411745757940594e-10,
    'count': 50.7400016784668,
    'sum': 1.796792048480711e-08,
    'std': 2.529567011545018e-10,
    'median': 3.784424162933675e-10,
    'majority': 0.0,
    'minority': 6.789848631255646e-12,
    'unique': 62.0,
    'histogram': [[15.0, 7.0, 8.0, 5.0, 15.0, 4.0, 6.0, 3.0, 3.0, 3.0],
     [0.0,
      8.733219009071647e-11,
      1.7466438018143293e-10,
      2.619965633332555e-10,
      3.4932876036286586e-10,
      4.3666095739247623e-10,
      5.23993126666511e-10,
      6.113253236961214e-10,
      6.986575207257317e-10,
      7.859897177553421e-10,
      8.733219147849525e-10]],
    'valid_percent': 62.73,
    'masked_pixels': 41.0,
    'valid_pixels': 69.0,
    'percentile_2': 0.0,
    'percentile_98': 8.708753718167372e-10}},
  'datetime': '2021-08-01T00:00:00+00:00'},
 {'statistics': {'b1': {'min': 0.0,
    'max': 9.537600709208505e-10,
    'mean': 4.273670306531585e-10,
    'count': 50.7400016784668,
    'sum': 2.168460433438213e-08,
    'std': 3.0848437933321594e-10,
    'median': 4.5575368479156e-10,
    'majority': 0.0,
    'minority': 7.648091361611709e-12,
    'unique': 62.0,
    'histogram': [[15.0, 7.0, 9.0, 6.0, 4.0, 9.0, 5.0, 3.0, 2.0, 9.0],
     [0.0,
      9.537600570430627e-11,
      1.9075201140861253e-10,
      2.861280101740249e-10,
      3.8150402281722506e-10,
      4.768800354604252e-10,
      5.722560203480498e-10,
      6.676320607468256e-10,
      7.630080456344501e-10,
      8.583840305220747e-10,
      9.537600709208505e-10]],
    'valid_percent': 62.73,
    'masked_pixels': 41.0,
    'valid_pixels': 69.0,
    'percentile_2': 0.0,
    'percentile_98': 9.479937945755523e-10}},
  'datetime': '2021-07-01T00:00:00+00:00'},
 {'statistics': {'b1': {'min': 0.0,
    'max': 7.682411928833233e-10,
    'mean': 3.661831116108516e-10,
    'count': 50.7400016784668,
    'sum': 1.858013121136537e-08,
    'std': 2.357954498551176e-10,
    'median': 4.349228477362743e-10,
    'majority': 0.0,
    'minority': 7.148038671384027e-12,
    'unique': 62.0,
    'histogram': [[15.0, 5.0, 5.0, 5.0, 3.0, 14.0, 6.0, 7.0, 5.0, 4.0],
     [0.0,
      7.682411651277476e-11,
      1.5364823302554953e-10,
      2.304723495383243e-10,
      3.0729646605109906e-10,
      3.84120568686086e-10,
      4.609446990766486e-10,
      5.377688294672112e-10,
      6.145929321021981e-10,
      6.914170347371851e-10,
      7.682411928833233e-10]],
    'valid_percent': 62.73,
    'masked_pixels': 41.0,
    'valid_pixels': 69.0,
    'percentile_2': 0.0,
    'percentile_98': 7.159188242233938e-10}},
  'datetime': '2021-06-01T00:00:00+00:00'},
 {'statistics': {'b1': {'min': 0.0,
    'max': 6.463339863316264e-10,
    'mean': 3.1208433060037066e-10,
    'count': 50.7400016784668,
    'sum': 1.583515896186327e-08,
    'std': 1.9885634052178184e-10,
    'median': 3.59803659089053e-10,
    'majority': 0.0,
    'minority': 6.672622957643037e-12,
    'unique': 62.0,
    'histogram': [[15.0, 5.0, 6.0, 3.0, 5.0, 8.0, 12.0, 7.0, 4.0, 4.0],
     [0.0,
      6.463339585760508e-11,
      1.2926679171521016e-10,
      1.9390018757281524e-10,
      2.585335834304203e-10,
      3.231669931658132e-10,
      3.878003751456305e-10,
      4.5243375712544776e-10,
      5.170671668608406e-10,
      5.817005765962335e-10,
      6.463339863316264e-10]],
    'valid_percent': 62.73,
    'masked_pixels': 41.0,
    'valid_pixels': 69.0,
    'percentile_2': 0.0,
    'percentile_98': 6.220721160410392e-10}},
  'datetime': '2021-05-01T00:00:00+00:00'},
 {'statistics': {'b1': {'min': 0.0,
    'max': 4.4046835623312575e-10,
    'mean': 2.1511584180622378e-10,
    'count': 50.7400016784668,
    'sum': 1.0914978254561447e-08,
    'std': 1.387249574856683e-10,
    'median': 2.539241872323572e-10,
    'majority': 0.0,
    'minority': 3.829924224985071e-12,
    'unique': 62.0,
    'histogram': [[15.0, 5.0, 5.0, 5.0, 4.0, 10.0, 7.0, 8.0, 6.0, 4.0],
     [0.0,
      4.4046835623312575e-11,
      8.809367124662515e-11,
      1.3214050686993772e-10,
      1.761873424932503e-10,
      2.2023417811656287e-10,
      2.6428101373987545e-10,
      3.0832786324097583e-10,
      3.523746849865006e-10,
      3.9642150673202536e-10,
      4.4046835623312575e-10]],
    'valid_percent': 62.73,
    'masked_pixels': 41.0,
    'valid_pixels': 69.0,
    'percentile_2': 0.0,
    'percentile_98': 4.35462860215452e-10}},
  'datetime': '2021-04-01T00:00:00+00:00'},
 {'statistics': {'b1': {'min': 0.0,
    'max': 3.33559957432783e-10,
    'mean': 1.6867582330881703e-10,
    'count': 50.7400016784668,
    'sum': 8.558611597209165e-09,
    'std': 1.0792223826122726e-10,
    'median': 1.985175079877166e-10,
    'majority': 0.0,
    'minority': 3.347083461086031e-12,
    'unique': 62.0,
    'histogram': [[15.0, 5.0, 5.0, 4.0, 2.0, 9.0, 7.0, 11.0, 6.0, 5.0],
     [0.0,
      3.335599504938891e-11,
      6.671199009877782e-11,
      1.0006798167871978e-10,
      1.3342398019755564e-10,
      1.667799787163915e-10,
      2.0013596335743955e-10,
      2.334919757540632e-10,
      2.6684796039511127e-10,
      3.002039450361593e-10,
      3.33559957432783e-10]],
    'valid_percent': 62.73,
    'masked_pixels': 41.0,
    'valid_pixels': 69.0,
    'percentile_2': 0.0,
    'percentile_98': 3.2655958492888715e-10}},
  'datetime': '2021-03-01T00:00:00+00:00'},
 {'statistics': {'b1': {'min': 0.0,
    'max': 2.3184754116556405e-10,
    'mean': 1.1125794729949234e-10,
    'count': 50.7400016784668,
    'sum': 5.645228284834047e-09,
    'std': 7.634972372744984e-11,
    'median': 1.2166037621774706e-10,
    'majority': 0.0,
    'minority': 2.2384329632918476e-12,
    'unique': 62.0,
    'histogram': [[15.0, 6.0, 8.0, 3.0, 5.0, 10.0, 5.0, 5.0, 4.0, 8.0],
     [0.0,
      2.31847544635011e-11,
      4.63695089270022e-11,
      6.955426512522678e-11,
      9.27390178540044e-11,
      1.1592377058278203e-10,
      1.3910853025045355e-10,
      1.6229327604033728e-10,
      1.854780357080088e-10,
      2.0866279537568033e-10,
      2.3184754116556405e-10]],
    'valid_percent': 62.73,
    'masked_pixels': 41.0,
    'valid_pixels': 69.0,
    'percentile_2': 0.0,
    'percentile_98': 2.2816423750349202e-10}},
  'datetime': '2021-02-01T00:00:00+00:00'},
 {'statistics': {'b1': {'min': 0.0,
    'max': 2.8160682119526825e-10,
    'mean': 1.3195500248031067e-10,
    'count': 50.7400016784668,
    'sum': 6.69539712561118e-09,
    'std': 8.730843357740964e-11,
    'median': 1.5282211607292595e-10,
    'majority': 0.0,
    'minority': 2.8309392590547544e-12,
    'unique': 62.0,
    'histogram': [[15.0, 6.0, 8.0, 4.0, 4.0, 9.0, 9.0, 4.0, 5.0, 5.0],
     [0.0,
      2.8160682119526825e-11,
      5.632136423905365e-11,
      8.448204635858048e-11,
      1.126427284781073e-10,
      1.4080341059763413e-10,
      1.6896409271716095e-10,
      1.9712477483668778e-10,
      2.252854569562146e-10,
      2.5344615295352924e-10,
      2.8160682119526825e-10]],
    'valid_percent': 62.73,
    'masked_pixels': 41.0,
    'valid_pixels': 69.0,
    'percentile_2': 0.0,
    'percentile_98': 2.673118670859509e-10}},
  'datetime': '2021-01-01T00:00:00+00:00'},
 {'statistics': {'b1': {'min': 0.0,
    'max': 2.648110064562559e-10,
    'mean': 1.2158876683265873e-10,
    'count': 50.7400016784668,
    'sum': 6.169414312751087e-09,
    'std': 8.392084741908101e-11,
    'median': 1.3157598621749145e-10,
    'majority': 0.0,
    'minority': 2.4618558060185425e-12,
    'unique': 62.0,
    'histogram': [[15.0, 7.0, 6.0, 5.0, 7.0, 8.0, 5.0, 6.0, 4.0, 6.0],
     [0.0,
      2.6481100298680893e-11,
      5.2962200597361786e-11,
      7.94432991613192e-11,
      1.0592440119472357e-10,
      1.3240550322812794e-10,
      1.588865983226384e-10,
      1.8536770729493668e-10,
      2.1184880238944714e-10,
      2.383299113617454e-10,
      2.648110064562559e-10]],
    'valid_percent': 62.73,
    'masked_pixels': 41.0,
    'valid_pixels': 69.0,
    'percentile_2': 0.0,
    'percentile_98': 2.5922325397331747e-10}},
  'datetime': '2020-12-01T00:00:00+00:00'},
 {'statistics': {'b1': {'min': 0.0,
    'max': 2.717949754149629e-10,
    'mean': 1.0414255569024533e-10,
    'count': 50.7400016784668,
    'sum': 5.284193527188563e-09,
    'std': 7.326889854182361e-11,
    'median': 1.0357469049093737e-10,
    'majority': 0.0,
    'minority': 1.9587144406418844e-12,
    'unique': 62.0,
    'histogram': [[15.0, 8.0, 7.0, 9.0, 12.0, 5.0, 3.0, 4.0, 5.0, 1.0],
     [0.0,
      2.717949823538568e-11,
      5.435899647077136e-11,
      8.153849817560399e-11,
      1.0871799294154272e-10,
      1.3589748770748145e-10,
      1.6307699635120798e-10,
      1.902564911171467e-10,
      2.1743598588308544e-10,
      2.4461549452681197e-10,
      2.717949754149629e-10]],
    'valid_percent': 62.73,
    'masked_pixels': 41.0,
    'valid_pixels': 69.0,
    'percentile_2': 0.0,
    'percentile_98': 2.4095761497200385e-10}},
  'datetime': '2020-11-01T00:00:00+00:00'},
 {'statistics': {'b1': {'min': 0.0,
    'max': 4.310547196961778e-10,
    'mean': 1.918020325897274e-10,
    'count': 50.7400016784668,
    'sum': 9.732035621823343e-09,
    'std': 1.312358760604362e-10,
    'median': 2.2632656859755684e-10,
    'majority': 0.0,
    'minority': 4.136179680008789e-12,
    'unique': 62.0,
    'histogram': [[15.0, 8.0, 6.0, 6.0, 4.0, 10.0, 4.0, 8.0, 4.0, 4.0],
     [0.0,
      4.3105470581839e-11,
      8.6210941163678e-11,
      1.293164186844109e-10,
      1.72421882327356e-10,
      2.155273459703011e-10,
      2.586328373688218e-10,
      3.017383010117669e-10,
      3.44843764654712e-10,
      3.879492282976571e-10,
      4.310547196961778e-10]],
    'valid_percent': 62.73,
    'masked_pixels': 41.0,
    'valid_pixels': 69.0,
    'percentile_2': 0.0,
    'percentile_98': 4.2999878657745683e-10}},
  'datetime': '2020-10-01T00:00:00+00:00'},
 {'statistics': {'b1': {'min': 0.0,
    'max': 6.264283536339121e-10,
    'mean': 2.796445297548189e-10,
    'count': 50.7400016784668,
    'sum': 1.4189164510014507e-08,
    'std': 1.9289630560255983e-10,
    'median': 3.0842731146840663e-10,
    'majority': 0.0,
    'minority': 5.683463248640219e-12,
    'unique': 62.0,
    'histogram': [[16.0, 6.0, 4.0, 10.0, 4.0, 9.0, 7.0, 3.0, 5.0, 5.0],
     [0.0,
      6.264283536339121e-11,
      1.2528567072678243e-10,
      1.8792850609017364e-10,
      2.5057134145356486e-10,
      3.1321417681695607e-10,
      3.758570121803473e-10,
      4.384998475437385e-10,
      5.011426829071297e-10,
      5.637855182705209e-10,
      6.264283536339121e-10]],
    'valid_percent': 62.73,
    'masked_pixels': 41.0,
    'valid_pixels': 69.0,
    'percentile_2': 0.0,
    'percentile_98': 6.141340214149693e-10}},
  'datetime': '2020-09-01T00:00:00+00:00'},
 {'statistics': {'b1': {'min': 0.0,
    'max': 6.708232858088081e-10,
    'mean': 2.897228568166099e-10,
    'count': 50.7400016784668,
    'sum': 1.4700537676048953e-08,
    'std': 2.1059689637594565e-10,
    'median': 2.781424257580767e-10,
    'majority': 0.0,
    'minority': 5.702030427684468e-12,
    'unique': 62.0,
    'histogram': [[16.0, 7.0, 6.0, 8.0, 4.0, 8.0, 6.0, 4.0, 5.0, 5.0],
     [0.0,
      6.708232580532325e-11,
      1.341646516106465e-10,
      2.0124697741596975e-10,
      2.68329303221293e-10,
      3.3541164290440406e-10,
      4.024939548319395e-10,
      4.695762667594749e-10,
      5.36658606442586e-10,
      6.037409461256971e-10,
      6.708232858088081e-10]],
    'valid_percent': 62.73,
    'masked_pixels': 41.0,
    'valid_pixels': 69.0,
    'percentile_2': 0.0,
    'percentile_98': 6.563689591843058e-10}},
  'datetime': '2020-08-01T00:00:00+00:00'},
 {'statistics': {'b1': {'min': 0.0,
    'max': 7.929303880160887e-10,
    'mean': 3.560508277100638e-10,
    'count': 50.7400016784668,
    'sum': 1.8066019791262988e-08,
    'std': 2.304642304169844e-10,
    'median': 4.2078254769428725e-10,
    'majority': 0.0,
    'minority': 7.581872629724984e-12,
    'unique': 62.0,
    'histogram': [[15.0, 6.0, 4.0, 7.0, 5.0, 11.0, 7.0, 8.0, 4.0, 2.0],
     [0.0,
      7.929303741383009e-11,
      1.5858607482766018e-10,
      2.3787910530259637e-10,
      3.1717214965532037e-10,
      3.9646519400804436e-10,
      4.757582106051927e-10,
      5.550512827134924e-10,
      6.343442993106407e-10,
      7.136373159077891e-10,
      7.929303880160887e-10]],
    'valid_percent': 62.73,
    'masked_pixels': 41.0,
    'valid_pixels': 69.0,
    'percentile_2': 0.0,
    'percentile_98': 7.183983963265916e-10}},
  'datetime': '2020-07-01T00:00:00+00:00'},
 {'statistics': {'b1': {'min': 0.0,
    'max': 5.799246638460431e-10,
    'mean': 2.6909194317248364e-10,
    'count': 50.7400016784668,
    'sum': 1.3653726149698286e-08,
    'std': 1.6771352836501439e-10,
    'median': 3.323915864772431e-10,
    'majority': 0.0,
    'minority': 5.4579314158476055e-12,
    'unique': 62.0,
    'histogram': [[14.0, 6.0, 3.0, 7.0, 3.0, 8.0, 16.0, 5.0, 6.0, 1.0],
     [0.0,
      5.799246499682553e-11,
      1.1598492999365106e-10,
      1.739773880515827e-10,
      2.3196985998730213e-10,
      2.8996233192302157e-10,
      3.479547761031654e-10,
      4.059472480388848e-10,
      4.6393971997460426e-10,
      5.219321641547481e-10,
      5.799246638460431e-10]],
    'valid_percent': 62.73,
    'masked_pixels': 41.0,
    'valid_pixels': 69.0,
    'percentile_2': 0.0,
    'percentile_98': 5.097296473799418e-10}},
  'datetime': '2020-06-01T00:00:00+00:00'},
 {'statistics': {'b1': {'min': 0.0,
    'max': 5.091709276427991e-10,
    'mean': 2.307394691980491e-10,
    'count': 50.7400016784668,
    'sum': 1.1707721014886374e-08,
    'std': 1.421560091653288e-10,
    'median': 2.693225920058495e-10,
    'majority': 0.0,
    'minority': 5.328217901612309e-12,
    'unique': 62.0,
    'histogram': [[16.0, 4.0, 4.0, 4.0, 8.0, 9.0, 13.0, 7.0, 3.0, 1.0],
     [0.0,
      5.0917093458169305e-11,
      1.0183418691633861e-10,
      1.5275128384395487e-10,
      2.0366837383267722e-10,
      2.5458546382139957e-10,
      3.0550256768790973e-10,
      3.564196437988443e-10,
      4.0733674766535444e-10,
      4.582538515318646e-10,
      5.091709276427991e-10]],
    'valid_percent': 62.73,
    'masked_pixels': 41.0,
    'valid_pixels': 69.0,
    'percentile_2': 0.0,
    'percentile_98': 4.3187328713223394e-10}},
  'datetime': '2020-05-01T00:00:00+00:00'},
 {'statistics': {'b1': {'min': 0.0,
    'max': 4.056825708698142e-10,
    'mean': 1.6614522257984987e-10,
    'count': 50.7400016784668,
    'sum': 8.430208531251537e-09,
    'std': 1.0901136555669306e-10,
    'median': 1.7692246279121804e-10,
    'majority': 0.0,
    'minority': 4.416985440597321e-12,
    'unique': 62.0,
    'histogram': [[15.0, 4.0, 9.0, 2.0, 10.0, 10.0, 8.0, 7.0, 3.0, 1.0],
     [0.0,
      4.056825708698142e-11,
      8.113651417396284e-11,
      1.2170477126094426e-10,
      1.6227302834792567e-10,
      2.028412854349071e-10,
      2.434095425218885e-10,
      2.839777857310821e-10,
      3.2454605669585135e-10,
      3.651143276606206e-10,
      4.056825708698142e-10]],
    'valid_percent': 62.73,
    'masked_pixels': 41.0,
    'valid_pixels': 69.0,
    'percentile_2': 0.0,
    'percentile_98': 3.432379380718942e-10}},
  'datetime': '2020-04-01T00:00:00+00:00'},
 {'statistics': {'b1': {'min': 0.0,
    'max': 4.137748754740045e-10,
    'mean': 1.9076612511881308e-10,
    'count': 50.7400016784668,
    'sum': 9.67947322294549e-09,
    'std': 1.2037232492517806e-10,
    'median': 2.17308060435073e-10,
    'majority': 0.0,
    'minority': 4.401263641734543e-12,
    'unique': 62.0,
    'histogram': [[16.0, 3.0, 4.0, 8.0, 6.0, 4.0, 13.0, 10.0, 3.0, 2.0],
     [0.0,
      4.137748824128984e-11,
      8.275497648257968e-11,
      1.2413246819331647e-10,
      1.6550995296515936e-10,
      2.0688743773700224e-10,
      2.4826493638663294e-10,
      2.8964242115847583e-10,
      3.310199059303187e-10,
      3.723973907021616e-10,
      4.137748754740045e-10]],
    'valid_percent': 62.73,
    'masked_pixels': 41.0,
    'valid_pixels': 69.0,
    'percentile_2': 0.0,
    'percentile_98': 3.9333974966027085e-10}},
  'datetime': '2020-03-01T00:00:00+00:00'},
 {'statistics': {'b1': {'min': 0.0,
    'max': 3.389031555389721e-10,
    'mean': 1.644631514308159e-10,
    'count': 50.7400016784668,
    'sum': 8.344860802367293e-09,
    'std': 1.1008571948608436e-10,
    'median': 1.8891545272570198e-10,
    'majority': 0.0,
    'minority': 3.1559084772564416e-12,
    'unique': 62.0,
    'histogram': [[15.0, 6.0, 6.0, 4.0, 3.0, 13.0, 6.0, 4.0, 3.0, 9.0],
     [0.0,
      3.389031416611843e-11,
      6.778062833223686e-11,
      1.0167094249835529e-10,
      1.3556125666447372e-10,
      1.6945156389169824e-10,
      2.0334188499671058e-10,
      2.372322061017229e-10,
      2.7112251332894743e-10,
      3.0501282055617196e-10,
      3.389031555389721e-10]],
    'valid_percent': 62.73,
    'masked_pixels': 41.0,
    'valid_pixels': 69.0,
    'percentile_2': 0.0,
    'percentile_98': 3.367382761521043e-10}},
  'datetime': '2020-02-01T00:00:00+00:00'},
 {'statistics': {'b1': {'min': 0.0,
    'max': 3.2636207625280633e-10,
    'mean': 1.5284970511508789e-10,
    'count': 50.7400016784668,
    'sum': 7.755594388925147e-09,
    'std': 1.011071024654434e-10,
    'median': 1.861473475361919e-10,
    'majority': 0.0,
    'minority': 3.0835748451168987e-12,
    'unique': 62.0,
    'histogram': [[15.0, 7.0, 5.0, 4.0, 5.0, 11.0, 6.0, 7.0, 4.0, 5.0],
     [0.0,
      3.263620623750185e-11,
      6.52724124750037e-11,
      9.790861871250556e-11,
      1.305448249500074e-10,
      1.6318102424861536e-10,
      1.9581723742501111e-10,
      2.2845345060140687e-10,
      2.610896499000148e-10,
      2.9372584919862277e-10,
      3.2636207625280633e-10]],
    'valid_percent': 62.73,
    'masked_pixels': 41.0,
    'valid_pixels': 69.0,
    'percentile_2': 0.0,
    'percentile_98': 3.136762793953807e-10}},
  'datetime': '2020-01-01T00:00:00+00:00'}]
# Manipulating and cleaning the stats output from previous cell
def clean_stats(stats_json) -> pd.DataFrame:
    df = pd.json_normalize(stats_json)
    df.columns = [col.replace("statistics.b1.", "") for col in df.columns]
    df["date"] = pd.to_datetime(df["datetime"])
    return df


df = clean_stats(stats)
df.head(5)
datetime min max mean count sum std median majority minority unique histogram valid_percent masked_pixels valid_pixels percentile_2 percentile_98 date
0 2021-12-01T00:00:00+00:00 0.0 2.533012e-10 9.193027e-11 50.740002 4.664542e-09 5.961294e-11 1.052550e-10 0.0 2.248816e-12 62.0 [[16.0, 5.0, 8.0, 8.0, 11.0, 10.0, 7.0, 2.0, 1... 62.73 41.0 69.0 0.0 2.231585e-10 2021-12-01 00:00:00+00:00
1 2021-11-01T00:00:00+00:00 0.0 1.971992e-10 7.804688e-11 50.740002 3.960099e-09 5.380752e-11 8.573551e-11 0.0 1.434573e-12 62.0 [[15.0, 7.0, 8.0, 5.0, 12.0, 7.0, 6.0, 5.0, 2.... 62.73 41.0 69.0 0.0 1.949506e-10 2021-11-01 00:00:00+00:00
2 2021-10-01T00:00:00+00:00 0.0 5.438833e-10 2.312554e-10 50.740002 1.173390e-08 1.706886e-10 2.529461e-10 0.0 2.577652e-12 62.0 [[15.0, 10.0, 7.0, 7.0, 4.0, 8.0, 4.0, 5.0, 4.... 62.73 41.0 69.0 0.0 5.435278e-10 2021-10-01 00:00:00+00:00
3 2021-09-01T00:00:00+00:00 0.0 9.205273e-10 3.299918e-10 50.740002 1.674378e-08 2.597679e-10 3.156697e-10 0.0 3.283788e-12 62.0 [[18.0, 13.0, 3.0, 9.0, 9.0, 5.0, 6.0, 1.0, 2.... 62.73 41.0 69.0 0.0 8.539198e-10 2021-09-01 00:00:00+00:00
4 2021-08-01T00:00:00+00:00 0.0 8.733219e-10 3.541175e-10 50.740002 1.796792e-08 2.529567e-10 3.784424e-10 0.0 6.789849e-12 62.0 [[15.0, 7.0, 8.0, 5.0, 15.0, 4.0, 6.0, 3.0, 3.... 62.73 41.0 69.0 0.0 8.708754e-10 2021-08-01 00:00:00+00:00
df['year'] = pd.to_datetime(df['datetime']).dt.year
df['month'] = pd.to_datetime(df['datetime']).dt.month
df
datetime min max mean count sum std median majority minority unique histogram valid_percent masked_pixels valid_pixels percentile_2 percentile_98 date year month
0 2021-12-01T00:00:00+00:00 0.0 2.533012e-10 9.193027e-11 50.740002 4.664542e-09 5.961294e-11 1.052550e-10 0.0 2.248816e-12 62.0 [[16.0, 5.0, 8.0, 8.0, 11.0, 10.0, 7.0, 2.0, 1... 62.73 41.0 69.0 0.0 2.231585e-10 2021-12-01 00:00:00+00:00 2021 12
1 2021-11-01T00:00:00+00:00 0.0 1.971992e-10 7.804688e-11 50.740002 3.960099e-09 5.380752e-11 8.573551e-11 0.0 1.434573e-12 62.0 [[15.0, 7.0, 8.0, 5.0, 12.0, 7.0, 6.0, 5.0, 2.... 62.73 41.0 69.0 0.0 1.949506e-10 2021-11-01 00:00:00+00:00 2021 11
2 2021-10-01T00:00:00+00:00 0.0 5.438833e-10 2.312554e-10 50.740002 1.173390e-08 1.706886e-10 2.529461e-10 0.0 2.577652e-12 62.0 [[15.0, 10.0, 7.0, 7.0, 4.0, 8.0, 4.0, 5.0, 4.... 62.73 41.0 69.0 0.0 5.435278e-10 2021-10-01 00:00:00+00:00 2021 10
3 2021-09-01T00:00:00+00:00 0.0 9.205273e-10 3.299918e-10 50.740002 1.674378e-08 2.597679e-10 3.156697e-10 0.0 3.283788e-12 62.0 [[18.0, 13.0, 3.0, 9.0, 9.0, 5.0, 6.0, 1.0, 2.... 62.73 41.0 69.0 0.0 8.539198e-10 2021-09-01 00:00:00+00:00 2021 9
4 2021-08-01T00:00:00+00:00 0.0 8.733219e-10 3.541175e-10 50.740002 1.796792e-08 2.529567e-10 3.784424e-10 0.0 6.789849e-12 62.0 [[15.0, 7.0, 8.0, 5.0, 15.0, 4.0, 6.0, 3.0, 3.... 62.73 41.0 69.0 0.0 8.708754e-10 2021-08-01 00:00:00+00:00 2021 8
5 2021-07-01T00:00:00+00:00 0.0 9.537601e-10 4.273670e-10 50.740002 2.168460e-08 3.084844e-10 4.557537e-10 0.0 7.648091e-12 62.0 [[15.0, 7.0, 9.0, 6.0, 4.0, 9.0, 5.0, 3.0, 2.0... 62.73 41.0 69.0 0.0 9.479938e-10 2021-07-01 00:00:00+00:00 2021 7
6 2021-06-01T00:00:00+00:00 0.0 7.682412e-10 3.661831e-10 50.740002 1.858013e-08 2.357954e-10 4.349228e-10 0.0 7.148039e-12 62.0 [[15.0, 5.0, 5.0, 5.0, 3.0, 14.0, 6.0, 7.0, 5.... 62.73 41.0 69.0 0.0 7.159188e-10 2021-06-01 00:00:00+00:00 2021 6
7 2021-05-01T00:00:00+00:00 0.0 6.463340e-10 3.120843e-10 50.740002 1.583516e-08 1.988563e-10 3.598037e-10 0.0 6.672623e-12 62.0 [[15.0, 5.0, 6.0, 3.0, 5.0, 8.0, 12.0, 7.0, 4.... 62.73 41.0 69.0 0.0 6.220721e-10 2021-05-01 00:00:00+00:00 2021 5
8 2021-04-01T00:00:00+00:00 0.0 4.404684e-10 2.151158e-10 50.740002 1.091498e-08 1.387250e-10 2.539242e-10 0.0 3.829924e-12 62.0 [[15.0, 5.0, 5.0, 5.0, 4.0, 10.0, 7.0, 8.0, 6.... 62.73 41.0 69.0 0.0 4.354629e-10 2021-04-01 00:00:00+00:00 2021 4
9 2021-03-01T00:00:00+00:00 0.0 3.335600e-10 1.686758e-10 50.740002 8.558612e-09 1.079222e-10 1.985175e-10 0.0 3.347083e-12 62.0 [[15.0, 5.0, 5.0, 4.0, 2.0, 9.0, 7.0, 11.0, 6.... 62.73 41.0 69.0 0.0 3.265596e-10 2021-03-01 00:00:00+00:00 2021 3
10 2021-02-01T00:00:00+00:00 0.0 2.318475e-10 1.112579e-10 50.740002 5.645228e-09 7.634972e-11 1.216604e-10 0.0 2.238433e-12 62.0 [[15.0, 6.0, 8.0, 3.0, 5.0, 10.0, 5.0, 5.0, 4.... 62.73 41.0 69.0 0.0 2.281642e-10 2021-02-01 00:00:00+00:00 2021 2
11 2021-01-01T00:00:00+00:00 0.0 2.816068e-10 1.319550e-10 50.740002 6.695397e-09 8.730843e-11 1.528221e-10 0.0 2.830939e-12 62.0 [[15.0, 6.0, 8.0, 4.0, 4.0, 9.0, 9.0, 4.0, 5.0... 62.73 41.0 69.0 0.0 2.673119e-10 2021-01-01 00:00:00+00:00 2021 1
12 2020-12-01T00:00:00+00:00 0.0 2.648110e-10 1.215888e-10 50.740002 6.169414e-09 8.392085e-11 1.315760e-10 0.0 2.461856e-12 62.0 [[15.0, 7.0, 6.0, 5.0, 7.0, 8.0, 5.0, 6.0, 4.0... 62.73 41.0 69.0 0.0 2.592233e-10 2020-12-01 00:00:00+00:00 2020 12
13 2020-11-01T00:00:00+00:00 0.0 2.717950e-10 1.041426e-10 50.740002 5.284194e-09 7.326890e-11 1.035747e-10 0.0 1.958714e-12 62.0 [[15.0, 8.0, 7.0, 9.0, 12.0, 5.0, 3.0, 4.0, 5.... 62.73 41.0 69.0 0.0 2.409576e-10 2020-11-01 00:00:00+00:00 2020 11
14 2020-10-01T00:00:00+00:00 0.0 4.310547e-10 1.918020e-10 50.740002 9.732036e-09 1.312359e-10 2.263266e-10 0.0 4.136180e-12 62.0 [[15.0, 8.0, 6.0, 6.0, 4.0, 10.0, 4.0, 8.0, 4.... 62.73 41.0 69.0 0.0 4.299988e-10 2020-10-01 00:00:00+00:00 2020 10
15 2020-09-01T00:00:00+00:00 0.0 6.264284e-10 2.796445e-10 50.740002 1.418916e-08 1.928963e-10 3.084273e-10 0.0 5.683463e-12 62.0 [[16.0, 6.0, 4.0, 10.0, 4.0, 9.0, 7.0, 3.0, 5.... 62.73 41.0 69.0 0.0 6.141340e-10 2020-09-01 00:00:00+00:00 2020 9
16 2020-08-01T00:00:00+00:00 0.0 6.708233e-10 2.897229e-10 50.740002 1.470054e-08 2.105969e-10 2.781424e-10 0.0 5.702030e-12 62.0 [[16.0, 7.0, 6.0, 8.0, 4.0, 8.0, 6.0, 4.0, 5.0... 62.73 41.0 69.0 0.0 6.563690e-10 2020-08-01 00:00:00+00:00 2020 8
17 2020-07-01T00:00:00+00:00 0.0 7.929304e-10 3.560508e-10 50.740002 1.806602e-08 2.304642e-10 4.207825e-10 0.0 7.581873e-12 62.0 [[15.0, 6.0, 4.0, 7.0, 5.0, 11.0, 7.0, 8.0, 4.... 62.73 41.0 69.0 0.0 7.183984e-10 2020-07-01 00:00:00+00:00 2020 7
18 2020-06-01T00:00:00+00:00 0.0 5.799247e-10 2.690919e-10 50.740002 1.365373e-08 1.677135e-10 3.323916e-10 0.0 5.457931e-12 62.0 [[14.0, 6.0, 3.0, 7.0, 3.0, 8.0, 16.0, 5.0, 6.... 62.73 41.0 69.0 0.0 5.097296e-10 2020-06-01 00:00:00+00:00 2020 6
19 2020-05-01T00:00:00+00:00 0.0 5.091709e-10 2.307395e-10 50.740002 1.170772e-08 1.421560e-10 2.693226e-10 0.0 5.328218e-12 62.0 [[16.0, 4.0, 4.0, 4.0, 8.0, 9.0, 13.0, 7.0, 3.... 62.73 41.0 69.0 0.0 4.318733e-10 2020-05-01 00:00:00+00:00 2020 5
20 2020-04-01T00:00:00+00:00 0.0 4.056826e-10 1.661452e-10 50.740002 8.430209e-09 1.090114e-10 1.769225e-10 0.0 4.416985e-12 62.0 [[15.0, 4.0, 9.0, 2.0, 10.0, 10.0, 8.0, 7.0, 3... 62.73 41.0 69.0 0.0 3.432379e-10 2020-04-01 00:00:00+00:00 2020 4
21 2020-03-01T00:00:00+00:00 0.0 4.137749e-10 1.907661e-10 50.740002 9.679473e-09 1.203723e-10 2.173081e-10 0.0 4.401264e-12 62.0 [[16.0, 3.0, 4.0, 8.0, 6.0, 4.0, 13.0, 10.0, 3... 62.73 41.0 69.0 0.0 3.933397e-10 2020-03-01 00:00:00+00:00 2020 3
22 2020-02-01T00:00:00+00:00 0.0 3.389032e-10 1.644632e-10 50.740002 8.344861e-09 1.100857e-10 1.889155e-10 0.0 3.155908e-12 62.0 [[15.0, 6.0, 6.0, 4.0, 3.0, 13.0, 6.0, 4.0, 3.... 62.73 41.0 69.0 0.0 3.367383e-10 2020-02-01 00:00:00+00:00 2020 2
23 2020-01-01T00:00:00+00:00 0.0 3.263621e-10 1.528497e-10 50.740002 7.755594e-09 1.011071e-10 1.861473e-10 0.0 3.083575e-12 62.0 [[15.0, 7.0, 5.0, 4.0, 5.0, 11.0, 6.0, 7.0, 4.... 62.73 41.0 69.0 0.0 3.136763e-10 2020-01-01 00:00:00+00:00 2020 1

Visualizing the Data as a Time Series

We can now plot the time-series of the wetland methane emissions for the state of Louisiana for the 2023-2024 (January - December) period.

fig = plt.figure(figsize=(20, 10))

# Set the plot elements 
sns.lineplot(
    df,
    x = 'month', 
    y = 'sum',
    hue= 'year',
    palette='flare'
)


# Set the labels for the X and Y axis and assign a title for the plot 
# plt.legend()
plt.xlabel("months")
plt.ylabel("CH4 emissions g/m2")
plt.title("CH4 emission Values for Louisiana for 2020 and 2021")
Text(0.5, 1.0, 'CH4 emission Values for Louisiana for 2020 and 2021')

⚠️ Note: The calculation above does not currently translate lat/lon grid boxes to meters squared, so the final numbers are not total emissions over the AOI. This is a bug and will be fixed in future. See Method # 2 using xarray and rioxarray for a correctly weighted total over the AOI

Alternatively,

Use stackstac to read in the dataset into xarray and use rioxarray to generate the timeseries

# Read in LPJ data to xarray DataArray
ds = stackstac.stack(items.item_collection(),epsg=4326).squeeze()
# Let's take a look
ds
<xarray.DataArray 'stackstac-832e5ff502af6903e5fc4ff92bb07e45' (time: 24,
                                                                band: 3,
                                                                y: 360, x: 720)> Size: 149MB
dask.array<fetch_raster_window, shape=(24, 3, 360, 720), dtype=float64, chunksize=(1, 1, 360, 720), chunktype=numpy.ndarray>
Coordinates: (12/15)
  * time            (time) datetime64[ns] 192B NaT NaT NaT NaT ... NaT NaT NaT
    id              (time) <U39 4kB 'lpjeosim-wetlandch4-monthgrid-v1-202112'...
  * band            (band) <U36 432B 'era5-ch4-wetlands-emissions' ... 'ensem...
  * x               (x) float64 6kB -180.0 -179.5 -179.0 ... 178.5 179.0 179.5
  * y               (y) float64 3kB 90.0 89.5 89.0 88.5 ... -88.5 -89.0 -89.5
    end_datetime    (time) <U25 2kB '2021-12-31T00:00:00+00:00' ... '2020-01-...
    ...              ...
    proj:geometry   object 8B {'type': 'Polygon', 'coordinates': [[[-180.0, -...
    description     (band) <U207 2kB 'Methane emissions from wetlands in unit...
    proj:shape      object 8B {360, 720}
    proj:wkt2       <U302 1kB 'GEOGCS["WGS 84",DATUM["WGS_1984",SPHEROID["WGS...
    proj:transform  object 8B {0.5, 0.0, -0.5, 1.0, -180.0, 90.0}
    epsg            int64 8B 4326
Attributes:
    spec:        RasterSpec(epsg=4326, bounds=(-180.0, -90.0, 180.0, 90.0), r...
    crs:         epsg:4326
    transform:   | 0.50, 0.00,-180.00|\n| 0.00,-0.50, 90.00|\n| 0.00, 0.00, 1...
    resolution:  0.5

Use rioxarray to select data within AOI

The rio.clip function has a few options for selection of grid cells relative to the specified geometry. Here we will use the default functionality. See documentation for more info.

# Clip data to our polygon
clip = ds.rio.clip(geometries=louisiana_aoi.geometry.values)
# We need the latitude values reversed to utilize a function correctly in the next step.
#clip = clip.reindex(y=clip.y[::-1])
# Quick plot to visualize our data selection
fig=plt.figure()
ax1=fig.add_subplot(projection=ccrs.PlateCarree())
clip.sel(band=asset_name)[6,:,:].plot(ax=ax1,cmap='magma') # index 6 corresponds to July 2021
louisiana_aoi.plot(ax=ax1,facecolor='none',edgecolor='#04E762',linewidth=2)
ax1.add_feature(cf.STATES,linewidth=0.5)

Calculate and apply area weights

Our CH4 emissions are in g m-2 month-1, but our grid cells are in lat/lon space - we need to calculate how many meters are in each grid cell, so we can calculate emissions in g month-1.

# We need the latitude values reversed to utilize surfaceAreaGrid correctly.
clip = clip.reindex(y=clip.y[::-1])
weights = surfaceAreaGrid.surfaceAreaGridd(
    lat_centers=clip.y.values,
    lon_centers=clip.x.values,
    ret_area=True)
# Apply these weights - simple as a multiplication
data_weighted = clip.sel(band=asset_name)*weights
# Take the total emissions over our polygon
means = data_weighted.sum(dim=['x','y'])
# Define year and month from start_datetime values
# and add them to the xarray DataArray, 
# specifying that they corresponds to the 'time' dimension.
means['year'] = (['time'],[datetime.fromisoformat(sd).year for sd in ds['start_datetime'].values])
means['month'] = (['time'],[datetime.fromisoformat(sd).strftime('%b') for sd in ds['start_datetime'].values])

Plot time series

means[means['year']==years[1]][::-1].plot(x='month',label=str(years[1]),figsize=(10,5))
means[means['year']==years[0]][::-1].plot(x='month',label=str(years[0]))
plt.legend()
plt.title('Total monthly CH4 emissions over AOI')
plt.ylabel('Total CH4 emissions, g')
Text(0, 0.5, 'Total CH4 emissions, g')

Advanced users: Bring in supplemental data through NASA Earthdata

To extend this type of work in a Jupyter notebook, you can connect through an existing NASA Earthdata account to access external datasets. For example, one might examine meteorological variables from MERRA-2, a reanalysis product from NASA’s Global Modeling and Assimilation Office, to see whether precipitation or surface temperature are related to higher methane emissions.

We have provided below the steps for connecting to NASA Earthdata, but we will not be demonstrating this capability during the workshop. Feel free to experiment with this later on!

NASA Earth Data Login Credentials

To download or stream NASA data you will need an Earthdata account, you can create one here https://urs.earthdata.nasa.gov/home. We will use the login function from the earthaccess library for authentication before downloading at the end of the notebook. This function can also be used to create a local .netrc file if it doesn’t exist or add your login info to an existing .netrc file. If no Earthdata Login credentials are found in the .netrc you’ll be prompted for them. This step is not necessary to conduct searches but is needed to download or stream data.

# from netrc import netrc
# from subprocess import Popen
# from platform import system
# from getpass import getpass
# import os
# import requests
# import xarray as xr
# import s3fs
# import boto3
# import cartopy.crs as ccrs
# import cartopy.feature as cfeature
# import matplotlib.pyplot as plt
# import warnings
# from IPython.display import display, Markdown

# if (boto3.client('s3').meta.region_name == 'us-west-2'):
#     display(Markdown('### us-west-2 Region Check: &#x2705;'))
# else:
#     display(Markdown('### us-west-2 Region Check: &#10060;'))
#     raise ValueError('Your notebook is not running inside the AWS us-west-2 region, and will not be able to directly access NASA Earthdata S3 buckets')

# urs = 'urs.earthdata.nasa.gov'    # Earthdata URL endpoint for authentication
# prompts = ['Enter NASA Earthdata Login Username: ',
#            'Enter NASA Earthdata Login Password: ']

# netrc_name = ".netrc"

# # Determine if netrc file exists, and if so, if it includes NASA Earthdata Login Credentials
# try:
#     netrcDir = os.path.expanduser(f"~/{netrc_name}")
#     # Check credentials against URS, and if username exists
#     netrc(netrcDir).authenticators(urs)[0]

# # Below, create a netrc file and prompt user for NASA Earthdata Login Username and Password
# except FileNotFoundError:
#     homeDir = os.path.expanduser("~")
#     Popen('touch {0}{2} | echo machine {1} >> {0}{2}'.format(homeDir + os.sep, urs, netrc_name), shell=True)
#     Popen('echo login {} >> {}{}'.format(getpass(prompt=prompts[0]), homeDir + os.sep, netrc_name), shell=True)
#     Popen('echo \'password {} \'>> {}{}'.format(getpass(prompt=prompts[1]), homeDir + os.sep, netrc_name), shell=True)
#     # Set restrictive permissions
#     Popen('chmod 0600 {0}{1}'.format(homeDir + os.sep, netrc_name), shell=True)

# gesdisc_s3 = "https://data.gesdisc.earthdata.nasa.gov/s3credentials"

# # Define a function for S3 access credentials

# def begin_s3_direct_access(url: str=gesdisc_s3):
#     response = requests.get(url).json()
#     return s3fs.S3FileSystem(key=response['accessKeyId'],
#                              secret=response['secretAccessKey'],
#                              token=response['sessionToken'],
#                              client_kwargs={'region_name':'us-west-2'})

# fs = begin_s3_direct_access()
# fn = 's3://gesdisc-cumulus-prod-protected/MERRA2/M2T1NXSLV.5.12.4/2019/03/MERRA2_400.tavg1_2d_slv_Nx.20190313.nc4'

# fs.info(fn)
# fs.ls('s3://gesdisc-cumulus-prod-protected/MERRA2/')