diff --git a/.nojekyll b/.nojekyll index 84f3f38..c6236fa 100644 --- a/.nojekyll +++ b/.nojekyll @@ -1 +1 @@ -23b9cc05 \ No newline at end of file +226aab89 \ No newline at end of file diff --git a/how-tos/authentication/NASA_Earthdata_Authentication.html b/how-tos/authentication/NASA_Earthdata_Authentication.html index 5b4fb07..9a48725 100644 --- a/how-tos/authentication/NASA_Earthdata_Authentication.html +++ b/how-tos/authentication/NASA_Earthdata_Authentication.html @@ -156,7 +156,7 @@ Programmatic Access
  • - + Icepyx
  • @@ -164,6 +164,10 @@
  • Overview +
  • +
  • + + GEDI Level 2B V002 Data
  • @@ -276,7 +280,7 @@ @@ -296,6 +300,12 @@ Overview + + diff --git a/how-tos/authentication/NASA_Earthdata_Login_Token.html b/how-tos/authentication/NASA_Earthdata_Login_Token.html index a85e5e8..5c00400 100644 --- a/how-tos/authentication/NASA_Earthdata_Login_Token.html +++ b/how-tos/authentication/NASA_Earthdata_Login_Token.html @@ -156,7 +156,7 @@ Programmatic Access
  • - + Icepyx
  • @@ -164,6 +164,10 @@
  • Overview +
  • +
  • + + GEDI Level 2B V002 Data
  • @@ -276,7 +280,7 @@ @@ -296,6 +300,12 @@ Overview + + diff --git a/how-tos/data-access/Earthdata_Cloud__Single_File__Direct_S3_Access_Clip_COG_Example.html b/how-tos/data-access/Earthdata_Cloud__Single_File__Direct_S3_Access_Clip_COG_Example.html index 33bae0d..bec0d4a 100644 --- a/how-tos/data-access/Earthdata_Cloud__Single_File__Direct_S3_Access_Clip_COG_Example.html +++ b/how-tos/data-access/Earthdata_Cloud__Single_File__Direct_S3_Access_Clip_COG_Example.html @@ -156,7 +156,7 @@ Programmatic Access
  • - + Icepyx
  • @@ -164,6 +164,10 @@
  • Overview +
  • +
  • + + GEDI Level 2B V002 Data
  • @@ -276,7 +280,7 @@ @@ -296,6 +300,12 @@ Overview + + diff --git a/how-tos/data-access/Intro_xarray_hvplot.html b/how-tos/data-access/Intro_xarray_hvplot.html index dcd666a..73baa4b 100644 --- a/how-tos/data-access/Intro_xarray_hvplot.html +++ b/how-tos/data-access/Intro_xarray_hvplot.html @@ -156,7 +156,7 @@ Programmatic Access
  • - + Icepyx
  • @@ -164,6 +164,10 @@
  • Overview +
  • +
  • + + GEDI Level 2B V002 Data
  • @@ -276,7 +280,7 @@ @@ -296,6 +300,12 @@ Overview + + diff --git a/how-tos/data-discovery/Data_Discovery_CMR_API.html b/how-tos/data-discovery/Data_Discovery_CMR_API.html index 1904991..13797c3 100644 --- a/how-tos/data-discovery/Data_Discovery_CMR_API.html +++ b/how-tos/data-discovery/Data_Discovery_CMR_API.html @@ -156,7 +156,7 @@ Programmatic Access
  • - + Icepyx
  • @@ -164,6 +164,10 @@
  • Overview +
  • +
  • + + GEDI Level 2B V002 Data
  • @@ -276,7 +280,7 @@ @@ -296,6 +300,12 @@ Overview + + diff --git a/index.html b/index.html index 803bb73..528045a 100644 --- a/index.html +++ b/index.html @@ -123,7 +123,7 @@ Programmatic Access
  • - + Icepyx
  • @@ -131,6 +131,10 @@
  • Overview +
  • +
  • + + GEDI Level 2B V002 Data
  • @@ -243,7 +247,7 @@ @@ -263,6 +267,12 @@ Overview + + diff --git a/search.json b/search.json index 9b02fa3..ef9e9ac 100644 --- a/search.json +++ b/search.json @@ -112,39 +112,130 @@ "text": "These tutorials are a combination of narrative, links, code, and outputs. They have been developed for live demos during the Workshop, and are available for self-paced learning.\nHands-on exercises will be executed from a Jupyter Lab instance in 2i2c. Please pass along your Github Username to get access.\nTutorials are markdown (.md) and Jupyter (.ipynb) notebooks, and are available on GitHub" }, { - "objectID": "tutorials/schedule.html", - "href": "tutorials/schedule.html", - "title": "Schedule", + "objectID": "tutorials/setup.html", + "href": "tutorials/setup.html", + "title": "Setup for tutorials", "section": "", - "text": "The SSC GEDI/ICESAT-2 Workshop will take place on November 15th.\nNote, hands-on exercises will be executed from a Jupyter Lab instance in 2i2c. Please pass along your Github Username to get access." + "text": "This tutorial will help you set up your JupyterHub (or Hub) with tutorials and other materials from our Workshop folder." }, { - "objectID": "tutorials/schedule.html#workshop-schedule", - "href": "tutorials/schedule.html#workshop-schedule", - "title": "Schedule", - "section": "Workshop Schedule", - "text": "Workshop Schedule\n\n\n\nHour\nEvent\nInstructor\n\n\n\n\n3:00 pm CST/MX\nWelcome and Overview of Tutorial\n\n\n\n3:10 pm\nCryoCloud - A Shared Cloud Platform for NASA\nTasha Snow (Colorado School of Mines)\n\n\n3:25 pm\nHub task - clone repo\n\n\n\n3:35 pm\nBreak (Q&A)\n\n\n\n3:40 pm\nICESat-2 Data Access, NASA DAAC @ NSIDC\nLuis Alberto Lopez Espinosa (NSIDC, University of Colorado)\n\n\n4:00 pm\nBreak (Q&A)\n\n\n\n4:10 pm\nThe icepyx Software Library and Community\nRachel Wegener (University of Maryland)\n\n\n4:30 pm\nBreak\n\n\n\n4:40 pm\nAccess and Discovery of GEDI Data via the DAAC at the ORNL\nRupesh Shrestha (Oakridge National Laboratory, ORNL-DAAC)\n\n\n5:00 pm\nBreak (Q&A)\n\n\n\n5:10 pm\nGEDI Data User Resources at the LP DAAC\nMahsa Jami (NASA LP-DAAC)\n\n\n5:30 pm\nBreak (Q&A)\n\n\n\n5:40 pm\nEjemplos de aplicaciones de uso de éxito GEDI y posibilidades(Mapas, Reforestacion, Especie protegida)\nAdrian Pascual\n\n\n6:00 pm CST/MX\nEnd of Tutorial\n\n\n\n\n\nThank you!\nJupyterHub: close out.\n\nclose out your JupyterHub instance if you are finished for the day, following these instructions.\n\nYou will continue to have access to the 2i2c JupyterHub in AWS for a week following the SSC GEDI/ICESAT-2 Cloud Workshop. You may use that time to continue work and all learn more about migrating data accass routines and science workflows to the Cloud. This cloud compute environment is supported by the NASA Openscapes project." + "objectID": "tutorials/setup.html#step-1.-login-to-the-hub", + "href": "tutorials/setup.html#step-1.-login-to-the-hub", + "title": "Setup for tutorials", + "section": "Step 1. Login to the Hub", + "text": "Step 1. Login to the Hub\nPlease go to Jupyter Hub and Log in with your GitHub Account, and select “Small”.\nAlternatively, you can also click this badge to launch the Hub:\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nNote: It takes a few minutes for the Hub to load. Please be patient!\n\nWhile the Hub loads, we’ll:\n\nDiscuss cloud environments\n\nSee how my Desktop is setup\n\nDiscuss python and conda environments\n\nThen, when the Hub is loaded, we’ll get oriented in the Hub." }, { - "objectID": "tutorials/schedule.html#getting-help-during-the-workshop", - "href": "tutorials/schedule.html#getting-help-during-the-workshop", - "title": "Schedule", - "section": "Getting help during the Workshop", - "text": "Getting help during the Workshop\nPlease use the webex chat platform to ask any questions you have during the workshop." + "objectID": "tutorials/setup.html#discussion-cloud-environment", + "href": "tutorials/setup.html#discussion-cloud-environment", + "title": "Setup for tutorials", + "section": "Discussion: Cloud environment", + "text": "Discussion: Cloud environment\nA brief overview. See NASA Openscapes Cloud Environment in the 2021-Cloud-Hackathon book for more detail.\n\nCloud infrastructure\n\nCloud: AWS us-west-2\n\nData: AWS S3 (cloud) and NASA DAAC data centers (on-prem).\n\nCloud compute environment: 2i2c Jupyterhub deployment\n\nIDE: JupyterLab" }, { - "objectID": "tutorials/cloud/cloud-paradigm.html", - "href": "tutorials/cloud/cloud-paradigm.html", - "title": "NASA and the Cloud Paradigm", + "objectID": "tutorials/setup.html#discussion-my-desktop-setup", + "href": "tutorials/setup.html#discussion-my-desktop-setup", + "title": "Setup for tutorials", + "section": "Discussion: My desktop setup", + "text": "Discussion: My desktop setup\nI’ll screenshare to show and/or talk through how I have oriented the following software we’re using:\n\nWorkshop Book\nSlack" + }, + { + "objectID": "tutorials/setup.html#discussion-python-and-conda-environments", + "href": "tutorials/setup.html#discussion-python-and-conda-environments", + "title": "Setup for tutorials", + "section": "Discussion: Python and Conda environments", + "text": "Discussion: Python and Conda environments\nWhy Python?\n\n\n\nPython Data Stack. Source: Jake VanderPlas, “The State of the Stack,” SciPy Keynote (SciPy 2015).\n\n\nDefault Python Environment:\nWe’ve set up the Python environment with conda.\n\n\n\n\n\n\nConda environment\n\n\n\n\n\nname: openscapes\nchannels:\n - conda-forge\ndependencies:\n - python=3.9\n - pangeo-notebook\n - awscli~=1.20\n - boto3~=1.19\n - gdal~=3.3\n - rioxarray~=0.8\n - xarray~=0.19\n - h5netcdf~=0.11\n - netcdf4~=1.5\n - h5py~=2.10\n - geoviews~=1.9\n - matplotlib-base~=3.4\n - hvplot~=0.7\n - pyproj~=3.2\n - bqplot~=0.12\n - geopandas~=0.10\n - zarr~=2.10\n - cartopy~=0.20\n - shapely==1.7.1\n - pyresample~=1.22\n - joblib~=1.1\n - pystac-client~=0.3\n - s3fs~=2021.7\n - ipyleaflet~=0.14\n - sidecar~=0.5\n - jupyterlab-geojson~=3.1\n - jupyterlab-git\n - jupyter-resource-usage\n - ipympl~=0.6\n - conda-lock~=0.12\n - pooch~=1.5\n - pip\n - pip:\n - tqdm\n - harmony-py\n - earthdata\n - zarr-eosdis-store\n\n\n\n\nBash terminal and installed software\nLibraries that are available from the terminal\n\ngdal 3.3 commands ( gdalinfo, gdaltransform…)\nhdf5 commands ( h5dump, h5ls..)\nnetcdf4 commands (ncdump, ncinfo …)\njq (parsing json files or streams from curl)\ncurl (fetch resources from the web)\nawscli (AWS API client, to interact with AWS cloud services)\nvim (editor)\ntree ( directory tree)\nmore …\n\n\n\nUpdating the environment\nScientific Python is a vast space and we only included libraries that are needed in our tutorials. Our default environment can be updated to include any Python library that’s available on pip or conda.\nThe project used to create our default environment is called corn (as it can include many Python kernels).\nIf we want to update a library or install a whole new environment we need to open an issue on this repository.\n\n\ncorn 🌽" + }, + { + "objectID": "tutorials/setup.html#step-2.-jupyterhub-orientation", + "href": "tutorials/setup.html#step-2.-jupyterhub-orientation", + "title": "Setup for tutorials", + "section": "Step 2. JupyterHub orientation", + "text": "Step 2. JupyterHub orientation\nNow that the Hub is loaded, let’s get oriented.\n\n\n\n\n\n\nFirst impressions\n\nLauncher & the big blue button\n“home directory”" + }, + { + "objectID": "tutorials/setup.html#step-3.-navigate-to-the-workshop-folder", + "href": "tutorials/setup.html#step-3.-navigate-to-the-workshop-folder", + "title": "Setup for tutorials", + "section": "Step 3. Navigate to the Workshop folder", + "text": "Step 3. Navigate to the Workshop folder\nThe workshop folder 2022-ECOSTRESS-Cloud-Workshop is in the shared folder on JupyterHub." + }, + { + "objectID": "tutorials/setup.html#jupyter-notebooks", + "href": "tutorials/setup.html#jupyter-notebooks", + "title": "Setup for tutorials", + "section": "Jupyter notebooks", + "text": "Jupyter notebooks\nLet’s get oriented to Jupyter notebooks, which we’ll use in all the tutorials." + }, + { + "objectID": "tutorials/setup.html#how-do-i-end-my-session", + "href": "tutorials/setup.html#how-do-i-end-my-session", + "title": "Setup for tutorials", + "section": "How do I end my session?", + "text": "How do I end my session?\n(Also see How do I end my Openscapes session? Will I lose all of my work?) When you are finished working for the day it is important to explicitly log out of your Openscapes session. The reason for this is it will save money and is a good habit to be in. When you keep a session active it uses up AWS resources and keeps a series of virtual machines deployed.\nStopping the server happens automatically when you log out, so navigate to “File -> Log Out” and click “Log Out”!\n\n\n\nhub-control-panel-button (credit: UW Hackweek)\n\n\n!!! NOTE “logging out” - Logging out will NOT cause any of your work to be lost or deleted. It simply shuts down some resources. It would be equivalent to turning off your desktop computer at the end of the day." + }, + { + "objectID": "tutorials/cloud/index.html", + "href": "tutorials/cloud/index.html", + "title": "CryoCloud / Openscapes", "section": "", - "text": "Slides that introduce NASA Earthdata Cloud & the Cloud Paradigm." + "text": "CryoCloud / Openscapes\nPlaceholder" + }, + { + "objectID": "tutorials/science/Intro_xarray_hvplot.html", + "href": "tutorials/science/Intro_xarray_hvplot.html", + "title": "Introduction to xarray… and hvplot", + "section": "", + "text": "As Geoscientists, we often work with time series of data with two or more dimensions: a time series of calibrated, orthorectified satellite images; two-dimensional grids of surface air temperature from an atmospheric reanalysis; or three-dimensional (level, x, y) cubes of ocean salinity from an ocean model. These data are often provided in GeoTIFF, NetCDF or HDF format with rich and useful metadata that we want to retain, or even use in our analysis. Common analyses include calculating means, standard deviations and anomalies over time or one or more spatial dimensions (e.g. zonal means). Model output often includes multiple variables that you want to apply similar analyses to.\n\n\n\nA schematic of multi-dimensional data\n\n\nThe schematic above shows a typical data structure for multi-dimensional data. There are two data cubes, one for temperature and one for precipitation. Common coordinate variables, in this case latitude, longitude and time are associated with each variable. Each variable, including coordinate variables, will have a set of attributes: name, units, missing value, etc. The file containing the data may also have attributes: source of the data, model name coordinate reference system if the data are projected. Writing code using low-level packages such as netcdf4 and numpy to read the data, then perform analysis, and write the results to file is time consuming and prone to errors." + }, + { + "objectID": "tutorials/science/Intro_xarray_hvplot.html#why-do-we-need-xarray", + "href": "tutorials/science/Intro_xarray_hvplot.html#why-do-we-need-xarray", + "title": "Introduction to xarray… and hvplot", + "section": "", + "text": "As Geoscientists, we often work with time series of data with two or more dimensions: a time series of calibrated, orthorectified satellite images; two-dimensional grids of surface air temperature from an atmospheric reanalysis; or three-dimensional (level, x, y) cubes of ocean salinity from an ocean model. These data are often provided in GeoTIFF, NetCDF or HDF format with rich and useful metadata that we want to retain, or even use in our analysis. Common analyses include calculating means, standard deviations and anomalies over time or one or more spatial dimensions (e.g. zonal means). Model output often includes multiple variables that you want to apply similar analyses to.\n\n\n\nA schematic of multi-dimensional data\n\n\nThe schematic above shows a typical data structure for multi-dimensional data. There are two data cubes, one for temperature and one for precipitation. Common coordinate variables, in this case latitude, longitude and time are associated with each variable. Each variable, including coordinate variables, will have a set of attributes: name, units, missing value, etc. The file containing the data may also have attributes: source of the data, model name coordinate reference system if the data are projected. Writing code using low-level packages such as netcdf4 and numpy to read the data, then perform analysis, and write the results to file is time consuming and prone to errors." + }, + { + "objectID": "tutorials/science/Intro_xarray_hvplot.html#what-is-xarray", + "href": "tutorials/science/Intro_xarray_hvplot.html#what-is-xarray", + "title": "Introduction to xarray… and hvplot", + "section": "What is xarray", + "text": "What is xarray\nxarray is an open-source project and python package to work with labelled multi-dimensional arrays. It is leverages numpy, pandas, matplotlib and dask to build Dataset and DataArray objects with built-in methods to subset, analyze, interpolate, and plot multi-dimensional data. It makes working with multi-dimensional data cubes efficient and fun. It will change your life for the better. You’ll be more attractive, more interesting, and better equiped to take on lifes challenges." + }, + { + "objectID": "tutorials/science/Intro_xarray_hvplot.html#what-you-will-learn-from-this-tutorial", + "href": "tutorials/science/Intro_xarray_hvplot.html#what-you-will-learn-from-this-tutorial", + "title": "Introduction to xarray… and hvplot", + "section": "What you will learn from this tutorial", + "text": "What you will learn from this tutorial\nIn this tutorial you will learn how to:\n\nload a netcdf file into xarray\ninterrogate the Dataset and understand the difference between DataArray and Dataset\nsubset a Dataset\ncalculate annual and monthly mean fields\ncalculate a time series of zonal means\nplot these results\n\nAs always, we’ll start by importing xarray. We’ll follow convention by giving the module the shortname xr\n\nimport xarray as xr\nxr.set_options(keep_attrs=True)\nimport hvplot.xarray\n\nI’m going to use one of xarray’s tutorial datasets. In this case, air temperature from the NCEP reanalysis. I’ll assign the result of the open_dataset to ds. I may change this to access a dataset directly\n\nds = xr.tutorial.open_dataset(\"air_temperature\")\n\nAs we are in an interactive environment, we can just type ds to see what we have.\n\nds\n\nFirst thing to notice is that ds is an xarray.Dataset object. It has dimensions, lat, lon, and time. It also has coordinate variables with the same names as these dimensions. These coordinate variables are 1-dimensional. This is a NetCDF convention. The Dataset contains one data variable, air. This has dimensions (time, lat, lon).\nClicking on the document icon reveals attributes for each variable. Clicking on the disk icon reveals a representation of the data.\nEach of the data and coordinate variables can be accessed and examined using the variable name as a key.\n\nds.air\n\n\nds['air']\n\nThese are xarray.DataArray objects. This is the basic building block for xarray.\nVariables can also be accessed as attributes of ds.\n\nds.time\n\nA major difference between accessing a variable as an attribute versus using a key is that the attribute is read-only but the key method can be used to update the variable. For example, if I want to convert the units of air from Kelvin to degrees Celsius.\n\nds['air'] = ds.air - 273.15\n\nThis approach can also be used to add new variables\n\nds['air_kelvin'] = ds.air + 273.15\n\n\nds\n\nIt is helpful to update attributes such as units, this saves time, confusion and mistakes, especially when you save the dataset.\n\nds['air'].attrs['units'] = 'degC'\n\n\nds" + }, + { + "objectID": "tutorials/science/Intro_xarray_hvplot.html#subsetting-and-indexing", + "href": "tutorials/science/Intro_xarray_hvplot.html#subsetting-and-indexing", + "title": "Introduction to xarray… and hvplot", + "section": "Subsetting and Indexing", + "text": "Subsetting and Indexing\nSubsetting and indexing methods depend on whether you are working with a Dataset or DataArray. A DataArray can be accessed using positional indexing just like a numpy array. To access the temperature field for the first time step, you do the following.\n\nds['air'][0,:,:]\n\nNote this returns a DataArray with coordinates but not attributes.\nHowever, the real power is being able to access variables using coordinate variables. I can get the same subset using the following. (It’s also more explicit about what is being selected and robust in case I modify the DataArray and expect the same output.)\n\nds['air'].sel(time='2013-01-01').time\n\n\nds.air.sel(time='2013-01-01')\n\nI can also do slices. I’ll extract temperatures for the state of Colorado. The bounding box for the state is [-109 E, -102 E, 37 N, 41 N].\nIn the code below, pay attention to both the order of the coordinates and the range of values. The first value of the lat coordinate variable is 41 N, the second value is 37 N. Unfortunately, xarray expects slices of coordinates to be in the same order as the coordinates. Note lon is 0 to 360 not -180 to 180, and I let python calculate it for me within the slice.\n\nds.air.sel(lat=slice(41.,37.), lon=slice(360-109,360-102))\n\nWhat if we want temperature for a point, for example Denver, CO (39.72510678889283 N, -104.98785545855408 E). xarray can handle this! If we just want data from the nearest grid point, we can use sel and specify the method as “nearest”.\n\ndenver_lat, denver_lon = 39.72510678889283, -104.98785545855408\n\n\nds.air.sel(lat=denver_lat, lon=360+denver_lon, method='nearest').hvplot()\n\nIf we want to interpolate, we can use interp(). In this case I use linear or bilinear interpolation.\ninterp() can also be used to resample data to a new grid and even reproject data\n\nds.air.interp(lat=denver_lat, lon=360+denver_lon, method='linear')\n\nsel() and interp() can also be used on Dataset objects.\n\nds.sel(lat=slice(41,37), lon=slice(360-109,360-102))\n\n\nds.interp(lat=denver_lat, lon=360+denver_lon, method='linear')" + }, + { + "objectID": "tutorials/science/Intro_xarray_hvplot.html#analysis", + "href": "tutorials/science/Intro_xarray_hvplot.html#analysis", + "title": "Introduction to xarray… and hvplot", + "section": "Analysis", + "text": "Analysis\nAs a simple example, let’s try to calculate a mean field for the whole time range.\n\nds.mean(dim='time').hvplot()\n\nWe can also calculate a zonal mean (averaging over longitude)\n\nds.mean(dim='lon').hvplot()\n\nOther aggregation methods include min(), max(), std(), along with others.\n\nds.std(dim='time').hvplot()\n\nThe data we have are in 6h timesteps. This can be resampled to daily or monthly. If you are familiar with pandas, xarray uses the same methods.\n\nds_mon = ds.resample(time='M').mean()\nds_mon\n\nThis is a really short time series but as an example, let’s calculate a monthly climatology (at least for 2 months). For this we can use groupby()\n\nds_clim = ds_mon.groupby(ds_mon.time.dt.month).mean()\nds_clim" + }, + { + "objectID": "tutorials/science/Intro_xarray_hvplot.html#plot-results", + "href": "tutorials/science/Intro_xarray_hvplot.html#plot-results", + "title": "Introduction to xarray… and hvplot", + "section": "Plot results", + "text": "Plot results\nFinally, let’s plot the results! This will plot the lat/lon axes of the original ds DataArray.\n\nds_clim.air.sel(month=10).hvplot()" }, { "objectID": "tutorials/jupyterhub_demo/jupyterhub_demo.html", "href": "tutorials/jupyterhub_demo/jupyterhub_demo.html", "title": "Demo JupyterHub", "section": "", - "text": "Author: Tasha Snow\nndyskzgkzdrs Learning Objectives - **Learn how to access and use the Openscapes JupyterHub** - **Open the JupyterHub and clone the Openscapes Espacio and Sostenibilidad Colloquium repository**" + "text": "Author: Tasha Snow\nnhboyzuyyncd Learning Objectives - **Learn how to access and use the Openscapes JupyterHub** - **Open the JupyterHub and clone the Openscapes Espacio and Sostenibilidad Colloquium repository**" }, { "objectID": "tutorials/jupyterhub_demo/jupyterhub_demo.html#access-the-cryocloud-powerpoint-whenever-you-need-to-reference-it", @@ -158,7 +249,7 @@ "href": "tutorials/jupyterhub_demo/jupyterhub_demo.html#open-cryocloud", "title": "Demo JupyterHub", "section": "Open CryoCloud", - "text": "Open CryoCloud\n\nScroll through the server sizes. Stick with the 3.7Gb server (the default).\n\n```ndyskzgkzdrs Tip Be realistic about the max memory you will need. The amount you select, you are guaranteed, but if you use more you risk crashing your server for you and anyone else who is sharing with you. If you crash the server, it just requires logging out and reopening it, but it could be annoying for everyone.\nCheck your memory usage at the bottom in the middle of the screen.\n\n2) Choose the Python programming language.\n\n3) Sit back and learn about each of the tools!\n - JupyterHub options and viewing setup\n - Github\n - Virtual Linux desktop\n - SyncThing\n - Viewing and editing of different files\n\nNow after the demo...\n\n## Task: Clone the Espacio and Sostenibilidad Colloquium jupyterbook\n\nWe will import the [NASA Openscapes Espacio and Sostenibilidad Colloquium Github repository](https://github.com/NASA-Openscapes/2023-ssc.git).\n\nTo do this: \n1. Select the plus (`+`) sign above the `File Browser` to the left, which will bring up a `Launcher` window. \n\n2. Click the `terminal` button under Other to open it. This is your command line like you would have on any computer. \n\nBefore cloning the repo, you have the option to switch to another file folder using the _change directory_ terminal command: `cd folder` if you do not want the Hackweek repo in your current directory (you can check which directory you are currently in using _print working directory_ command: `pwd`).\ncd yourfoldername\n\n3. Now clone the hackweek code into your current directory: \ngit clone https://github.com/NASA-Openscapes/2023-ssc.git\n\n4. You will see the folder pop into your `File Browser` on the left if you have the current directory open. Click on the folder to navigate through the files. \n\n5. To open this tutorial, click on the `book` subdirectory > `tutorials` > `jupyterhub_demo` > and double click on `jupyterhub_demo`. This should open up this tutorial in case you want to review it in the future. \n\n## Shutting down your JupyterHub\n\n```{admonition} TIP\n**Best Practice: Shut down the Openscapes server when you are done to save us money.**\n\n**If you only close your tab or click log out, your server will continue running for 90 minutes.**\nWhenever you are done, it is best to shut down your server when you sign out to save money. Time on the JupyterHub costs money and there are systems in place to make sure your server doesn’t run indefinitely if you forget about it. After 90 minutes of no use, it will shut down. We prefer you shut down the server when so we save that 90 minutes of computing cost. To do so:\n\nIn upper left, click on File > Hub Control Panel, which will open another tab\nClick the Stop Server button. Once this button disappears after you clicked it, your server is off.\nClick Log Out in the top right of your screen and you will be logged out, or you can start a new server\nYou can now close this tab and the other tab where you were just working" + "text": "Open CryoCloud\n\nScroll through the server sizes. Stick with the 3.7Gb server (the default).\n\n```nhboyzuyyncd Tip Be realistic about the max memory you will need. The amount you select, you are guaranteed, but if you use more you risk crashing your server for you and anyone else who is sharing with you. If you crash the server, it just requires logging out and reopening it, but it could be annoying for everyone.\nCheck your memory usage at the bottom in the middle of the screen.\n\n2) Choose the Python programming language.\n\n3) Sit back and learn about each of the tools!\n - JupyterHub options and viewing setup\n - Github\n - Virtual Linux desktop\n - SyncThing\n - Viewing and editing of different files\n\nNow after the demo...\n\n## Task: Clone the Espacio and Sostenibilidad Colloquium jupyterbook\n\nWe will import the [NASA Openscapes Espacio and Sostenibilidad Colloquium Github repository](https://github.com/NASA-Openscapes/2023-ssc.git).\n\nTo do this: \n1. Select the plus (`+`) sign above the `File Browser` to the left, which will bring up a `Launcher` window. \n\n2. Click the `terminal` button under Other to open it. This is your command line like you would have on any computer. \n\nBefore cloning the repo, you have the option to switch to another file folder using the _change directory_ terminal command: `cd folder` if you do not want the Hackweek repo in your current directory (you can check which directory you are currently in using _print working directory_ command: `pwd`).\ncd yourfoldername\n\n3. Now clone the hackweek code into your current directory: \ngit clone https://github.com/NASA-Openscapes/2023-ssc.git\n\n4. You will see the folder pop into your `File Browser` on the left if you have the current directory open. Click on the folder to navigate through the files. \n\n5. To open this tutorial, click on the `book` subdirectory > `tutorials` > `jupyterhub_demo` > and double click on `jupyterhub_demo`. This should open up this tutorial in case you want to review it in the future. \n\n## Shutting down your JupyterHub\n\n```{admonition} TIP\n**Best Practice: Shut down the Openscapes server when you are done to save us money.**\n\n**If you only close your tab or click log out, your server will continue running for 90 minutes.**\nWhenever you are done, it is best to shut down your server when you sign out to save money. Time on the JupyterHub costs money and there are systems in place to make sure your server doesn’t run indefinitely if you forget about it. After 90 minutes of no use, it will shut down. We prefer you shut down the server when so we save that 90 minutes of computing cost. To do so:\n\nIn upper left, click on File > Hub Control Panel, which will open another tab\nClick the Stop Server button. Once this button disappears after you clicked it, your server is off.\nClick Log Out in the top right of your screen and you will be logged out, or you can start a new server\nYou can now close this tab and the other tab where you were just working" }, { "objectID": "tutorials/jupyterhub_demo/jupyterhub_demo.html#summary", @@ -210,123 +301,116 @@ "text": "Additional tutorials\n\nData_Access__Direct_S3_Access__PODAAC_ECCO_SSH using CMR-STAC API to retrieve S3 links\nDirect access to ECCO data in S3 (from us-west-2) - Direct S3 access example with netCDF data\nDirect_S3_Access__gdalvrt\nDirect_S3_Access__rioxarray_clipping\nCalculate black-sky, white-sky, and actual albedo (MCD43A) from MCD43A1 BRDF Parameters using R\nXarray Zonal Statistics" }, { - "objectID": "tutorials/science/Intro_xarray_hvplot.html", - "href": "tutorials/science/Intro_xarray_hvplot.html", - "title": "Introduction to xarray… and hvplot", - "section": "", - "text": "As Geoscientists, we often work with time series of data with two or more dimensions: a time series of calibrated, orthorectified satellite images; two-dimensional grids of surface air temperature from an atmospheric reanalysis; or three-dimensional (level, x, y) cubes of ocean salinity from an ocean model. These data are often provided in GeoTIFF, NetCDF or HDF format with rich and useful metadata that we want to retain, or even use in our analysis. Common analyses include calculating means, standard deviations and anomalies over time or one or more spatial dimensions (e.g. zonal means). Model output often includes multiple variables that you want to apply similar analyses to.\n\n\n\nA schematic of multi-dimensional data\n\n\nThe schematic above shows a typical data structure for multi-dimensional data. There are two data cubes, one for temperature and one for precipitation. Common coordinate variables, in this case latitude, longitude and time are associated with each variable. Each variable, including coordinate variables, will have a set of attributes: name, units, missing value, etc. The file containing the data may also have attributes: source of the data, model name coordinate reference system if the data are projected. Writing code using low-level packages such as netcdf4 and numpy to read the data, then perform analysis, and write the results to file is time consuming and prone to errors." + "objectID": "tutorials/GEDI_data_SSC23.html#helpful-links", + "href": "tutorials/GEDI_data_SSC23.html#helpful-links", + "title": "How to work with GEDI Level 2B V002 Data", + "section": "Helpful Links", + "text": "Helpful Links\n\nLP DAAC Website\nLP DAAC GitHub\nGEDI Data Resources GitHub\nGEDI Data Product Pages\nUniversity of Maryland GEDI - Learn more about the GEDI Mission\n\nOpenAltimetry - Learn about GEDI coverage\n\nNASA Earthdata Search" }, { - "objectID": "tutorials/science/Intro_xarray_hvplot.html#why-do-we-need-xarray", - "href": "tutorials/science/Intro_xarray_hvplot.html#why-do-we-need-xarray", - "title": "Introduction to xarray… and hvplot", - "section": "", - "text": "As Geoscientists, we often work with time series of data with two or more dimensions: a time series of calibrated, orthorectified satellite images; two-dimensional grids of surface air temperature from an atmospheric reanalysis; or three-dimensional (level, x, y) cubes of ocean salinity from an ocean model. These data are often provided in GeoTIFF, NetCDF or HDF format with rich and useful metadata that we want to retain, or even use in our analysis. Common analyses include calculating means, standard deviations and anomalies over time or one or more spatial dimensions (e.g. zonal means). Model output often includes multiple variables that you want to apply similar analyses to.\n\n\n\nA schematic of multi-dimensional data\n\n\nThe schematic above shows a typical data structure for multi-dimensional data. There are two data cubes, one for temperature and one for precipitation. Common coordinate variables, in this case latitude, longitude and time are associated with each variable. Each variable, including coordinate variables, will have a set of attributes: name, units, missing value, etc. The file containing the data may also have attributes: source of the data, model name coordinate reference system if the data are projected. Writing code using low-level packages such as netcdf4 and numpy to read the data, then perform analysis, and write the results to file is time consuming and prone to errors." + "objectID": "tutorials/GEDI_data_SSC23.html#contact-info", + "href": "tutorials/GEDI_data_SSC23.html#contact-info", + "title": "How to work with GEDI Level 2B V002 Data", + "section": "Contact Info:", + "text": "Contact Info:\nEmail: LPDAAC@usgs.gov\nVoice: +1-866-573-3222\nOrganization: Land Processes Distributed Active Archive Center (LP DAAC)¹\nWebsite: https://lpdaac.usgs.gov/\nDate last modified: 11-15-2023\n¹Work performed under USGS contract G15PD00467 for NASA contract NNG14HH33I." }, { - "objectID": "tutorials/science/Intro_xarray_hvplot.html#what-is-xarray", - "href": "tutorials/science/Intro_xarray_hvplot.html#what-is-xarray", - "title": "Introduction to xarray… and hvplot", - "section": "What is xarray", - "text": "What is xarray\nxarray is an open-source project and python package to work with labelled multi-dimensional arrays. It is leverages numpy, pandas, matplotlib and dask to build Dataset and DataArray objects with built-in methods to subset, analyze, interpolate, and plot multi-dimensional data. It makes working with multi-dimensional data cubes efficient and fun. It will change your life for the better. You’ll be more attractive, more interesting, and better equiped to take on lifes challenges." - }, - { - "objectID": "tutorials/science/Intro_xarray_hvplot.html#what-you-will-learn-from-this-tutorial", - "href": "tutorials/science/Intro_xarray_hvplot.html#what-you-will-learn-from-this-tutorial", - "title": "Introduction to xarray… and hvplot", - "section": "What you will learn from this tutorial", - "text": "What you will learn from this tutorial\nIn this tutorial you will learn how to:\n\nload a netcdf file into xarray\ninterrogate the Dataset and understand the difference between DataArray and Dataset\nsubset a Dataset\ncalculate annual and monthly mean fields\ncalculate a time series of zonal means\nplot these results\n\nAs always, we’ll start by importing xarray. We’ll follow convention by giving the module the shortname xr\n\nimport xarray as xr\nxr.set_options(keep_attrs=True)\nimport hvplot.xarray\n\nI’m going to use one of xarray’s tutorial datasets. In this case, air temperature from the NCEP reanalysis. I’ll assign the result of the open_dataset to ds. I may change this to access a dataset directly\n\nds = xr.tutorial.open_dataset(\"air_temperature\")\n\nAs we are in an interactive environment, we can just type ds to see what we have.\n\nds\n\nFirst thing to notice is that ds is an xarray.Dataset object. It has dimensions, lat, lon, and time. It also has coordinate variables with the same names as these dimensions. These coordinate variables are 1-dimensional. This is a NetCDF convention. The Dataset contains one data variable, air. This has dimensions (time, lat, lon).\nClicking on the document icon reveals attributes for each variable. Clicking on the disk icon reveals a representation of the data.\nEach of the data and coordinate variables can be accessed and examined using the variable name as a key.\n\nds.air\n\n\nds['air']\n\nThese are xarray.DataArray objects. This is the basic building block for xarray.\nVariables can also be accessed as attributes of ds.\n\nds.time\n\nA major difference between accessing a variable as an attribute versus using a key is that the attribute is read-only but the key method can be used to update the variable. For example, if I want to convert the units of air from Kelvin to degrees Celsius.\n\nds['air'] = ds.air - 273.15\n\nThis approach can also be used to add new variables\n\nds['air_kelvin'] = ds.air + 273.15\n\n\nds\n\nIt is helpful to update attributes such as units, this saves time, confusion and mistakes, especially when you save the dataset.\n\nds['air'].attrs['units'] = 'degC'\n\n\nds" + "objectID": "tutorials/cloud/cloud-paradigm.html", + "href": "tutorials/cloud/cloud-paradigm.html", + "title": "NASA and the Cloud Paradigm", + "section": "", + "text": "Slides that introduce NASA Earthdata Cloud & the Cloud Paradigm." }, { - "objectID": "tutorials/science/Intro_xarray_hvplot.html#subsetting-and-indexing", - "href": "tutorials/science/Intro_xarray_hvplot.html#subsetting-and-indexing", - "title": "Introduction to xarray… and hvplot", - "section": "Subsetting and Indexing", - "text": "Subsetting and Indexing\nSubsetting and indexing methods depend on whether you are working with a Dataset or DataArray. A DataArray can be accessed using positional indexing just like a numpy array. To access the temperature field for the first time step, you do the following.\n\nds['air'][0,:,:]\n\nNote this returns a DataArray with coordinates but not attributes.\nHowever, the real power is being able to access variables using coordinate variables. I can get the same subset using the following. (It’s also more explicit about what is being selected and robust in case I modify the DataArray and expect the same output.)\n\nds['air'].sel(time='2013-01-01').time\n\n\nds.air.sel(time='2013-01-01')\n\nI can also do slices. I’ll extract temperatures for the state of Colorado. The bounding box for the state is [-109 E, -102 E, 37 N, 41 N].\nIn the code below, pay attention to both the order of the coordinates and the range of values. The first value of the lat coordinate variable is 41 N, the second value is 37 N. Unfortunately, xarray expects slices of coordinates to be in the same order as the coordinates. Note lon is 0 to 360 not -180 to 180, and I let python calculate it for me within the slice.\n\nds.air.sel(lat=slice(41.,37.), lon=slice(360-109,360-102))\n\nWhat if we want temperature for a point, for example Denver, CO (39.72510678889283 N, -104.98785545855408 E). xarray can handle this! If we just want data from the nearest grid point, we can use sel and specify the method as “nearest”.\n\ndenver_lat, denver_lon = 39.72510678889283, -104.98785545855408\n\n\nds.air.sel(lat=denver_lat, lon=360+denver_lon, method='nearest').hvplot()\n\nIf we want to interpolate, we can use interp(). In this case I use linear or bilinear interpolation.\ninterp() can also be used to resample data to a new grid and even reproject data\n\nds.air.interp(lat=denver_lat, lon=360+denver_lon, method='linear')\n\nsel() and interp() can also be used on Dataset objects.\n\nds.sel(lat=slice(41,37), lon=slice(360-109,360-102))\n\n\nds.interp(lat=denver_lat, lon=360+denver_lon, method='linear')" + "objectID": "tutorials/schedule.html", + "href": "tutorials/schedule.html", + "title": "Schedule", + "section": "", + "text": "The SSC GEDI/ICESAT-2 Workshop will take place on November 15th.\nNote, hands-on exercises will be executed from a Jupyter Lab instance in 2i2c. Please pass along your Github Username to get access." }, { - "objectID": "tutorials/science/Intro_xarray_hvplot.html#analysis", - "href": "tutorials/science/Intro_xarray_hvplot.html#analysis", - "title": "Introduction to xarray… and hvplot", - "section": "Analysis", - "text": "Analysis\nAs a simple example, let’s try to calculate a mean field for the whole time range.\n\nds.mean(dim='time').hvplot()\n\nWe can also calculate a zonal mean (averaging over longitude)\n\nds.mean(dim='lon').hvplot()\n\nOther aggregation methods include min(), max(), std(), along with others.\n\nds.std(dim='time').hvplot()\n\nThe data we have are in 6h timesteps. This can be resampled to daily or monthly. If you are familiar with pandas, xarray uses the same methods.\n\nds_mon = ds.resample(time='M').mean()\nds_mon\n\nThis is a really short time series but as an example, let’s calculate a monthly climatology (at least for 2 months). For this we can use groupby()\n\nds_clim = ds_mon.groupby(ds_mon.time.dt.month).mean()\nds_clim" + "objectID": "tutorials/schedule.html#workshop-schedule", + "href": "tutorials/schedule.html#workshop-schedule", + "title": "Schedule", + "section": "Workshop Schedule", + "text": "Workshop Schedule\n\n\n\nHour\nEvent\nInstructor\n\n\n\n\n3:00 pm CST/MX\nWelcome and Overview of Tutorial\n\n\n\n3:10 pm\nCryoCloud - A Shared Cloud Platform for NASA\nTasha Snow (Colorado School of Mines)\n\n\n3:25 pm\nHub task - clone repo\n\n\n\n3:35 pm\nBreak (Q&A)\n\n\n\n3:40 pm\nICESat-2 Data Access, NASA DAAC @ NSIDC\nLuis Alberto Lopez Espinosa (NSIDC, University of Colorado)\n\n\n4:00 pm\nBreak (Q&A)\n\n\n\n4:10 pm\nThe icepyx Software Library and Community\nRachel Wegener (University of Maryland)\n\n\n4:30 pm\nBreak\n\n\n\n4:40 pm\nAccess and Discovery of GEDI Data via the DAAC at the ORNL\nRupesh Shrestha (Oakridge National Laboratory, ORNL-DAAC)\n\n\n5:00 pm\nBreak (Q&A)\n\n\n\n5:10 pm\nGEDI Data User Resources at the LP DAAC\nMahsa Jami (NASA LP-DAAC)\n\n\n5:30 pm\nBreak (Q&A)\n\n\n\n5:40 pm\nEjemplos de aplicaciones de uso de éxito GEDI y posibilidades(Mapas, Reforestacion, Especie protegida)\nAdrian Pascual\n\n\n6:00 pm CST/MX\nEnd of Tutorial\n\n\n\n\n\nThank you!\nJupyterHub: close out.\n\nclose out your JupyterHub instance if you are finished for the day, following these instructions.\n\nYou will continue to have access to the 2i2c JupyterHub in AWS for a week following the SSC GEDI/ICESAT-2 Cloud Workshop. You may use that time to continue work and all learn more about migrating data accass routines and science workflows to the Cloud. This cloud compute environment is supported by the NASA Openscapes project." }, { - "objectID": "tutorials/science/Intro_xarray_hvplot.html#plot-results", - "href": "tutorials/science/Intro_xarray_hvplot.html#plot-results", - "title": "Introduction to xarray… and hvplot", - "section": "Plot results", - "text": "Plot results\nFinally, let’s plot the results! This will plot the lat/lon axes of the original ds DataArray.\n\nds_clim.air.sel(month=10).hvplot()" + "objectID": "tutorials/schedule.html#getting-help-during-the-workshop", + "href": "tutorials/schedule.html#getting-help-during-the-workshop", + "title": "Schedule", + "section": "Getting help during the Workshop", + "text": "Getting help during the Workshop\nPlease use the webex chat platform to ask any questions you have during the workshop." }, { - "objectID": "tutorials/cloud/index.html", - "href": "tutorials/cloud/index.html", - "title": "CryoCloud / Openscapes", + "objectID": "tutorials/GEDI_L2B_V2_earthaccess.html", + "href": "tutorials/GEDI_L2B_V2_earthaccess.html", + "title": "Getting Started with GEDI L2B Version 2 Data in Python", "section": "", - "text": "CryoCloud / Openscapes\nPlaceholder" + "text": "The Global Ecosystem Dynamics Investigation (GEDI) mission aims to characterize ecosystem structure and dynamics to enable radically improved quantification and understanding of the Earth’s carbon cycle and biodiversity. The GEDI instrument produces high resolution laser ranging observations of the 3-dimensional structure of the Earth. GEDI is attached to the International Space Station and collects data globally between 51.6 N and 51.6 S latitudes at the highest resolution and densest sampling of any light detection and ranging (lidar) instrument in orbit to date. The Land Processes Distributed Active Archive Center (LP DAAC) distributes the GEDI Level 1 and Level 2 Version 1 and Version 2 products. The L1B and L2 GEDI products are archived and distributed in the HDF-EOS5 file format." }, { - "objectID": "tutorials/setup.html", - "href": "tutorials/setup.html", - "title": "Setup for tutorials", - "section": "", - "text": "This tutorial will help you set up your JupyterHub (or Hub) with tutorials and other materials from our Workshop folder." + "objectID": "tutorials/GEDI_L2B_V2_earthaccess.html#use-case-example", + "href": "tutorials/GEDI_L2B_V2_earthaccess.html#use-case-example", + "title": "Getting Started with GEDI L2B Version 2 Data in Python", + "section": "Use Case Example:", + "text": "Use Case Example:\nThis tutorial was developed using an example use case for a project being completed by the National Park Service. The goal of the project is to use GEDI L2B Version 2 data to observe tree canopy height, cover, and profile over Redwood National Park in northern California.\nThis tutorial will show how to use Python to open GEDI L2B Version 2 files, visualize the sub-orbit of GEDI points (shots), subset to a region of interest, visualize GEDI canopy height and vertical profile metrics, and export subsets of GEDI science dataset (SDS) layers as GeoJSON files that can be loaded into GIS and/or Remote Sensing software programs.\n\nRedwood National Park GeoJSON\n\nContains the administrative boundary for Redwood National Park, available from: Administrative Boundaries of National Park System Units 12/31/2017 - National Geospatial Data Asset (NGDA) NPS National Parks Dataset\n\n\n\nData Used in the Example:\n\nGEDI L2B Canopy Cover and Vertical Profile Metrics Data Global Footprint Level - GEDI02_B.002\n\nThe purpose of the L2B dataset is to extract biophysical metrics from each GEDI waveform. These metrics are based on the directional gap probability profile derived from the L1B waveform and include canopy cover, Plant Area Index (PAI), Plant Area Volume Density (PAVD) and Foliage Height Diversity (FHD).\n\nScience Dataset (SDS) layers:\n\n/geolocation/digital_elevation_model\n/geolocation/elev_lowestmode\n\n/geolocation/elev_highestreturn\n\n/geolocation/lat_lowestmode\n\n/geolocation/lon_lowestmode\n\n/rh100\n\n/l2b_quality_flag\n\n/degrade_flag\n\n/sensitivity\n\n/pai\n\n/pavd_z\n\n/geolocation/shot_number\n\n/dz\n\n/selected_l2a_algorithm" }, { - "objectID": "tutorials/setup.html#step-1.-login-to-the-hub", - "href": "tutorials/setup.html#step-1.-login-to-the-hub", - "title": "Setup for tutorials", - "section": "Step 1. Login to the Hub", - "text": "Step 1. Login to the Hub\nPlease go to Jupyter Hub and Log in with your GitHub Account, and select “Small”.\nAlternatively, you can also click this badge to launch the Hub:\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nNote: It takes a few minutes for the Hub to load. Please be patient!\n\nWhile the Hub loads, we’ll:\n\nDiscuss cloud environments\n\nSee how my Desktop is setup\n\nDiscuss python and conda environments\n\nThen, when the Hub is loaded, we’ll get oriented in the Hub." + "objectID": "tutorials/GEDI_L2B_V2_earthaccess.html#source-code-used-to-generate-this-tutorial", + "href": "tutorials/GEDI_L2B_V2_earthaccess.html#source-code-used-to-generate-this-tutorial", + "title": "Getting Started with GEDI L2B Version 2 Data in Python", + "section": "Source Code used to Generate this Tutorial:", + "text": "Source Code used to Generate this Tutorial:\nThe repository containing all of the required files is located at: https://github.com/nasa/GEDI-Data-Resources\n\nNOTE: This tutorial was developed for GEDI L2B Version 2 HDF-EOS5 files and should only be used for that product." }, { - "objectID": "tutorials/setup.html#discussion-cloud-environment", - "href": "tutorials/setup.html#discussion-cloud-environment", - "title": "Setup for tutorials", - "section": "Discussion: Cloud environment", - "text": "Discussion: Cloud environment\nA brief overview. See NASA Openscapes Cloud Environment in the 2021-Cloud-Hackathon book for more detail.\n\nCloud infrastructure\n\nCloud: AWS us-west-2\n\nData: AWS S3 (cloud) and NASA DAAC data centers (on-prem).\n\nCloud compute environment: 2i2c Jupyterhub deployment\n\nIDE: JupyterLab" + "objectID": "tutorials/GEDI_L2B_V2_earthaccess.html#import-packages", + "href": "tutorials/GEDI_L2B_V2_earthaccess.html#import-packages", + "title": "Getting Started with GEDI L2B Version 2 Data in Python", + "section": "1.1 Import Packages ", + "text": "1.1 Import Packages \n\nImport the required packages and set the input/working directory to run this Jupyter Notebook locally.\n\nimport os\nimport h5py\nimport numpy as np\nimport pandas as pd\nimport geopandas as gp\nfrom shapely.geometry import Point\nimport geoviews as gv\nfrom geoviews import opts, tile_sources as gvts\nimport holoviews as hv\ngv.extension('bokeh', 'matplotlib')\nimport shapely\nimport earthaccess\nimport warnings\nfrom shapely.errors import ShapelyDeprecationWarning\nwarnings.filterwarnings(\"ignore\", category=ShapelyDeprecationWarning)" }, { - "objectID": "tutorials/setup.html#discussion-my-desktop-setup", - "href": "tutorials/setup.html#discussion-my-desktop-setup", - "title": "Setup for tutorials", - "section": "Discussion: My desktop setup", - "text": "Discussion: My desktop setup\nI’ll screenshare to show and/or talk through how I have oriented the following software we’re using:\n\nWorkshop Book\nSlack" + "objectID": "tutorials/GEDI_L2B_V2_earthaccess.html#set-up-the-working-environment-and-retrieve-files", + "href": "tutorials/GEDI_L2B_V2_earthaccess.html#set-up-the-working-environment-and-retrieve-files", + "title": "Getting Started with GEDI L2B Version 2 Data in Python", + "section": "1.2 Set Up the Working Environment and Retrieve Files", + "text": "1.2 Set Up the Working Environment and Retrieve Files\n\nThe input directory is defined as the current working directory.\n\ninDir = os.getcwd() # Set input directory to the current working directory\nos.chdir(inDir)\ndata_dir = inDir.rsplit('2023-ssc')[0] + 'shared/2023SSC/'\ndata_dir\n\n'/home/jovyan/shared/2023SSC/'" }, { - "objectID": "tutorials/setup.html#discussion-python-and-conda-environments", - "href": "tutorials/setup.html#discussion-python-and-conda-environments", - "title": "Setup for tutorials", - "section": "Discussion: Python and Conda environments", - "text": "Discussion: Python and Conda environments\nWhy Python?\n\n\n\nPython Data Stack. Source: Jake VanderPlas, “The State of the Stack,” SciPy Keynote (SciPy 2015).\n\n\nDefault Python Environment:\nWe’ve set up the Python environment with conda.\n\n\n\n\n\n\nConda environment\n\n\n\n\n\nname: openscapes\nchannels:\n - conda-forge\ndependencies:\n - python=3.9\n - pangeo-notebook\n - awscli~=1.20\n - boto3~=1.19\n - gdal~=3.3\n - rioxarray~=0.8\n - xarray~=0.19\n - h5netcdf~=0.11\n - netcdf4~=1.5\n - h5py~=2.10\n - geoviews~=1.9\n - matplotlib-base~=3.4\n - hvplot~=0.7\n - pyproj~=3.2\n - bqplot~=0.12\n - geopandas~=0.10\n - zarr~=2.10\n - cartopy~=0.20\n - shapely==1.7.1\n - pyresample~=1.22\n - joblib~=1.1\n - pystac-client~=0.3\n - s3fs~=2021.7\n - ipyleaflet~=0.14\n - sidecar~=0.5\n - jupyterlab-geojson~=3.1\n - jupyterlab-git\n - jupyter-resource-usage\n - ipympl~=0.6\n - conda-lock~=0.12\n - pooch~=1.5\n - pip\n - pip:\n - tqdm\n - harmony-py\n - earthdata\n - zarr-eosdis-store\n\n\n\n\nBash terminal and installed software\nLibraries that are available from the terminal\n\ngdal 3.3 commands ( gdalinfo, gdaltransform…)\nhdf5 commands ( h5dump, h5ls..)\nnetcdf4 commands (ncdump, ncinfo …)\njq (parsing json files or streams from curl)\ncurl (fetch resources from the web)\nawscli (AWS API client, to interact with AWS cloud services)\nvim (editor)\ntree ( directory tree)\nmore …\n\n\n\nUpdating the environment\nScientific Python is a vast space and we only included libraries that are needed in our tutorials. Our default environment can be updated to include any Python library that’s available on pip or conda.\nThe project used to create our default environment is called corn (as it can include many Python kernels).\nIf we want to update a library or install a whole new environment we need to open an issue on this repository.\n\n\ncorn 🌽" + "objectID": "tutorials/GEDI_L2B_V2_earthaccess.html#authentication", + "href": "tutorials/GEDI_L2B_V2_earthaccess.html#authentication", + "title": "Getting Started with GEDI L2B Version 2 Data in Python", + "section": "1.3 Authentication", + "text": "1.3 Authentication\nLogin to your NASA Earthdata account and create a .netrc file using the login function from the earthaccess library. If you do not have an Earthdata Account, you can create one here.\n\n# authenticate\nearthaccess.login()\n\nEARTHDATA_USERNAME and EARTHDATA_PASSWORD are not set in the current environment, try setting them or use a different strategy (netrc, interactive)\nYou're now authenticated with NASA Earthdata Login\nUsing token with expiration date: 12/24/2023\nUsing .netrc file for EDL\n\n\n<earthaccess.auth.Auth at 0x7fa6508d1a20>" }, { - "objectID": "tutorials/setup.html#step-2.-jupyterhub-orientation", - "href": "tutorials/setup.html#step-2.-jupyterhub-orientation", - "title": "Setup for tutorials", - "section": "Step 2. JupyterHub orientation", - "text": "Step 2. JupyterHub orientation\nNow that the Hub is loaded, let’s get oriented.\n\n\n\n\n\n\nFirst impressions\n\nLauncher & the big blue button\n“home directory”" + "objectID": "tutorials/GEDI_L2B_V2_earthaccess.html#open-a-gedi-hdf5-file-and-read-file-metadata", + "href": "tutorials/GEDI_L2B_V2_earthaccess.html#open-a-gedi-hdf5-file-and-read-file-metadata", + "title": "Getting Started with GEDI L2B Version 2 Data in Python", + "section": "3.1 Open a GEDI HDF5 File and Read File Metadata ", + "text": "3.1 Open a GEDI HDF5 File and Read File Metadata \n\nRead the file using h5py.\n\nL2B = f'{data_dir}{gediFiles[0]}'\nL2B\n\n'/home/jovyan/shared/2023SSC/GEDI02_B_2022155015315_O19683_03_T05652_02_003_01_V002.h5'\n\n\n\n\nThe standard format for GEDI Version 2 filenames is as follows:\n\nGEDI02_B: Product Short Name\n2022159001702: Julian Date and Time of Acquisition (YYYYDDDHHMMSS)\nO19744: Orbit Number\n03: Sub-Orbit Granule Number (1-4)\nT08957: Track Number (Reference Ground Track)\n02: Positioning and Pointing Determination System (PPDS) type (00 is predict, 01 rapid, 02 and higher is final)\n003: PGE Version Number\n01: Granule Production Version\nV002: Product Version\n\n\n\nRead in a GEDI HDF5 file using the h5py package.\n\ngediL2B = h5py.File(L2B, 'r') # Read file using h5py\n\n\n\nNavigate the HDF5 file below.\n\nlist(gediL2B.keys())\n\n['BEAM0000',\n 'BEAM0001',\n 'BEAM0010',\n 'BEAM0011',\n 'BEAM0101',\n 'BEAM0110',\n 'BEAM1000',\n 'BEAM1011',\n 'METADATA']\n\n\n\n\nThe GEDI HDF5 file contains groups in which data and metadata are stored.\n\n\nFirst, the METADATA group contains the file-level metadata.\n\nlist(gediL2B['METADATA'])\n\n['DatasetIdentification']\n\n\nThis contains useful information such as the creation date, PGEVersion, and VersionID. Below, print the file-level metadata attributes.\n\nfor g in gediL2B['METADATA']['DatasetIdentification'].attrs:\n print(g, \": \", gediL2B['METADATA']['DatasetIdentification'].attrs[g]) \n\nPGEVersion : 003\nVersionID : 01\nabstract : The GEDI L2B standard data product contains precise latitude, longitude, elevation, height, cover and vertical profile metrics for each laser footprint located on the land surface.\ncharacterSet : utf8\ncreationDate : 2022-09-22T17:38:15.690108Z\ncredit : The software that generates the L2B product was implemented within the GEDI Science Data Processing System at the NASA Goddard Space Flight Center (GSFC) in Greenbelt, Maryland in collaboration with the Department of Geographical Sciences at the University of Maryland (UMD).\nfileName : GEDI02_B_2022155015315_O19683_03_T05652_02_003_01_V002.h5\nlanguage : eng\noriginatorOrganizationName : UMD/GSFC GEDI-SDPS > GEDI Science Data Processing System\npurpose : The purpose of the L2B dataset is to extract biophysical metrics from each GEDI waveform. These metrics are based on the directional gap probability profile derived from the L1B waveform and include canopy cover, Plant Area Index (PAI), Plant Area Volume Density (PAVD) and Foliage Height Diversity (FHD).\nshortName : GEDI_L2B\nspatialRepresentationType : along-track\nstatus : onGoing\ntopicCategory : geoscientificInformation\nuuid : f7ecc77a-3372-4f53-9131-f110b4bbfb5c" }, { - "objectID": "tutorials/setup.html#step-3.-navigate-to-the-workshop-folder", - "href": "tutorials/setup.html#step-3.-navigate-to-the-workshop-folder", - "title": "Setup for tutorials", - "section": "Step 3. Navigate to the Workshop folder", - "text": "Step 3. Navigate to the Workshop folder\nThe workshop folder 2022-ECOSTRESS-Cloud-Workshop is in the shared folder on JupyterHub." + "objectID": "tutorials/GEDI_L2B_V2_earthaccess.html#read-sds-metadata-and-subset-by-beam", + "href": "tutorials/GEDI_L2B_V2_earthaccess.html#read-sds-metadata-and-subset-by-beam", + "title": "Getting Started with GEDI L2B Version 2 Data in Python", + "section": "3.2 Read SDS Metadata and Subset by Beam ", + "text": "3.2 Read SDS Metadata and Subset by Beam \n\nThe GEDI instrument consists of 3 lasers producing a total of 8 beam ground transects. The eight remaining groups contain data for each of the eight GEDI beam transects. For additional information, be sure to check out: https://gedi.umd.edu/instrument/specifications/.\n\nbeamNames = [g for g in gediL2B.keys() if g.startswith('BEAM')]\nbeamNames\n\n['BEAM0000',\n 'BEAM0001',\n 'BEAM0010',\n 'BEAM0011',\n 'BEAM0101',\n 'BEAM0110',\n 'BEAM1000',\n 'BEAM1011']\n\n\n\n\nOne useful piece of metadata to retrieve from each beam transect is whether it is a full power beam or a coverage beam.\n\nfor b in beamNames: \n print(f\"{b} is a {gediL2B[b].attrs['description']}\")\n\nBEAM0000 is a Coverage beam\nBEAM0001 is a Coverage beam\nBEAM0010 is a Coverage beam\nBEAM0011 is a Coverage beam\nBEAM0101 is a Full power beam\nBEAM0110 is a Full power beam\nBEAM1000 is a Full power beam\nBEAM1011 is a Full power beam\n\n\n\n\nBelow, pick one of the full power beams that will be used to retrieve GEDI L2B shots in next section.\n\n\nIdentify all the objects in the GEDI HDF5 file below.\nNote: This step may take a while to complete.\n\ngediL2B_objs = []\ngediL2B.visit(gediL2B_objs.append) # Retrieve list of datasets\ngediSDS = [o for o in gediL2B_objs if isinstance(gediL2B[o], h5py.Dataset)] # Search for relevant SDS inside data file\n# gediSDS\n[i for i in gediSDS if beamNames[4] in i] # Print the datasets for a selected beam \n\n['BEAM0101/algorithmrun_flag',\n 'BEAM0101/ancillary/dz',\n 'BEAM0101/ancillary/l2a_alg_count',\n 'BEAM0101/ancillary/maxheight_cuttoff',\n 'BEAM0101/ancillary/rg_eg_constraint_center_buffer',\n 'BEAM0101/ancillary/rg_eg_mpfit_max_func_evals',\n 'BEAM0101/ancillary/rg_eg_mpfit_maxiters',\n 'BEAM0101/ancillary/rg_eg_mpfit_tolerance',\n 'BEAM0101/ancillary/signal_search_buff',\n 'BEAM0101/ancillary/tx_noise_stddev_multiplier',\n 'BEAM0101/beam',\n 'BEAM0101/channel',\n 'BEAM0101/cover',\n 'BEAM0101/cover_z',\n 'BEAM0101/fhd_normal',\n 'BEAM0101/geolocation/degrade_flag',\n 'BEAM0101/geolocation/delta_time',\n 'BEAM0101/geolocation/digital_elevation_model',\n 'BEAM0101/geolocation/elev_highestreturn',\n 'BEAM0101/geolocation/elev_lowestmode',\n 'BEAM0101/geolocation/elevation_bin0',\n 'BEAM0101/geolocation/elevation_bin0_error',\n 'BEAM0101/geolocation/elevation_lastbin',\n 'BEAM0101/geolocation/elevation_lastbin_error',\n 'BEAM0101/geolocation/height_bin0',\n 'BEAM0101/geolocation/height_lastbin',\n 'BEAM0101/geolocation/lat_highestreturn',\n 'BEAM0101/geolocation/lat_lowestmode',\n 'BEAM0101/geolocation/latitude_bin0',\n 'BEAM0101/geolocation/latitude_bin0_error',\n 'BEAM0101/geolocation/latitude_lastbin',\n 'BEAM0101/geolocation/latitude_lastbin_error',\n 'BEAM0101/geolocation/local_beam_azimuth',\n 'BEAM0101/geolocation/local_beam_elevation',\n 'BEAM0101/geolocation/lon_highestreturn',\n 'BEAM0101/geolocation/lon_lowestmode',\n 'BEAM0101/geolocation/longitude_bin0',\n 'BEAM0101/geolocation/longitude_bin0_error',\n 'BEAM0101/geolocation/longitude_lastbin',\n 'BEAM0101/geolocation/longitude_lastbin_error',\n 'BEAM0101/geolocation/shot_number',\n 'BEAM0101/geolocation/solar_azimuth',\n 'BEAM0101/geolocation/solar_elevation',\n 'BEAM0101/l2a_quality_flag',\n 'BEAM0101/l2b_quality_flag',\n 'BEAM0101/land_cover_data/landsat_treecover',\n 'BEAM0101/land_cover_data/landsat_water_persistence',\n 'BEAM0101/land_cover_data/leaf_off_doy',\n 'BEAM0101/land_cover_data/leaf_off_flag',\n 'BEAM0101/land_cover_data/leaf_on_cycle',\n 'BEAM0101/land_cover_data/leaf_on_doy',\n 'BEAM0101/land_cover_data/modis_nonvegetated',\n 'BEAM0101/land_cover_data/modis_nonvegetated_sd',\n 'BEAM0101/land_cover_data/modis_treecover',\n 'BEAM0101/land_cover_data/modis_treecover_sd',\n 'BEAM0101/land_cover_data/pft_class',\n 'BEAM0101/land_cover_data/region_class',\n 'BEAM0101/land_cover_data/urban_focal_window_size',\n 'BEAM0101/land_cover_data/urban_proportion',\n 'BEAM0101/master_frac',\n 'BEAM0101/master_int',\n 'BEAM0101/num_detectedmodes',\n 'BEAM0101/omega',\n 'BEAM0101/pai',\n 'BEAM0101/pai_z',\n 'BEAM0101/pavd_z',\n 'BEAM0101/pgap_theta',\n 'BEAM0101/pgap_theta_error',\n 'BEAM0101/pgap_theta_z',\n 'BEAM0101/rg',\n 'BEAM0101/rh100',\n 'BEAM0101/rhog',\n 'BEAM0101/rhog_error',\n 'BEAM0101/rhov',\n 'BEAM0101/rhov_error',\n 'BEAM0101/rossg',\n 'BEAM0101/rv',\n 'BEAM0101/rx_processing/algorithmrun_flag_a1',\n 'BEAM0101/rx_processing/algorithmrun_flag_a2',\n 'BEAM0101/rx_processing/algorithmrun_flag_a3',\n 'BEAM0101/rx_processing/algorithmrun_flag_a4',\n 'BEAM0101/rx_processing/algorithmrun_flag_a5',\n 'BEAM0101/rx_processing/algorithmrun_flag_a6',\n 'BEAM0101/rx_processing/pgap_theta_a1',\n 'BEAM0101/rx_processing/pgap_theta_a2',\n 'BEAM0101/rx_processing/pgap_theta_a3',\n 'BEAM0101/rx_processing/pgap_theta_a4',\n 'BEAM0101/rx_processing/pgap_theta_a5',\n 'BEAM0101/rx_processing/pgap_theta_a6',\n 'BEAM0101/rx_processing/pgap_theta_error_a1',\n 'BEAM0101/rx_processing/pgap_theta_error_a2',\n 'BEAM0101/rx_processing/pgap_theta_error_a3',\n 'BEAM0101/rx_processing/pgap_theta_error_a4',\n 'BEAM0101/rx_processing/pgap_theta_error_a5',\n 'BEAM0101/rx_processing/pgap_theta_error_a6',\n 'BEAM0101/rx_processing/rg_a1',\n 'BEAM0101/rx_processing/rg_a2',\n 'BEAM0101/rx_processing/rg_a3',\n 'BEAM0101/rx_processing/rg_a4',\n 'BEAM0101/rx_processing/rg_a5',\n 'BEAM0101/rx_processing/rg_a6',\n 'BEAM0101/rx_processing/rg_eg_amplitude_a1',\n 'BEAM0101/rx_processing/rg_eg_amplitude_a2',\n 'BEAM0101/rx_processing/rg_eg_amplitude_a3',\n 'BEAM0101/rx_processing/rg_eg_amplitude_a4',\n 'BEAM0101/rx_processing/rg_eg_amplitude_a5',\n 'BEAM0101/rx_processing/rg_eg_amplitude_a6',\n 'BEAM0101/rx_processing/rg_eg_amplitude_error_a1',\n 'BEAM0101/rx_processing/rg_eg_amplitude_error_a2',\n 'BEAM0101/rx_processing/rg_eg_amplitude_error_a3',\n 'BEAM0101/rx_processing/rg_eg_amplitude_error_a4',\n 'BEAM0101/rx_processing/rg_eg_amplitude_error_a5',\n 'BEAM0101/rx_processing/rg_eg_amplitude_error_a6',\n 'BEAM0101/rx_processing/rg_eg_center_a1',\n 'BEAM0101/rx_processing/rg_eg_center_a2',\n 'BEAM0101/rx_processing/rg_eg_center_a3',\n 'BEAM0101/rx_processing/rg_eg_center_a4',\n 'BEAM0101/rx_processing/rg_eg_center_a5',\n 'BEAM0101/rx_processing/rg_eg_center_a6',\n 'BEAM0101/rx_processing/rg_eg_center_error_a1',\n 'BEAM0101/rx_processing/rg_eg_center_error_a2',\n 'BEAM0101/rx_processing/rg_eg_center_error_a3',\n 'BEAM0101/rx_processing/rg_eg_center_error_a4',\n 'BEAM0101/rx_processing/rg_eg_center_error_a5',\n 'BEAM0101/rx_processing/rg_eg_center_error_a6',\n 'BEAM0101/rx_processing/rg_eg_chisq_a1',\n 'BEAM0101/rx_processing/rg_eg_chisq_a2',\n 'BEAM0101/rx_processing/rg_eg_chisq_a3',\n 'BEAM0101/rx_processing/rg_eg_chisq_a4',\n 'BEAM0101/rx_processing/rg_eg_chisq_a5',\n 'BEAM0101/rx_processing/rg_eg_chisq_a6',\n 'BEAM0101/rx_processing/rg_eg_flag_a1',\n 'BEAM0101/rx_processing/rg_eg_flag_a2',\n 'BEAM0101/rx_processing/rg_eg_flag_a3',\n 'BEAM0101/rx_processing/rg_eg_flag_a4',\n 'BEAM0101/rx_processing/rg_eg_flag_a5',\n 'BEAM0101/rx_processing/rg_eg_flag_a6',\n 'BEAM0101/rx_processing/rg_eg_gamma_a1',\n 'BEAM0101/rx_processing/rg_eg_gamma_a2',\n 'BEAM0101/rx_processing/rg_eg_gamma_a3',\n 'BEAM0101/rx_processing/rg_eg_gamma_a4',\n 'BEAM0101/rx_processing/rg_eg_gamma_a5',\n 'BEAM0101/rx_processing/rg_eg_gamma_a6',\n 'BEAM0101/rx_processing/rg_eg_gamma_error_a1',\n 'BEAM0101/rx_processing/rg_eg_gamma_error_a2',\n 'BEAM0101/rx_processing/rg_eg_gamma_error_a3',\n 'BEAM0101/rx_processing/rg_eg_gamma_error_a4',\n 'BEAM0101/rx_processing/rg_eg_gamma_error_a5',\n 'BEAM0101/rx_processing/rg_eg_gamma_error_a6',\n 'BEAM0101/rx_processing/rg_eg_niter_a1',\n 'BEAM0101/rx_processing/rg_eg_niter_a2',\n 'BEAM0101/rx_processing/rg_eg_niter_a3',\n 'BEAM0101/rx_processing/rg_eg_niter_a4',\n 'BEAM0101/rx_processing/rg_eg_niter_a5',\n 'BEAM0101/rx_processing/rg_eg_niter_a6',\n 'BEAM0101/rx_processing/rg_eg_sigma_a1',\n 'BEAM0101/rx_processing/rg_eg_sigma_a2',\n 'BEAM0101/rx_processing/rg_eg_sigma_a3',\n 'BEAM0101/rx_processing/rg_eg_sigma_a4',\n 'BEAM0101/rx_processing/rg_eg_sigma_a5',\n 'BEAM0101/rx_processing/rg_eg_sigma_a6',\n 'BEAM0101/rx_processing/rg_eg_sigma_error_a1',\n 'BEAM0101/rx_processing/rg_eg_sigma_error_a2',\n 'BEAM0101/rx_processing/rg_eg_sigma_error_a3',\n 'BEAM0101/rx_processing/rg_eg_sigma_error_a4',\n 'BEAM0101/rx_processing/rg_eg_sigma_error_a5',\n 'BEAM0101/rx_processing/rg_eg_sigma_error_a6',\n 'BEAM0101/rx_processing/rg_error_a1',\n 'BEAM0101/rx_processing/rg_error_a2',\n 'BEAM0101/rx_processing/rg_error_a3',\n 'BEAM0101/rx_processing/rg_error_a4',\n 'BEAM0101/rx_processing/rg_error_a5',\n 'BEAM0101/rx_processing/rg_error_a6',\n 'BEAM0101/rx_processing/rv_a1',\n 'BEAM0101/rx_processing/rv_a2',\n 'BEAM0101/rx_processing/rv_a3',\n 'BEAM0101/rx_processing/rv_a4',\n 'BEAM0101/rx_processing/rv_a5',\n 'BEAM0101/rx_processing/rv_a6',\n 'BEAM0101/rx_processing/rx_energy_a1',\n 'BEAM0101/rx_processing/rx_energy_a2',\n 'BEAM0101/rx_processing/rx_energy_a3',\n 'BEAM0101/rx_processing/rx_energy_a4',\n 'BEAM0101/rx_processing/rx_energy_a5',\n 'BEAM0101/rx_processing/rx_energy_a6',\n 'BEAM0101/rx_processing/shot_number',\n 'BEAM0101/rx_range_highestreturn',\n 'BEAM0101/rx_sample_count',\n 'BEAM0101/rx_sample_start_index',\n 'BEAM0101/selected_l2a_algorithm',\n 'BEAM0101/selected_mode',\n 'BEAM0101/selected_mode_flag',\n 'BEAM0101/selected_rg_algorithm',\n 'BEAM0101/sensitivity',\n 'BEAM0101/shot_number',\n 'BEAM0101/stale_return_flag',\n 'BEAM0101/surface_flag']\n\n\nThere are several datasets for each beam. View the GEDI L2B Dictionary for more details. You can also print the description for desired datasets.\n\nprint('pai: ', gediL2B['BEAM0101/pai'].attrs['description'])\nprint('pai_z: ', gediL2B['BEAM0101/pai_z'].attrs['description'])\nprint('pavd_z: ', gediL2B['BEAM0101/pavd_z'].attrs['description'])\nprint('shot_number: ', gediL2B['BEAM0101/geolocation/shot_number'].attrs['description'])\nprint('rh100: ', gediL2B['BEAM0101/rh100'].attrs['description'])\nprint('Quality Flag: ', gediL2B['BEAM0101/l2b_quality_flag'].attrs['description'])\n\npai: Total plant area index\npai_z: Vertical PAI profile from canopy height (z) to ground (z=0) with a vertical step size of dZ, where cover(z > z_max) = 0\npavd_z: Vertical Plant Area Volume Density profile with a vertical step size of dZ\nshot_number: Unique shot ID.\nrh100: Height above ground of the received waveform signal start (rh[101] from L2A)\nQuality Flag: Flag simpilfying selection of most useful data for Level 2B\n\n\n\n\nWe will set the shot index used as an example from the GEDI L1B Tutorial and GEDI L2A Tutorial to show how to subset a single shot of GEDI L2B data." }, { - "objectID": "tutorials/setup.html#jupyter-notebooks", - "href": "tutorials/setup.html#jupyter-notebooks", - "title": "Setup for tutorials", - "section": "Jupyter notebooks", - "text": "Jupyter notebooks\nLet’s get oriented to Jupyter notebooks, which we’ll use in all the tutorials." + "objectID": "tutorials/GEDI_L2B_V2_earthaccess.html#subset-by-layer-and-create-a-geodataframe", + "href": "tutorials/GEDI_L2B_V2_earthaccess.html#subset-by-layer-and-create-a-geodataframe", + "title": "Getting Started with GEDI L2B Version 2 Data in Python", + "section": "4.1 Subset by Layer and Create a Geodataframe ", + "text": "4.1 Subset by Layer and Create a Geodataframe \n\nRead in the SDS and take a representative sample (every 100th shot) and append to lists, then use the lists to generate a pandas dataframe.\n\nlonSample, latSample, shotSample, qualitySample, beamSample = [], [], [], [], [] # Set up lists to store data\n\n# Open the SDS\nlats = gediL2B[f'{beamNames[0]}/geolocation/lat_lowestmode'][()]\nlons = gediL2B[f'{beamNames[0]}/geolocation/lon_lowestmode'][()]\nshots = gediL2B[f'{beamNames[0]}/geolocation/shot_number'][()]\nquality = gediL2B[f'{beamNames[0]}/l2b_quality_flag'][()]\n\n# Take every 100th shot and append to list\nfor i in range(len(shots)):\n if i % 100 == 0:\n shotSample.append(str(shots[i]))\n lonSample.append(lons[i])\n latSample.append(lats[i])\n qualitySample.append(quality[i])\n beamSample.append(beamNames[0])\n \n# Write all of the sample shots to a dataframe\nlatslons = pd.DataFrame({'Beam': beamSample, 'Shot Number': shotSample, 'Longitude': lonSample, 'Latitude': latSample,\n 'Quality Flag': qualitySample})\nlatslons\n\n\n\n\n\n\n\n\nBeam\nShot Number\nLongitude\nLatitude\nQuality Flag\n\n\n\n\n0\nBEAM0000\n196830000300204328\n-150.407079\n51.480311\n0\n\n\n1\nBEAM0000\n196830000300204428\n-150.363476\n51.474715\n0\n\n\n2\nBEAM0000\n196830000300204528\n-150.322943\n51.470677\n0\n\n\n3\nBEAM0000\n196830000300204628\n-150.280632\n51.465678\n0\n\n\n4\nBEAM0000\n196830000300204728\n-150.239797\n51.461442\n0\n\n\n...\n...\n...\n...\n...\n...\n\n\n1532\nBEAM0000\n196830000300357528\n-77.574387\n0.617701\n0\n\n\n1533\nBEAM0000\n196830000300357628\n-77.544344\n0.575149\n0\n\n\n1534\nBEAM0000\n196830000300357728\n-77.514584\n0.532945\n0\n\n\n1535\nBEAM0000\n196830000300357828\n-77.484620\n0.490324\n0\n\n\n1536\nBEAM0000\n196830000300357928\n-77.454636\n0.447691\n0\n\n\n\n\n1537 rows × 5 columns\n\n\n\n\n\nAbove is a dataframe containing columns describing the beam, shot number, lat/lon location, and quality information about each shot.\n\n\nSide Note: Wondering what the 0’s and 1’s for l2b_quality_flag mean?\n\n\nAbove, 0 is poor quality and a quality_flag value of 1 indicates the laser shot meets criteria based on energy, sensitivity, amplitude, and real-time surface tracking quality. We will show an example of how to quality filter GEDI data.\n\n# Clean up variables that will no longer be needed\n# del beamSample, quality, qualitySample, gediL2B_objs, latSample, lats, lonSample, lons, shotSample, shots \n\n\n\nBelow, create an additional column called ‘geometry’ that contains a shapely point generated from each lat/lon location from the shot.\n\n# Take the lat/lon dataframe and convert each lat/lon to a shapely point\nlatslons['geometry'] = latslons.apply(lambda row: Point(row.Longitude, row.Latitude), axis=1)\n\n\n\nNext, convert to a Geopandas GeoDataFrame.\n\n# Convert to a Geodataframe\nlatslons = gp.GeoDataFrame(latslons)\nlatslons = latslons.drop(columns=['Latitude','Longitude'])\nlatslons['geometry']\n\n0 POINT (-150.40708 51.48031)\n1 POINT (-150.36348 51.47471)\n2 POINT (-150.32294 51.47068)\n3 POINT (-150.28063 51.46568)\n4 POINT (-150.23980 51.46144)\n ... \n1532 POINT (-77.57439 0.61770)\n1533 POINT (-77.54434 0.57515)\n1534 POINT (-77.51458 0.53295)\n1535 POINT (-77.48462 0.49032)\n1536 POINT (-77.45464 0.44769)\nName: geometry, Length: 1537, dtype: geometry\n\n\n\n\nPull out and plot an example shapely point below." }, { - "objectID": "tutorials/setup.html#how-do-i-end-my-session", - "href": "tutorials/setup.html#how-do-i-end-my-session", - "title": "Setup for tutorials", - "section": "How do I end my session?", - "text": "How do I end my session?\n(Also see How do I end my Openscapes session? Will I lose all of my work?) When you are finished working for the day it is important to explicitly log out of your Openscapes session. The reason for this is it will save money and is a good habit to be in. When you keep a session active it uses up AWS resources and keeps a series of virtual machines deployed.\nStopping the server happens automatically when you log out, so navigate to “File -> Log Out” and click “Log Out”!\n\n\n\nhub-control-panel-button (credit: UW Hackweek)\n\n\n!!! NOTE “logging out” - Logging out will NOT cause any of your work to be lost or deleted. It simply shuts down some resources. It would be equivalent to turning off your desktop computer at the end of the day." + "objectID": "tutorials/GEDI_L2B_V2_earthaccess.html#visualize-a-geodataframe", + "href": "tutorials/GEDI_L2B_V2_earthaccess.html#visualize-a-geodataframe", + "title": "Getting Started with GEDI L2B Version 2 Data in Python", + "section": "4.2 Visualize a GeoDataFrame ", + "text": "4.2 Visualize a GeoDataFrame \n\nIn this section, use the GeoDataFrame and the geoviews python package to spatially visualize the location of the GEDI shots on a basemap and import a GeoJSON file of the spatial region of interest for the use case example: Redwood National Park.\n\n# Define a function for visualizing GEDI points\ndef pointVisual(features, vdims):\n return (gvts.EsriImagery * gv.Points(features, vdims=vdims).options(tools=['hover'], height=500, width=900, size=5, \n color='yellow', fontsize={'xticks': 10, 'yticks': 10, \n 'xlabel':16, 'ylabel': 16}))\n\n\n\nImport a GeoJSON of Reserva de la Biósfera Calakmul National Park as an additional GeoDataFrame.\n\ncalakmul = gp.GeoDataFrame.from_file(f'{data_dir}calakmul.geojson') # Import GeoJSON as GeoDataFrame\n\n\ncalakmul\n\n\n\n\n\n\n\n\ngeometry\n\n\n\n\n0\nPOLYGON ((-89.00000 19.00000, -91.50000 19.000...\n\n\n\n\n\n\n\n\ncalakmul['geometry'][0] # Plot GeoDataFrame\n\n\n\n\n\n\nDefining the vdims below will allow you to hover over specific shots and view information about them.\n\n# Create a list of geodataframe columns to be included as attributes in the output map\nvdims = []\nfor f in latslons:\n if f not in ['geometry']:\n vdims.append(f)\nvdims\n\n['Beam', 'Shot Number', 'Quality Flag']\n\n\n\n\nBelow, combine a plot of the Redwood National Park Boundary (combine two geoviews plots using *) with the point visual mapping function defined above in order to plot (1) the representative GEDI shots, (2) the region of interest, and (3) a basemap layer.\n\n# Call the function for plotting the GEDI points\ngv.Polygons(calakmul['geometry']).opts(line_color='red', color=None) * pointVisual(latslons, vdims = vdims)\n\n\n\n\n\n \n\n\n\n\n\n\nEach GEDI shot has a unique shot identifier (shot number) that is available within each data group of the product. The shot number is important to retain in any data subsetting as it will allow the user to link any shot record back to the original orbit data, and to link any shot and its data between the L1 and L2 products. The standard format for GEDI Shots is as follows:" }, { "objectID": "tutorials/data-access/index.html", @@ -398,48 +482,6 @@ "section": "4. Additional resources", "text": "4. Additional resources\nFor general information about NSIDC DAAC data in the Earthdata Cloud:\nFAQs About NSIDC DAAC’s Earthdata Cloud Migration\nNASA Earthdata Cloud Data Access Guide\nAdditional tutorials and How Tos:\nNASA Earthdata Cloud Cookbook" }, - { - "objectID": "tutorials/data-access/icepyx.html", - "href": "tutorials/data-access/icepyx.html", - "title": "Using icepyx to access Icesat-2 data", - "section": "", - "text": "!pip install icepyx==0.8.1 -qq" - }, - { - "objectID": "tutorials/data-access/icepyx.html#what-is-icesat-2", - "href": "tutorials/data-access/icepyx.html#what-is-icesat-2", - "title": "Using icepyx to access Icesat-2 data", - "section": "What is Icesat-2?", - "text": "What is Icesat-2?\n\n\n\nIS2\n\n\nIcesat-2 is a satellite lidar instrument. Lidar is an active remote sensing instrument in which pulses of light are emitted and the return time is used to mesure distance. The available Icesat-2 data products range from sea ice freeboard to land elevation to cloud backscatter characteristics. A list of availble products can be found here. In this tutorial we will look at ATL08 Land Water Vegetation Elevation.\n\nData Collection\nIcesat-2 measures data along 6 different beams: 3 strong beams and 3 weak beams. The strong and weak beams are calibrated such that the weak beams have more sensitivity to viewing very bright surfaces (Ex. ice), which the strong beams are able to view surfaces with lower reflectances (Ex. water). The beams are called gt1l, gt1r, gt2l, gt2r, gt3l, and gt3r, where the l and r denotes whether the beam was strong or weak.\nJessica which one (l/r) is which? Or is this is what spot is for?\n\n\n\nTracks\n\n\nPhoto: Neuenschwander et. al. 2019, Remote Sens. Env. DOI\n\n\nCounting Photons\nThe Icesat-2 lidar collects at the single photon level, different from most commercial lidar systems. A lot of additional photons get returned as solar background noise, and removing these unwanted photons is a key part of the algorithms that produce the higher level data products.\ndragon algorithm image Photo: Neuenschwander et. al. 2019, Remote Sens. Env. DOI\nTo aggregate all these photons into more manegable chunks ATL08 consolidates the photons into 100m segments, each made up of five 20m segments." - }, - { - "objectID": "tutorials/data-access/icepyx.html#what-is-icepyx", - "href": "tutorials/data-access/icepyx.html#what-is-icepyx", - "title": "Using icepyx to access Icesat-2 data", - "section": "What is icepyx?", - "text": "What is icepyx?\n\nicepyx is a community built library for searching, downloading, and reading Icesat-2 data. While opening data should be straightforward, there are some oddities in navigating the organization of the Icesat-2 data. icepyx provides tools to help with those oddities.\n\nFitting icepyx into the data access package landscape\nFor Icesat-2 data, the icepyx package can: - search for available data granules (data files) - order and download data - order a subset of data: either clipped in space or containing fewer variables - provides functionality to search through the available data variables - read Icesat-2 data into xarray DataArrays, including merging data from multiple files\n\n\nUsing icepyx to search for data\nWe won’t dive into using icepyx to search for and download data in this tutorial, since we already discussed how to do that with earthaccess. The code to search and download is still provided below for the curious reader. The icepyx documentation shows more detail about different search parameters and how to inspect the results of a query.\n\nimport icepyx as ipx\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n \n \n\n\n\n\n\n\n\n\nipx.__version__\n\nJessica does icepyx search by roi?\n\nimport json\nfrom shapely.geometry import shape, GeometryCollection\n\nwith open(\"bosque_primavera.json\") as f:\n features = json.load(f)[\"features\"]\n\n# NOTE: buffer(0) is a trick for fixing scenarios where polygons have overlapping coordinates \nbosque = GeometryCollection([shape(feature[\"geometry\"]).buffer(0) for feature in features])\n\n\nspatial_extent = list(bosque.bounds)\n\n\nshort_name = 'ATL08'\ndate_range = ['2019-05-04','2019-05-04']\nregion = ipx.Query(short_name, spatial_extent, date_range)\n\n\nregion.avail_granules(ids=True)\n\n\n# Download the granules to a into a folder called 'download'\nregion.download_granules('./bosque_primavera_ATL08')\n\n\nTip: If you don’t want to type your earthdata login information everytime it is required there are alternate methods for authenticating. Two common methods are 1) Add your earthdata password and username to as environment variables as EARTHDATA_LOGIN and EARTHDATA_PASSWORD. 2) setup a .netrc file in your home directory. See: https://nasa-openscapes.github.io/2021-Cloud-Hackathon/tutorials/04_NASA_Earthdata_Authentication.html" - }, - { - "objectID": "tutorials/data-access/icepyx.html#reading-a-file-with-icepyx", - "href": "tutorials/data-access/icepyx.html#reading-a-file-with-icepyx", - "title": "Using icepyx to access Icesat-2 data", - "section": "Reading a file with icepyx", - "text": "Reading a file with icepyx\nTo read a file with icepyx there are several steps: 1. Create a Read object. This sets up an initial connection to your file(s) and validates the metadata. 2. Tell the Read object what variables you would like to read 3. Load your data!\n\nCreate a Read object\n\npattern = \"processed_ATL{product:2}_{datetime:%Y%m%d%H%M%S}_{rgt:4}{cycle:2}{orbitsegment:2}_{version:3}_{revision:2}.h5\"\nreader = ipx.Read('./bosque_primavera_ATL08', \"ATL08\", pattern)\n\nYou have 1 files matching the filename pattern to be read in.\n\n\n\nreader\n\n<icepyx.core.read.Read at 0x7f58011d1b70>\n\n\n\n\nSelect your variables\nTo view the variables contained in your dataset you can call .vars on your data reader.\n\nreader.vars.avail()\n\n['ancillary_data/atlas_sdp_gps_epoch',\n 'ancillary_data/control',\n 'ancillary_data/data_end_utc',\n 'ancillary_data/data_start_utc',\n 'ancillary_data/end_cycle',\n 'ancillary_data/end_delta_time',\n 'ancillary_data/end_geoseg',\n 'ancillary_data/end_gpssow',\n 'ancillary_data/end_gpsweek',\n 'ancillary_data/end_orbit',\n 'ancillary_data/end_region',\n 'ancillary_data/end_rgt',\n 'ancillary_data/granule_end_utc',\n 'ancillary_data/granule_start_utc',\n 'ancillary_data/land/atl08_region',\n 'ancillary_data/land/bin_size_h',\n 'ancillary_data/land/bin_size_n',\n 'ancillary_data/land/bright_thresh',\n 'ancillary_data/land/ca_class',\n 'ancillary_data/land/can_noise_thresh',\n 'ancillary_data/land/can_stat_thresh',\n 'ancillary_data/land/canopy20m_thresh',\n 'ancillary_data/land/canopy_flag_switch',\n 'ancillary_data/land/canopy_seg',\n 'ancillary_data/land/class_thresh',\n 'ancillary_data/land/cloud_filter_switch',\n 'ancillary_data/land/del_amp',\n 'ancillary_data/land/del_mu',\n 'ancillary_data/land/del_sigma',\n 'ancillary_data/land/dem_filter_switch',\n 'ancillary_data/land/dem_removal_percent_limit',\n 'ancillary_data/land/dragann_switch',\n 'ancillary_data/land/dseg',\n 'ancillary_data/land/dseg_buf',\n 'ancillary_data/land/fnlgnd_filter_switch',\n 'ancillary_data/land/gnd_stat_thresh',\n 'ancillary_data/land/gthresh_factor',\n 'ancillary_data/land/h_canopy_perc',\n 'ancillary_data/land/iter_gnd',\n 'ancillary_data/land/iter_max',\n 'ancillary_data/land/lseg',\n 'ancillary_data/land/lseg_buf',\n 'ancillary_data/land/lw_filt_bnd',\n 'ancillary_data/land/lw_gnd_bnd',\n 'ancillary_data/land/lw_toc_bnd',\n 'ancillary_data/land/lw_toc_cut',\n 'ancillary_data/land/max_atl03files',\n 'ancillary_data/land/max_atl09files',\n 'ancillary_data/land/max_peaks',\n 'ancillary_data/land/max_try',\n 'ancillary_data/land/min_nphs',\n 'ancillary_data/land/n_dec_mode',\n 'ancillary_data/land/night_thresh',\n 'ancillary_data/land/noise_class',\n 'ancillary_data/land/outlier_filter_switch',\n 'ancillary_data/land/p_static',\n 'ancillary_data/land/ph_removal_percent_limit',\n 'ancillary_data/land/proc_geoseg',\n 'ancillary_data/land/psf',\n 'ancillary_data/land/ref_dem_limit',\n 'ancillary_data/land/ref_finalground_limit',\n 'ancillary_data/land/relief_hbot',\n 'ancillary_data/land/relief_htop',\n 'ancillary_data/land/shp_param',\n 'ancillary_data/land/sig_rsq_search',\n 'ancillary_data/land/sseg',\n 'ancillary_data/land/stat20m_thresh',\n 'ancillary_data/land/stat_thresh',\n 'ancillary_data/land/tc_thresh',\n 'ancillary_data/land/te_class',\n 'ancillary_data/land/terrain20m_thresh',\n 'ancillary_data/land/toc_class',\n 'ancillary_data/land/up_filt_bnd',\n 'ancillary_data/land/up_gnd_bnd',\n 'ancillary_data/land/up_toc_bnd',\n 'ancillary_data/land/up_toc_cut',\n 'ancillary_data/land/yapc_switch',\n 'ancillary_data/qa_at_interval',\n 'ancillary_data/release',\n 'ancillary_data/start_cycle',\n 'ancillary_data/start_delta_time',\n 'ancillary_data/start_geoseg',\n 'ancillary_data/start_gpssow',\n 'ancillary_data/start_gpsweek',\n 'ancillary_data/start_orbit',\n 'ancillary_data/start_region',\n 'ancillary_data/start_rgt',\n 'ancillary_data/version',\n 'ds_geosegments',\n 'ds_metrics',\n 'ds_surf_type',\n 'gt3l/land_segments/asr',\n 'gt3l/land_segments/atlas_pa',\n 'gt3l/land_segments/beam_azimuth',\n 'gt3l/land_segments/beam_coelev',\n 'gt3l/land_segments/brightness_flag',\n 'gt3l/land_segments/canopy/can_noise',\n 'gt3l/land_segments/canopy/canopy_h_metrics',\n 'gt3l/land_segments/canopy/canopy_h_metrics_abs',\n 'gt3l/land_segments/canopy/canopy_openness',\n 'gt3l/land_segments/canopy/canopy_rh_conf',\n 'gt3l/land_segments/canopy/centroid_height',\n 'gt3l/land_segments/canopy/h_canopy',\n 'gt3l/land_segments/canopy/h_canopy_20m',\n 'gt3l/land_segments/canopy/h_canopy_abs',\n 'gt3l/land_segments/canopy/h_canopy_quad',\n 'gt3l/land_segments/canopy/h_canopy_uncertainty',\n 'gt3l/land_segments/canopy/h_dif_canopy',\n 'gt3l/land_segments/canopy/h_max_canopy',\n 'gt3l/land_segments/canopy/h_max_canopy_abs',\n 'gt3l/land_segments/canopy/h_mean_canopy',\n 'gt3l/land_segments/canopy/h_mean_canopy_abs',\n 'gt3l/land_segments/canopy/h_median_canopy',\n 'gt3l/land_segments/canopy/h_median_canopy_abs',\n 'gt3l/land_segments/canopy/h_min_canopy',\n 'gt3l/land_segments/canopy/h_min_canopy_abs',\n 'gt3l/land_segments/canopy/n_ca_photons',\n 'gt3l/land_segments/canopy/n_toc_photons',\n 'gt3l/land_segments/canopy/photon_rate_can',\n 'gt3l/land_segments/canopy/photon_rate_can_nr',\n 'gt3l/land_segments/canopy/segment_cover',\n 'gt3l/land_segments/canopy/subset_can_flag',\n 'gt3l/land_segments/canopy/toc_roughness',\n 'gt3l/land_segments/cloud_flag_atm',\n 'gt3l/land_segments/cloud_fold_flag',\n 'gt3l/land_segments/delta_time',\n 'gt3l/land_segments/delta_time_beg',\n 'gt3l/land_segments/delta_time_end',\n 'gt3l/land_segments/dem_flag',\n 'gt3l/land_segments/dem_h',\n 'gt3l/land_segments/dem_removal_flag',\n 'gt3l/land_segments/h_dif_ref',\n 'gt3l/land_segments/last_seg_extend',\n 'gt3l/land_segments/latitude',\n 'gt3l/land_segments/latitude_20m',\n 'gt3l/land_segments/layer_flag',\n 'gt3l/land_segments/longitude',\n 'gt3l/land_segments/longitude_20m',\n 'gt3l/land_segments/msw_flag',\n 'gt3l/land_segments/n_seg_ph',\n 'gt3l/land_segments/night_flag',\n 'gt3l/land_segments/ph_ndx_beg',\n 'gt3l/land_segments/ph_removal_flag',\n 'gt3l/land_segments/psf_flag',\n 'gt3l/land_segments/rgt',\n 'gt3l/land_segments/sat_flag',\n 'gt3l/land_segments/segment_id_beg',\n 'gt3l/land_segments/segment_id_end',\n 'gt3l/land_segments/segment_landcover',\n 'gt3l/land_segments/segment_snowcover',\n 'gt3l/land_segments/segment_watermask',\n 'gt3l/land_segments/sigma_across',\n 'gt3l/land_segments/sigma_along',\n 'gt3l/land_segments/sigma_atlas_land',\n 'gt3l/land_segments/sigma_h',\n 'gt3l/land_segments/sigma_topo',\n 'gt3l/land_segments/snr',\n 'gt3l/land_segments/solar_azimuth',\n 'gt3l/land_segments/solar_elevation',\n 'gt3l/land_segments/surf_type',\n 'gt3l/land_segments/terrain/h_te_best_fit',\n 'gt3l/land_segments/terrain/h_te_best_fit_20m',\n 'gt3l/land_segments/terrain/h_te_interp',\n 'gt3l/land_segments/terrain/h_te_max',\n 'gt3l/land_segments/terrain/h_te_mean',\n 'gt3l/land_segments/terrain/h_te_median',\n 'gt3l/land_segments/terrain/h_te_min',\n 'gt3l/land_segments/terrain/h_te_mode',\n 'gt3l/land_segments/terrain/h_te_rh25',\n 'gt3l/land_segments/terrain/h_te_skew',\n 'gt3l/land_segments/terrain/h_te_std',\n 'gt3l/land_segments/terrain/h_te_uncertainty',\n 'gt3l/land_segments/terrain/n_te_photons',\n 'gt3l/land_segments/terrain/photon_rate_te',\n 'gt3l/land_segments/terrain/subset_te_flag',\n 'gt3l/land_segments/terrain/terrain_slope',\n 'gt3l/land_segments/terrain_flg',\n 'gt3l/land_segments/urban_flag',\n 'gt3l/signal_photons/classed_pc_flag',\n 'gt3l/signal_photons/classed_pc_indx',\n 'gt3l/signal_photons/d_flag',\n 'gt3l/signal_photons/delta_time',\n 'gt3l/signal_photons/ph_h',\n 'gt3l/signal_photons/ph_segment_id',\n 'gt3r/land_segments/asr',\n 'gt3r/land_segments/atlas_pa',\n 'gt3r/land_segments/beam_azimuth',\n 'gt3r/land_segments/beam_coelev',\n 'gt3r/land_segments/brightness_flag',\n 'gt3r/land_segments/canopy/can_noise',\n 'gt3r/land_segments/canopy/canopy_h_metrics',\n 'gt3r/land_segments/canopy/canopy_h_metrics_abs',\n 'gt3r/land_segments/canopy/canopy_openness',\n 'gt3r/land_segments/canopy/canopy_rh_conf',\n 'gt3r/land_segments/canopy/centroid_height',\n 'gt3r/land_segments/canopy/h_canopy',\n 'gt3r/land_segments/canopy/h_canopy_20m',\n 'gt3r/land_segments/canopy/h_canopy_abs',\n 'gt3r/land_segments/canopy/h_canopy_quad',\n 'gt3r/land_segments/canopy/h_canopy_uncertainty',\n 'gt3r/land_segments/canopy/h_dif_canopy',\n 'gt3r/land_segments/canopy/h_max_canopy',\n 'gt3r/land_segments/canopy/h_max_canopy_abs',\n 'gt3r/land_segments/canopy/h_mean_canopy',\n 'gt3r/land_segments/canopy/h_mean_canopy_abs',\n 'gt3r/land_segments/canopy/h_median_canopy',\n 'gt3r/land_segments/canopy/h_median_canopy_abs',\n 'gt3r/land_segments/canopy/h_min_canopy',\n 'gt3r/land_segments/canopy/h_min_canopy_abs',\n 'gt3r/land_segments/canopy/n_ca_photons',\n 'gt3r/land_segments/canopy/n_toc_photons',\n 'gt3r/land_segments/canopy/photon_rate_can',\n 'gt3r/land_segments/canopy/photon_rate_can_nr',\n 'gt3r/land_segments/canopy/segment_cover',\n 'gt3r/land_segments/canopy/subset_can_flag',\n 'gt3r/land_segments/canopy/toc_roughness',\n 'gt3r/land_segments/cloud_flag_atm',\n 'gt3r/land_segments/cloud_fold_flag',\n 'gt3r/land_segments/delta_time',\n 'gt3r/land_segments/delta_time_beg',\n 'gt3r/land_segments/delta_time_end',\n 'gt3r/land_segments/dem_flag',\n 'gt3r/land_segments/dem_h',\n 'gt3r/land_segments/dem_removal_flag',\n 'gt3r/land_segments/h_dif_ref',\n 'gt3r/land_segments/last_seg_extend',\n 'gt3r/land_segments/latitude',\n 'gt3r/land_segments/latitude_20m',\n 'gt3r/land_segments/layer_flag',\n 'gt3r/land_segments/longitude',\n 'gt3r/land_segments/longitude_20m',\n 'gt3r/land_segments/msw_flag',\n 'gt3r/land_segments/n_seg_ph',\n 'gt3r/land_segments/night_flag',\n 'gt3r/land_segments/ph_ndx_beg',\n 'gt3r/land_segments/ph_removal_flag',\n 'gt3r/land_segments/psf_flag',\n 'gt3r/land_segments/rgt',\n 'gt3r/land_segments/sat_flag',\n 'gt3r/land_segments/segment_id_beg',\n 'gt3r/land_segments/segment_id_end',\n 'gt3r/land_segments/segment_landcover',\n 'gt3r/land_segments/segment_snowcover',\n 'gt3r/land_segments/segment_watermask',\n 'gt3r/land_segments/sigma_across',\n 'gt3r/land_segments/sigma_along',\n 'gt3r/land_segments/sigma_atlas_land',\n 'gt3r/land_segments/sigma_h',\n 'gt3r/land_segments/sigma_topo',\n 'gt3r/land_segments/snr',\n 'gt3r/land_segments/solar_azimuth',\n 'gt3r/land_segments/solar_elevation',\n 'gt3r/land_segments/surf_type',\n 'gt3r/land_segments/terrain/h_te_best_fit',\n 'gt3r/land_segments/terrain/h_te_best_fit_20m',\n 'gt3r/land_segments/terrain/h_te_interp',\n 'gt3r/land_segments/terrain/h_te_max',\n 'gt3r/land_segments/terrain/h_te_mean',\n 'gt3r/land_segments/terrain/h_te_median',\n 'gt3r/land_segments/terrain/h_te_min',\n 'gt3r/land_segments/terrain/h_te_mode',\n 'gt3r/land_segments/terrain/h_te_rh25',\n 'gt3r/land_segments/terrain/h_te_skew',\n 'gt3r/land_segments/terrain/h_te_std',\n 'gt3r/land_segments/terrain/h_te_uncertainty',\n 'gt3r/land_segments/terrain/n_te_photons',\n 'gt3r/land_segments/terrain/photon_rate_te',\n 'gt3r/land_segments/terrain/subset_te_flag',\n 'gt3r/land_segments/terrain/terrain_slope',\n 'gt3r/land_segments/terrain_flg',\n 'gt3r/land_segments/urban_flag',\n 'gt3r/signal_photons/classed_pc_flag',\n 'gt3r/signal_photons/classed_pc_indx',\n 'gt3r/signal_photons/d_flag',\n 'gt3r/signal_photons/delta_time',\n 'gt3r/signal_photons/ph_h',\n 'gt3r/signal_photons/ph_segment_id',\n 'orbit_info/bounding_polygon_lat1',\n 'orbit_info/bounding_polygon_lon1',\n 'orbit_info/crossing_time',\n 'orbit_info/cycle_number',\n 'orbit_info/lan',\n 'orbit_info/orbit_number',\n 'orbit_info/rgt',\n 'orbit_info/sc_orient',\n 'orbit_info/sc_orient_time',\n 'quality_assessment/qa_granule_fail_reason',\n 'quality_assessment/qa_granule_pass_fail']\n\n\nThats a lot of variables!\nOne key feature of icepyx is the ability to browse the variables available in the dataset. There are typically hundreds of variables in a single dataset, so that is a lot to sort through! Let’s take a moment to get oriented to the organization of ATL08 variables, by first a few important pieces of the algorithm.\nTo create higher level variables like canopy or terrain height, the ATL08 algorithms goes through a series of steps: 1. Identify signal photons from noise photons 2. Classify each of the signal photons as either terrain, canopy, or canopy top 3. Remove elevation, so the heights are with respect to the ground 3. Group the signal photons into 100m segments. If there are a sufficient number of photons in that group, calculate statistics for terrain and canopy (ex. mean height, max height, standard deviation, etc.)\n\n\nFig. 4. An example of the classified photons produced from the ATL08 algorithm. Ground photons (red dots) are labeled as all photons falling within a point spread function distance of the estimated ground surface. The top of canopy photons (green dots) are photons that fall within a buffer distance from the upper canopy surface, and the photons that lie between the top of canopy surface and ground surface are labeled as canopy photons (blue dots). (Neuenschwander & Pitts, 2019)\n\nProviding all the potentially useful information from all these processing steps results in a data file that looks like:\nTODO: loose file structure for ATL08\nAnother way to visualize these structure is to download one file and open it using https://myhdf5.hdfgroup.org/.\nNote Mixing variables (Ex. h_canopy with dem_h and h_te_best_fit) gives a numpy type error\n\nreader.vars.append(var_list=['h_canopy', 'latitude', 'longitude'])\n\n\n\nLoad the data!\n\nds = reader.load()\nds\n\n/srv/conda/envs/notebook/lib/python3.10/site-packages/icepyx/core/read.py:520: UserWarning: rename 'delta_time' to 'photon_idx' does not create an index anymore. Try using swap_dims instead or use set_index after rename to create an indexed coordinate.\n .rename({\"delta_time\": \"photon_idx\"})\n/srv/conda/envs/notebook/lib/python3.10/site-packages/icepyx/core/read.py:520: UserWarning: rename 'delta_time' to 'photon_idx' does not create an index anymore. Try using swap_dims instead or use set_index after rename to create an indexed coordinate.\n .rename({\"delta_time\": \"photon_idx\"})\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n<xarray.Dataset>\nDimensions: (gran_idx: 1, photon_idx: 211, spot: 2)\nCoordinates:\n * gran_idx (gran_idx) float64 5.54e+04\n * photon_idx (photon_idx) int64 0 1 2 3 4 5 ... 206 207 208 209 210\n * spot (spot) uint8 1 2\n source_file (gran_idx) <U74 './bosque_primavera_ATL08/processed_...\n delta_time (photon_idx) datetime64[ns] 2019-05-04T12:47:13.5766...\nData variables:\n sc_orient (gran_idx) int8 0\n cycle_number (gran_idx) int8 3\n rgt (gran_idx, spot, photon_idx) float32 554.0 ... 554.0\n atlas_sdp_gps_epoch (gran_idx) datetime64[ns] 2018-01-01T00:00:18\n data_start_utc (gran_idx) datetime64[ns] 2019-05-04T12:46:31.876322\n data_end_utc (gran_idx) datetime64[ns] 2019-05-04T12:48:54.200826\n latitude (spot, gran_idx, photon_idx) float32 20.59 ... nan\n longitude (spot, gran_idx, photon_idx) float32 -103.7 ... nan\n gt (gran_idx, spot) <U4 'gt3l' 'gt3r'\n h_canopy (photon_idx) float32 12.12 4.747 11.83 ... nan nan nan\nAttributes:\n data_product: ATL08\n Description: Contains data categorized as land at 100 meter intervals.\n data_rate: Data are stored as aggregates of 100 meters.xarray.DatasetDimensions:gran_idx: 1photon_idx: 211spot: 2Coordinates: (5)gran_idx(gran_idx)float645.54e+04array([55402.])photon_idx(photon_idx)int640 1 2 3 4 5 ... 206 207 208 209 210array([ 0, 1, 2, ..., 208, 209, 210])spot(spot)uint81 2array([1, 2], dtype=uint8)source_file(gran_idx)<U74'./bosque_primavera_ATL08/proces...array(['./bosque_primavera_ATL08/processed_ATL08_20190504124152_05540301_006_02.h5'],\n dtype='<U74')delta_time(photon_idx)datetime64[ns]2019-05-04T12:47:13.576668792 .....array(['2019-05-04T12:47:13.576668792', '2019-05-04T12:47:13.590795176',\n '2019-05-04T12:47:13.604878696', '2019-05-04T12:47:13.618858776',\n '2019-05-04T12:47:13.647116752', '2019-05-04T12:47:13.731658440',\n '2019-05-04T12:47:13.788115696', '2019-05-04T12:47:13.802188288',\n '2019-05-04T12:47:14.013615136', '2019-05-04T12:47:14.027716720',\n '2019-05-04T12:47:14.041828320', '2019-05-04T12:47:14.069985944',\n '2019-05-04T12:47:14.084116656', '2019-05-04T12:47:14.098204416',\n '2019-05-04T12:47:14.112308544', '2019-05-04T12:47:14.126439192',\n '2019-05-04T12:47:14.140474800', '2019-05-04T12:47:14.154503088',\n '2019-05-04T12:47:14.168615944', '2019-05-04T12:47:14.182727944',\n '2019-05-04T12:47:14.196803520', '2019-05-04T12:47:14.225002096',\n '2019-05-04T12:47:14.239145008', '2019-05-04T12:47:14.253240544',\n '2019-05-04T12:47:14.267282136', '2019-05-04T12:47:14.281345400',\n '2019-05-04T12:47:14.295463616', '2019-05-04T12:47:14.309582960',\n '2019-05-04T12:47:14.323643288', '2019-05-04T12:47:14.337699200',\n '2019-05-04T12:47:14.351769576', '2019-05-04T12:47:14.363045864',\n '2019-05-04T12:47:14.379987728', '2019-05-04T12:47:14.394098040',\n '2019-05-04T12:47:14.408184296', '2019-05-04T12:47:14.422336984',\n '2019-05-04T12:47:14.436399800', '2019-05-04T12:47:14.450439312',\n '2019-05-04T12:47:14.464605056', '2019-05-04T12:47:14.478736368',\n...\n '2019-05-04T12:47:15.425911016', '2019-05-04T12:47:15.439995088',\n '2019-05-04T12:47:15.454061472', '2019-05-04T12:47:15.468143592',\n '2019-05-04T12:47:15.482238848', '2019-05-04T12:47:15.496324880',\n '2019-05-04T12:47:15.510409496', '2019-05-04T12:47:15.524510280',\n '2019-05-04T12:47:15.538615648', '2019-05-04T12:47:15.566816696',\n '2019-05-04T12:47:15.580919696', '2019-05-04T12:47:15.594985688',\n '2019-05-04T12:47:15.609048944', '2019-05-04T12:47:15.623173096',\n '2019-05-04T12:47:15.637281512', '2019-05-04T12:47:15.651381832',\n '2019-05-04T12:47:15.665494736', '2019-05-04T12:47:15.679564576',\n '2019-05-04T12:47:15.693640304', '2019-05-04T12:47:15.707745176',\n '2019-05-04T12:47:15.721833264', '2019-05-04T12:47:15.735931400',\n '2019-05-04T12:47:15.750026272', '2019-05-04T12:47:15.764102288',\n '2019-05-04T12:47:15.778227184', '2019-05-04T12:47:15.806428968',\n '2019-05-04T12:47:15.820523432', '2019-05-04T12:47:15.834607024',\n '2019-05-04T12:47:15.848673504', '2019-05-04T12:47:15.862757488',\n '2019-05-04T12:47:15.876856944', '2019-05-04T12:47:15.890974768',\n '2019-05-04T12:47:15.905085432', '2019-05-04T12:47:15.919119064',\n '2019-05-04T12:47:15.933193432', '2019-05-04T12:47:15.947348696',\n '2019-05-04T12:47:15.961461904', '2019-05-04T12:47:15.975561616',\n '2019-05-04T12:47:15.989663088'], dtype='datetime64[ns]')Data variables: (10)sc_orient(gran_idx)int80array([0], dtype=int8)cycle_number(gran_idx)int83array([3], dtype=int8)rgt(gran_idx, spot, photon_idx)float32554.0 554.0 554.0 ... 554.0 554.0contentType :referenceInformationdescription :The reference ground track (RGT) is the track on the earth at which a specified unit vector within the observatory is pointed. Under nominal operating conditions, there will be no data collected along the RGT, as the RGT is spanned by GT3 and GT4. During slews or off-pointing, it is possible that ground tracks may intersect the RGT. The ICESat-2 mission has 1387 RGTs.long_name :reference ground tracksource :Operationsunits :1valid_max :1387valid_min :1array([[[554., 554., 554., 554., 554., 554., 554., 554., 554., 554.,\n 554., 554., 554., 554., 554., 554., 554., 554., 554., 554.,\n 554., 554., 554., 554., 554., 554., 554., 554., 554., 554.,\n 554., 554., 554., 554., 554., 554., 554., 554., 554., 554.,\n 554., 554., 554., 554., 554., 554., 554., 554., 554., 554.,\n 554., 554., 554., 554., 554., 554., 554., 554., 554., 554.,\n 554., 554., 554., 554., 554., 554., 554., 554., 554., 554.,\n 554., 554., 554., 554., 554., 554., 554., 554., 554., 554.,\n 554., 554., 554., 554., 554., 554., 554., 554., 554., 554.,\n 554., 554., 554., 554., 554., 554., 554., 554., 554., 554.,\n 554., 554., 554., 554., 554., 554., 554., 554., 554., 554.,\n 554., 554., 554., 554., 554., 554., 554., 554., 554., 554.,\n nan, nan, nan, nan, nan, nan, nan, nan, nan, nan,\n nan, nan, nan, nan, nan, nan, nan, nan, nan, nan,\n nan, nan, nan, nan, nan, nan, nan, nan, nan, nan,\n nan, nan, nan, nan, nan, nan, nan, nan, nan, nan,\n nan, nan, nan, nan, nan, nan, nan, nan, nan, nan,\n nan, nan, nan, nan, nan, nan, nan, nan, nan, nan,\n nan, nan, nan, nan, nan, nan, nan, nan, nan, nan,\n nan, nan, nan, nan, nan, nan, nan, nan, nan, nan,\n...\n nan, nan, nan, nan, nan, nan, nan, nan, nan, nan,\n nan, nan, nan, nan, nan, nan, nan, nan, nan, nan,\n nan, nan, nan, nan, nan, nan, nan, nan, nan, nan,\n nan, nan, nan, nan, nan, nan, nan, nan, nan, nan,\n nan, nan, nan, nan, nan, nan, nan, nan, nan, nan,\n nan, nan, nan, nan, nan, nan, nan, nan, nan, nan,\n nan, nan, nan, nan, nan, nan, nan, nan, nan, nan,\n nan, nan, nan, nan, nan, nan, nan, nan, nan, nan,\n nan, nan, nan, nan, nan, nan, nan, nan, nan, nan,\n nan, nan, nan, nan, nan, nan, nan, nan, nan, nan,\n 554., 554., 554., 554., 554., 554., 554., 554., 554., 554.,\n 554., 554., 554., 554., 554., 554., 554., 554., 554., 554.,\n 554., 554., 554., 554., 554., 554., 554., 554., 554., 554.,\n 554., 554., 554., 554., 554., 554., 554., 554., 554., 554.,\n 554., 554., 554., 554., 554., 554., 554., 554., 554., 554.,\n 554., 554., 554., 554., 554., 554., 554., 554., 554., 554.,\n 554., 554., 554., 554., 554., 554., 554., 554., 554., 554.,\n 554., 554., 554., 554., 554., 554., 554., 554., 554., 554.,\n 554., 554., 554., 554., 554., 554., 554., 554., 554., 554.,\n 554.]]], dtype=float32)atlas_sdp_gps_epoch(gran_idx)datetime64[ns]2018-01-01T00:00:18array(['2018-01-01T00:00:18.000000000'], dtype='datetime64[ns]')data_start_utc(gran_idx)datetime64[ns]2019-05-04T12:46:31.876322array(['2019-05-04T12:46:31.876322000'], dtype='datetime64[ns]')data_end_utc(gran_idx)datetime64[ns]2019-05-04T12:48:54.200826array(['2019-05-04T12:48:54.200826000'], dtype='datetime64[ns]')latitude(spot, gran_idx, photon_idx)float3220.59 20.59 20.59 ... nan nan nancontentType :modelResultdescription :Latitude of the center-most signal photon within each segment.long_name :latitudesource :Land ATBD section 2.4standard_name :latitudeunits :degreesvalid_max :90.0valid_min :-90.0array([[[20.592943, 20.593845, 20.594746, 20.595648, 20.59745 ,\n 20.60286 , 20.606464, 20.607367, 20.620888, 20.621788,\n 20.62269 , 20.624493, 20.625395, 20.626297, 20.627197,\n 20.6281 , 20.629 , 20.629902, 20.630804, 20.631704,\n 20.632607, 20.634409, 20.635311, 20.636211, 20.637114,\n 20.638014, 20.638916, 20.639816, 20.640718, 20.64162 ,\n 20.642523, 20.643244, 20.644325, 20.645226, 20.646128,\n 20.64703 , 20.64793 , 20.648832, 20.649734, 20.650635,\n 20.651537, 20.652437, 20.65334 , 20.65424 , 20.655142,\n 20.656044, 20.656944, 20.657846, 20.658749, 20.659649,\n 20.660551, 20.661451, 20.662354, 20.663254, 20.664156,\n 20.665058, 20.665958, 20.66686 , 20.667763, 20.668663,\n 20.669565, 20.670467, 20.671368, 20.67227 , 20.67317 ,\n 20.674072, 20.674973, 20.675875, 20.676777, 20.677677,\n 20.67858 , 20.679482, 20.680382, 20.681284, 20.682184,\n 20.683086, 20.683989, 20.684889, 20.685791, 20.686691,\n 20.687593, 20.688496, 20.689217, 20.690298, 20.691198,\n 20.6921 , 20.693003, 20.693903, 20.694805, 20.695707,\n 20.696608, 20.69751 , 20.69841 , 20.699312, 20.700212,\n 20.701115, 20.702017, 20.702917, 20.70382 , 20.704721,\n...\n nan, nan, nan, nan, nan,\n nan, nan, nan, nan, nan,\n nan, nan, nan, nan, nan,\n nan, nan, nan, nan, nan,\n nan, nan, nan, nan, nan,\n nan, nan, nan, nan, nan,\n nan, nan, nan, nan, nan,\n nan, nan, nan, nan, nan,\n nan, nan, nan, nan, nan,\n nan, nan, nan, nan, nan,\n nan, nan, nan, nan, nan,\n nan, nan, nan, nan, nan,\n nan, nan, nan, nan, nan,\n nan, nan, nan, nan, nan,\n nan, nan, nan, nan, nan,\n nan, nan, nan, nan, nan,\n nan, nan, nan, nan, nan,\n nan, nan, nan, nan, nan,\n nan, nan, nan, nan, nan,\n nan]]], dtype=float32)longitude(spot, gran_idx, photon_idx)float32-103.7 -103.7 -103.7 ... nan nancontentType :modelResultdescription :Longitude of the center-most signal photon within each segment.long_name :longitudesource :Land ATBD section 2.4standard_name :longitudeunits :degreesvalid_max :180.0valid_min :-180.0array([[[-103.67242 , -103.672516, -103.67261 , -103.6727 ,\n -103.6729 , -103.67346 , -103.673836, -103.673935,\n -103.67535 , -103.675446, -103.67554 , -103.67573 ,\n -103.67583 , -103.67592 , -103.67601 , -103.67611 ,\n -103.6762 , -103.6763 , -103.67639 , -103.67649 ,\n -103.67658 , -103.676765, -103.676865, -103.676956,\n -103.67705 , -103.67715 , -103.677246, -103.677345,\n -103.67743 , -103.67753 , -103.67762 , -103.6777 ,\n -103.67781 , -103.67791 , -103.678 , -103.678085,\n -103.678185, -103.67828 , -103.678375, -103.678474,\n -103.678566, -103.67866 , -103.67876 , -103.678856,\n -103.67895 , -103.67904 , -103.67913 , -103.67922 ,\n -103.67932 , -103.67941 , -103.679504, -103.6796 ,\n -103.6797 , -103.6798 , -103.67989 , -103.679985,\n -103.68008 , -103.680176, -103.68027 , -103.68037 ,\n -103.68046 , -103.68055 , -103.68064 , -103.68073 ,\n -103.68083 , -103.68093 , -103.68103 , -103.68112 ,\n -103.68121 , -103.681305, -103.6814 , -103.68149 ,\n -103.68159 , -103.68169 , -103.681786, -103.68188 ,\n -103.68197 , -103.68207 , -103.68216 , -103.68226 ,\n...\n nan, nan, nan, nan,\n nan, nan, nan, nan,\n nan, nan, nan, nan,\n nan, nan, nan, nan,\n nan, nan, nan, nan,\n nan, nan, nan, nan,\n nan, nan, nan, nan,\n nan, nan, nan, nan,\n nan, nan, nan, nan,\n nan, nan, nan, nan,\n nan, nan, nan, nan,\n nan, nan, nan, nan,\n nan, nan, nan, nan,\n nan, nan, nan, nan,\n nan, nan, nan, nan,\n nan, nan, nan, nan,\n nan, nan, nan, nan,\n nan, nan, nan, nan,\n nan, nan, nan, nan,\n nan, nan, nan]]], dtype=float32)gt(gran_idx, spot)<U4'gt3l' 'gt3r'array([['gt3l', 'gt3r']], dtype='<U4')h_canopy(photon_idx)float3212.12 4.747 11.83 ... nan nan nancontentType :modelResultcoordinates :../delta_time ../latitude ../longitudedescription :98% height of all the individual canopy relative heights for the segment above the estimated terrain surface. Relative canopy heights have been computed by differencing the canopy photon height from the estimated terrain surface.long_name :height canopysource :Land ATBD section 4.12units :metersarray([12.117554 , 4.7471924, 11.826294 , 12.599121 , nan,\n 18.487427 , nan, 24.531128 , 23.573975 , 6.973877 ,\n 15.614014 , 18.686768 , 10.208862 , 19.486816 , 19.792969 ,\n 24.182617 , 26.141113 , nan, 27.215698 , 27.964355 ,\n 28.768066 , 23.500977 , 20.939087 , 12.468384 , 12.3302 ,\n 12.56543 , 18.28833 , nan, 3.2608643, 15.973389 ,\n 20.57251 , 16.383667 , 19.53479 , 19.167236 , 8.956299 ,\n 10.339844 , 6.9119873, nan, 6.6381836, 13.006592 ,\n 10.125366 , 7.1741943, 6.220581 , 13.171265 , 13.741211 ,\n 14.266846 , 13.998291 , 6.2819824, 10.767212 , nan,\n 11.753906 , 19.83789 , 8.949463 , 6.9605713, 17.22107 ,\n 20.040527 , 8.8289795, 10.093262 , 6.963379 , 10.654053 ,\n 13.63623 , 8.8897705, nan, 8.487671 , 4.117676 ,\n 2.7399902, 5.741211 , 9.786987 , 5.447876 , 6.3466797,\n 2.6264648, nan, nan, 14.463623 , 19.986572 ,\n 26.920166 , 23.636475 , 20.366577 , 23.44165 , 18.091675 ,\n 12.490723 , 21.749268 , 10.508667 , 18.734863 , 16.601318 ,\n 7.385254 , nan, nan, 9.800293 , 5.3067627,\n 12.211426 , 15.874878 , 8.875732 , 15.800903 , 12.877563 ,\n nan, nan, 2.3807373, 6.1132812, nan,\n...\n nan, 5.647461 , 8.42688 , nan, nan,\n nan, nan, nan, nan, nan,\n nan, nan, nan, nan, nan,\n nan, nan, nan, nan, nan,\n nan, nan, nan, nan, nan,\n nan, nan, nan, nan, nan,\n nan, nan, nan, nan, nan,\n nan, nan, nan, nan, nan,\n nan, nan, nan, nan, nan,\n nan, nan, nan, nan, nan,\n nan, nan, nan, nan, nan,\n nan, nan, nan, nan, nan,\n nan, nan, nan, nan, nan,\n nan, nan, nan, nan, nan,\n nan, nan, nan, nan, nan,\n nan, nan, nan, nan, nan,\n nan, nan, nan, nan, nan,\n nan, nan, nan, nan, nan,\n nan, nan, nan, nan, nan,\n nan], dtype=float32)Indexes: (3)gran_idxPandasIndexPandasIndex(Float64Index([55402.0], dtype='float64', name='gran_idx'))photon_idxPandasIndexPandasIndex(Int64Index([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,\n ...\n 201, 202, 203, 204, 205, 206, 207, 208, 209, 210],\n dtype='int64', name='photon_idx', length=211))spotPandasIndexPandasIndex(UInt64Index([1, 2], dtype='uint64', name='spot'))Attributes: (3)data_product :ATL08Description :Contains data categorized as land at 100 meter intervals.data_rate :Data are stored as aggregates of 100 meters.\n\n\nHere we have an xarray Dataset, a common Python data structure for analysis. To visualize the data we can plot it using:\n\nds.plot.scatter(ax=ax, x=\"longitude\", y=\"latitude\", hue=\"h_canopy\")\n\n<matplotlib.collections.PathCollection at 0x7f57e0943400>" - }, - { - "objectID": "tutorials/data-access/icepyx.html#using-icepyx-to-download-a-subset-of-a-granule", - "href": "tutorials/data-access/icepyx.html#using-icepyx-to-download-a-subset-of-a-granule", - "title": "Using icepyx to access Icesat-2 data", - "section": "Using icepyx to download a subset of a granule", - "text": "Using icepyx to download a subset of a granule\nOne feature which is not yet available in earthaccess is the ability to download just a subset of the file. This could mean a smaller spatial area or fewer variables. This feature is available in icepyx.\nWe saw above that icepyx by default will subset your data to the bounding box you provided when downloading. If you know in advance which variables you want icepyx can also subset variables.\n\nSubset variables\n\n# Create our Query\nshort_name = 'ATL08'\nspatial_extent = [-99.8, 21, -99.0, 21.7]\ndate_range = ['2019-06-11','2019-06-11']\nregion = ipx.Query(short_name, spatial_extent, date_range)\n\n\n# Specify desired variables\nregion.order_vars.append(var_list=['h_canopy', 'latitude', 'longitude'])\n\n\n# Download the granules, using the Coverage kwarg to specify variables\nregion.download_granules(path='./ATL08_h_canopy', Coverage=region.order_vars.wanted)\n\n\n# Read the new data\npattern = \"processed_ATL{product:2}_{datetime:%Y%m%d%H%M%S}_{rgt:4}{cycle:2}{orbitsegment:2}_{version:3}_{revision:2}.h5\"\nreader = ipx.Read('./ATL08_h_canopy', \"ATL08\", pattern)\n\nThe available variables list on the subset dataset is a lot shorter!\n\nreader.vars.avail()" - }, - { - "objectID": "tutorials/data-access/icepyx.html#final-fun-visual-revisit-thurs.-morn", - "href": "tutorials/data-access/icepyx.html#final-fun-visual-revisit-thurs.-morn", - "title": "Using icepyx to access Icesat-2 data", - "section": "Final fun visual (revisit Thurs. Morn)", - "text": "Final fun visual (revisit Thurs. Morn)\nTrying to come up with a fun final plot, if there is time. Ignore this for now and revisit in the morning.\n\nRecreate the plot from the paper with photon classifications\n\nreader.vars.remove(all=True)\nreader.vars.append(var_list=['ph_h', 'classed_pc_flag', 'latitude', 'longitude'])\n\n\nds_photons = reader.load()\nds_photons\n\n\nds_photons\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n<xarray.Dataset>\nDimensions: (gran_idx: 1, photon_idx: 25234, spot: 2)\nCoordinates:\n * gran_idx (gran_idx) float64 5.54e+04\n * photon_idx (photon_idx) int64 0 1 2 3 ... 25230 25231 25232 25233\n * spot (spot) uint8 1 2\n source_file (gran_idx) <U74 './bosque_primavera_ATL08/processed_...\n delta_time (photon_idx) datetime64[ns] 2019-05-04T12:47:13.5766...\nData variables:\n sc_orient (gran_idx) int8 0\n cycle_number (gran_idx) int8 3\n rgt (gran_idx, spot, photon_idx) float32 554.0 ... nan\n atlas_sdp_gps_epoch (gran_idx) datetime64[ns] 2018-01-01T00:00:18\n data_start_utc (gran_idx) datetime64[ns] 2019-05-04T12:46:31.876322\n data_end_utc (gran_idx) datetime64[ns] 2019-05-04T12:48:54.200826\n latitude (spot, gran_idx, photon_idx) float32 20.59 ... nan\n longitude (spot, gran_idx, photon_idx) float32 -103.7 ... nan\n gt (gran_idx, spot) <U4 'gt3l' 'gt3r'\n h_te_best_fit (photon_idx) float32 1.342e+03 1.34e+03 ... nan nan\n ph_h (spot, gran_idx, photon_idx) float32 nan ... 0.05542\n classed_pc_flag (spot, gran_idx, photon_idx) float32 nan nan ... 1.0\nAttributes:\n data_product: ATL08xarray.DatasetDimensions:gran_idx: 1photon_idx: 25234spot: 2Coordinates: (5)gran_idx(gran_idx)float645.54e+04array([55402.])photon_idx(photon_idx)int640 1 2 3 ... 25230 25231 25232 25233array([ 0, 1, 2, ..., 25231, 25232, 25233])spot(spot)uint81 2array([1, 2], dtype=uint8)source_file(gran_idx)<U74'./bosque_primavera_ATL08/proces...array(['./bosque_primavera_ATL08/processed_ATL08_20190504124152_05540301_006_02.h5'],\n dtype='<U74')delta_time(photon_idx)datetime64[ns]2019-05-04T12:47:13.576668792 .....array(['2019-05-04T12:47:13.576668792', '2019-05-04T12:47:13.590795176',\n '2019-05-04T12:47:13.604878696', ...,\n '2019-05-04T12:47:15.995923304', '2019-05-04T12:47:15.996123296',\n '2019-05-04T12:47:15.996323304'], dtype='datetime64[ns]')Data variables: (12)sc_orient(gran_idx)int80array([0], dtype=int8)cycle_number(gran_idx)int83array([3], dtype=int8)rgt(gran_idx, spot, photon_idx)float32554.0 554.0 554.0 ... nan nan nancontentType :referenceInformationdescription :The reference ground track (RGT) is the track on the earth at which a specified unit vector within the observatory is pointed. Under nominal operating conditions, there will be no data collected along the RGT, as the RGT is spanned by GT3 and GT4. During slews or off-pointing, it is possible that ground tracks may intersect the RGT. The ICESat-2 mission has 1387 RGTs.long_name :reference ground tracksource :Operationsunits :1valid_max :1387valid_min :1array([[[554., 554., 554., ..., nan, nan, nan],\n [ nan, nan, nan, ..., nan, nan, nan]]], dtype=float32)atlas_sdp_gps_epoch(gran_idx)datetime64[ns]2018-01-01T00:00:18array(['2018-01-01T00:00:18.000000000'], dtype='datetime64[ns]')data_start_utc(gran_idx)datetime64[ns]2019-05-04T12:46:31.876322array(['2019-05-04T12:46:31.876322000'], dtype='datetime64[ns]')data_end_utc(gran_idx)datetime64[ns]2019-05-04T12:48:54.200826array(['2019-05-04T12:48:54.200826000'], dtype='datetime64[ns]')latitude(spot, gran_idx, photon_idx)float3220.59 20.59 20.59 ... nan nan nancontentType :modelResultdescription :Latitude of the center-most signal photon within each segment.long_name :latitudesource :Land ATBD section 2.4standard_name :latitudeunits :degreesvalid_max :90.0valid_min :-90.0array([[[20.592943, 20.593845, 20.594746, ..., nan, nan,\n nan]],\n\n [[ nan, nan, nan, ..., nan, nan,\n nan]]], dtype=float32)longitude(spot, gran_idx, photon_idx)float32-103.7 -103.7 -103.7 ... nan nancontentType :modelResultdescription :Longitude of the center-most signal photon within each segment.long_name :longitudesource :Land ATBD section 2.4standard_name :longitudeunits :degreesvalid_max :180.0valid_min :-180.0array([[[-103.67242 , -103.672516, -103.67261 , ..., nan,\n nan, nan]],\n\n [[ nan, nan, nan, ..., nan,\n nan, nan]]], dtype=float32)gt(gran_idx, spot)<U4'gt3l' 'gt3r'array([['gt3l', 'gt3r']], dtype='<U4')h_te_best_fit(photon_idx)float321.342e+03 1.34e+03 ... nan nancontentType :modelResultcoordinates :../delta_time ../latitude ../longitudedescription :The best fit terrain elevation at the the mid-point location of each 100m segment. The mid-segment terrain elevation is determined by selecting the best of three fits- linear, 3rd order and 4th order polynomials - to the terrain photons and interpolating the elevation at the mid-point location of the 100 m segment. For the linear fit, a slope correction and weighting is applied to each ground photon based on the distance to the slope height at the center of the segment.long_name :segment terrain height best fitsource :Land ATBD section 2.1.15units :metersarray([1341.6261, 1339.7549, 1342.2279, ..., nan, nan,\n nan], dtype=float32)ph_h(spot, gran_idx, photon_idx)float32nan nan nan ... 0.05103 0.05542contentType :physicalMeasurementdescription :Height of photons above interpolated land surfacelong_name :relative photon heightsource :land/veg ATBD, 15May2020, Section 2.3.4standard_name :heightunits :metersarray([[[ nan, nan, nan, ..., nan,\n nan, nan]],\n\n [[ nan, nan, nan, ..., 0.15209961,\n 0.05102539, 0.05541992]]], dtype=float32)classed_pc_flag(spot, gran_idx, photon_idx)float32nan nan nan nan ... 1.0 1.0 1.0 1.0contentType :modelResultdescription :Land Vegetation ATBD classification flag for each photon as either noise, ground, canopy, and top of canopy. 0 = noise, 1 = ground, 2 = canopy, or 3 = top of canopy.flag_meanings :noise ground canopy top_of_canopyflag_values :[0 1 2 3]long_name :photon land atbd classificationsource :Land ATBD section 4.10units :1array([[[nan, nan, nan, ..., nan, nan, nan]],\n\n [[nan, nan, nan, ..., 1., 1., 1.]]], dtype=float32)Indexes: (3)gran_idxPandasIndexPandasIndex(Float64Index([55402.0], dtype='float64', name='gran_idx'))photon_idxPandasIndexPandasIndex(Int64Index([ 0, 1, 2, 3, 4, 5, 6, 7, 8,\n 9,\n ...\n 25224, 25225, 25226, 25227, 25228, 25229, 25230, 25231, 25232,\n 25233],\n dtype='int64', name='photon_idx', length=25234))spotPandasIndexPandasIndex(UInt64Index([1, 2], dtype='uint64', name='spot'))Attributes: (1)data_product :ATL08\n\n\n\nds_photons.plot.scatter(x='delta_time', y='ph_h', hue='classed_pc_flag')\n\n<matplotlib.collections.PathCollection at 0x7f57e160a2c0>\n\n\n\n\n\n\n\nAdd more of a basemap to the spatial plot\nCartopy doesn’t seem to have any nice built in basemaps, and I think foluim would be too complicated.\n\nfig, ax = plt.subplots(subplot_kw={'projection': ccrs.PlateCarree()})\n\n# Add background features\nax.add_feature(cfeature.COASTLINE, alpha=0.3)\nax.add_feature(cfeature.BORDERS, linestyle=':')\nax.add_feature(cfeature.RIVERS)\n\n# ax.set_extent([-77.5, -75.4, 36.6, 39.7])\n\n# Add and format gridlines. Remove top and right labels\ngl = ax.gridlines(crs=ccrs.PlateCarree(), draw_labels=True,\n linewidth=1, color='gray', alpha=0.2, linestyle='--')\ngl.top_labels, gl.right_labels = False, False\n\nds.plot.scatter(ax=ax, x=\"longitude\", y=\"latitude\", hue=\"h_canopy\")\n\n<matplotlib.collections.PathCollection at 0x7f57e3b2fe20>\n\n\n\n\n\nNotice that the data is already subset to our area of interest! (Also download the full granule with earthaccess to compare the area?)\n\n\nPlot the canopy compared to the ground height\nA nice idea, but there are a few places where the ground may be above the canopy. Not sure how to talk about that. Maybe consider if h_te_best_fit is the best variable to use for height?\n\nreader.vars.remove(all=True)\nreader.vars.append(var_list=['h_te_best_fit', 'latitude', 'longitude'])\n\n\nds_te = reader.load()\nds_te\n\n\nds.h_canopy + ds_te.h_te_best_fit\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n<xarray.DataArray (photon_idx: 211)>\narray([1353.7437, 1344.5021, 1354.0542, 1365.1449, nan, 1388.0896,\n nan, 1367.1438, 1403.1825, 1394.4102, 1393.9043, 1416.9154,\n 1419.0438, 1431.773 , 1427.9192, 1426.2251, 1416.8427, nan,\n 1401.4824, 1390.8745, 1380.5767, 1380.2539, 1393.4421, 1386.7036,\n 1384.1562, 1385.3413, 1387.8845, nan, 1383.2649, 1385.1476,\n 1351.6632, 1348.4186, 1356.7253, 1383.4984, 1378.7352, 1378.3448,\n 1387.8447, nan, 1384.6409, 1378.7225, 1351.8608, 1369.9244,\n 1375.6143, 1378.7357, 1385.3104, 1374.63 , 1385.7798, 1384.4376,\n 1385.4879, nan, 1386.6517, 1363.0527, 1383.036 , 1384.011 ,\n 1393.2178, 1368.4326, 1379.6318, 1381.6879, 1375.5375, 1377.1417,\n 1362.7836, 1358.7225, nan, 1345.983 , 1352.2463, 1352.8934,\n 1353.0276, 1353.9401, 1355.2495, 1362.6967, 1364.1461, nan,\n nan, 1367.4513, 1368.7175, 1372.8689, 1355.3347, 1366.3495,\n 1371.091 , 1369.8829, 1371.3533, 1366.4882, 1365.5226, 1349.8981,\n 1340.5991, 1332.43 , nan, nan, 1337.899 , 1337.3844,\n 1353.7922, 1364.3038, 1374.5607, 1387.6923, 1389.9014, nan,\n nan, 1385.0403, 1393.3284, nan, nan, 1407.526 ,\n 1408.1254, nan, nan, nan, nan, nan,\n nan, nan, nan, nan, nan, nan,\n nan, nan, 1391.213 , 1391.9713, nan, nan,\n nan, nan, nan, nan, nan, nan,\n nan, nan, nan, nan, nan, nan,\n nan, nan, nan, nan, nan, nan,\n nan, nan, nan, nan, nan, nan,\n nan, nan, nan, nan, nan, nan,\n nan, nan, nan, nan, nan, nan,\n nan, nan, nan, nan, nan, nan,\n nan, nan, nan, nan, nan, nan,\n nan, nan, nan, nan, nan, nan,\n nan, nan, nan, nan, nan, nan,\n nan, nan, nan, nan, nan, nan,\n nan, nan, nan, nan, nan, nan,\n nan, nan, nan, nan, nan, nan,\n nan, nan, nan, nan, nan, nan,\n nan, nan, nan, nan, nan, nan,\n nan], dtype=float32)\nCoordinates:\n * photon_idx (photon_idx) int64 0 1 2 3 4 5 6 ... 204 205 206 207 208 209 210\n delta_time (photon_idx) datetime64[ns] 2019-05-04T12:47:13.576668792 ......xarray.DataArrayphoton_idx: 2111.354e+03 1.345e+03 1.354e+03 1.365e+03 nan ... nan nan nan nan nanarray([1353.7437, 1344.5021, 1354.0542, 1365.1449, nan, 1388.0896,\n nan, 1367.1438, 1403.1825, 1394.4102, 1393.9043, 1416.9154,\n 1419.0438, 1431.773 , 1427.9192, 1426.2251, 1416.8427, nan,\n 1401.4824, 1390.8745, 1380.5767, 1380.2539, 1393.4421, 1386.7036,\n 1384.1562, 1385.3413, 1387.8845, nan, 1383.2649, 1385.1476,\n 1351.6632, 1348.4186, 1356.7253, 1383.4984, 1378.7352, 1378.3448,\n 1387.8447, nan, 1384.6409, 1378.7225, 1351.8608, 1369.9244,\n 1375.6143, 1378.7357, 1385.3104, 1374.63 , 1385.7798, 1384.4376,\n 1385.4879, nan, 1386.6517, 1363.0527, 1383.036 , 1384.011 ,\n 1393.2178, 1368.4326, 1379.6318, 1381.6879, 1375.5375, 1377.1417,\n 1362.7836, 1358.7225, nan, 1345.983 , 1352.2463, 1352.8934,\n 1353.0276, 1353.9401, 1355.2495, 1362.6967, 1364.1461, nan,\n nan, 1367.4513, 1368.7175, 1372.8689, 1355.3347, 1366.3495,\n 1371.091 , 1369.8829, 1371.3533, 1366.4882, 1365.5226, 1349.8981,\n 1340.5991, 1332.43 , nan, nan, 1337.899 , 1337.3844,\n 1353.7922, 1364.3038, 1374.5607, 1387.6923, 1389.9014, nan,\n nan, 1385.0403, 1393.3284, nan, nan, 1407.526 ,\n 1408.1254, nan, nan, nan, nan, nan,\n nan, nan, nan, nan, nan, nan,\n nan, nan, 1391.213 , 1391.9713, nan, nan,\n nan, nan, nan, nan, nan, nan,\n nan, nan, nan, nan, nan, nan,\n nan, nan, nan, nan, nan, nan,\n nan, nan, nan, nan, nan, nan,\n nan, nan, nan, nan, nan, nan,\n nan, nan, nan, nan, nan, nan,\n nan, nan, nan, nan, nan, nan,\n nan, nan, nan, nan, nan, nan,\n nan, nan, nan, nan, nan, nan,\n nan, nan, nan, nan, nan, nan,\n nan, nan, nan, nan, nan, nan,\n nan, nan, nan, nan, nan, nan,\n nan, nan, nan, nan, nan, nan,\n nan, nan, nan, nan, nan, nan,\n nan, nan, nan, nan, nan, nan,\n nan], dtype=float32)Coordinates: (2)photon_idx(photon_idx)int640 1 2 3 4 5 ... 206 207 208 209 210array([ 0, 1, 2, ..., 208, 209, 210])delta_time(photon_idx)datetime64[ns]2019-05-04T12:47:13.576668792 .....array(['2019-05-04T12:47:13.576668792', '2019-05-04T12:47:13.590795176',\n '2019-05-04T12:47:13.604878696', '2019-05-04T12:47:13.618858776',\n '2019-05-04T12:47:13.647116752', '2019-05-04T12:47:13.731658440',\n '2019-05-04T12:47:13.788115696', '2019-05-04T12:47:13.802188288',\n '2019-05-04T12:47:14.013615136', '2019-05-04T12:47:14.027716720',\n '2019-05-04T12:47:14.041828320', '2019-05-04T12:47:14.069985944',\n '2019-05-04T12:47:14.084116656', '2019-05-04T12:47:14.098204416',\n '2019-05-04T12:47:14.112308544', '2019-05-04T12:47:14.126439192',\n '2019-05-04T12:47:14.140474800', '2019-05-04T12:47:14.154503088',\n '2019-05-04T12:47:14.168615944', '2019-05-04T12:47:14.182727944',\n '2019-05-04T12:47:14.196803520', '2019-05-04T12:47:14.225002096',\n '2019-05-04T12:47:14.239145008', '2019-05-04T12:47:14.253240544',\n '2019-05-04T12:47:14.267282136', '2019-05-04T12:47:14.281345400',\n '2019-05-04T12:47:14.295463616', '2019-05-04T12:47:14.309582960',\n '2019-05-04T12:47:14.323643288', '2019-05-04T12:47:14.337699200',\n '2019-05-04T12:47:14.351769576', '2019-05-04T12:47:14.363045864',\n '2019-05-04T12:47:14.379987728', '2019-05-04T12:47:14.394098040',\n '2019-05-04T12:47:14.408184296', '2019-05-04T12:47:14.422336984',\n '2019-05-04T12:47:14.436399800', '2019-05-04T12:47:14.450439312',\n '2019-05-04T12:47:14.464605056', '2019-05-04T12:47:14.478736368',\n...\n '2019-05-04T12:47:15.425911016', '2019-05-04T12:47:15.439995088',\n '2019-05-04T12:47:15.454061472', '2019-05-04T12:47:15.468143592',\n '2019-05-04T12:47:15.482238848', '2019-05-04T12:47:15.496324880',\n '2019-05-04T12:47:15.510409496', '2019-05-04T12:47:15.524510280',\n '2019-05-04T12:47:15.538615648', '2019-05-04T12:47:15.566816696',\n '2019-05-04T12:47:15.580919696', '2019-05-04T12:47:15.594985688',\n '2019-05-04T12:47:15.609048944', '2019-05-04T12:47:15.623173096',\n '2019-05-04T12:47:15.637281512', '2019-05-04T12:47:15.651381832',\n '2019-05-04T12:47:15.665494736', '2019-05-04T12:47:15.679564576',\n '2019-05-04T12:47:15.693640304', '2019-05-04T12:47:15.707745176',\n '2019-05-04T12:47:15.721833264', '2019-05-04T12:47:15.735931400',\n '2019-05-04T12:47:15.750026272', '2019-05-04T12:47:15.764102288',\n '2019-05-04T12:47:15.778227184', '2019-05-04T12:47:15.806428968',\n '2019-05-04T12:47:15.820523432', '2019-05-04T12:47:15.834607024',\n '2019-05-04T12:47:15.848673504', '2019-05-04T12:47:15.862757488',\n '2019-05-04T12:47:15.876856944', '2019-05-04T12:47:15.890974768',\n '2019-05-04T12:47:15.905085432', '2019-05-04T12:47:15.919119064',\n '2019-05-04T12:47:15.933193432', '2019-05-04T12:47:15.947348696',\n '2019-05-04T12:47:15.961461904', '2019-05-04T12:47:15.975561616',\n '2019-05-04T12:47:15.989663088'], dtype='datetime64[ns]')Indexes: (1)photon_idxPandasIndexPandasIndex(Int64Index([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,\n ...\n 201, 202, 203, 204, 205, 206, 207, 208, 209, 210],\n dtype='int64', name='photon_idx', length=211))Attributes: (0)\n\n\n\nfig, ax = plt.subplots()\nfig.set_size_inches(12, 3)\n\n(ds.h_canopy + ds_te.h_te_best_fit).plot.scatter(ax=ax, x=\"delta_time\", y=\"h_canopy\") # orange\n\nds_te.plot.scatter(ax=ax, x=\"delta_time\", y=\"h_te_best_fit\") # blue\n\n<matplotlib.collections.PathCollection at 0x7f57e0943730>\n\n\n\n\n\n\n\nInteractive plot with holoviz\n\nimport hvplot.xarray\n\n\nds.hvplot.scatter(y=\"h_canopy\", x=\"latitude\",\n by=['spot', 'photon_idx', 'gran_idx'], legend=False)\n\n\n\n\n\n \n\n\n\n\n\ngt1l = ds.where(ds.gt == 'gt1l')" - }, { "objectID": "how-tos/data-access/Earthdata_Cloud__Single_File__Direct_S3_Access_Clip_COG_Example.html", "href": "how-tos/data-access/Earthdata_Cloud__Single_File__Direct_S3_Access_Clip_COG_Example.html", diff --git a/sitemap.xml b/sitemap.xml index 543f09e..2dc7252 100644 --- a/sitemap.xml +++ b/sitemap.xml @@ -2,78 +2,86 @@ https://nasa-openscapes.github.io/2023-ssc/index.html - 2023-11-16T03:13:04.765Z + 2023-11-16T03:17:06.126Z https://nasa-openscapes.github.io/2023-ssc/how-tos/authentication/NASA_Earthdata_Authentication.html - 2023-11-16T03:13:04.133Z + 2023-11-16T03:17:05.474Z https://nasa-openscapes.github.io/2023-ssc/how-tos/data-access/Intro_xarray_hvplot.html - 2023-11-16T03:13:02.745Z + 2023-11-16T03:17:04.266Z - https://nasa-openscapes.github.io/2023-ssc/tutorials/data-access/earthaccess.html - 2023-11-16T03:13:01.681Z + https://nasa-openscapes.github.io/2023-ssc/tutorials/data-access/icepyx.html + 2023-11-16T03:17:03.174Z https://nasa-openscapes.github.io/2023-ssc/tutorials/data-access/earthdata-search.html - 2023-11-16T03:13:00.493Z + 2023-11-16T03:17:02.622Z https://nasa-openscapes.github.io/2023-ssc/tutorials/index.html - 2023-11-16T03:12:59.525Z + 2023-11-16T03:17:01.654Z - https://nasa-openscapes.github.io/2023-ssc/tutorials/schedule.html - 2023-11-16T03:12:58.773Z + https://nasa-openscapes.github.io/2023-ssc/tutorials/setup.html + 2023-11-16T03:17:00.518Z - https://nasa-openscapes.github.io/2023-ssc/tutorials/cloud/cloud-paradigm.html - 2023-11-16T03:12:58.097Z + https://nasa-openscapes.github.io/2023-ssc/tutorials/cloud/index.html + 2023-11-16T03:16:59.694Z + + + https://nasa-openscapes.github.io/2023-ssc/tutorials/science/Intro_xarray_hvplot.html + 2023-11-16T03:16:59.126Z https://nasa-openscapes.github.io/2023-ssc/tutorials/jupyterhub_demo/jupyterhub_demo.html - 2023-11-16T03:12:57.317Z + 2023-11-16T03:16:56.582Z https://nasa-openscapes.github.io/2023-ssc/tutorials/prerequisites.html - 2023-11-16T03:12:56.021Z + 2023-11-16T03:16:55.218Z https://nasa-openscapes.github.io/2023-ssc/tutorials/further-resources.html - 2023-11-16T03:12:56.953Z + 2023-11-16T03:16:56.222Z - https://nasa-openscapes.github.io/2023-ssc/tutorials/science/Intro_xarray_hvplot.html - 2023-11-16T03:12:57.801Z + https://nasa-openscapes.github.io/2023-ssc/tutorials/GEDI_data_SSC23.html + 2023-11-16T03:16:58.626Z - https://nasa-openscapes.github.io/2023-ssc/tutorials/cloud/index.html - 2023-11-16T03:12:58.397Z + https://nasa-openscapes.github.io/2023-ssc/tutorials/cloud/cloud-paradigm.html + 2023-11-16T03:16:59.410Z - https://nasa-openscapes.github.io/2023-ssc/tutorials/setup.html - 2023-11-16T03:12:59.221Z + https://nasa-openscapes.github.io/2023-ssc/tutorials/schedule.html + 2023-11-16T03:17:00.066Z + + + https://nasa-openscapes.github.io/2023-ssc/tutorials/GEDI_L2B_V2_earthaccess.html + 2023-11-16T03:17:01.346Z https://nasa-openscapes.github.io/2023-ssc/tutorials/data-access/index.html - 2023-11-16T03:13:00.093Z + 2023-11-16T03:17:02.226Z - https://nasa-openscapes.github.io/2023-ssc/tutorials/data-access/icepyx.html - 2023-11-16T03:13:01.397Z + https://nasa-openscapes.github.io/2023-ssc/tutorials/data-access/earthaccess.html + 2023-11-16T03:17:02.898Z https://nasa-openscapes.github.io/2023-ssc/how-tos/data-access/Earthdata_Cloud__Single_File__Direct_S3_Access_Clip_COG_Example.html - 2023-11-16T03:13:02.173Z + 2023-11-16T03:17:03.678Z https://nasa-openscapes.github.io/2023-ssc/how-tos/data-discovery/Data_Discovery_CMR_API.html - 2023-11-16T03:13:03.569Z + 2023-11-16T03:17:04.922Z https://nasa-openscapes.github.io/2023-ssc/how-tos/authentication/NASA_Earthdata_Login_Token.html - 2023-11-16T03:13:04.453Z + 2023-11-16T03:17:05.810Z diff --git a/tutorials/GEDI_L2B_V2_earthaccess.html b/tutorials/GEDI_L2B_V2_earthaccess.html new file mode 100644 index 0000000..a29783c --- /dev/null +++ b/tutorials/GEDI_L2B_V2_earthaccess.html @@ -0,0 +1,2389 @@ + + + + + + + + + +2023 GEDI/ICESAT-2 Workshop - Getting Started with GEDI L2B Version 2 Data in Python + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + + +
    + +
    + + +
    + + + +
    + +
    +
    +

    Getting Started with GEDI L2B Version 2 Data in Python

    +
    + + + +
    + + + + +
    + + +
    + +
    +

    This tutorial demonstrates how to work with the Canopy Cover and Vertical Profile Metrics (GEDI02_B.002) data product.

    +

    The Global Ecosystem Dynamics Investigation (GEDI) mission aims to characterize ecosystem structure and dynamics to enable radically improved quantification and understanding of the Earth’s carbon cycle and biodiversity. The GEDI instrument produces high resolution laser ranging observations of the 3-dimensional structure of the Earth. GEDI is attached to the International Space Station and collects data globally between 51.6 N and 51.6 S latitudes at the highest resolution and densest sampling of any light detection and ranging (lidar) instrument in orbit to date. The Land Processes Distributed Active Archive Center (LP DAAC) distributes the GEDI Level 1 and Level 2 Version 1 and Version 2 products. The L1B and L2 GEDI products are archived and distributed in the HDF-EOS5 file format.

    +
    +
    +

    Use Case Example:

    +

    This tutorial was developed using an example use case for a project being completed by the National Park Service. The goal of the project is to use GEDI L2B Version 2 data to observe tree canopy height, cover, and profile over Redwood National Park in northern California.

    +

    This tutorial will show how to use Python to open GEDI L2B Version 2 files, visualize the sub-orbit of GEDI points (shots), subset to a region of interest, visualize GEDI canopy height and vertical profile metrics, and export subsets of GEDI science dataset (SDS) layers as GeoJSON files that can be loaded into GIS and/or Remote Sensing software programs.

    + +
    +

    Data Used in the Example:

    +
      +
    • GEDI L2B Canopy Cover and Vertical Profile Metrics Data Global Footprint Level - GEDI02_B.002 +
        +
      • The purpose of the L2B dataset is to extract biophysical metrics from each GEDI waveform. These metrics are based on the directional gap probability profile derived from the L1B waveform and include canopy cover, Plant Area Index (PAI), Plant Area Volume Density (PAVD) and Foliage Height Diversity (FHD).
        +
      • +
      • Science Dataset (SDS) layers: +
          +
        • /geolocation/digital_elevation_model
        • +
        • /geolocation/elev_lowestmode
          +
        • +
        • /geolocation/elev_highestreturn
          +
        • +
        • /geolocation/lat_lowestmode
          +
        • +
        • /geolocation/lon_lowestmode
          +
        • +
        • /rh100
          +
        • +
        • /l2b_quality_flag
          +
        • +
        • /degrade_flag
          +
        • +
        • /sensitivity
          +
        • +
        • /pai
          +
        • +
        • /pavd_z
          +
        • +
        • /geolocation/shot_number
          +
        • +
        • /dz
          +
        • +
        • /selected_l2a_algorithm
        • +
      • +
    • +
    +
    +
    +
    +

    Topics Covered:

    +
      +
    1. Get Started 1.1 Import Packages
      +1.2 Set Up the Working Environment and Retrieve Files
      +1.3 Authentication
      +
    2. +
    3. Search for GEDI Granules
      +
    4. +
    5. Import and Interpret Data
      +3.1 Open a GEDI HDF5 File and Read File Metadata
      +3.2 Read SDS Metadata and Subset by Beam
      +
    6. +
    7. Visualize a GEDI Sub-Orbit
      +4.1 Subset by Layer and Create a Geodataframe
      +4.2 Visualize a Geodataframe
    8. +
    9. Work with GEDI L2B Data
      +5.1 Import and Extract PAVD
      +5.2 Visualize PAVD
      +
    10. +
    11. Work with GEDI L2B Beam Transects
      +6.1 Quality Filtering
      +6.2 Plot Beam Transects
      +6.3 Subset Beam Transects
      +
    12. +
    13. Plot Profile Transects
      +7.1 Plot PAVD Transects
      +
    14. +
    15. Spatial Visualization
      +8.1 Import, Subset, and Quality Filter all Beams
      +8.2 Spatial Subsetting
      +8.3 Visualize All Beams: Canopy Height, Elevation, and PAI
      +
    16. +
    17. Export Subsets as GeoJSON Files
    18. +
    +
    +

    Source Code used to Generate this Tutorial:

    +

    The repository containing all of the required files is located at: https://github.com/nasa/GEDI-Data-Resources

    +
    +NOTE: This tutorial was developed for GEDI L2B Version 2 HDF-EOS5 files and should only be used for that product. +
    +
    +
    +
    +

    1. Get Started

    +
    +

    1.1 Import Packages

    +
    +

    Import the required packages and set the input/working directory to run this Jupyter Notebook locally.

    +
    +
    import os
    +import h5py
    +import numpy as np
    +import pandas as pd
    +import geopandas as gp
    +from shapely.geometry import Point
    +import geoviews as gv
    +from geoviews import opts, tile_sources as gvts
    +import holoviews as hv
    +gv.extension('bokeh', 'matplotlib')
    +import shapely
    +import earthaccess
    +import warnings
    +from shapely.errors import ShapelyDeprecationWarning
    +warnings.filterwarnings("ignore", category=ShapelyDeprecationWarning) 
    +
    + + +
    +
    + +
    +
    + +
    +
    + +
    + + + + + + + + + + + +
    +
    +
    +
    +
    +
    +

    1.2 Set Up the Working Environment and Retrieve Files

    +
    +

    The input directory is defined as the current working directory.

    +
    +
    inDir = os.getcwd()   # Set input directory to the current working directory
    +os.chdir(inDir)
    +data_dir = inDir.rsplit('2023-ssc')[0] + 'shared/2023SSC/'
    +data_dir
    +
    +
    '/home/jovyan/shared/2023SSC/'
    +
    +
    +
    +
    +
    +

    1.3 Authentication

    +

    Login to your NASA Earthdata account and create a .netrc file using the login function from the earthaccess library. If you do not have an Earthdata Account, you can create one here.

    +
    +
    # authenticate
    +earthaccess.login()
    +
    +
    EARTHDATA_USERNAME and EARTHDATA_PASSWORD are not set in the current environment, try setting them or use a different strategy (netrc, interactive)
    +You're now authenticated with NASA Earthdata Login
    +Using token with expiration date: 12/24/2023
    +Using .netrc file for EDL
    +
    +
    +
    <earthaccess.auth.Auth at 0x7fa6508d1a20>
    +
    +
    +
    +
    +
    +

    2. Search for GEDI Granules

    +
    +

    Below, earthaccess library is used to find GEDI L2B V2 Granules for an area of interest and a temporal range. The .h5 file will be downloaded to the data folder. You will need to download the files in order to execute this tutorial.

    +
    +
    # Define query parameters
    +conceptID = ["C1908350066-LPDAAC_ECS"]
    +bbx = (-91.5,18,-89,19)  # Lower lon, lower lat, upper lon, upper lat
    +tempRange = ('2022-06-01', '2022-06-30')
    +# search 
    +results = earthaccess.search_data(
    +    # short_name = 'GEDI02_B'
    +    concept_id = conceptID, 
    +    bounding_box = bbx,      
    +    temporal=tempRange,
    +    count=500
    +)
    +# download
    +downloaded_files = earthaccess.download(
    +    results,
    +    local_path= f'{data_dir}',  # Update the directory only to avoid overwritting by attendees 
    +)
    +
    +
    Granules found: 5
    + Getting 5 granules, approx download size: 1.59 GB
    +File GEDI02_B_2022154163608_O19677_02_T01836_02_003_01_V002.h5 already downloaded
    +File GEDI02_B_2022155015315_O19683_03_T05652_02_003_01_V002.h5 already downloaded
    +File GEDI02_B_2022158145957_O19738_02_T03565_02_003_01_V002.h5 already downloaded
    +File GEDI02_B_2022162224038_O19805_03_T06723_02_003_02_V002.h5 already downloaded
    +File GEDI02_B_2022159001702_O19744_03_T08957_02_003_01_V002.h5 already downloaded
    +
    +
    + +
    +
    + +
    +
    + +
    +
    +
    +
    gediFiles = [g for g in os.listdir(data_dir) if g.startswith('GEDI02_B') and g.endswith('.h5')]  # List all GEDI L2B .h5 files in inDir
    +gediFiles
    +
    +
    ['GEDI02_B_2022155015315_O19683_03_T05652_02_003_01_V002.h5',
    + 'GEDI02_B_2022159001702_O19744_03_T08957_02_003_01_V002.h5',
    + 'GEDI02_B_2022158145957_O19738_02_T03565_02_003_01_V002.h5',
    + 'GEDI02_B_2022154163608_O19677_02_T01836_02_003_01_V002.h5',
    + 'GEDI02_B_2022162224038_O19805_03_T06723_02_003_02_V002.h5']
    +
    +
    +
    +
    +
    +

    3. Import and Interpret Data

    +
    +

    3.1 Open a GEDI HDF5 File and Read File Metadata

    +
    +

    Read the file using h5py.

    +
    +
    L2B = f'{data_dir}{gediFiles[0]}'
    +L2B
    +
    +
    '/home/jovyan/shared/2023SSC/GEDI02_B_2022155015315_O19683_03_T05652_02_003_01_V002.h5'
    +
    +
    +
    +
    +

    The standard format for GEDI Version 2 filenames is as follows:

    +
    +

    GEDI02_B: Product Short Name
    +2022159001702: Julian Date and Time of Acquisition (YYYYDDDHHMMSS)
    +O19744: Orbit Number
    +03: Sub-Orbit Granule Number (1-4)
    +T08957: Track Number (Reference Ground Track)
    +02: Positioning and Pointing Determination System (PPDS) type (00 is predict, 01 rapid, 02 and higher is final)
    +003: PGE Version Number
    +01: Granule Production Version
    +V002: Product Version

    +
    +
    +
    +

    Read in a GEDI HDF5 file using the h5py package.

    +
    +
    gediL2B = h5py.File(L2B, 'r')  # Read file using h5py
    +
    +
    + +
    +

    The GEDI HDF5 file contains groups in which data and metadata are stored.

    +
    +
    +

    First, the METADATA group contains the file-level metadata.

    +
    +
    list(gediL2B['METADATA'])
    +
    +
    ['DatasetIdentification']
    +
    +
    +

    This contains useful information such as the creation date, PGEVersion, and VersionID. Below, print the file-level metadata attributes.

    +
    +
    for g in gediL2B['METADATA']['DatasetIdentification'].attrs:
    +    print(g, ": ", gediL2B['METADATA']['DatasetIdentification'].attrs[g]) 
    +
    +
    PGEVersion :  003
    +VersionID :  01
    +abstract :  The GEDI L2B standard data product contains precise latitude, longitude, elevation, height, cover and vertical profile metrics for each laser footprint located on the land surface.
    +characterSet :  utf8
    +creationDate :  2022-09-22T17:38:15.690108Z
    +credit :  The software that generates the L2B product was implemented within the GEDI Science Data Processing System at the NASA Goddard Space Flight Center (GSFC) in Greenbelt, Maryland in collaboration with the Department of Geographical Sciences at the University of Maryland (UMD).
    +fileName :  GEDI02_B_2022155015315_O19683_03_T05652_02_003_01_V002.h5
    +language :  eng
    +originatorOrganizationName :  UMD/GSFC GEDI-SDPS > GEDI Science Data Processing System
    +purpose :  The purpose of the L2B dataset is to extract biophysical metrics from each GEDI waveform. These metrics are based on the directional gap probability profile derived from the L1B waveform and include canopy cover, Plant Area Index (PAI), Plant Area Volume Density (PAVD) and Foliage Height Diversity (FHD).
    +shortName :  GEDI_L2B
    +spatialRepresentationType :  along-track
    +status :  onGoing
    +topicCategory :  geoscientificInformation
    +uuid :  f7ecc77a-3372-4f53-9131-f110b4bbfb5c
    +
    +
    +
    +
    +
    +

    3.2 Read SDS Metadata and Subset by Beam

    +
    +

    The GEDI instrument consists of 3 lasers producing a total of 8 beam ground transects. The eight remaining groups contain data for each of the eight GEDI beam transects. For additional information, be sure to check out: https://gedi.umd.edu/instrument/specifications/.

    +
    +
    beamNames = [g for g in gediL2B.keys() if g.startswith('BEAM')]
    +beamNames
    +
    +
    ['BEAM0000',
    + 'BEAM0001',
    + 'BEAM0010',
    + 'BEAM0011',
    + 'BEAM0101',
    + 'BEAM0110',
    + 'BEAM1000',
    + 'BEAM1011']
    +
    +
    +
    +
    +

    One useful piece of metadata to retrieve from each beam transect is whether it is a full power beam or a coverage beam.

    +
    +
    for b in beamNames: 
    +    print(f"{b} is a {gediL2B[b].attrs['description']}")
    +
    +
    BEAM0000 is a Coverage beam
    +BEAM0001 is a Coverage beam
    +BEAM0010 is a Coverage beam
    +BEAM0011 is a Coverage beam
    +BEAM0101 is a Full power beam
    +BEAM0110 is a Full power beam
    +BEAM1000 is a Full power beam
    +BEAM1011 is a Full power beam
    +
    +
    +
    +
    +

    Below, pick one of the full power beams that will be used to retrieve GEDI L2B shots in next section.

    +
    +
    +

    Identify all the objects in the GEDI HDF5 file below.

    +

    Note: This step may take a while to complete.

    +
    +
    gediL2B_objs = []
    +gediL2B.visit(gediL2B_objs.append)                                           # Retrieve list of datasets
    +gediSDS = [o for o in gediL2B_objs if isinstance(gediL2B[o], h5py.Dataset)]  # Search for relevant SDS inside data file
    +# gediSDS
    +[i for i in gediSDS if beamNames[4] in i]                               # Print the datasets for a selected beam 
    +
    +
    ['BEAM0101/algorithmrun_flag',
    + 'BEAM0101/ancillary/dz',
    + 'BEAM0101/ancillary/l2a_alg_count',
    + 'BEAM0101/ancillary/maxheight_cuttoff',
    + 'BEAM0101/ancillary/rg_eg_constraint_center_buffer',
    + 'BEAM0101/ancillary/rg_eg_mpfit_max_func_evals',
    + 'BEAM0101/ancillary/rg_eg_mpfit_maxiters',
    + 'BEAM0101/ancillary/rg_eg_mpfit_tolerance',
    + 'BEAM0101/ancillary/signal_search_buff',
    + 'BEAM0101/ancillary/tx_noise_stddev_multiplier',
    + 'BEAM0101/beam',
    + 'BEAM0101/channel',
    + 'BEAM0101/cover',
    + 'BEAM0101/cover_z',
    + 'BEAM0101/fhd_normal',
    + 'BEAM0101/geolocation/degrade_flag',
    + 'BEAM0101/geolocation/delta_time',
    + 'BEAM0101/geolocation/digital_elevation_model',
    + 'BEAM0101/geolocation/elev_highestreturn',
    + 'BEAM0101/geolocation/elev_lowestmode',
    + 'BEAM0101/geolocation/elevation_bin0',
    + 'BEAM0101/geolocation/elevation_bin0_error',
    + 'BEAM0101/geolocation/elevation_lastbin',
    + 'BEAM0101/geolocation/elevation_lastbin_error',
    + 'BEAM0101/geolocation/height_bin0',
    + 'BEAM0101/geolocation/height_lastbin',
    + 'BEAM0101/geolocation/lat_highestreturn',
    + 'BEAM0101/geolocation/lat_lowestmode',
    + 'BEAM0101/geolocation/latitude_bin0',
    + 'BEAM0101/geolocation/latitude_bin0_error',
    + 'BEAM0101/geolocation/latitude_lastbin',
    + 'BEAM0101/geolocation/latitude_lastbin_error',
    + 'BEAM0101/geolocation/local_beam_azimuth',
    + 'BEAM0101/geolocation/local_beam_elevation',
    + 'BEAM0101/geolocation/lon_highestreturn',
    + 'BEAM0101/geolocation/lon_lowestmode',
    + 'BEAM0101/geolocation/longitude_bin0',
    + 'BEAM0101/geolocation/longitude_bin0_error',
    + 'BEAM0101/geolocation/longitude_lastbin',
    + 'BEAM0101/geolocation/longitude_lastbin_error',
    + 'BEAM0101/geolocation/shot_number',
    + 'BEAM0101/geolocation/solar_azimuth',
    + 'BEAM0101/geolocation/solar_elevation',
    + 'BEAM0101/l2a_quality_flag',
    + 'BEAM0101/l2b_quality_flag',
    + 'BEAM0101/land_cover_data/landsat_treecover',
    + 'BEAM0101/land_cover_data/landsat_water_persistence',
    + 'BEAM0101/land_cover_data/leaf_off_doy',
    + 'BEAM0101/land_cover_data/leaf_off_flag',
    + 'BEAM0101/land_cover_data/leaf_on_cycle',
    + 'BEAM0101/land_cover_data/leaf_on_doy',
    + 'BEAM0101/land_cover_data/modis_nonvegetated',
    + 'BEAM0101/land_cover_data/modis_nonvegetated_sd',
    + 'BEAM0101/land_cover_data/modis_treecover',
    + 'BEAM0101/land_cover_data/modis_treecover_sd',
    + 'BEAM0101/land_cover_data/pft_class',
    + 'BEAM0101/land_cover_data/region_class',
    + 'BEAM0101/land_cover_data/urban_focal_window_size',
    + 'BEAM0101/land_cover_data/urban_proportion',
    + 'BEAM0101/master_frac',
    + 'BEAM0101/master_int',
    + 'BEAM0101/num_detectedmodes',
    + 'BEAM0101/omega',
    + 'BEAM0101/pai',
    + 'BEAM0101/pai_z',
    + 'BEAM0101/pavd_z',
    + 'BEAM0101/pgap_theta',
    + 'BEAM0101/pgap_theta_error',
    + 'BEAM0101/pgap_theta_z',
    + 'BEAM0101/rg',
    + 'BEAM0101/rh100',
    + 'BEAM0101/rhog',
    + 'BEAM0101/rhog_error',
    + 'BEAM0101/rhov',
    + 'BEAM0101/rhov_error',
    + 'BEAM0101/rossg',
    + 'BEAM0101/rv',
    + 'BEAM0101/rx_processing/algorithmrun_flag_a1',
    + 'BEAM0101/rx_processing/algorithmrun_flag_a2',
    + 'BEAM0101/rx_processing/algorithmrun_flag_a3',
    + 'BEAM0101/rx_processing/algorithmrun_flag_a4',
    + 'BEAM0101/rx_processing/algorithmrun_flag_a5',
    + 'BEAM0101/rx_processing/algorithmrun_flag_a6',
    + 'BEAM0101/rx_processing/pgap_theta_a1',
    + 'BEAM0101/rx_processing/pgap_theta_a2',
    + 'BEAM0101/rx_processing/pgap_theta_a3',
    + 'BEAM0101/rx_processing/pgap_theta_a4',
    + 'BEAM0101/rx_processing/pgap_theta_a5',
    + 'BEAM0101/rx_processing/pgap_theta_a6',
    + 'BEAM0101/rx_processing/pgap_theta_error_a1',
    + 'BEAM0101/rx_processing/pgap_theta_error_a2',
    + 'BEAM0101/rx_processing/pgap_theta_error_a3',
    + 'BEAM0101/rx_processing/pgap_theta_error_a4',
    + 'BEAM0101/rx_processing/pgap_theta_error_a5',
    + 'BEAM0101/rx_processing/pgap_theta_error_a6',
    + 'BEAM0101/rx_processing/rg_a1',
    + 'BEAM0101/rx_processing/rg_a2',
    + 'BEAM0101/rx_processing/rg_a3',
    + 'BEAM0101/rx_processing/rg_a4',
    + 'BEAM0101/rx_processing/rg_a5',
    + 'BEAM0101/rx_processing/rg_a6',
    + 'BEAM0101/rx_processing/rg_eg_amplitude_a1',
    + 'BEAM0101/rx_processing/rg_eg_amplitude_a2',
    + 'BEAM0101/rx_processing/rg_eg_amplitude_a3',
    + 'BEAM0101/rx_processing/rg_eg_amplitude_a4',
    + 'BEAM0101/rx_processing/rg_eg_amplitude_a5',
    + 'BEAM0101/rx_processing/rg_eg_amplitude_a6',
    + 'BEAM0101/rx_processing/rg_eg_amplitude_error_a1',
    + 'BEAM0101/rx_processing/rg_eg_amplitude_error_a2',
    + 'BEAM0101/rx_processing/rg_eg_amplitude_error_a3',
    + 'BEAM0101/rx_processing/rg_eg_amplitude_error_a4',
    + 'BEAM0101/rx_processing/rg_eg_amplitude_error_a5',
    + 'BEAM0101/rx_processing/rg_eg_amplitude_error_a6',
    + 'BEAM0101/rx_processing/rg_eg_center_a1',
    + 'BEAM0101/rx_processing/rg_eg_center_a2',
    + 'BEAM0101/rx_processing/rg_eg_center_a3',
    + 'BEAM0101/rx_processing/rg_eg_center_a4',
    + 'BEAM0101/rx_processing/rg_eg_center_a5',
    + 'BEAM0101/rx_processing/rg_eg_center_a6',
    + 'BEAM0101/rx_processing/rg_eg_center_error_a1',
    + 'BEAM0101/rx_processing/rg_eg_center_error_a2',
    + 'BEAM0101/rx_processing/rg_eg_center_error_a3',
    + 'BEAM0101/rx_processing/rg_eg_center_error_a4',
    + 'BEAM0101/rx_processing/rg_eg_center_error_a5',
    + 'BEAM0101/rx_processing/rg_eg_center_error_a6',
    + 'BEAM0101/rx_processing/rg_eg_chisq_a1',
    + 'BEAM0101/rx_processing/rg_eg_chisq_a2',
    + 'BEAM0101/rx_processing/rg_eg_chisq_a3',
    + 'BEAM0101/rx_processing/rg_eg_chisq_a4',
    + 'BEAM0101/rx_processing/rg_eg_chisq_a5',
    + 'BEAM0101/rx_processing/rg_eg_chisq_a6',
    + 'BEAM0101/rx_processing/rg_eg_flag_a1',
    + 'BEAM0101/rx_processing/rg_eg_flag_a2',
    + 'BEAM0101/rx_processing/rg_eg_flag_a3',
    + 'BEAM0101/rx_processing/rg_eg_flag_a4',
    + 'BEAM0101/rx_processing/rg_eg_flag_a5',
    + 'BEAM0101/rx_processing/rg_eg_flag_a6',
    + 'BEAM0101/rx_processing/rg_eg_gamma_a1',
    + 'BEAM0101/rx_processing/rg_eg_gamma_a2',
    + 'BEAM0101/rx_processing/rg_eg_gamma_a3',
    + 'BEAM0101/rx_processing/rg_eg_gamma_a4',
    + 'BEAM0101/rx_processing/rg_eg_gamma_a5',
    + 'BEAM0101/rx_processing/rg_eg_gamma_a6',
    + 'BEAM0101/rx_processing/rg_eg_gamma_error_a1',
    + 'BEAM0101/rx_processing/rg_eg_gamma_error_a2',
    + 'BEAM0101/rx_processing/rg_eg_gamma_error_a3',
    + 'BEAM0101/rx_processing/rg_eg_gamma_error_a4',
    + 'BEAM0101/rx_processing/rg_eg_gamma_error_a5',
    + 'BEAM0101/rx_processing/rg_eg_gamma_error_a6',
    + 'BEAM0101/rx_processing/rg_eg_niter_a1',
    + 'BEAM0101/rx_processing/rg_eg_niter_a2',
    + 'BEAM0101/rx_processing/rg_eg_niter_a3',
    + 'BEAM0101/rx_processing/rg_eg_niter_a4',
    + 'BEAM0101/rx_processing/rg_eg_niter_a5',
    + 'BEAM0101/rx_processing/rg_eg_niter_a6',
    + 'BEAM0101/rx_processing/rg_eg_sigma_a1',
    + 'BEAM0101/rx_processing/rg_eg_sigma_a2',
    + 'BEAM0101/rx_processing/rg_eg_sigma_a3',
    + 'BEAM0101/rx_processing/rg_eg_sigma_a4',
    + 'BEAM0101/rx_processing/rg_eg_sigma_a5',
    + 'BEAM0101/rx_processing/rg_eg_sigma_a6',
    + 'BEAM0101/rx_processing/rg_eg_sigma_error_a1',
    + 'BEAM0101/rx_processing/rg_eg_sigma_error_a2',
    + 'BEAM0101/rx_processing/rg_eg_sigma_error_a3',
    + 'BEAM0101/rx_processing/rg_eg_sigma_error_a4',
    + 'BEAM0101/rx_processing/rg_eg_sigma_error_a5',
    + 'BEAM0101/rx_processing/rg_eg_sigma_error_a6',
    + 'BEAM0101/rx_processing/rg_error_a1',
    + 'BEAM0101/rx_processing/rg_error_a2',
    + 'BEAM0101/rx_processing/rg_error_a3',
    + 'BEAM0101/rx_processing/rg_error_a4',
    + 'BEAM0101/rx_processing/rg_error_a5',
    + 'BEAM0101/rx_processing/rg_error_a6',
    + 'BEAM0101/rx_processing/rv_a1',
    + 'BEAM0101/rx_processing/rv_a2',
    + 'BEAM0101/rx_processing/rv_a3',
    + 'BEAM0101/rx_processing/rv_a4',
    + 'BEAM0101/rx_processing/rv_a5',
    + 'BEAM0101/rx_processing/rv_a6',
    + 'BEAM0101/rx_processing/rx_energy_a1',
    + 'BEAM0101/rx_processing/rx_energy_a2',
    + 'BEAM0101/rx_processing/rx_energy_a3',
    + 'BEAM0101/rx_processing/rx_energy_a4',
    + 'BEAM0101/rx_processing/rx_energy_a5',
    + 'BEAM0101/rx_processing/rx_energy_a6',
    + 'BEAM0101/rx_processing/shot_number',
    + 'BEAM0101/rx_range_highestreturn',
    + 'BEAM0101/rx_sample_count',
    + 'BEAM0101/rx_sample_start_index',
    + 'BEAM0101/selected_l2a_algorithm',
    + 'BEAM0101/selected_mode',
    + 'BEAM0101/selected_mode_flag',
    + 'BEAM0101/selected_rg_algorithm',
    + 'BEAM0101/sensitivity',
    + 'BEAM0101/shot_number',
    + 'BEAM0101/stale_return_flag',
    + 'BEAM0101/surface_flag']
    +
    +
    +

    There are several datasets for each beam. View the GEDI L2B Dictionary for more details. You can also print the description for desired datasets.

    +
    +
    print('pai: ', gediL2B['BEAM0101/pai'].attrs['description'])
    +print('pai_z: ', gediL2B['BEAM0101/pai_z'].attrs['description'])
    +print('pavd_z: ', gediL2B['BEAM0101/pavd_z'].attrs['description'])
    +print('shot_number: ', gediL2B['BEAM0101/geolocation/shot_number'].attrs['description'])
    +print('rh100: ', gediL2B['BEAM0101/rh100'].attrs['description'])
    +print('Quality Flag: ', gediL2B['BEAM0101/l2b_quality_flag'].attrs['description'])
    +
    +
    pai:  Total plant area index
    +pai_z:  Vertical PAI profile from canopy height (z) to ground (z=0) with a vertical step size of dZ, where cover(z > z_max) = 0
    +pavd_z:  Vertical Plant Area Volume Density profile with a vertical step size of dZ
    +shot_number:  Unique shot ID.
    +rh100:  Height above ground of the received waveform signal start (rh[101] from L2A)
    +Quality Flag:  Flag simpilfying selection of most useful data for Level 2B
    +
    +
    +
    +
    +

    We will set the shot index used as an example from the GEDI L1B Tutorial and GEDI L2A Tutorial to show how to subset a single shot of GEDI L2B data.

    +
    +
    +
    +
    +

    4. Visualize a GEDI Orbit

    +
    +

    In the section below, import GEDI L2B SDS layers into a GeoPandas GeoDataFrame for the beam specified above.

    +
    +
    +

    Use the lat_lowestmode and lon_lowestmode to create a shapely point for each GEDI shot location.

    +
    +
    +

    4.1 Subset by Layer and Create a Geodataframe

    +
    +

    Read in the SDS and take a representative sample (every 100th shot) and append to lists, then use the lists to generate a pandas dataframe.

    +
    +
    lonSample, latSample, shotSample, qualitySample, beamSample = [], [], [], [], []  # Set up lists to store data
    +
    +# Open the SDS
    +lats = gediL2B[f'{beamNames[0]}/geolocation/lat_lowestmode'][()]
    +lons = gediL2B[f'{beamNames[0]}/geolocation/lon_lowestmode'][()]
    +shots = gediL2B[f'{beamNames[0]}/geolocation/shot_number'][()]
    +quality = gediL2B[f'{beamNames[0]}/l2b_quality_flag'][()]
    +
    +# Take every 100th shot and append to list
    +for i in range(len(shots)):
    +    if i % 100 == 0:
    +        shotSample.append(str(shots[i]))
    +        lonSample.append(lons[i])
    +        latSample.append(lats[i])
    +        qualitySample.append(quality[i])
    +        beamSample.append(beamNames[0])
    +            
    +# Write all of the sample shots to a dataframe
    +latslons = pd.DataFrame({'Beam': beamSample, 'Shot Number': shotSample, 'Longitude': lonSample, 'Latitude': latSample,
    +                         'Quality Flag': qualitySample})
    +latslons
    +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    BeamShot NumberLongitudeLatitudeQuality Flag
    0BEAM0000196830000300204328-150.40707951.4803110
    1BEAM0000196830000300204428-150.36347651.4747150
    2BEAM0000196830000300204528-150.32294351.4706770
    3BEAM0000196830000300204628-150.28063251.4656780
    4BEAM0000196830000300204728-150.23979751.4614420
    ..................
    1532BEAM0000196830000300357528-77.5743870.6177010
    1533BEAM0000196830000300357628-77.5443440.5751490
    1534BEAM0000196830000300357728-77.5145840.5329450
    1535BEAM0000196830000300357828-77.4846200.4903240
    1536BEAM0000196830000300357928-77.4546360.4476910
    + +

    1537 rows × 5 columns

    +
    +
    +
    +
    +
    +

    Above is a dataframe containing columns describing the beam, shot number, lat/lon location, and quality information about each shot.

    +
    +
    +

    Side Note: Wondering what the 0’s and 1’s for l2b_quality_flag mean?

    +
    +
    +

    Above, 0 is poor quality and a quality_flag value of 1 indicates the laser shot meets criteria based on energy, sensitivity, amplitude, and real-time surface tracking quality. We will show an example of how to quality filter GEDI data.

    +
    +
    # Clean up variables that will no longer be needed
    +# del beamSample, quality, qualitySample, gediL2B_objs, latSample, lats, lonSample, lons, shotSample, shots 
    +
    +
    +
    +

    Below, create an additional column called ‘geometry’ that contains a shapely point generated from each lat/lon location from the shot.

    +
    +
    # Take the lat/lon dataframe and convert each lat/lon to a shapely point
    +latslons['geometry'] = latslons.apply(lambda row: Point(row.Longitude, row.Latitude), axis=1)
    +
    +
    +
    +

    Next, convert to a Geopandas GeoDataFrame.

    +
    +
    # Convert to a Geodataframe
    +latslons = gp.GeoDataFrame(latslons)
    +latslons = latslons.drop(columns=['Latitude','Longitude'])
    +latslons['geometry']
    +
    +
    0       POINT (-150.40708 51.48031)
    +1       POINT (-150.36348 51.47471)
    +2       POINT (-150.32294 51.47068)
    +3       POINT (-150.28063 51.46568)
    +4       POINT (-150.23980 51.46144)
    +                   ...             
    +1532      POINT (-77.57439 0.61770)
    +1533      POINT (-77.54434 0.57515)
    +1534      POINT (-77.51458 0.53295)
    +1535      POINT (-77.48462 0.49032)
    +1536      POINT (-77.45464 0.44769)
    +Name: geometry, Length: 1537, dtype: geometry
    +
    +
    +
    +
    +

    Pull out and plot an example shapely point below.

    +
    +
    +
    +

    4.2 Visualize a GeoDataFrame

    +
    +

    In this section, use the GeoDataFrame and the geoviews python package to spatially visualize the location of the GEDI shots on a basemap and import a GeoJSON file of the spatial region of interest for the use case example: Redwood National Park.

    +
    +
    # Define a function for visualizing GEDI points
    +def pointVisual(features, vdims):
    +    return (gvts.EsriImagery * gv.Points(features, vdims=vdims).options(tools=['hover'], height=500, width=900, size=5, 
    +                                                                        color='yellow', fontsize={'xticks': 10, 'yticks': 10, 
    +                                                                                                  'xlabel':16, 'ylabel': 16}))
    +
    +
    +
    +

    Import a GeoJSON of Reserva de la Biósfera Calakmul National Park as an additional GeoDataFrame.

    +
    +
    calakmul = gp.GeoDataFrame.from_file(f'{data_dir}calakmul.geojson')  # Import GeoJSON as GeoDataFrame
    +
    +
    +
    calakmul
    +
    +
    + + + + + + + + + + + + + + + +
    geometry
    0POLYGON ((-89.00000 19.00000, -91.50000 19.000...
    + +
    +
    +
    +
    +
    calakmul['geometry'][0]  # Plot GeoDataFrame
    +
    +

    +
    +
    +
    +
    +

    Defining the vdims below will allow you to hover over specific shots and view information about them.

    +
    +
    # Create a list of geodataframe columns to be included as attributes in the output map
    +vdims = []
    +for f in latslons:
    +    if f not in ['geometry']:
    +        vdims.append(f)
    +vdims
    +
    +
    ['Beam', 'Shot Number', 'Quality Flag']
    +
    +
    +
    +
    +

    Below, combine a plot of the Redwood National Park Boundary (combine two geoviews plots using *) with the point visual mapping function defined above in order to plot (1) the representative GEDI shots, (2) the region of interest, and (3) a basemap layer.

    +
    +
    # Call the function for plotting the GEDI points
    +gv.Polygons(calakmul['geometry']).opts(line_color='red', color=None) * pointVisual(latslons, vdims = vdims)
    +
    + +
    +
    +
    +
    +
    + +
    +
    +
    + +
    +
    +
    +

    5. Work with GEDI L2B Data

    +
    +

    The L2B product contains biophysical information derived from the geolocated GEDI return waveforms including total and vertical profiles of canopy cover and Plant Area Index (PAI), the vertical Plant Area Volume Density (PAVD) profile, and Foliage Height Diversity (FHD).

    +
    +
    +

    Detailed product information can be found on the GEDI L2B Product Page.

    +
    +
    +

    Below, only data for one shot is extracted.

    +
    +
    beamNames[4]
    +
    +
    'BEAM0101'
    +
    +
    +
    +
    beamSDS = [g for g in gediSDS if beamNames[4] in g]  # Subset to a single beam
    +len(beamSDS)
    +
    +
    197
    +
    +
    +
    +
    +

    In the GEDI L2B product, Canopy Height is stored in units (cm), so below convert to meters.

    +
    +
    canopyHeight = canopyHeight / 100  # Convert RH100 from cm to m 
    +
    +
    +
    +

    Below, notice the reformatted PAVD layer, which should now fit into the dataframe created below.

    +
    +
    # Take the DEM, GEDI-produced Elevation, and Canopy height and add to a Pandas dataframe
    +transectDF = pd.DataFrame({
    +    'Shot Index': shotIndex,
    +    'Shot Number': shotNums,
    +    'Latitude': zLat,
    +    'Longitude': zLon,
    +    'Tandem-X DEM': dem,
    +    'Elevation (m)': zElevation,
    +    'Canopy Elevation (m)': zHigh,
    +    'Canopy Height (rh100)': canopyHeight,
    +    'Quality Flag': quality,
    +    'Degrade Flag': degrade, 
    +    'Sensitivity': sensitivity,
    +    'Selected L2A Algorithm': selectedAlgorithmL2A
    +    })
    +
    +
    ValueError: All arrays must be of the same length
    +
    +
    +
    +
    transectDF
    +
    + + +
    +
    + +
    + +
    + + + + + \ No newline at end of file diff --git a/tutorials/GEDI_L2B_V2_earthaccess_files/figure-html/cell-23-output-1.svg b/tutorials/GEDI_L2B_V2_earthaccess_files/figure-html/cell-23-output-1.svg new file mode 100644 index 0000000..8b4f3f0 --- /dev/null +++ b/tutorials/GEDI_L2B_V2_earthaccess_files/figure-html/cell-23-output-1.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/tutorials/GEDI_data_SSC23.html b/tutorials/GEDI_data_SSC23.html new file mode 100644 index 0000000..437c7af --- /dev/null +++ b/tutorials/GEDI_data_SSC23.html @@ -0,0 +1,3317 @@ + + + + + + + + + +2023 GEDI/ICESAT-2 Workshop - How to work with GEDI Level 2B V002 Data + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + + +
    + +
    + + +
    + + + +
    + +
    +
    +

    How to work with GEDI Level 2B V002 Data

    +
    + + + +
    + + + + +
    + + +
    + +
    +

    This tutorial was developed as a walkthrough at the SPACE AND SUSTAINABILITY ,first international colloquiqm, on Nov 16, 2023 in Guadalajara, Jal., Mexico.

    +
    +
    +

    This tutorial will show how to use Python to open GEDI L2B Version 2 files, subset layer and to a region of interest, filter by quality, and visualize GEDI Elevation, Canopy Elevation, Plant Area Index,and Canopy Height along with Tandem-X DEM and Non-vegetated area from MODIS.

    +
    +
    +

    A small area of Reserva de la Biósfera de Calakmul National Forest is used as the ROI for this tutorial.

    +

    Note: Follow the steps provided in setup instructions to create a local Python environment to execute this notebook.

    +
    +
    +

    1. Set Up the Working Environment

    +
    +

    Import the required packages and set the input/working directory to run this Jupyter Notebook locally.

    +
    +
    import os
    +import h5py
    +import pandas
    +import geopandas 
    +from shapely.geometry import Point
    +import geoviews
    +from geoviews import opts, tile_sources as gvts
    +import shapely
    +import earthaccess
    +import warnings
    +from datetime import datetime
    +
    +from shapely.errors import ShapelyDeprecationWarning
    +geoviews.extension('bokeh','matplotlib')
    +warnings.filterwarnings("ignore", category=ShapelyDeprecationWarning) 
    +
    + + +
    +
    + +
    +
    + +
    +
    + +
    + + + + + + + + + + + +
    +
    +
    +
    +
    inDir = os.getcwd()   # Set input directory to the current working directory
    +os.chdir(inDir)
    +data_dir = inDir.rsplit('2023-ssc')[0] + 'shared/2023SSC/'
    +data_dir
    +
    +
    '/home/jovyan/shared/2023SSC/'
    +
    +
    +
    +
    +
    +

    2. Authentication and Search for GEDI Data

    +

    Login to your NASA Earthdata account and create a .netrc file using the login function from the earthaccess library. If you do not have an Earthdata Account, you can create one here.

    +
    +
    # authenticate
    +earthaccess.login()
    +
    +
    EARTHDATA_USERNAME and EARTHDATA_PASSWORD are not set in the current environment, try setting them or use a different strategy (netrc, interactive)
    +You're now authenticated with NASA Earthdata Login
    +Using token with expiration date: 12/24/2023
    +Using .netrc file for EDL
    +
    +
    +
    <earthaccess.auth.Auth at 0x7f32e62bc2e0>
    +
    +
    +
    +

    Below, earthaccess library is used to find GEDI L2B V2 Granules for an area of interest and a temporal range. The .h5 file will be downloaded to the data folder. You will need to download the files in order to execute this tutorial.

    +
    +
    # Define query parameters
    +conceptID = ["C1908350066-LPDAAC_ECS"]
    +bbx = (-91.5,18,-89,19)  # Lower lon, lower lat, upper lon, upper lat
    +tempRange = ('2022-06-01', '2022-06-30') #'2022-04-01', '2022-08-30'
    +# search 
    +results = earthaccess.search_data(
    +    # short_name = 'GEDI02_B'
    +    concept_id = conceptID, 
    +    bounding_box = bbx,      
    +    temporal=tempRange,
    +    count=500
    +)
    +
    +
    Granules found: 5
    +
    +
    +

    Next, download the granules.
    +Note: Considering the time limitations in this workshop, the download section will be skipped. The downloaded granules are stored in shared folder and they are accessible to execute this notebook.

    +
    +
    # # download
    +# downloaded_files = earthaccess.download(
    +#     results,
    +#     local_path= f'{data_dir}/data',  # Update the directory only to avoid overwritting by attendees 
    +# )
    +
    +
    +
    +

    The standard format for GEDI Version 2 filenames is as follows:

    +
    +

    GEDI02_B: Product Short Name
    +2022120091720: Julian Date and Time of Acquisition (YYYYDDDHHMMSS)
    +O19145: Orbit Number
    +02: Sub-Orbit Granule Number (1-4)
    +T09106: Track Number (Reference Ground Track)
    +02: Positioning and Pointing Determination System (PPDS) type (00 is predict, 01 rapid, 02 and higher is final)
    +003: PGE Version Number
    +01: Granule Production Version
    +V002: Product Version

    +
    +
    +
    +

    Next, retrieve the granule downloaded.

    +
    +
    gediFiles = [g for g in os.listdir(data_dir) if g.startswith('GEDI02_B') and g.endswith('.h5')]  # List all GEDI L2B .h5 files in inDir
    +gediFiles
    +
    +
    ['GEDI02_B_2022155015315_O19683_03_T05652_02_003_01_V002.h5',
    + 'GEDI02_B_2022159001702_O19744_03_T08957_02_003_01_V002.h5',
    + 'GEDI02_B_2022158145957_O19738_02_T03565_02_003_01_V002.h5',
    + 'GEDI02_B_2022154163608_O19677_02_T01836_02_003_01_V002.h5',
    + 'GEDI02_B_2022162224038_O19805_03_T06723_02_003_02_V002.h5']
    +
    +
    +
    +
    +
    +

    2. Open a GEDI HDF5 File and Read File Metadata

    +
    +

    Read in a GEDI HDF5 file using the h5py package and navigate the HDF5 file. The GEDI HDF5 file contains groups in which data and metadata are stored.

    +
    +
    L2B = h5py.File(f'{data_dir}{gediFiles[0]}', 'r')  # Read file using h5py
    +L2B
    +
    +
    <HDF5 file "GEDI02_B_2022155015315_O19683_03_T05652_02_003_01_V002.h5" (mode r)>
    +
    +
    +
    +
    list(L2B.keys())
    +
    +
    ['BEAM0000',
    + 'BEAM0001',
    + 'BEAM0010',
    + 'BEAM0011',
    + 'BEAM0101',
    + 'BEAM0110',
    + 'BEAM1000',
    + 'BEAM1011',
    + 'METADATA']
    +
    +
    +

    #### The METADATA group contains the file-level metadata such as the creation date, PGEVersion, and VersionID. Below, print the file-level metadata attributes and their values.

    +
    +
    for g in L2B['METADATA']['DatasetIdentification'].attrs:
    +    print(g, ':', L2B['METADATA']['DatasetIdentification'].attrs[g]) 
    +    
    +
    +
    PGEVersion : 003
    +VersionID : 01
    +abstract : The GEDI L2B standard data product contains precise latitude, longitude, elevation, height, cover and vertical profile metrics for each laser footprint located on the land surface.
    +characterSet : utf8
    +creationDate : 2022-09-22T17:38:15.690108Z
    +credit : The software that generates the L2B product was implemented within the GEDI Science Data Processing System at the NASA Goddard Space Flight Center (GSFC) in Greenbelt, Maryland in collaboration with the Department of Geographical Sciences at the University of Maryland (UMD).
    +fileName : GEDI02_B_2022155015315_O19683_03_T05652_02_003_01_V002.h5
    +language : eng
    +originatorOrganizationName : UMD/GSFC GEDI-SDPS > GEDI Science Data Processing System
    +purpose : The purpose of the L2B dataset is to extract biophysical metrics from each GEDI waveform. These metrics are based on the directional gap probability profile derived from the L1B waveform and include canopy cover, Plant Area Index (PAI), Plant Area Volume Density (PAVD) and Foliage Height Diversity (FHD).
    +shortName : GEDI_L2B
    +spatialRepresentationType : along-track
    +status : onGoing
    +topicCategory : geoscientificInformation
    +uuid : f7ecc77a-3372-4f53-9131-f110b4bbfb5c
    +
    +
    +
    +
    +
    +

    3. Read SDS Metadata and Subset by Beam

    +
    +

    The GEDI instrument consists of 3 lasers producing a total of 8 beam ground transects. The eight remaining groups contain data for each of the eight GEDI beam transects. For additional information, be sure to check out: https://gedi.umd.edu/instrument/specifications/.

    +
    +
    +

    One useful piece of metadata to retrieve from each beam transect is whether it is a full power beam or a coverage beam. GEDI coverage beams will not penetrate dense forest. The GEDI coverage beams were only designed to penetrate canopies of up to 95% canopy cover under “average” conditions, so users should use GEDI Full power beams in the case of dense forest.

    +
    +
    for beam in list(L2B.keys()):
    +    if beam == 'METADATA':
    +        continue
    +    else:
    +        print(beam, 'is:', L2B[beam].attrs['description'])
    +
    +
    BEAM0000 is: Coverage beam
    +BEAM0001 is: Coverage beam
    +BEAM0010 is: Coverage beam
    +BEAM0011 is: Coverage beam
    +BEAM0101 is: Full power beam
    +BEAM0110 is: Full power beam
    +BEAM1000 is: Full power beam
    +BEAM1011 is: Full power beam
    +
    +
    +
    +
    +

    Identify all the datasets in the GEDI HDF5 file below.

    +
    +
    # list(L2B['BEAM1011'].keys())
    +L2B_objs = []
    +L2B.visit(L2B_objs.append)                                           # Retrieve list of datasets
    +SDS = [o for o in L2B_objs if isinstance(L2B[o], h5py.Dataset)]  # Search for relevant SDS inside data file
    +len(SDS)
    +
    +
    1576
    +
    +
    +

    Print the datasets available in this L2B granule and print the description for desired datasets.

    +
    +
    SDS[:30]
    +
    +
    ['BEAM0000/algorithmrun_flag',
    + 'BEAM0000/ancillary/dz',
    + 'BEAM0000/ancillary/l2a_alg_count',
    + 'BEAM0000/ancillary/maxheight_cuttoff',
    + 'BEAM0000/ancillary/rg_eg_constraint_center_buffer',
    + 'BEAM0000/ancillary/rg_eg_mpfit_max_func_evals',
    + 'BEAM0000/ancillary/rg_eg_mpfit_maxiters',
    + 'BEAM0000/ancillary/rg_eg_mpfit_tolerance',
    + 'BEAM0000/ancillary/signal_search_buff',
    + 'BEAM0000/ancillary/tx_noise_stddev_multiplier',
    + 'BEAM0000/beam',
    + 'BEAM0000/channel',
    + 'BEAM0000/cover',
    + 'BEAM0000/cover_z',
    + 'BEAM0000/fhd_normal',
    + 'BEAM0000/geolocation/degrade_flag',
    + 'BEAM0000/geolocation/delta_time',
    + 'BEAM0000/geolocation/digital_elevation_model',
    + 'BEAM0000/geolocation/elev_highestreturn',
    + 'BEAM0000/geolocation/elev_lowestmode',
    + 'BEAM0000/geolocation/elevation_bin0',
    + 'BEAM0000/geolocation/elevation_bin0_error',
    + 'BEAM0000/geolocation/elevation_lastbin',
    + 'BEAM0000/geolocation/elevation_lastbin_error',
    + 'BEAM0000/geolocation/height_bin0',
    + 'BEAM0000/geolocation/height_lastbin',
    + 'BEAM0000/geolocation/lat_highestreturn',
    + 'BEAM0000/geolocation/lat_lowestmode',
    + 'BEAM0000/geolocation/latitude_bin0',
    + 'BEAM0000/geolocation/latitude_bin0_error']
    +
    +
    +
    +
    print('rh100: ', L2B['BEAM0101/rh100'].attrs['description'])
    +print('Quality Flag: ', L2B['BEAM0101/l2b_quality_flag'].attrs['description'])
    +
    +
    rh100:  Height above ground of the received waveform signal start (rh[101] from L2A)
    +Quality Flag:  Flag simpilfying selection of most useful data for Level 2B
    +
    +
    +

    View the GEDI L2B Dictionary for more details.

    +
    +
    +
    +

    4. Subset by Layer and Filter by Quality

    +
    +

    below are the list of datasets will be read and then used to generate a pandas dataframe.

    + +++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    LabelDescriptionUnits
    lat_lowestmodeLatitude of center of lowest modedegree
    lon_lowestmodeLongitude of center of lowest modedegree
    elev_lowestmodeelevation of center of lowest mode relative to reference ellipsoidm
    elev_highestreturnelevation of highest detected return relative to reference ellipsoidm
    shot_numberUnique shot IDcounter
    l2b_quality_flagFlag simpilfying selection of most useful data for Level 2B**-
    degrade_flagNon-zero values indicate the shot occured during a degraded period. A non-zero tens digit indicates degraded attitude, a non-zero ones digit indicates a degraded trajectory. 3X=ADF CHU solution unavailable (ST-2); 4X=Platform attitude; 5X=Poor solution (filter covariance large); 6X=Data outage (platform attitude gap also); 7X=ST 1+2 unavailable (similar boresight FOV); 8X=ST 1+2+3 unavailable; 9X=ST 1+2+3 and ISS unavailable; X1=Maneuver; X2=GPS data gap; X3=ST blinding; X4=Other; X5=GPS receiver clock drift; X6=X5+X1; X7=X5+X2; X8=X5+X3; X9=X5+X4-
    paiTotal plant area indexm2/m2
    rh100Height above ground of the received waveform signal start (rh[101] from L2A)cm
    digital_elevation_modelDigital elevation model height above the WGS84 ellipsoid. Interpolated at latitude_bin0 and longitude_bin0 from the TandemX 90m productm
    modis_nonvegetatedPercent non-vegetated from MODIS data. Interpolated at latitude_bin0 and longitude_bin0percent
    +

    ** quality_flag is a summation of several individual quality assessment parameters and other flags and is intended to provide general guidance only. A quality_flag value of 1 indicates the cover and vertical profile metrics represent the land surface and meet criteria based on waveform shot energy, sensitivity, amplitude, and real-time surface tracking quality, and the quality of extended Gaussian fitting to the lowest mode.

    +
    +
    
    +columns= ['Beam', 'Shot Number', 'Longitude', 'Latitude', 'Quality Flag', 'Canopy Elevation (m)',
    +          'Elevation (m)', 'Plant Area Index', 'Canopy Height/rh100 (cm)', 'Degrade Flag']
    +latslons_f1 = pandas.DataFrame(columns=columns)
    +
    +beamNames = ['BEAM0000', 'BEAM0001', 'BEAM0010', 'BEAM0011', 'BEAM0101', 'BEAM0110',  'BEAM1000', 'BEAM1011' ]
    +for beamname in beamNames:
    +    # Open the SDS
    +    lats = L2B[f'{beamname}/geolocation/lat_lowestmode'][()]
    +    lons = L2B[f'{beamname}/geolocation/lon_lowestmode'][()]
    +    elevs = L2B[f'{beamname}/geolocation/elev_lowestmode'][()]
    +    shots = L2B[f'{beamname}/geolocation/shot_number'][()].astype(str)
    +    quality = L2B[f'{beamname}/l2b_quality_flag'][()]
    +    pai = L2B[f'{beamname}/pai'][()]
    +    rh100 = L2B[f'{beamname}/rh100'][()]
    +    degrade_flag = L2B[f'{beamname}/geolocation/degrade_flag'][()] 
    +    canopy = L2B[f'{beamname}/geolocation/elev_highestreturn'][()]
    +
    +    latslons = pandas.DataFrame({'Beam':beamname, 'Shot Number':shots, 'Longitude':lons, 'Latitude':lats, 'Quality Flag':quality,
    +                                 'Canopy Elevation (m)':canopy, 'Elevation (m)':elevs, 'Plant Area Index':pai, 
    +                                 'Canopy Height/rh100 (cm)':rh100, 'Degrade Flag':degrade_flag}) 
    +        
    +
    +    latslons_f1 = pandas.concat([latslons_f1, latslons],join="inner")
    +    
    +    
    +latslons_f1
    +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    BeamShot NumberLongitudeLatitudeQuality FlagCanopy Elevation (m)Elevation (m)Plant Area IndexCanopy Height/rh100 (cm)Degrade Flag
    0BEAM0000196830000300204328-150.40707951.48031103148.3305663148.330566-9999.0080
    1BEAM0000196830000300204329-150.40667451.48027103148.3068853148.306885-9999.0080
    2BEAM0000196830000300204330-150.40626851.48023103148.2829593148.282959-9999.0080
    3BEAM0000196830000300204331-150.40586251.48019103148.8547363148.854736-9999.0080
    4BEAM0000196830000300204332-150.40545751.48015103148.2348633148.234863-9999.0080
    .................................
    152101BEAM1011196831100300353743-77.4939290.4241500-59.045544-59.045544-9999.000
    152102BEAM1011196831100300353744-77.4936310.4237300-59.179871-59.179871-9999.000
    152103BEAM1011196831100300353745-77.4933320.4233100-58.958637-58.958637-9999.000
    152104BEAM1011196831100300353746-77.4930340.4228910-59.209381-59.209381-9999.000
    152105BEAM1011196831100300353747-77.4927350.4224700-58.726070-58.726070-9999.000
    + +

    1233557 rows × 10 columns

    +
    +
    +
    +

    We can generate the data frame for all GEDI granules intersecting our region of interest.

    +
    +
    columns= ['Date', 'Beam', 'Shot Number', 'Longitude', 'Latitude', 'Quality Flag', 
    +          'Canopy Elevation (m)','Elevation (m)', 'Plant Area Index', 'Canopy Height/rh100 (cm)' , 'Degrade Flag']
    +
    +latslons_all = pandas.DataFrame(columns=columns)
    +
    +for f in gediFiles:
    +    print(f)
    +    date_str = f.rsplit('_')[2]
    +    date = datetime.strptime(date_str, '%Y%j%H%M%S').date().strftime("%m-%d-%Y") 
    +    L2B = h5py.File(f'{data_dir}{f}', 'r')  # Read file using h5py
    +    for beamname in beamNames:
    +        # Open the SDS
    +        lats = L2B[f'{beamname}/geolocation/lat_lowestmode'][()]
    +        lons = L2B[f'{beamname}/geolocation/lon_lowestmode'][()]
    +        elevs = L2B[f'{beamname}/geolocation/elev_lowestmode'][()]
    +        shots = L2B[f'{beamname}/geolocation/shot_number'][()].astype(str)
    +        quality = L2B[f'{beamname}/l2b_quality_flag'][()]
    +        pai = L2B[f'{beamname}/pai'][()]
    +        rh100 = L2B[f'{beamname}/rh100'][()]
    +        degrade_flag = L2B[f'{beamname}/geolocation/degrade_flag'][()] 
    +        canopy = L2B[f'{beamname}/geolocation/elev_highestreturn'][()]
    +
    +        latslons = pandas.DataFrame({'Date': date ,'Beam':beamname, 'Shot Number':shots, 'Longitude':lons, 'Latitude':lats, 'Quality Flag':quality,
    +                                     'Canopy Elevation (m)':canopy, 'Elevation (m)':elevs, 'Plant Area Index':pai, 
    +                                     'Canopy Height/rh100 (cm)':rh100, 'Degrade Flag':degrade_flag}) 
    +
    +
    +        latslons_all = pandas.concat([latslons_all, latslons],join="inner")
    +
    +del(lats, lons, elevs, shots, quality, pai, rh100, degrade_flag, canopy, latslons)
    +
    +
    GEDI02_B_2022155015315_O19683_03_T05652_02_003_01_V002.h5
    +GEDI02_B_2022159001702_O19744_03_T08957_02_003_01_V002.h5
    +GEDI02_B_2022158145957_O19738_02_T03565_02_003_01_V002.h5
    +GEDI02_B_2022154163608_O19677_02_T01836_02_003_01_V002.h5
    +GEDI02_B_2022162224038_O19805_03_T06723_02_003_02_V002.h5
    +
    +
    +
    +
    +
    +

    Create a list of geodataframe columns to be included as attributes in the output map

    +

    Plotting the entire sub-orbit for all granules will take a long time, and might include information that we do not need necessarily. So lets make a subset of data to only keep the data we need.

    +
    +

    below, the shots that occured during a degraded period and low quality are removed from the dataframe.

    +
    +
    latslons_all  = latslons_all [latslons_all ['Degrade Flag'] == 0].drop(columns = 'Degrade Flag') 
    +latslons_all = latslons_all [latslons_all['Quality Flag'] == 1].drop(columns = 'Quality Flag') 
    + 
    +
    +
    +
    latslons_all
    +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    DateBeamShot NumberLongitudeLatitudeCanopy Elevation (m)Elevation (m)Plant Area IndexCanopy Height/rh100 (cm)
    10544706-04-2022BEAM0000196830000300309775-92.33507120.843354-12.388881-14.9579010.320302255
    10544806-04-2022BEAM0000196830000300309776-92.33473620.842946-12.912969-15.5564540.318079264
    10545406-04-2022BEAM0000196830000300309782-92.33273620.840486-12.179410-15.5675410.409812338
    10545906-04-2022BEAM0000196830000300309787-92.33107320.838435-14.535298-16.8809300.267779233
    10546106-04-2022BEAM0000196830000300309789-92.33040520.837615-13.029422-15.3005900.184147226
    ..............................
    14605706-11-2022BEAM1011198051100300346228-78.3560994.28639112.79817710.1157040.079636268
    14605806-11-2022BEAM1011198051100300346229-78.3558014.28596913.22476810.0952150.269218311
    14605906-11-2022BEAM1011198051100300346230-78.3555034.28554713.37408111.3249690.015392203
    15061406-11-2022BEAM1011198051100300350785-76.9841062.3470541283.8328861276.0462650.723939778
    15061506-11-2022BEAM1011198051100300350786-76.9838132.3466511271.4229741256.0358892.6416451538
    + +

    404288 rows × 9 columns

    +
    +
    +
    +
    +
    # reset the index and drop the NAs
    +latslons_all = latslons_all.dropna() 
    +latslons_all = latslons_all.reset_index(drop=True)
    +latslons_all
    +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    DateBeamShot NumberLongitudeLatitudeCanopy Elevation (m)Elevation (m)Plant Area IndexCanopy Height/rh100 (cm)
    006-04-2022BEAM0000196830000300309775-92.33507120.843354-12.388881-14.9579010.320302255
    106-04-2022BEAM0000196830000300309776-92.33473620.842946-12.912969-15.5564540.318079264
    206-04-2022BEAM0000196830000300309782-92.33273620.840486-12.179410-15.5675410.409812338
    306-04-2022BEAM0000196830000300309787-92.33107320.838435-14.535298-16.8809300.267779233
    406-04-2022BEAM0000196830000300309789-92.33040520.837615-13.029422-15.3005900.184147226
    ..............................
    40428306-11-2022BEAM1011198051100300346228-78.3560994.28639112.79817710.1157040.079636268
    40428406-11-2022BEAM1011198051100300346229-78.3558014.28596913.22476810.0952150.269218311
    40428506-11-2022BEAM1011198051100300346230-78.3555034.28554713.37408111.3249690.015392203
    40428606-11-2022BEAM1011198051100300350785-76.9841062.3470541283.8328861276.0462650.723939778
    40428706-11-2022BEAM1011198051100300350786-76.9838132.3466511271.4229741256.0358892.6416451538
    + +

    404288 rows × 9 columns

    +
    +
    +
    +
    +
    +

    5. Create a Geodataframe and Subset Spatially

    +
    +

    Below, an additional column is created and called ‘geometry’ that contains a shapely point generated from each lat/lon location from the shot is created. Next, the dataframe is converted to a Geopandas GeoDataFrame.

    +
    +
    # Take the lat/lon dataframe and convert each lat/lon to a shapely point and convert to a Geodataframe
    +latslons_all = geopandas.GeoDataFrame(latslons_all, geometry=latslons_all.apply(lambda row: Point(row.Longitude, row.Latitude), axis=1))
    +latslons_all = latslons_all.set_crs('EPSG:4326')
    +
    +
    +
    +

    Import a GeoJSON of a section of Reserva de la Biósfera de Calakmul National Forest as an additional GeoDataFrame.

    +
    +
    ROI = geopandas.GeoDataFrame.from_file(f'{data_dir}calakmul.geojson')
    +ROI.crs = 'EPSG:4326'
    +
    +
    +
    ROI['geometry'][0]
    +
    +

    +
    +
    +
    +
    +

    Next, filter the shots that are within the ROI boundaries.

    +
    +
    shot_list = []
    +for num, geom in enumerate(latslons_all['geometry']):
    +    if ROI.contains(geom)[0]:
    +        shot_n = latslons_all.loc[num, 'Shot Number']
    +        shot_list.append(shot_n)
    +
    +
    +
    DF = latslons_all.where(latslons_all['Shot Number'].isin(shot_list))
    +DF = DF.reset_index(drop=True).dropna()
    +
    +
    +
    DF
    +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    DateBeamShot NumberLongitudeLatitudeCanopy Elevation (m)Elevation (m)Plant Area IndexCanopy Height/rh100 (cm)geometry
    70406-04-2022BEAM0000196830000300314188-90.88250118.994573-1.029900-4.9436800.099078391POINT (-90.88250 18.99457)
    70506-04-2022BEAM0000196830000300314189-90.88221718.9941371.437216-4.3402710.254931576POINT (-90.88222 18.99414)
    70606-04-2022BEAM0000196830000300314190-90.88193418.993701-0.111586-4.5472070.081328442POINT (-90.88193 18.99370)
    70706-04-2022BEAM0000196830000300314191-90.88165118.9932650.287704-4.4088360.100879469POINT (-90.88165 18.99326)
    70806-04-2022BEAM0000196830000300314192-90.88136718.9928270.891814-3.6183570.039722451POINT (-90.88137 18.99283)
    .................................
    40227306-11-2022BEAM1011198051100300312342-89.00152318.442686169.125259150.5703582.7205621854POINT (-89.00152 18.44269)
    40227406-11-2022BEAM1011198051100300312343-89.00119018.442281154.575348149.3218540.006572525POINT (-89.00119 18.44228)
    40227506-11-2022BEAM1011198051100300312344-89.00085718.441875154.223221148.8579410.101806536POINT (-89.00086 18.44187)
    40227606-11-2022BEAM1011198051100300312345-89.00052618.441474157.639175142.8101504.1595291481POINT (-89.00053 18.44147)
    40227706-11-2022BEAM1011198051100300312346-89.00019118.441063153.560394147.8598020.053789569POINT (-89.00019 18.44106)
    + +

    26126 rows × 10 columns

    +
    +
    +
    +
    +
    All_DF = geopandas.GeoDataFrame(DF).drop(columns=['Longitude', 'Latitude'])
    +
    +
    +
    +
    +

    6. Visualize a GeoDataFrame

    +
    +

    In this section, the GeoDataFrame and the geoviews python package are used to spatially visualize the location of the GEDI shots on a basemap layer and import a GeoJSON file of the spatial region of interest for this use case example.

    +
    +
    +

    Defining the vdims below will allow you to hover over specific shots and view information about them.

    +
    +
    # Create a list of geodataframe columns to be included as attributes in the output map
    +vdims = []
    +for f in All_DF:
    +    if f not in ['geometry']:
    +        vdims.append(f)
    +
    +vdims
    +
    +
    ['Date',
    + 'Beam',
    + 'Shot Number',
    + 'Canopy Elevation (m)',
    + 'Elevation (m)',
    + 'Plant Area Index',
    + 'Canopy Height/rh100 (cm)']
    +
    +
    +
    +
    # Define a function for visualizing GEDI points
    +def pointVisual(features, vdims):
    +    return (gvts.EsriImagery * geoviews.Points(features, vdims=vdims).options(tools=['hover'], height=500, width=900, size=4, 
    +                                                                        color='yellow', fontsize={'xticks': 10, 'yticks': 10, 
    +                                                                                                  'xlabel':16, 'ylabel': 16}))
    +# Visualize GEDI data
    +geoviews.Polygons(ROI['geometry']).opts(line_color='red', color=None)* pointVisual(All_DF, vdims = vdims)
    +
    + +
    +
    +
    +
    +
    + +
    +
    +
    +
    +

    Below, the shots are mapped to enable selection of datasets using dropdown menu to better visualize the spatial variations for each dataset.

    +
    +
    import panel 
    +panel.extension()
    +
    +mask_name = panel.widgets.Select(name='Datasets',options=vdims, value='Elevation (m)', disabled_options=['Beam', 'Shot Number', 'Date'])
    +
    + +
    +
    + +
    +
    + +
    +
    +
    +
    @panel.depends(mask_name)
    +def visual_map(mask_name):
    +    map = (gvts.EsriImagery * geoviews.Points(All_DF,
    +                                              vdims=vdims).options(color=mask_name,
    +                                                                   cmap='gnuplot', size=4, tools=['hover'],
    +                                                                   clim=(int(min(DF[mask_name])), 
    +                                                                         round(max(DF[mask_name]))),
    +                                                                   colorbar=True, 
    +                                                                   title=f'{mask_name} (Calakmul National Forest): 2022',
    +                                                                   fontsize={'xticks': 10, 'yticks': 10, 'xlabel':16, 'clabel':12,
    +                                                                             'cticks':10,'title':10,
    +                                                                             'ylabel':16})).options(height=500,width=700)
    +    return map 
    +
    +panel.Row(panel.WidgetBox(mask_name), visual_map)
    +
    + +
    +
    + +
    +
    +
    +
    +
    + +
    +
    +
    +
    +
    +

    7. Export Subsets as GeoJSON Files

    +
    +

    Finally, export the GeoDataFrame as a .geojson file that can be easily opened in your favorite remote sensing and/or GIS software and will include an attribute table with all of the shots/values for each of the SDS layers in the dataframe.

    +
    +
    outName = f'{data_dir}GEDI02_B_Calakmul.geojson'    # Create an output file name using the input file name
    +print(outName)
    +All_DF.to_file(outName, driver='GeoJSON')  # Export to GeoJSON
    +
    +
    /home/jovyan/shared/2023SSC/GEDI02_B_Calakmul.geojson
    +
    +
    +
    +
    + +
    +

    Contact Info:

    +

    Email: LPDAAC@usgs.gov
    +Voice: +1-866-573-3222
    +Organization: Land Processes Distributed Active Archive Center (LP DAAC)¹
    +Website: https://lpdaac.usgs.gov/
    +Date last modified: 11-15-2023

    +

    ¹Work performed under USGS contract G15PD00467 for NASA contract NNG14HH33I.

    + + +
    +
    + +
    + + +
    + + + + + \ No newline at end of file diff --git a/tutorials/GEDI_data_SSC23_files/figure-html/cell-22-output-1.svg b/tutorials/GEDI_data_SSC23_files/figure-html/cell-22-output-1.svg new file mode 100644 index 0000000..8b4f3f0 --- /dev/null +++ b/tutorials/GEDI_data_SSC23_files/figure-html/cell-22-output-1.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/tutorials/cloud/cloud-paradigm.html b/tutorials/cloud/cloud-paradigm.html index 6434205..a4c62a1 100644 --- a/tutorials/cloud/cloud-paradigm.html +++ b/tutorials/cloud/cloud-paradigm.html @@ -124,7 +124,7 @@ Programmatic Access
  • - + Icepyx
  • @@ -132,6 +132,10 @@
  • Overview +
  • +
  • + + GEDI Level 2B V002 Data
  • @@ -244,7 +248,7 @@ @@ -264,6 +268,12 @@ Overview + + diff --git a/tutorials/cloud/index.html b/tutorials/cloud/index.html index 368dc4c..3ca9304 100644 --- a/tutorials/cloud/index.html +++ b/tutorials/cloud/index.html @@ -124,7 +124,7 @@ Programmatic Access
  • - + Icepyx
  • @@ -132,6 +132,10 @@
  • Overview +
  • +
  • + + GEDI Level 2B V002 Data
  • @@ -244,7 +248,7 @@ @@ -264,6 +268,12 @@ Overview + + diff --git a/tutorials/data-access/.images/ATL08_photon_classification_example.jpg b/tutorials/data-access/.images/ATL08_photon_classification_example.jpg deleted file mode 100644 index 679831f..0000000 Binary files a/tutorials/data-access/.images/ATL08_photon_classification_example.jpg and /dev/null differ diff --git a/tutorials/data-access/earthaccess.html b/tutorials/data-access/earthaccess.html index 068ece7..c4c21fb 100644 --- a/tutorials/data-access/earthaccess.html +++ b/tutorials/data-access/earthaccess.html @@ -30,7 +30,7 @@ - + @@ -124,7 +124,7 @@ Programmatic Access
  • - + Icepyx
  • @@ -132,6 +132,10 @@
  • Overview +
  • +
  • + + GEDI Level 2B V002 Data
  • @@ -244,7 +248,7 @@ @@ -264,6 +268,12 @@ Overview + + @@ -639,7 +649,7 @@ diff --git a/tutorials/data-access/earthdata-search.html b/tutorials/data-access/earthdata-search.html index 63c8141..80f9889 100644 --- a/tutorials/data-access/earthdata-search.html +++ b/tutorials/data-access/earthdata-search.html @@ -124,7 +124,7 @@ Programmatic Access
  • - + Icepyx
  • @@ -132,6 +132,10 @@
  • Overview +
  • +
  • + + GEDI Level 2B V002 Data
  • @@ -244,7 +248,7 @@ @@ -264,6 +268,12 @@ Overview + + diff --git a/tutorials/data-access/icepyx.html b/tutorials/data-access/icepyx.html index a11f354..03eaaa3 100644 --- a/tutorials/data-access/icepyx.html +++ b/tutorials/data-access/icepyx.html @@ -7,7 +7,7 @@ -2023 GEDI/ICESAT-2 Workshop - Using icepyx to access Icesat-2 data +2023 GEDI/ICESAT-2 Workshop – icepyx @@ -64,6 +30,8 @@ + + @@ -85,3030 +53,245 @@ "language": { "search-no-results-text": "No results", "search-matching-documents-text": "matching documents", - "search-copy-link-title": "Copy link to search", - "search-hide-matches-text": "Hide additional matches", - "search-more-match-text": "more match in this document", - "search-more-matches-text": "more matches in this document", - "search-clear-button-title": "Clear", - "search-detached-cancel-button-title": "Cancel", - "search-submit-button-title": "Submit", - "search-label": "Search" - } -} - - - - - - - - - - -
    -
    - - -
    - -
    - - -
    - - - -
    - -
    -
    -

    Using icepyx to access Icesat-2 data

    -
    - - - -
    - - - - -
    - - -
    - -
    -
    !pip install icepyx==0.8.1 -qq
    -
    -
    -

    What is Icesat-2?

    -
    -
    -

    -
    IS2
    -
    -
    -

    Icesat-2 is a satellite lidar instrument. Lidar is an active remote sensing instrument in which pulses of light are emitted and the return time is used to mesure distance. The available Icesat-2 data products range from sea ice freeboard to land elevation to cloud backscatter characteristics. A list of availble products can be found here. In this tutorial we will look at ATL08 Land Water Vegetation Elevation.

    -
    -

    Data Collection

    -

    Icesat-2 measures data along 6 different beams: 3 strong beams and 3 weak beams. The strong and weak beams are calibrated such that the weak beams have more sensitivity to viewing very bright surfaces (Ex. ice), which the strong beams are able to view surfaces with lower reflectances (Ex. water). The beams are called gt1l, gt1r, gt2l, gt2r, gt3l, and gt3r, where the l and r denotes whether the beam was strong or weak.

    -

    Jessica which one (l/r) is which? Or is this is what spot is for?

    -
    -
    -

    -
    Tracks
    -
    -
    -

    Photo: Neuenschwander et. al. 2019, Remote Sens. Env. DOI

    -
    -
    -

    Counting Photons

    -

    The Icesat-2 lidar collects at the single photon level, different from most commercial lidar systems. A lot of additional photons get returned as solar background noise, and removing these unwanted photons is a key part of the algorithms that produce the higher level data products.

    -

    dragon algorithm image Photo: Neuenschwander et. al. 2019, Remote Sens. Env. DOI

    -

    To aggregate all these photons into more manegable chunks ATL08 consolidates the photons into 100m segments, each made up of five 20m segments.

    -
    -
    -
    -

    What is icepyx?

    -

    -

    icepyx is a community built library for searching, downloading, and reading Icesat-2 data. While opening data should be straightforward, there are some oddities in navigating the organization of the Icesat-2 data. icepyx provides tools to help with those oddities.

    -
    -

    Fitting icepyx into the data access package landscape

    -

    For Icesat-2 data, the icepyx package can: - search for available data granules (data files) - order and download data - order a subset of data: either clipped in space or containing fewer variables - provides functionality to search through the available data variables - read Icesat-2 data into xarray DataArrays, including merging data from multiple files

    -
    -
    -

    Using icepyx to search for data

    -

    We won’t dive into using icepyx to search for and download data in this tutorial, since we already discussed how to do that with earthaccess. The code to search and download is still provided below for the curious reader. The icepyx documentation shows more detail about different search parameters and how to inspect the results of a query.

    -
    -
    import icepyx as ipx
    -
    - - -
    -
    - -
    -
    - -
    -
    - -
    - - - - - - - - - -
    -
    -
    -
    -
    ipx.__version__
    -
    -

    Jessica does icepyx search by roi?

    -
    -
    import json
    -from shapely.geometry import shape, GeometryCollection
    -
    -with open("bosque_primavera.json") as f:
    -    features = json.load(f)["features"]
    -
    -# NOTE: buffer(0) is a trick for fixing scenarios where polygons have overlapping coordinates 
    -bosque = GeometryCollection([shape(feature["geometry"]).buffer(0) for feature in features])
    -
    -
    -
    spatial_extent = list(bosque.bounds)
    -
    -
    -
    short_name = 'ATL08'
    -date_range = ['2019-05-04','2019-05-04']
    -region = ipx.Query(short_name, spatial_extent, date_range)
    -
    -
    -
    region.avail_granules(ids=True)
    -
    -
    -
    # Download the granules to a into a folder called 'download'
    -region.download_granules('./bosque_primavera_ATL08')
    -
    -
    -Tip: If you don’t want to type your earthdata login information everytime it is required there are alternate methods for authenticating. Two common methods are 1) Add your earthdata password and username to as environment variables as EARTHDATA_LOGIN and EARTHDATA_PASSWORD. 2) setup a .netrc file in your home directory. See: https://nasa-openscapes.github.io/2021-Cloud-Hackathon/tutorials/04_NASA_Earthdata_Authentication.html -
    -
    -
    -
    -

    Reading a file with icepyx

    -

    To read a file with icepyx there are several steps: 1. Create a Read object. This sets up an initial connection to your file(s) and validates the metadata. 2. Tell the Read object what variables you would like to read 3. Load your data!

    -
    -

    Create a Read object

    -
    -
    pattern = "processed_ATL{product:2}_{datetime:%Y%m%d%H%M%S}_{rgt:4}{cycle:2}{orbitsegment:2}_{version:3}_{revision:2}.h5"
    -reader = ipx.Read('./bosque_primavera_ATL08', "ATL08", pattern)
    -
    -
    You have 1 files matching the filename pattern to be read in.
    -
    -
    -
    -
    reader
    -
    -
    <icepyx.core.read.Read at 0x7f58011d1b70>
    -
    -
    -
    -
    -

    Select your variables

    -

    To view the variables contained in your dataset you can call .vars on your data reader.

    -
    -
    reader.vars.avail()
    -
    -
    ['ancillary_data/atlas_sdp_gps_epoch',
    - 'ancillary_data/control',
    - 'ancillary_data/data_end_utc',
    - 'ancillary_data/data_start_utc',
    - 'ancillary_data/end_cycle',
    - 'ancillary_data/end_delta_time',
    - 'ancillary_data/end_geoseg',
    - 'ancillary_data/end_gpssow',
    - 'ancillary_data/end_gpsweek',
    - 'ancillary_data/end_orbit',
    - 'ancillary_data/end_region',
    - 'ancillary_data/end_rgt',
    - 'ancillary_data/granule_end_utc',
    - 'ancillary_data/granule_start_utc',
    - 'ancillary_data/land/atl08_region',
    - 'ancillary_data/land/bin_size_h',
    - 'ancillary_data/land/bin_size_n',
    - 'ancillary_data/land/bright_thresh',
    - 'ancillary_data/land/ca_class',
    - 'ancillary_data/land/can_noise_thresh',
    - 'ancillary_data/land/can_stat_thresh',
    - 'ancillary_data/land/canopy20m_thresh',
    - 'ancillary_data/land/canopy_flag_switch',
    - 'ancillary_data/land/canopy_seg',
    - 'ancillary_data/land/class_thresh',
    - 'ancillary_data/land/cloud_filter_switch',
    - 'ancillary_data/land/del_amp',
    - 'ancillary_data/land/del_mu',
    - 'ancillary_data/land/del_sigma',
    - 'ancillary_data/land/dem_filter_switch',
    - 'ancillary_data/land/dem_removal_percent_limit',
    - 'ancillary_data/land/dragann_switch',
    - 'ancillary_data/land/dseg',
    - 'ancillary_data/land/dseg_buf',
    - 'ancillary_data/land/fnlgnd_filter_switch',
    - 'ancillary_data/land/gnd_stat_thresh',
    - 'ancillary_data/land/gthresh_factor',
    - 'ancillary_data/land/h_canopy_perc',
    - 'ancillary_data/land/iter_gnd',
    - 'ancillary_data/land/iter_max',
    - 'ancillary_data/land/lseg',
    - 'ancillary_data/land/lseg_buf',
    - 'ancillary_data/land/lw_filt_bnd',
    - 'ancillary_data/land/lw_gnd_bnd',
    - 'ancillary_data/land/lw_toc_bnd',
    - 'ancillary_data/land/lw_toc_cut',
    - 'ancillary_data/land/max_atl03files',
    - 'ancillary_data/land/max_atl09files',
    - 'ancillary_data/land/max_peaks',
    - 'ancillary_data/land/max_try',
    - 'ancillary_data/land/min_nphs',
    - 'ancillary_data/land/n_dec_mode',
    - 'ancillary_data/land/night_thresh',
    - 'ancillary_data/land/noise_class',
    - 'ancillary_data/land/outlier_filter_switch',
    - 'ancillary_data/land/p_static',
    - 'ancillary_data/land/ph_removal_percent_limit',
    - 'ancillary_data/land/proc_geoseg',
    - 'ancillary_data/land/psf',
    - 'ancillary_data/land/ref_dem_limit',
    - 'ancillary_data/land/ref_finalground_limit',
    - 'ancillary_data/land/relief_hbot',
    - 'ancillary_data/land/relief_htop',
    - 'ancillary_data/land/shp_param',
    - 'ancillary_data/land/sig_rsq_search',
    - 'ancillary_data/land/sseg',
    - 'ancillary_data/land/stat20m_thresh',
    - 'ancillary_data/land/stat_thresh',
    - 'ancillary_data/land/tc_thresh',
    - 'ancillary_data/land/te_class',
    - 'ancillary_data/land/terrain20m_thresh',
    - 'ancillary_data/land/toc_class',
    - 'ancillary_data/land/up_filt_bnd',
    - 'ancillary_data/land/up_gnd_bnd',
    - 'ancillary_data/land/up_toc_bnd',
    - 'ancillary_data/land/up_toc_cut',
    - 'ancillary_data/land/yapc_switch',
    - 'ancillary_data/qa_at_interval',
    - 'ancillary_data/release',
    - 'ancillary_data/start_cycle',
    - 'ancillary_data/start_delta_time',
    - 'ancillary_data/start_geoseg',
    - 'ancillary_data/start_gpssow',
    - 'ancillary_data/start_gpsweek',
    - 'ancillary_data/start_orbit',
    - 'ancillary_data/start_region',
    - 'ancillary_data/start_rgt',
    - 'ancillary_data/version',
    - 'ds_geosegments',
    - 'ds_metrics',
    - 'ds_surf_type',
    - 'gt3l/land_segments/asr',
    - 'gt3l/land_segments/atlas_pa',
    - 'gt3l/land_segments/beam_azimuth',
    - 'gt3l/land_segments/beam_coelev',
    - 'gt3l/land_segments/brightness_flag',
    - 'gt3l/land_segments/canopy/can_noise',
    - 'gt3l/land_segments/canopy/canopy_h_metrics',
    - 'gt3l/land_segments/canopy/canopy_h_metrics_abs',
    - 'gt3l/land_segments/canopy/canopy_openness',
    - 'gt3l/land_segments/canopy/canopy_rh_conf',
    - 'gt3l/land_segments/canopy/centroid_height',
    - 'gt3l/land_segments/canopy/h_canopy',
    - 'gt3l/land_segments/canopy/h_canopy_20m',
    - 'gt3l/land_segments/canopy/h_canopy_abs',
    - 'gt3l/land_segments/canopy/h_canopy_quad',
    - 'gt3l/land_segments/canopy/h_canopy_uncertainty',
    - 'gt3l/land_segments/canopy/h_dif_canopy',
    - 'gt3l/land_segments/canopy/h_max_canopy',
    - 'gt3l/land_segments/canopy/h_max_canopy_abs',
    - 'gt3l/land_segments/canopy/h_mean_canopy',
    - 'gt3l/land_segments/canopy/h_mean_canopy_abs',
    - 'gt3l/land_segments/canopy/h_median_canopy',
    - 'gt3l/land_segments/canopy/h_median_canopy_abs',
    - 'gt3l/land_segments/canopy/h_min_canopy',
    - 'gt3l/land_segments/canopy/h_min_canopy_abs',
    - 'gt3l/land_segments/canopy/n_ca_photons',
    - 'gt3l/land_segments/canopy/n_toc_photons',
    - 'gt3l/land_segments/canopy/photon_rate_can',
    - 'gt3l/land_segments/canopy/photon_rate_can_nr',
    - 'gt3l/land_segments/canopy/segment_cover',
    - 'gt3l/land_segments/canopy/subset_can_flag',
    - 'gt3l/land_segments/canopy/toc_roughness',
    - 'gt3l/land_segments/cloud_flag_atm',
    - 'gt3l/land_segments/cloud_fold_flag',
    - 'gt3l/land_segments/delta_time',
    - 'gt3l/land_segments/delta_time_beg',
    - 'gt3l/land_segments/delta_time_end',
    - 'gt3l/land_segments/dem_flag',
    - 'gt3l/land_segments/dem_h',
    - 'gt3l/land_segments/dem_removal_flag',
    - 'gt3l/land_segments/h_dif_ref',
    - 'gt3l/land_segments/last_seg_extend',
    - 'gt3l/land_segments/latitude',
    - 'gt3l/land_segments/latitude_20m',
    - 'gt3l/land_segments/layer_flag',
    - 'gt3l/land_segments/longitude',
    - 'gt3l/land_segments/longitude_20m',
    - 'gt3l/land_segments/msw_flag',
    - 'gt3l/land_segments/n_seg_ph',
    - 'gt3l/land_segments/night_flag',
    - 'gt3l/land_segments/ph_ndx_beg',
    - 'gt3l/land_segments/ph_removal_flag',
    - 'gt3l/land_segments/psf_flag',
    - 'gt3l/land_segments/rgt',
    - 'gt3l/land_segments/sat_flag',
    - 'gt3l/land_segments/segment_id_beg',
    - 'gt3l/land_segments/segment_id_end',
    - 'gt3l/land_segments/segment_landcover',
    - 'gt3l/land_segments/segment_snowcover',
    - 'gt3l/land_segments/segment_watermask',
    - 'gt3l/land_segments/sigma_across',
    - 'gt3l/land_segments/sigma_along',
    - 'gt3l/land_segments/sigma_atlas_land',
    - 'gt3l/land_segments/sigma_h',
    - 'gt3l/land_segments/sigma_topo',
    - 'gt3l/land_segments/snr',
    - 'gt3l/land_segments/solar_azimuth',
    - 'gt3l/land_segments/solar_elevation',
    - 'gt3l/land_segments/surf_type',
    - 'gt3l/land_segments/terrain/h_te_best_fit',
    - 'gt3l/land_segments/terrain/h_te_best_fit_20m',
    - 'gt3l/land_segments/terrain/h_te_interp',
    - 'gt3l/land_segments/terrain/h_te_max',
    - 'gt3l/land_segments/terrain/h_te_mean',
    - 'gt3l/land_segments/terrain/h_te_median',
    - 'gt3l/land_segments/terrain/h_te_min',
    - 'gt3l/land_segments/terrain/h_te_mode',
    - 'gt3l/land_segments/terrain/h_te_rh25',
    - 'gt3l/land_segments/terrain/h_te_skew',
    - 'gt3l/land_segments/terrain/h_te_std',
    - 'gt3l/land_segments/terrain/h_te_uncertainty',
    - 'gt3l/land_segments/terrain/n_te_photons',
    - 'gt3l/land_segments/terrain/photon_rate_te',
    - 'gt3l/land_segments/terrain/subset_te_flag',
    - 'gt3l/land_segments/terrain/terrain_slope',
    - 'gt3l/land_segments/terrain_flg',
    - 'gt3l/land_segments/urban_flag',
    - 'gt3l/signal_photons/classed_pc_flag',
    - 'gt3l/signal_photons/classed_pc_indx',
    - 'gt3l/signal_photons/d_flag',
    - 'gt3l/signal_photons/delta_time',
    - 'gt3l/signal_photons/ph_h',
    - 'gt3l/signal_photons/ph_segment_id',
    - 'gt3r/land_segments/asr',
    - 'gt3r/land_segments/atlas_pa',
    - 'gt3r/land_segments/beam_azimuth',
    - 'gt3r/land_segments/beam_coelev',
    - 'gt3r/land_segments/brightness_flag',
    - 'gt3r/land_segments/canopy/can_noise',
    - 'gt3r/land_segments/canopy/canopy_h_metrics',
    - 'gt3r/land_segments/canopy/canopy_h_metrics_abs',
    - 'gt3r/land_segments/canopy/canopy_openness',
    - 'gt3r/land_segments/canopy/canopy_rh_conf',
    - 'gt3r/land_segments/canopy/centroid_height',
    - 'gt3r/land_segments/canopy/h_canopy',
    - 'gt3r/land_segments/canopy/h_canopy_20m',
    - 'gt3r/land_segments/canopy/h_canopy_abs',
    - 'gt3r/land_segments/canopy/h_canopy_quad',
    - 'gt3r/land_segments/canopy/h_canopy_uncertainty',
    - 'gt3r/land_segments/canopy/h_dif_canopy',
    - 'gt3r/land_segments/canopy/h_max_canopy',
    - 'gt3r/land_segments/canopy/h_max_canopy_abs',
    - 'gt3r/land_segments/canopy/h_mean_canopy',
    - 'gt3r/land_segments/canopy/h_mean_canopy_abs',
    - 'gt3r/land_segments/canopy/h_median_canopy',
    - 'gt3r/land_segments/canopy/h_median_canopy_abs',
    - 'gt3r/land_segments/canopy/h_min_canopy',
    - 'gt3r/land_segments/canopy/h_min_canopy_abs',
    - 'gt3r/land_segments/canopy/n_ca_photons',
    - 'gt3r/land_segments/canopy/n_toc_photons',
    - 'gt3r/land_segments/canopy/photon_rate_can',
    - 'gt3r/land_segments/canopy/photon_rate_can_nr',
    - 'gt3r/land_segments/canopy/segment_cover',
    - 'gt3r/land_segments/canopy/subset_can_flag',
    - 'gt3r/land_segments/canopy/toc_roughness',
    - 'gt3r/land_segments/cloud_flag_atm',
    - 'gt3r/land_segments/cloud_fold_flag',
    - 'gt3r/land_segments/delta_time',
    - 'gt3r/land_segments/delta_time_beg',
    - 'gt3r/land_segments/delta_time_end',
    - 'gt3r/land_segments/dem_flag',
    - 'gt3r/land_segments/dem_h',
    - 'gt3r/land_segments/dem_removal_flag',
    - 'gt3r/land_segments/h_dif_ref',
    - 'gt3r/land_segments/last_seg_extend',
    - 'gt3r/land_segments/latitude',
    - 'gt3r/land_segments/latitude_20m',
    - 'gt3r/land_segments/layer_flag',
    - 'gt3r/land_segments/longitude',
    - 'gt3r/land_segments/longitude_20m',
    - 'gt3r/land_segments/msw_flag',
    - 'gt3r/land_segments/n_seg_ph',
    - 'gt3r/land_segments/night_flag',
    - 'gt3r/land_segments/ph_ndx_beg',
    - 'gt3r/land_segments/ph_removal_flag',
    - 'gt3r/land_segments/psf_flag',
    - 'gt3r/land_segments/rgt',
    - 'gt3r/land_segments/sat_flag',
    - 'gt3r/land_segments/segment_id_beg',
    - 'gt3r/land_segments/segment_id_end',
    - 'gt3r/land_segments/segment_landcover',
    - 'gt3r/land_segments/segment_snowcover',
    - 'gt3r/land_segments/segment_watermask',
    - 'gt3r/land_segments/sigma_across',
    - 'gt3r/land_segments/sigma_along',
    - 'gt3r/land_segments/sigma_atlas_land',
    - 'gt3r/land_segments/sigma_h',
    - 'gt3r/land_segments/sigma_topo',
    - 'gt3r/land_segments/snr',
    - 'gt3r/land_segments/solar_azimuth',
    - 'gt3r/land_segments/solar_elevation',
    - 'gt3r/land_segments/surf_type',
    - 'gt3r/land_segments/terrain/h_te_best_fit',
    - 'gt3r/land_segments/terrain/h_te_best_fit_20m',
    - 'gt3r/land_segments/terrain/h_te_interp',
    - 'gt3r/land_segments/terrain/h_te_max',
    - 'gt3r/land_segments/terrain/h_te_mean',
    - 'gt3r/land_segments/terrain/h_te_median',
    - 'gt3r/land_segments/terrain/h_te_min',
    - 'gt3r/land_segments/terrain/h_te_mode',
    - 'gt3r/land_segments/terrain/h_te_rh25',
    - 'gt3r/land_segments/terrain/h_te_skew',
    - 'gt3r/land_segments/terrain/h_te_std',
    - 'gt3r/land_segments/terrain/h_te_uncertainty',
    - 'gt3r/land_segments/terrain/n_te_photons',
    - 'gt3r/land_segments/terrain/photon_rate_te',
    - 'gt3r/land_segments/terrain/subset_te_flag',
    - 'gt3r/land_segments/terrain/terrain_slope',
    - 'gt3r/land_segments/terrain_flg',
    - 'gt3r/land_segments/urban_flag',
    - 'gt3r/signal_photons/classed_pc_flag',
    - 'gt3r/signal_photons/classed_pc_indx',
    - 'gt3r/signal_photons/d_flag',
    - 'gt3r/signal_photons/delta_time',
    - 'gt3r/signal_photons/ph_h',
    - 'gt3r/signal_photons/ph_segment_id',
    - 'orbit_info/bounding_polygon_lat1',
    - 'orbit_info/bounding_polygon_lon1',
    - 'orbit_info/crossing_time',
    - 'orbit_info/cycle_number',
    - 'orbit_info/lan',
    - 'orbit_info/orbit_number',
    - 'orbit_info/rgt',
    - 'orbit_info/sc_orient',
    - 'orbit_info/sc_orient_time',
    - 'quality_assessment/qa_granule_fail_reason',
    - 'quality_assessment/qa_granule_pass_fail']
    -
    -
    -

    Thats a lot of variables!

    -

    One key feature of icepyx is the ability to browse the variables available in the dataset. There are typically hundreds of variables in a single dataset, so that is a lot to sort through! Let’s take a moment to get oriented to the organization of ATL08 variables, by first a few important pieces of the algorithm.

    -

    To create higher level variables like canopy or terrain height, the ATL08 algorithms goes through a series of steps: 1. Identify signal photons from noise photons 2. Classify each of the signal photons as either terrain, canopy, or canopy top 3. Remove elevation, so the heights are with respect to the ground 3. Group the signal photons into 100m segments. If there are a sufficient number of photons in that group, calculate statistics for terrain and canopy (ex. mean height, max height, standard deviation, etc.)

    -

    -
    -

    Fig. 4. An example of the classified photons produced from the ATL08 algorithm. Ground photons (red dots) are labeled as all photons falling within a point spread function distance of the estimated ground surface. The top of canopy photons (green dots) are photons that fall within a buffer distance from the upper canopy surface, and the photons that lie between the top of canopy surface and ground surface are labeled as canopy photons (blue dots). (Neuenschwander & Pitts, 2019)

    -
    -

    Providing all the potentially useful information from all these processing steps results in a data file that looks like:

    -

    TODO: loose file structure for ATL08

    -

    Another way to visualize these structure is to download one file and open it using https://myhdf5.hdfgroup.org/.

    -

    Note Mixing variables (Ex. h_canopy with dem_h and h_te_best_fit) gives a numpy type error

    -
    -
    reader.vars.append(var_list=['h_canopy', 'latitude', 'longitude'])
    -
    -
    -
    -

    Load the data!

    -
    -
    ds = reader.load()
    -ds
    -
    -
    /srv/conda/envs/notebook/lib/python3.10/site-packages/icepyx/core/read.py:520: UserWarning: rename 'delta_time' to 'photon_idx' does not create an index anymore. Try using swap_dims instead or use set_index after rename to create an indexed coordinate.
    -  .rename({"delta_time": "photon_idx"})
    -/srv/conda/envs/notebook/lib/python3.10/site-packages/icepyx/core/read.py:520: UserWarning: rename 'delta_time' to 'photon_idx' does not create an index anymore. Try using swap_dims instead or use set_index after rename to create an indexed coordinate.
    -  .rename({"delta_time": "photon_idx"})
    -
    -
    - -
    - - - - - - - - - - - - - - -
    <xarray.Dataset>
    -Dimensions:              (gran_idx: 1, photon_idx: 211, spot: 2)
    -Coordinates:
    -  * gran_idx             (gran_idx) float64 5.54e+04
    -  * photon_idx           (photon_idx) int64 0 1 2 3 4 5 ... 206 207 208 209 210
    -  * spot                 (spot) uint8 1 2
    -    source_file          (gran_idx) <U74 './bosque_primavera_ATL08/processed_...
    -    delta_time           (photon_idx) datetime64[ns] 2019-05-04T12:47:13.5766...
    -Data variables:
    -    sc_orient            (gran_idx) int8 0
    -    cycle_number         (gran_idx) int8 3
    -    rgt                  (gran_idx, spot, photon_idx) float32 554.0 ... 554.0
    -    atlas_sdp_gps_epoch  (gran_idx) datetime64[ns] 2018-01-01T00:00:18
    -    data_start_utc       (gran_idx) datetime64[ns] 2019-05-04T12:46:31.876322
    -    data_end_utc         (gran_idx) datetime64[ns] 2019-05-04T12:48:54.200826
    -    latitude             (spot, gran_idx, photon_idx) float32 20.59 ... nan
    -    longitude            (spot, gran_idx, photon_idx) float32 -103.7 ... nan
    -    gt                   (gran_idx, spot) <U4 'gt3l' 'gt3r'
    -    h_canopy             (photon_idx) float32 12.12 4.747 11.83 ... nan nan nan
    -Attributes:
    -    data_product:  ATL08
    -    Description:   Contains data categorized as land at 100 meter intervals.
    -    data_rate:     Data are stored as aggregates of 100 meters.
    -
    -
    -

    Here we have an xarray Dataset, a common Python data structure for analysis. To visualize the data we can plot it using:

    -
    -
    ds.plot.scatter(ax=ax, x="longitude", y="latitude", hue="h_canopy")
    -
    -
    <matplotlib.collections.PathCollection at 0x7f57e0943400>
    -
    -
    -
    -
    -
    -

    Using icepyx to download a subset of a granule

    -

    One feature which is not yet available in earthaccess is the ability to download just a subset of the file. This could mean a smaller spatial area or fewer variables. This feature is available in icepyx.

    -

    We saw above that icepyx by default will subset your data to the bounding box you provided when downloading. If you know in advance which variables you want icepyx can also subset variables.

    -
    -

    Subset variables

    -
    -
    # Create our Query
    -short_name = 'ATL08'
    -spatial_extent = [-99.8, 21, -99.0, 21.7]
    -date_range = ['2019-06-11','2019-06-11']
    -region = ipx.Query(short_name, spatial_extent, date_range)
    -
    -
    -
    # Specify desired variables
    -region.order_vars.append(var_list=['h_canopy', 'latitude', 'longitude'])
    -
    -
    -
    # Download the granules, using the Coverage kwarg to specify variables
    -region.download_granules(path='./ATL08_h_canopy', Coverage=region.order_vars.wanted)
    -
    -
    -
    # Read the new data
    -pattern = "processed_ATL{product:2}_{datetime:%Y%m%d%H%M%S}_{rgt:4}{cycle:2}{orbitsegment:2}_{version:3}_{revision:2}.h5"
    -reader = ipx.Read('./ATL08_h_canopy', "ATL08", pattern)
    -
    -

    The available variables list on the subset dataset is a lot shorter!

    -
    -
    reader.vars.avail()
    -
    -
    -
    -
    -

    Final fun visual (revisit Thurs. Morn)

    -

    Trying to come up with a fun final plot, if there is time. Ignore this for now and revisit in the morning.

    -
    -

    Recreate the plot from the paper with photon classifications

    -
    -
    reader.vars.remove(all=True)
    -reader.vars.append(var_list=['ph_h', 'classed_pc_flag', 'latitude', 'longitude'])
    -
    -
    -
    ds_photons = reader.load()
    -ds_photons
    -
    -
    -
    ds_photons
    -
    - -
    - - - - - - - - - - - - - - -
    <xarray.Dataset>
    -Dimensions:              (gran_idx: 1, photon_idx: 25234, spot: 2)
    -Coordinates:
    -  * gran_idx             (gran_idx) float64 5.54e+04
    -  * photon_idx           (photon_idx) int64 0 1 2 3 ... 25230 25231 25232 25233
    -  * spot                 (spot) uint8 1 2
    -    source_file          (gran_idx) <U74 './bosque_primavera_ATL08/processed_...
    -    delta_time           (photon_idx) datetime64[ns] 2019-05-04T12:47:13.5766...
    -Data variables:
    -    sc_orient            (gran_idx) int8 0
    -    cycle_number         (gran_idx) int8 3
    -    rgt                  (gran_idx, spot, photon_idx) float32 554.0 ... nan
    -    atlas_sdp_gps_epoch  (gran_idx) datetime64[ns] 2018-01-01T00:00:18
    -    data_start_utc       (gran_idx) datetime64[ns] 2019-05-04T12:46:31.876322
    -    data_end_utc         (gran_idx) datetime64[ns] 2019-05-04T12:48:54.200826
    -    latitude             (spot, gran_idx, photon_idx) float32 20.59 ... nan
    -    longitude            (spot, gran_idx, photon_idx) float32 -103.7 ... nan
    -    gt                   (gran_idx, spot) <U4 'gt3l' 'gt3r'
    -    h_te_best_fit        (photon_idx) float32 1.342e+03 1.34e+03 ... nan nan
    -    ph_h                 (spot, gran_idx, photon_idx) float32 nan ... 0.05542
    -    classed_pc_flag      (spot, gran_idx, photon_idx) float32 nan nan ... 1.0
    -Attributes:
    -    data_product:  ATL08
    -
    -
    -
    -
    ds_photons.plot.scatter(x='delta_time', y='ph_h', hue='classed_pc_flag')
    -
    -
    <matplotlib.collections.PathCollection at 0x7f57e160a2c0>
    -
    -
    -

    -
    -
    -
    -
    -

    Add more of a basemap to the spatial plot

    -

    Cartopy doesn’t seem to have any nice built in basemaps, and I think foluim would be too complicated.

    -
    -
    fig, ax = plt.subplots(subplot_kw={'projection': ccrs.PlateCarree()})
    -
    -# Add background features
    -ax.add_feature(cfeature.COASTLINE, alpha=0.3)
    -ax.add_feature(cfeature.BORDERS, linestyle=':')
    -ax.add_feature(cfeature.RIVERS)
    -
    -# ax.set_extent([-77.5, -75.4, 36.6, 39.7])
    -
    -# Add and format gridlines. Remove top and right labels
    -gl = ax.gridlines(crs=ccrs.PlateCarree(), draw_labels=True,
    -                  linewidth=1, color='gray', alpha=0.2, linestyle='--')
    -gl.top_labels, gl.right_labels = False, False
    -
    -ds.plot.scatter(ax=ax, x="longitude", y="latitude", hue="h_canopy")
    -
    -
    <matplotlib.collections.PathCollection at 0x7f57e3b2fe20>
    -
    -
    -

    -
    -
    -

    Notice that the data is already subset to our area of interest! (Also download the full granule with earthaccess to compare the area?)

    -
    -
    -

    Plot the canopy compared to the ground height

    -

    A nice idea, but there are a few places where the ground may be above the canopy. Not sure how to talk about that. Maybe consider if h_te_best_fit is the best variable to use for height?

    -
    -
    reader.vars.remove(all=True)
    -reader.vars.append(var_list=['h_te_best_fit', 'latitude', 'longitude'])
    -
    -
    -
    ds_te = reader.load()
    -ds_te
    -
    -
    -
    ds.h_canopy + ds_te.h_te_best_fit
    -
    - -
    - - - - - - - - - - - - - - -
    <xarray.DataArray (photon_idx: 211)>
    -array([1353.7437, 1344.5021, 1354.0542, 1365.1449,       nan, 1388.0896,
    -             nan, 1367.1438, 1403.1825, 1394.4102, 1393.9043, 1416.9154,
    -       1419.0438, 1431.773 , 1427.9192, 1426.2251, 1416.8427,       nan,
    -       1401.4824, 1390.8745, 1380.5767, 1380.2539, 1393.4421, 1386.7036,
    -       1384.1562, 1385.3413, 1387.8845,       nan, 1383.2649, 1385.1476,
    -       1351.6632, 1348.4186, 1356.7253, 1383.4984, 1378.7352, 1378.3448,
    -       1387.8447,       nan, 1384.6409, 1378.7225, 1351.8608, 1369.9244,
    -       1375.6143, 1378.7357, 1385.3104, 1374.63  , 1385.7798, 1384.4376,
    -       1385.4879,       nan, 1386.6517, 1363.0527, 1383.036 , 1384.011 ,
    -       1393.2178, 1368.4326, 1379.6318, 1381.6879, 1375.5375, 1377.1417,
    -       1362.7836, 1358.7225,       nan, 1345.983 , 1352.2463, 1352.8934,
    -       1353.0276, 1353.9401, 1355.2495, 1362.6967, 1364.1461,       nan,
    -             nan, 1367.4513, 1368.7175, 1372.8689, 1355.3347, 1366.3495,
    -       1371.091 , 1369.8829, 1371.3533, 1366.4882, 1365.5226, 1349.8981,
    -       1340.5991, 1332.43  ,       nan,       nan, 1337.899 , 1337.3844,
    -       1353.7922, 1364.3038, 1374.5607, 1387.6923, 1389.9014,       nan,
    -             nan, 1385.0403, 1393.3284,       nan,       nan, 1407.526 ,
    -       1408.1254,       nan,       nan,       nan,       nan,       nan,
    -             nan,       nan,       nan,       nan,       nan,       nan,
    -             nan,       nan, 1391.213 , 1391.9713,       nan,       nan,
    -             nan,       nan,       nan,       nan,       nan,       nan,
    -             nan,       nan,       nan,       nan,       nan,       nan,
    -             nan,       nan,       nan,       nan,       nan,       nan,
    -             nan,       nan,       nan,       nan,       nan,       nan,
    -             nan,       nan,       nan,       nan,       nan,       nan,
    -             nan,       nan,       nan,       nan,       nan,       nan,
    -             nan,       nan,       nan,       nan,       nan,       nan,
    -             nan,       nan,       nan,       nan,       nan,       nan,
    -             nan,       nan,       nan,       nan,       nan,       nan,
    -             nan,       nan,       nan,       nan,       nan,       nan,
    -             nan,       nan,       nan,       nan,       nan,       nan,
    -             nan,       nan,       nan,       nan,       nan,       nan,
    -             nan,       nan,       nan,       nan,       nan,       nan,
    -             nan,       nan,       nan,       nan,       nan,       nan,
    -             nan,       nan,       nan,       nan,       nan,       nan,
    -             nan], dtype=float32)
    -Coordinates:
    -  * photon_idx  (photon_idx) int64 0 1 2 3 4 5 6 ... 204 205 206 207 208 209 210
    -    delta_time  (photon_idx) datetime64[ns] 2019-05-04T12:47:13.576668792 ......
    -
    -
    -
    -
    fig, ax = plt.subplots()
    -fig.set_size_inches(12, 3)
    -
    -(ds.h_canopy + ds_te.h_te_best_fit).plot.scatter(ax=ax, x="delta_time", y="h_canopy") # orange
    -
    -ds_te.plot.scatter(ax=ax, x="delta_time", y="h_te_best_fit") # blue
    -
    -
    <matplotlib.collections.PathCollection at 0x7f57e0943730>
    -
    -
    -

    -
    -
    -
    -
    -

    Interactive plot with holoviz

    -
    -
    import hvplot.xarray
    -
    -
    -
    ds.hvplot.scatter(y="h_canopy", x="latitude",
    -                  by=['spot', 'photon_idx', 'gran_idx'], legend=False)
    -
    -
    -
    -
    -
    -
    - -
    -
    -
    -
    gt1l = ds.where(ds.gt == 'gt1l')
    -
    -
    -
    +