from tolnet import TOLNet
= TOLNet() # Creates an object that retrieves data from the API tolnet
TOLNet Toolbox
Authors: Maurice Roots, Arthur Perng
Advisor: John Sullivan
This notebook details how to use the TOLNet API to fetch and plot ozone data with various filters, such as processing type and instrument group/location. In addition, a section is included for fetching GEOS CF ozone profiles for comparison. Future work will incorporate analysis efforts and notebooks per community requests, for instance to better characterize future products from the TEMPO instrument.
Please send any questions or comments to John Sullivan (john.t.sullivan@nasa.gov).
For more information on TOLNet, visit https://tolnet.larc.nasa.gov/
Table of Contents:
- Overview
- Example Case Study
- Python package overview
- Additional plotting parameters
- Comparison with GEOS CF data
- Table of Lidar Locations
Overview
The Tropospheric Ozone Lidar Network (TOLNet) is an interagency network initiated by NASA, NOAA, and EPA in 2011 with the goal of enhancing our tropospheric ozone measurement capabilities. Ozone lidars within TOLNet provide accurate observations under both daytime and nighttime conditions and generate consistent, long-term datasets. Most of the instruments are portable and have been deployed previously in air quality campaigns in coordination with federal, state and local agency’s interests.
The data is currently stored as HDF4 files, but the TOLNet API returns JSON data which we will be using in this notebook.
Charter lidar systems are affiliated with NASA GSFC, NASA LaRC, NASA Jet Propulsion Laboratory (JPL), NOAA Earth System Research Laboratory/Chemical Sciences Lab (ESRL/CSL), and the University of Alabama, Huntsville. These systems have also been developed at CCNY and Hampton University. An international collaboration with Environment and Climate Change Canada (ECCC) has also been established, as well as a modeling component at NASA Ames Research Center (ARC) and data archiving administered at NASA LaRC.
The TOLNet data is accessible online (https://tolnet.larc.nasa.gov/) and can be accessed through this notebook. Consulting with the instrument principal or coinvestigators before usage is highly encouraged.
Example Case Study
On July 12th, 2023, the air quality in Flax Pond(Old Field, NY) was particularly poor, with an ozone index of about 133(Unhealthy for sensitive groups).
We will use the TOLNet API to graph the ozone data at GSFC during this time.
Then, we import it with python.
We only want data from the Old Field area around June 12th. As such, we filter accordingly:
= "2023-07-11"
date_start = "2023-07-13"
date_end = [2] # List of instrument group IDs to filter by. We only want GSFC(ID=2), so this list only contains 2.
group = [4] # Filter for high-resolution files only
product_ID
=date_start, max_date=date_end, instrument_group=group, product_type=product_ID) tolnet.import_data(min_date
Downloading TOLNet Data for: 100%|███████████████████████████████████████████████████████| 5/5 [00:09<00:00, 1.85s/it]
<tolnet.TOLNet at 0x28f024721b0>
Then, we plot the data. One curtain plot is created for each combination of instrument group and processing type, which is two in this case.(GSFC In-house processed, GSFC centrally processed)
tolnet.tolnet_curtains()
We can see that there is an enhancement of dark red and gray on both graphs at around 6:00-12:00 PM on July 12th, signalling an ozone ppbv(parts per billion) of 100 or higher. (The EPA standard is 75 parts per billion, and any more is considered unhealthy.) This corresponds to the worsened air quality index on that day.
Package Overview
from tolnet import TOLNet
= TOLNet() # tolnet now refers to an object that is capable of retrieving data from the API tolnet
Each of these functions prints the ID of each parameter you can filter by. It is recommended to filter your query by product type = 4(HIRES), as processing other products is not supported at this time.
# Prints querible parameters.
tolnet.print_product_types()# tolnet.print_processing_types()
# tolnet.print_instrument_groups()
# tolnet.print_file_types()
TOLNET product IDs:
id product_type_name description
1 O3Lidar Vertical profiles of ozone using a lidar technique
2 Surface In-situ measurements of surface products
3 Other Data that is not ozone lidar or surface in-situ measurements
4 HIRES Highest temporal and vertical resolution data
5 CALVAL Optimized for specific comparative evaluation of satellite or sonde
6 CLIM Optimized for climatology and trends studies
7 Gridded Regridded HIRES data to a common TOLNet-wide grid for evaluation
8 Legacy generic HDF or TOLNet ASCII data products (Contact PI for use)
= "2023-08-08" # YYYY-MM-DD format in a string
date_start = "2023-08-11"
date_end = [4] # HIRES
product_IDs
# Fetches data using the TOLNet object. min_date and max_date are required, but other parameters are optional.
# Once finished, this function stores the data in the object(tolnet in this case). The data can be accessed with tolnet.data and tolnet.meta_data.
# This will prompt the user for confirmation if the query would download every file from the API.
# Querible parameters are processing_type, instrument_group, product_type, and file_type.
# All parameters require a list of IDs to filter for.
= tolnet.import_data(min_date=date_start, max_date=date_end, product_type=product_IDs) data
Downloading TOLNet Data for: 100%|█████████████████████████████████████████████████████| 16/16 [00:47<00:00, 2.95s/it]
# Plots the data, used after import_data. Puts each combination of instrument group and processing type on a seperate plot.
data.tolnet_curtains()
Additional parameters for plotting
The tolnet_curtains function can also take the following arguments: title
, ylabel
, xlabel
, xlims
, ylims
, yticks
, and savefig
. Below are some examples.
# Copy of previous query for sample data
= TOLNet()
tolnet
= {"min_date": "2023-08-08",
params "max_date": "2023-08-11",
"product_type": [4],
"instrument_group": [2],
"processing_type": [1]
}
# central_processing = [1] # Filtering to only centrally processed data so that only 1 graph is created
= tolnet.import_data(**params).tolnet_curtains() data
Downloading TOLNet Data for: 100%|███████████████████████████████████████████████████████| 3/3 [00:01<00:00, 2.76it/s]
="Default Graph") data.tolnet_curtains(title
# xlims takes a list of two dates in ISO 8601 Format(YYYY-MM-DD), like this: ['2023-08-05', '2023-08-08'].
=['2023-08-08', '2023-08-09'], title="Cropped Graph(X-axis)") data.tolnet_curtains(xlims
=[0, 2], title="Cropped Graph (Y-axis)") data.tolnet_curtains(ylims
="Sample X Label", ylabel="Sample Y Label", title="Axis labelling demo") data.tolnet_curtains(xlabel
Adding savefig=True
saves each created figure to a file. Each figure is saved in a file named (Instrument Group)_(Processing type)_(Start date)_(End date).png
. For example, the above query that creates one graph would be saved as NASA_GSFC_Centrally_Processed_(GLASS)_2023_08_08_2023_08_11.png
.
Accessing data directly
# The data can also be accessed directly from the object.
# Returns each combination of instrument group and processing type that there is data for.
tolnet.data.keys() # This combination also includes an entry for 'dates', which stores the queried date range and is the default
dict_keys([('NASA GSFC', 'Centrally Processed (GLASS)', '40.96x-73.14')])
= list(tolnet.data.keys())[-1] # sample_key is now a tuple containing a combination of instrument group and processing type
sample_key # Returns each filename with the specified group and type. tolnet.data[sample_key].keys()
dict_keys(['2023-08-10', '2023-08-09', '2023-08-08'])
= list(tolnet.data[sample_key].keys())[0]
sample_file 10) # Returns a DataFrame containing the data for that file. tolnet.data[sample_key][sample_file].head(
0.1005 | 0.1305 | 0.1605 | 0.1905 | 0.2205 | 0.2505 | 0.2805 | 0.3105 | 0.3405 | 0.3705 | ... | 12.8805 | 12.9105 | 12.9405 | 12.9705 | 13.0005 | 13.0305 | 13.0605 | 13.0905 | 13.1205 | 13.1505 | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
2023-08-10 00:15:28+00:00 | NaN | NaN | NaN | NaN | NaN | NaN | NaN | 50.4 | 49.4 | 50.5 | ... | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN |
2023-08-10 00:45:25+00:00 | NaN | NaN | NaN | NaN | NaN | NaN | NaN | 41.3 | 45.5 | 46.9 | ... | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN |
2023-08-10 01:15:23+00:00 | NaN | NaN | NaN | NaN | NaN | NaN | NaN | 46.2 | 40.3 | 42.2 | ... | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN |
2023-08-10 01:45:30+00:00 | NaN | NaN | NaN | NaN | NaN | NaN | NaN | 41.5 | 49.2 | 56.6 | ... | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN |
2023-08-10 02:15:37+00:00 | NaN | NaN | NaN | NaN | NaN | NaN | NaN | 37.7 | 37.7 | 46.6 | ... | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN |
2023-08-10 02:45:34+00:00 | NaN | NaN | NaN | NaN | NaN | NaN | NaN | 48.9 | 53.2 | 49.4 | ... | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN |
2023-08-10 03:15:31+00:00 | NaN | NaN | NaN | NaN | NaN | NaN | NaN | 54.1 | 47.5 | 46.5 | ... | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN |
2023-08-10 03:45:28+00:00 | NaN | NaN | NaN | NaN | NaN | NaN | NaN | 53.9 | 54.5 | 51.6 | ... | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN |
2023-08-10 04:15:25+00:00 | NaN | NaN | NaN | NaN | NaN | NaN | NaN | 48.7 | 53.2 | 48.9 | ... | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN |
2023-08-10 04:45:22+00:00 | NaN | NaN | NaN | NaN | NaN | NaN | NaN | 57.7 | 56.8 | 56.6 | ... | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN |
10 rows × 436 columns
= list(tolnet.meta_data[sample_key].keys())[0] # Returns a dictionary containing that file's metadata.
sample_file = tolnet.meta_data[sample_key][sample_file]
metadata
# Remove the data section so that only the metadata is printed, not all of the data which floods the output with thousands of lines
if 'data' in metadata['value']:
del metadata['value']['data']
if 'data' in metadata['altitude']:
del metadata['altitude']['data']
if 'data' in metadata:
del metadata['data']
metadata
{'fileInfo': {'file_name': 'groundbased_lidar.o3_nasa.gsfc003_hires.glass.1.1_oldfield.ny_20230810t000009z_20230810t123041z_001.hdf',
'file_size': 676227,
'isAccessible': True,
'start_data_date': '2023-08-10 00:00:09',
'end_data_date': '2023-08-10 12:30:41',
'upload_date': '2024-05-01 08:51:53.737688',
'instrument_group_name': 'NASA GSFC',
'instrument_latitude': 40.96,
'instrument_longitude': -73.14,
'instrument_altitude': 3,
'doi': '10.5067/Lidar/Ozone/TOLNet/NASA-GSFC',
'citation_url': 'https://asdc.larc.nasa.gov/project/TOLNet/TOLNet_GSFC_Data_1/citation',
'product_type_name': 'HIRES',
'processing_type_name': 'Centrally Processed (GLASS)',
'file_type_name': 'HDF GEOMS (Standard)',
'revision': 1,
'near_real_time': 'f'},
'altitude': {'attributes': {'VAR_DESCRIPTION': 'Altitude above sea level (km)',
'VAR_VALID_MIN': -0.3,
'VAR_VALID_MAX': 120,
'VAR_UNITS': 'km',
'VAR_FILL_VALUE': -999}},
'datetime': {'attributes': {'VAR_DESCRIPTION': 'Weighted datetime of the LIDAR measurement.',
'DATA_START_DATE': '20230810T000009Z',
'DATA_STOP_DATE': '20230810T123041Z',
'VAR_UNITS': 'UT time',
'VAR_FILL_VALUE': -9999},
'data': ['2023-08-10 00:15:28+00:00',
'2023-08-10 00:45:25+00:00',
'2023-08-10 01:15:23+00:00',
'2023-08-10 01:45:30+00:00',
'2023-08-10 02:15:37+00:00',
'2023-08-10 02:45:34+00:00',
'2023-08-10 03:15:31+00:00',
'2023-08-10 03:45:28+00:00',
'2023-08-10 04:15:25+00:00',
'2023-08-10 04:45:22+00:00',
'2023-08-10 05:15:30+00:00',
'2023-08-10 05:45:37+00:00',
'2023-08-10 06:15:34+00:00',
'2023-08-10 06:45:31+00:00',
'2023-08-10 07:15:29+00:00',
'2023-08-10 07:45:26+00:00',
'2023-08-10 08:15:23+00:00',
'2023-08-10 08:45:31+00:00',
'2023-08-10 09:15:38+00:00',
'2023-08-10 09:45:36+00:00',
'2023-08-10 10:15:33+00:00',
'2023-08-10 10:45:30+00:00',
'2023-08-10 11:15:28+00:00',
'2023-08-10 11:45:25+00:00',
'2023-08-10 12:15:23+00:00']},
'value': {'attributes': {'VAR_DESCRIPTION': 'Derived Ozone mixing ratio',
'VAR_VALID_MIN': 2e-16,
'VAR_VALID_MAX': 20000,
'VAR_UNITS': 'ppbv',
'VAR_FILL_VALUE': -999}},
'id': 8398,
'file_name': 'groundbased_lidar.o3_nasa.gsfc003_hires.glass.1.1_oldfield.ny_20230810t000009z_20230810t123041z_001.hdf',
'attributes': {'PI_NAME': 'Sullivan;John', 'DATA_LOCATION': 'OLDFIELD.NY'},
'LATITUDE.INSTRUMENT': 40.96,
'LONGITUDE.INSTRUMENT': -73.14}
Comparison with GEOS CF
The package also supports fetching and plotting from the GEOS-CF API.
# Copy of previous query for sample data
from tolnet import TOLNet
= TOLNet()
tolnet
= {"min_date": "2023-08-01",
params "max_date": "2023-08-15",
"product_type": [4],
"instrument_group": [2],
"processing_type": [1],
"GEOS_CF": True
}
= tolnet.import_data(**params).tolnet_curtains() data
Downloading TOLNet Data for: 100%|█████████████████████████████████████████████████████| 14/14 [00:05<00:00, 2.53it/s]
Downloading GEOS_CF Data for 40.96x-73.14: 100%|███████████████████████████████████████| 15/15 [01:11<00:00, 4.76s/it]
C:\Users\arthu\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.12_qbz5n2kfra8p0\LocalCache\local-packages\Python312\site-packages\matplotlib\dates.py:449: UserWarning: no explicit representation of timezones available for np.datetime64
d = d.astype('datetime64[us]')
Table of Lidar Locations
Location | Mode | Instrument Group Name | Date Range | Latitude | Longitude | |
---|---|---|---|---|---|---|
Albuquerque Fiesta Park NM | Campaign | NASA JPL SMOL-1 | 2023-10-11 - 2023-10-15 | 35.19 | -106.56 | |
Cabauw | Campaign | NASA JPL SMOL-1 | 2024-05-22 - 2024-06-09 | 51.97 | 4.93 | |
Cabauw | Campaign | NASA GSFC | 2019-09-12 - 2019-10-02 | 51.97 | 4.93 | |
Fort Mackay | Campaign | ECCC | 2016-11-04 - 2019-09-23 | 57.19 | -111.62 | |
Guilford YCFS CT | Campaign | NOAA ESRL/CSL | 2023-07-04 - 2023-08-14 | 41.25 | -72.75 | |
Huntsville AL | Campaign | UAH | 2022-07-08 - 2022-07-10 | 30.27 | -88.12 | |
Kenosha WI | Campaign | UAH | 2023-07-18 - 2023-08-16 | 42.50 | -87.81 | |
La Porte TX | Campaign | NASA GSFC | 2021-08-11 - 2021-09-28 | 29.67 | -95.06 | |
Langley Research Center VA | Campaign | NASA LaRC | 2018-01-24 - 2024-07-05 | 37.09 | -76.38 | |
Pasadena JPL CA | Campaign | NASA JPL SMOL-1 | 2023-06-25 - 2023-09-07 | 34.19 | -118.19 | |
San Bernardino Calstate CA | Campaign | NASA JPL SMOL-2 | 2023-06-23 - 2023-12-16 | 34.19 | -117.31 | |
Sherwood Island CT | Campaign | NASA LaRC | 2018-07-12 - 2023-08-26 | 41.12 | -73.31 | |
University Of Houston Moody Tower TX | Campaign | NASA LaRC | 2021-08-26 - 2021-09-27 | 29.72 | -95.31 | |
Beltsville MD | Routine | NASA GSFC | 2015-06-10 - 2022-07-28 | 39.06 | -76.88 | |
Boulder CO | Routine | NOAA ESRL/CSL | 2018-02-08 - 2023-10-23 | 40.00 | -105.25 | |
Goddard Space Flight Center MD | Routine | NASA GSFC | 2015-02-03 - 2024-06-25 | 38.97 | -76.81 | |
Huntsville AL | Routine | UAH | 2017-07-31 - 2023-04-20 | 34.72 | -86.62 | |
New York NY | Routine | CCNY | 2023-06-01 - 2024-07-11 | 40.81 | -73.94 | |
Table Mountain CA | Routine | NASA JPL TMTOL | 2000-01-04 - 2024-07-10 | 34.38 | -117.69 |