import os
from pathlib import Path
import cartopy.crs as ccrs
import earthaccess
import h5py
import numpy as np
import PIL
from matplotlib import pyplot as plt
MOPITT Carbon Monoxide (CO) Mixing Ratio
Summary
This code makes a GIF from the RetrievedCOMixingRatioProfileDay
variable from Measurements Of Pollution In The Troposphere (MOPITT).
Prerequisites
A free(!) account at https://www.earthdata.nasa.gov/ is needed to login and download the appropriate files.
This notebook was tested last using Python 3.10.15, and requires these libraries:
1. Setup
2. Search for data using earthaccess
We use earthaccess
to streamline the login to NASA Earthdata.
Additional resources about earthaccess
earthaccess.login()
<earthaccess.auth.Auth at 0x103e4f160>
= "MOP03JM"
short_name = "9"
version
= earthaccess.search_data(
results =short_name,
short_name=version,
version="LARC_CLOUD", # this is needed only temporary, while there are still non-LARC_CLOUD versions of these granules.
provider=("2024-09", "2024-10"),
temporal
)
print(f"{len(results)} file(s) found.")
2 file(s) found.
print(results)
[Collection: {'ShortName': 'MOP03JM', 'Version': '9'}
Spatial coverage: {'HorizontalSpatialDomain': {'Geometry': {'BoundingRectangles': [{'WestBoundingCoordinate': -180.0, 'EastBoundingCoordinate': 180.0, 'NorthBoundingCoordinate': 90.0, 'SouthBoundingCoordinate': -90.0}]}}}
Temporal coverage: {'RangeDateTime': {'BeginningDateTime': '2024-09-01T00:00:04.694Z', 'EndingDateTime': '2024-09-01T23:59:59.999Z'}}
Size(MB): 146.863
Data: ['https://data.asdc.earthdata.nasa.gov/asdc-prod-protected/MOPITT/MOP03JM.9/2024.09.01/MOP03JM-202409-L3V95.10.3.he5'], Collection: {'ShortName': 'MOP03JM', 'Version': '9'}
Spatial coverage: {'HorizontalSpatialDomain': {'Geometry': {'BoundingRectangles': [{'WestBoundingCoordinate': -180.0, 'EastBoundingCoordinate': 180.0, 'NorthBoundingCoordinate': 90.0, 'SouthBoundingCoordinate': -90.0}]}}}
Temporal coverage: {'RangeDateTime': {'BeginningDateTime': '2024-10-01T00:00:05.832Z', 'EndingDateTime': '2024-10-01T23:59:59.999Z'}}
Size(MB): 149.263
Data: ['https://data.asdc.earthdata.nasa.gov/asdc-prod-protected/MOPITT/MOP03JM.9/2024.10.01/MOP03JM-202410-L3V95.10.3.he5']]
3. Download data
= earthaccess.download(results, local_path=".")
downloaded_files downloaded_files
['MOP03JM-202409-L3V95.10.3.he5', 'MOP03JM-202410-L3V95.10.3.he5']
4. Open the files
= {"lon": [], "lat": [], "CO_mixing_ratio": []}
arrays
# Open and read file
for i, file in enumerate(downloaded_files):
with h5py.File(file, mode="r") as f:
# Slice data to get the pressure level of your choice
# [Longitude(Xdim):360 , Latitude(Ydim):180, Presure level:9]
# Pressure Level: 0 = 900 hPa, 1 = 800 hPa, 2 = 700 hPa, 3 = 600 hPa
# 4 = 500 hPa, 5 = 400 hpa, 6 = 300 hPa, 7 = 200 hPa, 8 = 100 hPa
= f["/HDFEOS/GRIDS/MOP03/Data Fields/RetrievedCOMixingRatioProfileDay"][:]
data = np.transpose(data)
data
# Retrieve the lat and lon data as well as the area of your choice
= f["/HDFEOS/GRIDS/MOP03/Data Fields/Longitude"][:]
lon = f["/HDFEOS/GRIDS/MOP03/Data Fields/Latitude"][:]
lat
# Turn the -9999.0 into a NaN
= np.ma.masked_where(data <= 0, data)
masked_data = data.copy()
CO_mixing_ratio <= 0] = np.nan
CO_mixing_ratio[masked_data
"lon"].append(lon)
arrays["lat"].append(lat)
arrays["CO_mixing_ratio"].append(CO_mixing_ratio) arrays[
5. Generate plots
= np.arange(0, 9)
pressure_levels
= ccrs.PlateCarree()
proj
for file_index, file in enumerate(downloaded_files):
= Path(file).stem
filestem =True)
os.makedirs(filestem, exist_ok
# Plot all graphs.
for i in pressure_levels:
= plt.subplots(figsize=(7.20, 3.60), dpi=80, subplot_kw={"projection": proj})
fig, ax
= ax.contourf(
im "lon"][file_index],
arrays["lat"][file_index],
arrays["CO_mixing_ratio"][file_index][i, :, :],
arrays[=np.linspace(0, 430, 25),
levels="jet",
cmap=0,
vmin=430,
vmax=proj,
transform
)
ax.coastlines()
= plt.colorbar(im, shrink=0.76)
cb "ppbv", fontsize=8)
cb.set_label(
= -i + 9
pressure_prefix
plt.title(f"{file}\n RetrievedCOMixingRatioProfileDay_{str(pressure_prefix)}00hPa", fontsize=8
)
# Save the figure.
= f"{filestem}/{filestem}_RetrievedCOMixingRatioProfileDay"
name_prefix f"{name_prefix}_{pressure_prefix}00hPa.jpg", dpi=400)
plt.savefig(print(f"Plot has been saved: {name_prefix}_{pressure_prefix}00hPa.jpg")
plt.close()
Plot has been saved: MOP03JM-202409-L3V95.10.3/MOP03JM-202409-L3V95.10.3_RetrievedCOMixingRatioProfileDay_900hPa.jpg
Plot has been saved: MOP03JM-202409-L3V95.10.3/MOP03JM-202409-L3V95.10.3_RetrievedCOMixingRatioProfileDay_800hPa.jpg
Plot has been saved: MOP03JM-202409-L3V95.10.3/MOP03JM-202409-L3V95.10.3_RetrievedCOMixingRatioProfileDay_700hPa.jpg
Plot has been saved: MOP03JM-202409-L3V95.10.3/MOP03JM-202409-L3V95.10.3_RetrievedCOMixingRatioProfileDay_600hPa.jpg
Plot has been saved: MOP03JM-202409-L3V95.10.3/MOP03JM-202409-L3V95.10.3_RetrievedCOMixingRatioProfileDay_500hPa.jpg
Plot has been saved: MOP03JM-202409-L3V95.10.3/MOP03JM-202409-L3V95.10.3_RetrievedCOMixingRatioProfileDay_400hPa.jpg
Plot has been saved: MOP03JM-202409-L3V95.10.3/MOP03JM-202409-L3V95.10.3_RetrievedCOMixingRatioProfileDay_300hPa.jpg
Plot has been saved: MOP03JM-202409-L3V95.10.3/MOP03JM-202409-L3V95.10.3_RetrievedCOMixingRatioProfileDay_200hPa.jpg
Plot has been saved: MOP03JM-202409-L3V95.10.3/MOP03JM-202409-L3V95.10.3_RetrievedCOMixingRatioProfileDay_100hPa.jpg
Plot has been saved: MOP03JM-202410-L3V95.10.3/MOP03JM-202410-L3V95.10.3_RetrievedCOMixingRatioProfileDay_900hPa.jpg
Plot has been saved: MOP03JM-202410-L3V95.10.3/MOP03JM-202410-L3V95.10.3_RetrievedCOMixingRatioProfileDay_800hPa.jpg
Plot has been saved: MOP03JM-202410-L3V95.10.3/MOP03JM-202410-L3V95.10.3_RetrievedCOMixingRatioProfileDay_700hPa.jpg
Plot has been saved: MOP03JM-202410-L3V95.10.3/MOP03JM-202410-L3V95.10.3_RetrievedCOMixingRatioProfileDay_600hPa.jpg
Plot has been saved: MOP03JM-202410-L3V95.10.3/MOP03JM-202410-L3V95.10.3_RetrievedCOMixingRatioProfileDay_500hPa.jpg
Plot has been saved: MOP03JM-202410-L3V95.10.3/MOP03JM-202410-L3V95.10.3_RetrievedCOMixingRatioProfileDay_400hPa.jpg
Plot has been saved: MOP03JM-202410-L3V95.10.3/MOP03JM-202410-L3V95.10.3_RetrievedCOMixingRatioProfileDay_300hPa.jpg
Plot has been saved: MOP03JM-202410-L3V95.10.3/MOP03JM-202410-L3V95.10.3_RetrievedCOMixingRatioProfileDay_200hPa.jpg
Plot has been saved: MOP03JM-202410-L3V95.10.3/MOP03JM-202410-L3V95.10.3_RetrievedCOMixingRatioProfileDay_100hPa.jpg
6. Create gif
= []
frames = np.arange(1, 10)[::-1]
pressures
for file in downloaded_files:
= Path(file).stem
filestem = f"{filestem}/{filestem}_RetrievedCOMixingRatioProfileDay"
name_prefix
for j in pressures:
= PIL.Image.open(rf"{name_prefix}_{j}00hPa.jpg")
new_frame
frames.append(new_frame)0].save(
frames[f"{name_prefix}_PressureLevels.gif",
format="GIF",
=frames[:],
append_images=True,
save_all=250,
duration=0,
loop=75,
quality=True,
optimize
)
print(f"GIF has been saved: {name_prefix}_PressureLevels.gif")
GIF has been saved: MOP03JM-202409-L3V95.10.3/MOP03JM-202409-L3V95.10.3_RetrievedCOMixingRatioProfileDay_PressureLevels.gif
GIF has been saved: MOP03JM-202410-L3V95.10.3/MOP03JM-202410-L3V95.10.3_RetrievedCOMixingRatioProfileDay_PressureLevels.gif
# Display first frame of gif in notebook for illustration purposes.
import matplotlib.image as mpimg
= mpimg.imread(f"{name_prefix}_PressureLevels.gif")
img plt.imshow(img)