Created
March 26, 2025 20:40
-
-
Save barronh/fa8489fa6183bde20e2b4422fe35cb27 to your computer and use it in GitHub Desktop.
TEMPO_CloudRasterFormat.ipynb
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| { | |
| "nbformat": 4, | |
| "nbformat_minor": 0, | |
| "metadata": { | |
| "colab": { | |
| "provenance": [], | |
| "authorship_tag": "ABX9TyNxIyPFkJsdSNnV07qk8fFc", | |
| "include_colab_link": true | |
| }, | |
| "kernelspec": { | |
| "name": "python3", | |
| "display_name": "Python 3" | |
| }, | |
| "language_info": { | |
| "name": "python" | |
| } | |
| }, | |
| "cells": [ | |
| { | |
| "cell_type": "markdown", | |
| "metadata": { | |
| "id": "view-in-github", | |
| "colab_type": "text" | |
| }, | |
| "source": [ | |
| "<a href=\"https://colab.research.google.com/gist/barronh/fa8489fa6183bde20e2b4422fe35cb27/tempo_cloudrasterformat.ipynb\" target=\"_parent\"><img src=\"https://colab.research.google.com/assets/colab-badge.svg\" alt=\"Open In Colab\"/></a>" | |
| ] | |
| }, | |
| { | |
| "cell_type": "markdown", | |
| "source": [ | |
| "# Rapid Access to TEMPO through gis.earthdata.nasa.gov\n", | |
| "\n", | |
| "---\n", | |
| " author: Barron H. Henderson\n", | |
| " last updated: 2025-03-06\n", | |
| "---\n", | |
| "\n", | |
| "This example shows how to get a single location's NO2 from TEMPO for any amount of time in just a few seconds. The code is adapted from Hazem Mahmoud's code that he shared with me.\n" | |
| ], | |
| "metadata": { | |
| "id": "w_NCE5SdIA0E" | |
| } | |
| }, | |
| { | |
| "cell_type": "code", | |
| "source": [ | |
| "def getl3(lon, lat, start, end):\n", | |
| " \"\"\"\n", | |
| " Get Level 3 TEMPO Tropospheric NO2 quickly!\n", | |
| "\n", | |
| " Arguments\n", | |
| " ---------\n", | |
| " lon : float\n", | |
| " Longitude in degrees_east\n", | |
| " lat : float\n", | |
| " Latitude in degrees_north\n", | |
| " start : str or datetime-like\n", | |
| " Beginning of time-series. Must be convertable to a time using\n", | |
| " pandas.to_datetime with utc=True\n", | |
| " end : str or datetime-like\n", | |
| " End of time-series. Must be convertable to a time using\n", | |
| " pandas.to_datetime with utc=True\n", | |
| "\n", | |
| " Returns\n", | |
| " -------\n", | |
| " df : pandas.DataFrame\n", | |
| " DataFrame with time as an index and NO2 Tropospheric as the only column\n", | |
| " \"\"\"\n", | |
| " import pandas as pd\n", | |
| " import requests\n", | |
| " conceptid = 'C2930763263-LARC_CLOUD' # TEMPO L3 V03\n", | |
| " filename = 'TEMPO_NO2_L3_V03_HOURLY_TROPOSPHERIC_VERTICAL_COLUMN'\n", | |
| " base_url = 'https://gis.earthdata.nasa.gov/image/rest/services/'\n", | |
| " base_url += f'{conceptid}/{filename}/ImageServer/getSamples/'\n", | |
| "\n", | |
| " # time bounds in ms since EPOCH\n", | |
| " stime = pd.to_datetime(start, utc=True).timestamp() * 1000\n", | |
| " etime = pd.to_datetime(end, utc=True).timestamp() * 1000\n", | |
| "\n", | |
| " # Standard Settings\n", | |
| " # variable_name = 'NO2 Troposphere'\n", | |
| " params = {\n", | |
| " 'sampleDistance': '', 'sampleCount': '', 'pixelSize': '', 'outFields': '',\n", | |
| " 'sliceId': '', 'mosaicRule': '',\n", | |
| " # 'mosaicRule': f'{{\"multidimensionalDefinition\"{variable_name}}}',\n", | |
| " 'returnFirstValueOnly': 'false', 'interpolation': 'RSP_NearestNeighbor',\n", | |
| " 'geometryType': 'esriGeometryPoint',\n", | |
| " 'geometry': f'{lon},{lat}', # required, to be filled in by user\n", | |
| " 'time': f'{stime:.0f},{etime:.0f}', # required, to be filled in by user\n", | |
| " 'f': 'pjson'\n", | |
| " }\n", | |
| " # Make the request to the API\n", | |
| " response = requests.get(base_url, params=params, stream=True)\n", | |
| " response.raise_for_status()\n", | |
| "\n", | |
| " # Convert to JSON\n", | |
| " data = response.json()\n", | |
| " # Convert to DataFrame\n", | |
| " varkey = data['samples'][0]['attributes']['Variables']\n", | |
| " df = pd.DataFrame.from_records([\n", | |
| " {\n", | |
| " 'time': rec['attributes']['StdTime'],\n", | |
| " varkey: rec.get('value', rec['attributes'].get(varkey, ''))\n", | |
| " }\n", | |
| " for rec in data['samples']\n", | |
| " ])\n", | |
| " df['time'] = pd.to_datetime(df['time'], unit='ms')\n", | |
| " # convert string data to double precision floats\n", | |
| " df[varkey] = df[varkey].replace('', 'nan').astype('d')\n", | |
| " # Set the index as time\n", | |
| " df.set_index('time', inplace=True)\n", | |
| " return df" | |
| ], | |
| "metadata": { | |
| "id": "-mxPUoJ8IHqb" | |
| }, | |
| "execution_count": null, | |
| "outputs": [] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "source": [ | |
| "lon = -84.3885\n", | |
| "lat = 33.7501\n", | |
| "start = '2023-09-01 12:00:00+0000'\n", | |
| "end = '2025-03-01 12:00:00+0000'\n", | |
| "df = getl3(lon, lat, start, end)" | |
| ], | |
| "metadata": { | |
| "id": "bQeGNnjiJQjZ" | |
| }, | |
| "execution_count": null, | |
| "outputs": [] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "source": [ | |
| "ax = df.query(f'NO2_Troposphere > -5e15').resample('1h').mean().plot(marker='o', figsize=(24, 3))\n", | |
| "_ = ax.set(title=f'Hourly Trop NO2 VCD at {lon},{lat} from {start} to {end}', ylabel='NO2 [molec/cm$^3$]', ylim=(None, None))" | |
| ], | |
| "metadata": { | |
| "id": "pFu37NOMJQ1Q" | |
| }, | |
| "execution_count": null, | |
| "outputs": [] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "source": [], | |
| "metadata": { | |
| "id": "rRVEMOgUJl6G" | |
| }, | |
| "execution_count": null, | |
| "outputs": [] | |
| } | |
| ] | |
| } |
Author
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
This makes: