{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Rivulet: NASA POWER Surface Albedo\n", "_by Michelle H Wilkerson_" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Purpose of this Notebook\n", "\n", "This notebook explores **Surface Albedo**, a measure of how much sunlight is reflected by a surface. Light-colored surfaces, like snow and ice, have a high albedo and reflect most of the sun's energy back into space. Dark-colored surfaces, like oceans and forests, have a low albedo and absorb the energy, warming the Earth. \n", "\n", "Changes in albedo are a critical part of Earth's climate system. For example, as the planet warms, snow and ice melt earlier in the year. This exposes darker ground underneath, which absorbs more heat and causes even more melting—a process known as a positive feedback loop.\n", "\n", "This data tool connects to the **NASA POWER** (Prediction of Worldwide Energy Resources) API, which provides access to the CERES dataset. You will fetch daily surface albedo data for a location of your choice to observe its \"signature pattern\"—how albedo changes with the seasons. Then, you'll compare it to a contrasting environment to see how land cover affects reflection.\n", "\n", "
\n", " Click here for more information\n", "\n", "API stands for **Application Programming Interface**. Think of it as a language to communicate with data centers so you can search and get the data you need. For students, using APIs is like having a direct line to the most advanced scientific sensors on the planet.\n", "\n", "This notebook was developed as part of NSF Grant 2445609 to support accessing and processing public datasets for middle and high school classroom activities. It's written to be accessible to beginners. We use the NASA POWER API here because it requires no account or authentication, making it easy to jump straight into exploring data.\n", "
" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Part I: Setup & Connection\n", "\n", "First, we need to install and import the Python tools that will help us request the data, organize it, and visualize it on a map." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "%pip install requests pandas matplotlib folium\n", "\n", "import requests\n", "import pandas as pd\n", "import matplotlib.pyplot as plt\n", "import folium" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Part II: Defining Parameters\n", "\n", "Let's pick a location to investigate. To see a strong seasonal signature in albedo, it helps to pick a place that receives snow in the winter and is clear in the summer. \n", "\n", "By default, we are looking at the Rocky Mountains near Aspen, Colorado. But, you can change the latitude and longitude to a location you are curious about!" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Give your focal location a name\n", "focal_location = \"Mountains\"\n", "\n", "# Specify your location's lat and long\n", "latitude = 39\n", "longitude = -107\n", "# Let's map this location\n", "m = folium.Map(location=[latitude, longitude], zoom_start=8)\n", "folium.Marker([latitude, longitude], tooltip=\"Target Location\").add_to(m)\n", "m" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Next, we define the time period we want to investigate. Looking at a full year is a great way to see how the seasons change the land." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# EDIT HERE: Change the year to see if the patterns vary over time\n", "start_date = \"20230101\" # Format is YYYYMMDD\n", "end_date = \"20260101\" " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Part III: Data Retrieval (Primary Location)\n", "\n", "Now we send a request to the NASA POWER server asking for the `ALLSKY_SRF_ALB` (All-Sky Surface Albedo) data for our coordinates and dates." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "def fetch_albedo_data(lat, lon, start, end):\n", " # This is the web address we send our request to\n", " url = \"https://power.larc.nasa.gov/api/temporal/daily/point\"\n", " \n", " # These are the instructions we send along with our request\n", " params = {\n", " \"parameters\": \"ALLSKY_SRF_ALB\",\n", " \"community\": \"re\", # Renewable Energy community \n", " \"longitude\": lon,\n", " \"latitude\": lat,\n", " \"start\": start,\n", " \"end\": end,\n", " \"format\": \"json\"\n", " }\n", " \n", " # Send the request and get the response\n", " print(f\"Fetching data for {lat}, {lon}...\")\n", " response = requests.get(url, params=params)\n", " data = response.json()\n", " \n", " # Extract the albedo data from the complex JSON response\n", " albedo_dict = data['properties']['parameter']['ALLSKY_SRF_ALB']\n", " \n", " # Convert it into a structured Pandas DataFrame (a data table)\n", " df = pd.DataFrame(list(albedo_dict.items()), columns=['Date', 'Albedo'])\n", " \n", " # Clean up the dates so the computer understands them\n", " df['Date'] = pd.to_datetime(df['Date'], format='%Y%m%d')\n", " \n", " # Sometimes there is missing data marked as -999. We remove those.\n", " df = df[df['Albedo'] != -999.0]\n", " \n", " return df\n", "\n", "# Fetch the data for our primary location\n", "primary_data = fetch_albedo_data(latitude, longitude, start_date, end_date)\n", "primary_data" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Visualizing the Signature Pattern\n", "\n", "Let's graph the data. If your location has snow in the winter, you should see the albedo increase (closer to 1.0) during the winter months because snow is highly reflective. In the summer, when the snow melts and exposes dirt and trees, the albedo should drop (closer to 0.0)." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "plt.figure(figsize=(10, 5))\n", "plt.plot(primary_data['Date'], primary_data['Albedo'], color='blue', marker='o', markersize=3, linestyle='-')\n", "\n", "plt.title(f\"Surface Albedo over Time ({start_date[:4]})\")\n", "plt.xlabel(\"Date\")\n", "plt.ylabel(\"Albedo (0=Dark, 1=Bright)\")\n", "plt.grid(True, linestyle='--', alpha=0.6)\n", "plt.ylim(0, 1) # Albedo is a percentage between 0 and 1\n", "\n", "plt.show()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Part IV: Comparing to a Contrasting Environment\n", "\n", "To really understand how unique our signature pattern is, it helps to compare it to an environment that *doesn't* change much throughout the year. By default, we'll look at a desert environment (the Mojave Desert in California). Sand is relatively bright, but it doesn't melt!" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Give your comparison location a name\n", "comparison_location = \"Desert\"\n", "\n", "# Specify lat and long for the comparison location\n", "contrast_lat = 35\n", "contrast_lon = -118" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now, we'll fetch data from the comparison location and plot the albedos for both the focal and the comparison location on the same graph to compare." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Fetch the data\n", "contrast_data = fetch_albedo_data(contrast_lat, contrast_lon, start_date, end_date)\n", "\n", "# Plot both lines together!\n", "plt.figure(figsize=(10, 5))\n", "\n", "# Plot our primary location (Mountains)\n", "plt.plot(primary_data['Date'], primary_data['Albedo'], color='blue', label=focal_location, alpha=0.7)\n", "\n", "# Plot the contrasting location (Desert)\n", "plt.plot(contrast_data['Date'], contrast_data['Albedo'], color='orange', label=comparison_location, alpha=0.7)\n", "\n", "plt.title(f\"Comparing Albedo Signatures ({start_date[:4]}-{end_date[:4]})\")\n", "plt.xlabel(\"Date\")\n", "plt.ylabel(\"Albedo (0=Dark, 1=Bright)\")\n", "plt.legend()\n", "plt.grid(True, linestyle='--', alpha=0.6)\n", "plt.ylim(0, 1)\n", "\n", "plt.show()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Notice how the desert has a relatively stable, moderate albedo year-round, while the mountainous region has massive swings between summer and winter!" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Part V: Data Export\n", "\n", "Now that we have fetched our datasets, we can save them as `.csv` files so we can open them in Excel, Google Sheets, or CODAP to do more analysis." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Merge the two tables based on the Date\n", "combined_data = pd.merge(primary_data, contrast_data, on=\"Date\", suffixes=(focal_location, comparison_location))\n", "\n", "# Save the combined data to a single file\n", "combined_data.to_csv(\"combined_albedo.csv\", index=False)\n", "\n", "# OPTIONAL: If you are using Google Colab, uncomment the lines below to download the file to your computer.\n", "# from google.colab import files\n", "# files.download(\"combined_albedo.csv\")\n", "\n", "print(\"Data exported successfully!\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Credits\n", "\n", "This notebook was generated with the heavy assistance of Gemini 3.1 Pro, using an extensive custom context file to communicate Rivulet style and technical standards. All text and code were carefully reviewed by a squishy human.\n", "\n", "Data obtained from the NASA Prediction of Worldwide Energy Resources (POWER) Project, which is supported by the NASA Earth Science Data and Information System (ESDIS) Project. The data are derived from the CERES dataset.\n", "\n", "Learn more about the NASA POWER API here: https://power.larc.nasa.gov/\n", "\n", "This Rivulet was developed to provide real-world albedo data for a MoDa unit to be developed by Adelmo Eloy, Lucas Coletti, and Paulo Blikstein.\n", "\n", "This notebook was developed as part of NSF Grant 2445609." ] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.12.3" } }, "nbformat": 4, "nbformat_minor": 4 }