\n",
"\n",
"---\n",
"\n",
"\n",
"\n",
"### Focuses\n",
"\n",
"* Investigate what satellite data is available from an EDEX server.\n",
"* Define map properties in a function that can be used to plot multiple images.\n",
"* Retreive Mesoscale GOES satellite grid data from an EDEX server.\n",
"* Use matplotlib pcolormesh to plot the colorized images with a colorbar.\n",
"\n",
"\n",
"### Objectives\n",
"\n",
"1. [Define Data Request](#1.-Define-Data-Request)\n",
"1. [View Optional Identifiers](#2.-View-Optional-Identifiers)\n",
"1. [View Sources](#3.-View-Sources)\n",
"1. [View Creating Entities](#4.-View-Creating-Entities)\n",
"1. [View Sector IDs](#5.-View-Sector-IDs)\n",
"1. [Create a Satellite Product Tree](#6.-Create-a-Satellite-Product-Tree)\n",
"1. [Define Map Properties](#7.-Define-Map-Properties)\n",
"1. [Plot Image Data!](#8.-Plot-Image-Data!)\n",
"\n",
"---"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Imports"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"from awips.dataaccess import DataAccessLayer\n",
"import cartopy.crs as ccrs\n",
"import cartopy.feature as cfeat\n",
"import matplotlib.pyplot as plt\n",
"from cartopy.mpl.gridliner import LONGITUDE_FORMATTER, LATITUDE_FORMATTER\n",
"import numpy as np\n",
"import datetime"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"---\n",
"\n",
"## 1. Define Data Request\n",
"\n",
"If you read through the [python-awips: How to Access Data](https://nbviewer.jupyter.org/github/Unidata/pyaos-ams-2021/blob/master/notebooks/dataAccess/python-awips-HowToAccessData.ipynb) training, you will know that we need to set an EDEX url to access our server, and then we create a data request. In this example we use *satellite* as the data type to define our request."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Create an EDEX data request\n",
"DataAccessLayer.changeEDEXHost(\"edex-cloud.unidata.ucar.edu\")\n",
"request = DataAccessLayer.newDataRequest()\n",
"request.setDatatype(\"satellite\")\n",
"\n",
"# Take a look at our request\n",
"print(request)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Top\n",
"\n",
"---\n",
"\n",
"## 2. View Optional Identifiers\n",
"\n",
"There can be many sources of satellite data stored in an EDEX server. First, let's take a look at the available \"identifiers\". We will then look a little more in depth at a few of the identifiers."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"scrolled": true
},
"outputs": [],
"source": [
"# get optional identifiers for satellite datatype\n",
"identifiers = set(DataAccessLayer.getOptionalIdentifiers(request))\n",
"\n",
"print(\"Available Identifiers:\")\n",
"for id in identifiers:\n",
" if id.lower() == 'datauri':\n",
" continue\n",
" print(\" - \" + id)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Top\n",
"\n",
"---\n",
"## 3. View Sources\n",
"\n",
"Here, use *source* as the identifier, and take a look at the available sources are. The *source* is a parameter that is set in the netcdf file, and gives some insight to where the product is coming from."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Show available sources\n",
"identifier = \"source\"\n",
"sources = DataAccessLayer.getIdentifierValues(request, identifier)\n",
"print(identifier + \":\")\n",
"print(list(sources))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Top\n",
"\n",
"---\n",
"## 4. View Creating Entities\n",
"\n",
"Next, use *creatingEntity* as the identifier, and take a look at what creating entities are. The *creatingEntity* is related to what instrument or institute created the product."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"scrolled": true
},
"outputs": [],
"source": [
"# Show available creatingEntities\n",
"identifier = \"creatingEntity\"\n",
"creatingEntities = DataAccessLayer.getIdentifierValues(request, identifier)\n",
"print(identifier + \":\")\n",
"print(list(creatingEntities))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Top\n",
"\n",
"---\n",
"## 5. View Sector IDs\n",
"\n",
"Next, use *sectorID* as the identifier and take a look at what sectors are available. The *sectorID* is what AWIPS uses to know what geographic section the data is related to."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"scrolled": true
},
"outputs": [],
"source": [
"# Show available sectorIDs\n",
"identifier = \"sectorID\"\n",
"sectorIDs = DataAccessLayer.getIdentifierValues(request, identifier)\n",
"print(identifier + \":\")\n",
"print(list(sectorIDs))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Top\n",
"\n",
"---\n",
"## 6. Create a Satellite Product Tree\n",
"\n",
"By cycling through all the identifiers, a detailed overview of all available products can be created. In this example, first *creatingEntity* is used, and then *availableLocationNames*, and *availableParameters* are used to build the product list further. \n",
"\n",
"> Note: The identifieres *source* and *sectorID* are not used in this tree, but this is only one way to construct such a product overview."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Construct a full satellite product tree\n",
"for entity in creatingEntities:\n",
" print(entity)\n",
" # Create a new request each time through so only one Identifer is set per request\n",
" request = DataAccessLayer.newDataRequest(\"satellite\")\n",
" request.addIdentifier(\"creatingEntity\", entity)\n",
" # Group by available locations\n",
" availableSectors = DataAccessLayer.getAvailableLocationNames(request)\n",
" availableSectors.sort()\n",
" for sector in availableSectors:\n",
" print(\" - \" + sector)\n",
" request.setLocationNames(sector)\n",
" # Get all available products\n",
" availableProducts = DataAccessLayer.getAvailableParameters(request)\n",
" availableProducts.sort()\n",
" for product in availableProducts:\n",
" print(\" - \" + product)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Top\n",
"\n",
"---\n",
"## 7. Define Map Properties\n",
"\n",
"In order to plot more than one image, it's easiest to define common logic in a function. Here, a new function called **make_map** is defined. This function uses the [matplotlib.pyplot package (plt)](https://matplotlib.org/3.3.3/api/_as_gen/matplotlib.pyplot.html) to create a figure and axis. The coastlines (continental boundaries) are added, along with lat/lon grids. "
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"def make_map(bbox, projection=ccrs.PlateCarree()):\n",
" fig, ax = plt.subplots(figsize=(10,12),\n",
" subplot_kw=dict(projection=projection))\n",
" if bbox[0] is not np.nan:\n",
" ax.set_extent(bbox)\n",
" ax.coastlines(resolution='50m')\n",
" gl = ax.gridlines(draw_labels=True)\n",
" gl.top_labels = gl.right_labels = False\n",
" gl.xformatter = LONGITUDE_FORMATTER\n",
" gl.yformatter = LATITUDE_FORMATTER\n",
" return fig, ax"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Top\n",
"\n",
"---\n",
"## 8. Plot Image Data!\n",
"\n",
"For this example, use Channel 13 on the two mesoscale sectors from GOES-East satellite. Create a figure to contain the plot. Create a new *Data Request* for each sector and set the location and parameters on it. Limit the data to the most recently acquired image using the *getAvailableTimes* function. Then use pcolormesh to create a plot from the data in the response in the *GridData* object.\n",
"\n",
"> Note: You may see a warning appear with a red background, this is okay, and will go away with subsequent runs of the cell."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Specify the sectors - GOES East Mesocales\n",
"sectors = [\"EMESO-1\",\"EMESO-2\"]\n",
"# Create a figure to contain all subplots\n",
"fig = plt.figure(figsize=(16,7*len(sectors)))\n",
"\n",
"# Cycle through the sectors to create and plot recent data from each one\n",
"for i, sector in enumerate(sectors):\n",
"\n",
" # Create the Ch 13 data request\n",
" request = DataAccessLayer.newDataRequest()\n",
" request.setDatatype(\"satellite\")\n",
" request.setLocationNames(sector)\n",
" request.setParameters(\"CH-13-10.35um\")\n",
"\n",
" # Get the available times\n",
" utc = datetime.datetime.utcnow()\n",
" times = DataAccessLayer.getAvailableTimes(request)\n",
"\n",
" # Get the grid data using the latest time\n",
" response = DataAccessLayer.getGridData(request, [times[-1]])\n",
" grid = response[0]\n",
" data = grid.getRawData()\n",
" lons,lats = grid.getLatLonCoords()\n",
" \n",
" # Create the bounding box from the grid data\n",
" bbox = [lons.min(), lons.max(), lats.min(), lats.max()]\n",
"\n",
" # Draw a new subplot based on the bounding box\n",
" fig, ax = make_map(bbox=bbox)\n",
" \n",
" # Add state boundaries where available\n",
" states = cfeat.NaturalEarthFeature(category='cultural', name='admin_1_states_provinces_lines', scale='50m', facecolor='none')\n",
" ax.add_feature(states, linestyle=':')\n",
" \n",
" # Create the color scale\n",
" cs = ax.pcolormesh(lons, lats, data, cmap='coolwarm')\n",
" \n",
" #Create the colorbar and add a label\n",
" cbar = fig.colorbar(cs, shrink=0.6, orientation='horizontal')\n",
" cbar.set_label(sector + \" \" + grid.getParameter() + \" \" \\\n",
" + str(grid.getDataTime().getRefTime()))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Top\n",
"\n",
"---\n",
"## See also\n",
"\n",
"Documentation for:\n",
"\n",
"* [awips.DataAccessLayer](http://unidata.github.io/python-awips/api/DataAccessLayer.html#)\n",
"* [awips.PyGridData](http://unidata.github.io/python-awips/api/PyGridData.html)\n",
"* [matplotlib.pyplot](https://matplotlib.org/3.3.3/api/_as_gen/matplotlib.pyplot.html)\n",
"* [matplotlib.pyplot.pcolormesh](https://matplotlib.org/3.3.3/api/_as_gen/matplotlib.pyplot.pcolormesh.html)\n",
"* [matplotlib.pyplot.subplot](https://matplotlib.org/3.3.3/api/_as_gen/matplotlib.pyplot.subplot.html)\n",
"\n",
"\n",
"### Related Notebooks\n",
"\n",
"* [python-awips: How to Access Data](https://nbviewer.jupyter.org/github/Unidata/pyaos-ams-2021/blob/master/notebooks/dataAccess/python-awips-HowToAccessData.ipynb)\n",
"\n",
"Top"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python [conda env:pyaos-ams-2021]",
"language": "python",
"name": "conda-env-pyaos-ams-2021-py"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.9.1"
}
},
"nbformat": 4,
"nbformat_minor": 1
}