mirror of
https://github.com/Unidata/python-awips.git
synced 2025-02-23 22:57:56 -05:00
379 lines
14 KiB
Text
379 lines
14 KiB
Text
{
|
|
"cells": [
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"<a name=\"top\"></a>\n",
|
|
"<div style=\"width:1000 px\">\n",
|
|
"\n",
|
|
"<div style=\"float:right; width:98 px; height:98px;\">\n",
|
|
"<img src=\"https://docs.unidata.ucar.edu/images/logos/unidata_logo_vertical_150x150.png\" alt=\"Unidata Logo\" style=\"height: 98px;\">\n",
|
|
"</div>\n",
|
|
"\n",
|
|
"# NEXRAD Level 3 Radar\n",
|
|
"**Python-AWIPS Tutorial Notebook**\n",
|
|
"\n",
|
|
"<div style=\"clear:both\"></div>\n",
|
|
"</div>\n",
|
|
"\n",
|
|
"---\n",
|
|
"\n",
|
|
"<div style=\"float:right; width:250 px\"><img src=\"../images/NEXRAD_Level3_Radar_preview.png\" alt=\"NEXRAD Composite Reflectivity Example\" style=\"height: 300px;\"></div>\n",
|
|
"\n",
|
|
"\n",
|
|
"# Objectives\n",
|
|
"\n",
|
|
"* Use python-awips to connect to an edex server\n",
|
|
"* Define and filter data request for radar data\n",
|
|
"* Plot NEXRAD 3 algorithm, precipitation, and derived products (not base data)\n",
|
|
"\n",
|
|
"---"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"toc": true
|
|
},
|
|
"source": [
|
|
"<h1>Table of Contents<span class=\"tocSkip\"></span></h1>\n",
|
|
"<div class=\"toc\"><ul class=\"toc-item\"><li><span><a href=\"#Imports\" data-toc-modified-id=\"Imports-1\"><span class=\"toc-item-num\">1 </span>Imports</a></span></li><li><span><a href=\"#EDEX-Connection\" data-toc-modified-id=\"EDEX-Connection-2\"><span class=\"toc-item-num\">2 </span>EDEX Connection</a></span></li><li><span><a href=\"#Investigate-Data\" data-toc-modified-id=\"Investigate-Data-3\"><span class=\"toc-item-num\">3 </span>Investigate Data</a></span><ul class=\"toc-item\"><li><span><a href=\"#Available-Locations\" data-toc-modified-id=\"Available-Locations-3.1\"><span class=\"toc-item-num\">3.1 </span>Available Locations</a></span></li><li><span><a href=\"#Available-Parameters\" data-toc-modified-id=\"Available-Parameters-3.2\"><span class=\"toc-item-num\">3.2 </span>Available Parameters</a></span></li><li><span><a href=\"#Radar-Product-IDs-and-Names\" data-toc-modified-id=\"Radar-Product-IDs-and-Names-3.3\"><span class=\"toc-item-num\">3.3 </span>Radar Product IDs and Names</a></span></li></ul></li><li><span><a href=\"#Function:-make_map()\" data-toc-modified-id=\"Function:-make_map()-4\"><span class=\"toc-item-num\">4 </span>Function: make_map()</a></span></li><li><span><a href=\"#Plot-the-Data!\" data-toc-modified-id=\"Plot-the-Data!-5\"><span class=\"toc-item-num\">5 </span>Plot the Data!</a></span></li><li><span><a href=\"#See-Also\" data-toc-modified-id=\"See-Also-6\"><span class=\"toc-item-num\">6 </span>See Also</a></span><ul class=\"toc-item\"><li><span><a href=\"#Related-Notebooks\" data-toc-modified-id=\"Related-Notebooks-6.1\"><span class=\"toc-item-num\">6.1 </span>Related Notebooks</a></span></li><li><span><a href=\"#Additional-Documention\" data-toc-modified-id=\"Additional-Documention-6.2\"><span class=\"toc-item-num\">6.2 </span>Additional Documention</a></span></li></ul></li></ul></div>"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"## Imports\n",
|
|
"\n",
|
|
"The imports below are used throughout the notebook. Note the first import is coming directly from python-awips and allows us to connect to an EDEX server. The subsequent imports are for data manipulation and visualization. "
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"import warnings\n",
|
|
"from awips.dataaccess import DataAccessLayer\n",
|
|
"import matplotlib.pyplot as plt\n",
|
|
"import cartopy.crs as ccrs\n",
|
|
"import numpy as np\n",
|
|
"from cartopy.mpl.gridliner import LONGITUDE_FORMATTER, LATITUDE_FORMATTER"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"<a href=\"#top\">Top</a>\n",
|
|
"\n",
|
|
"---"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"## EDEX Connection\n",
|
|
"\n",
|
|
"First we establish a connection to Unidata's public EDEX server. This sets the proper server on the **DataAccessLayer**, which we will use numerous times throughout the notebook."
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"DataAccessLayer.changeEDEXHost(\"edex-cloud.unidata.ucar.edu\")\n",
|
|
"request = DataAccessLayer.newDataRequest(\"radar\")"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"<a href=\"#top\">Top</a>\n",
|
|
"\n",
|
|
"---"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"## Investigate Data\n",
|
|
"\n",
|
|
"Now that we've created a new radar data request, let's take a look at what locations and parameters are available for our current request."
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"### Available Locations\n",
|
|
"\n",
|
|
"We can take a look at what \"locations\" are available for our radar request. For radar, we'll see that radar station names are returned when looking at the availalbe location names.\n",
|
|
"\n",
|
|
"For this example we'll use Morehead City, NC as our region of interest. You can easily look up other station IDs and where they are using [this NWS webpage](https://radar.weather.gov/station/KMHX/standard)."
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"metadata": {
|
|
"scrolled": true
|
|
},
|
|
"outputs": [],
|
|
"source": [
|
|
"available_locs = DataAccessLayer.getAvailableLocationNames(request)\n",
|
|
"available_locs.sort()\n",
|
|
"print(available_locs)\n",
|
|
"\n",
|
|
"# Set our location to Morehead City (kmhx)\n",
|
|
"request.setLocationNames(\"kmhx\")"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"### Available Parameters\n",
|
|
"\n",
|
|
"Next, let's look at the parameters returned from the available parameters request. If we look closely, we can see that some of the parameters appear different from the others."
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"metadata": {
|
|
"scrolled": true
|
|
},
|
|
"outputs": [],
|
|
"source": [
|
|
"availableParms = DataAccessLayer.getAvailableParameters(request)\n",
|
|
"availableParms.sort()\n",
|
|
"print(availableParms)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"### Radar Product IDs and Names\n",
|
|
"\n",
|
|
"As we saw above, some parameters seem to be describing different things from the rest. The DataAccessLayer has a built in function to parse the available parameters into the separate **Product IDs** and **Product Names**. Here, we take a look at the two different arrays that are returned when parsing the *availableParms* array we just recieved in the previous code cell."
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"metadata": {
|
|
"scrolled": true
|
|
},
|
|
"outputs": [],
|
|
"source": [
|
|
"productIDs = DataAccessLayer.getRadarProductIDs(availableParms)\n",
|
|
"productNames = DataAccessLayer.getRadarProductNames(availableParms)\n",
|
|
"print(productIDs)\n",
|
|
"print(productNames)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"<a href=\"#top\">Top</a>\n",
|
|
"\n",
|
|
"---"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"## Function: make_map()\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=(16, 16),\n",
|
|
" subplot_kw=dict(projection=projection))\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": [
|
|
"<a href=\"#top\">Top</a>\n",
|
|
"\n",
|
|
"---"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"## Plot the Data!\n",
|
|
"\n",
|
|
"Here we'll create a plot for each of the Radar Product Names from our *productNames* array from the [previous section](#Radar-Product-IDs-and-Names)."
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"metadata": {
|
|
"scrolled": false
|
|
},
|
|
"outputs": [],
|
|
"source": [
|
|
"# suppress a few warnings that come from plotting\n",
|
|
"warnings.filterwarnings(\"ignore\",category =RuntimeWarning)\n",
|
|
"warnings.filterwarnings(\"ignore\",category =UserWarning)\n",
|
|
"\n",
|
|
"# Cycle through all of the products to try and plot each one\n",
|
|
"for prod in productNames:\n",
|
|
" \n",
|
|
" request.setParameters(prod)\n",
|
|
" availableLevels = DataAccessLayer.getAvailableLevels(request)\n",
|
|
" \n",
|
|
" # Check the available levels, if there are none, then skip this product\n",
|
|
" if availableLevels:\n",
|
|
" request.setLevels(availableLevels[0])\n",
|
|
" else:\n",
|
|
" print(\"No levels found for \" + prod)\n",
|
|
" continue\n",
|
|
"\n",
|
|
" cycles = DataAccessLayer.getAvailableTimes(request, True)\n",
|
|
" times = DataAccessLayer.getAvailableTimes(request)\n",
|
|
"\n",
|
|
" if times:\n",
|
|
" print()\n",
|
|
" response = DataAccessLayer.getGridData(request, [times[-1]])\n",
|
|
" print(\"Recs : \", len(response))\n",
|
|
" \n",
|
|
" if response:\n",
|
|
" grid = response[0]\n",
|
|
" else:\n",
|
|
" continue\n",
|
|
" data = grid.getRawData()\n",
|
|
" lons, lats = grid.getLatLonCoords()\n",
|
|
" \n",
|
|
" print('Time :', str(grid.getDataTime()))\n",
|
|
" flat = np.ndarray.flatten(data)\n",
|
|
" print('Name :', str(grid.getLocationName()))\n",
|
|
" print('Prod :', str(grid.getParameter()))\n",
|
|
" print('Range:' , np.nanmin(flat), \" to \", np.nanmax(flat), \" (Unit :\", grid.getUnit(), \")\")\n",
|
|
" print('Size :', str(data.shape))\n",
|
|
" print()\n",
|
|
"\n",
|
|
" cmap = plt.get_cmap('rainbow')\n",
|
|
" bbox = [lons.min()-0.5, lons.max()+0.5, lats.min()-0.5, lats.max()+0.5]\n",
|
|
" fig, ax = make_map(bbox=bbox)\n",
|
|
" cs = ax.pcolormesh(lons, lats, data, cmap=cmap)\n",
|
|
" cbar = fig.colorbar(cs, extend='both', shrink=0.5, orientation='horizontal')\n",
|
|
" cbar.set_label(grid.getParameter() +\" \" + grid.getLevel() + \" \" \\\n",
|
|
" + grid.getLocationName() + \" (\" + prod + \"), (\" + grid.getUnit() + \") \" \\\n",
|
|
" + \"valid \" + str(grid.getDataTime().getRefTime()))\n",
|
|
" plt.show()"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"<a href=\"#top\">Top</a>\n",
|
|
"\n",
|
|
"---"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"## See Also\n",
|
|
"\n",
|
|
"\n",
|
|
"### Related Notebooks\n",
|
|
"\n",
|
|
"* [Grid Levels and Parameters](https://unidata.github.io/python-awips/examples/generated/Grid_Levels_and_Parameters.html)\n",
|
|
"\n",
|
|
"\n",
|
|
"### Additional Documention\n",
|
|
"\n",
|
|
"**python-awips**\n",
|
|
"\n",
|
|
"- [DataAccessLayer.changeEDEXHost()](http://unidata.github.io/python-awips/api/DataAccessLayer.html#awips.dataaccess.DataAccessLayer.changeEDEXHost)\n",
|
|
"- [DataAccessLayer.newDataRequest()](http://unidata.github.io/python-awips/api/DataAccessLayer.html#awips.dataaccess.DataAccessLayer.newDataRequest)\n",
|
|
"- [DataAccessLayer.getRadarProductIDs()](http://unidata.github.io/python-awips/api/DataAccessLayer.html#awips.dataaccess.DataAccessLayer.getRadarProductIDs)\n",
|
|
"- [DataAccessLayer.getRadarProductNames()](http://unidata.github.io/python-awips/api/DataAccessLayer.html#awips.dataaccess.DataAccessLayer.getRadarProductNames)\n",
|
|
"\n",
|
|
"**matplotlib**\n",
|
|
"\n",
|
|
"- [matplotlib.pyplot()](https://matplotlib.org/stable/api/_as_gen/matplotlib.pyplot.html)\n",
|
|
"- [matplotlib.pyplot.axes()](https://matplotlib.org/stable/api/_as_gen/matplotlib.pyplot.axes.html)\n",
|
|
"- [matplotlib.pyplot.figure()](https://matplotlib.org/stable/api/_as_gen/matplotlib.pyplot.figure.html)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"<a href=\"#top\">Top</a>\n",
|
|
"\n",
|
|
"---"
|
|
]
|
|
}
|
|
],
|
|
"metadata": {
|
|
"kernelspec": {
|
|
"display_name": "Python 3",
|
|
"language": "python",
|
|
"name": "python3"
|
|
},
|
|
"language_info": {
|
|
"codemirror_mode": {
|
|
"name": "ipython",
|
|
"version": 3
|
|
},
|
|
"file_extension": ".py",
|
|
"mimetype": "text/x-python",
|
|
"name": "python",
|
|
"nbconvert_exporter": "python",
|
|
"pygments_lexer": "ipython3",
|
|
"version": "3.9.5"
|
|
},
|
|
"toc": {
|
|
"base_numbering": 1,
|
|
"nav_menu": {},
|
|
"number_sections": true,
|
|
"sideBar": true,
|
|
"skip_h1_title": true,
|
|
"title_cell": "Table of Contents",
|
|
"title_sidebar": "Contents",
|
|
"toc_cell": true,
|
|
"toc_position": {},
|
|
"toc_section_display": true,
|
|
"toc_window_display": true
|
|
}
|
|
},
|
|
"nbformat": 4,
|
|
"nbformat_minor": 4
|
|
}
|