mirror of
https://github.com/Unidata/python-awips.git
synced 2025-02-23 14:57:56 -05:00
298 lines
298 KiB
Text
298 lines
298 KiB
Text
|
{
|
||
|
"cells": [
|
||
|
{
|
||
|
"cell_type": "code",
|
||
|
"execution_count": 1,
|
||
|
"metadata": {},
|
||
|
"outputs": [],
|
||
|
"source": [
|
||
|
"%matplotlib inline"
|
||
|
]
|
||
|
},
|
||
|
{
|
||
|
"cell_type": "markdown",
|
||
|
"metadata": {},
|
||
|
"source": [
|
||
|
"\n",
|
||
|
"Station Plot with Layout\n",
|
||
|
"========================\n",
|
||
|
"\n",
|
||
|
"Make a station plot, complete with sky cover and weather symbols, using a\n",
|
||
|
"station plot layout built into MetPy.\n",
|
||
|
"\n",
|
||
|
"The station plot itself is straightforward, but there is a bit of code to perform the\n",
|
||
|
"data-wrangling (hopefully that situation will improve in the future). Certainly, if you have\n",
|
||
|
"existing point data in a format you can work with trivially, the station plot will be simple.\n",
|
||
|
"\n",
|
||
|
"The `StationPlotLayout` class is used to standardize the plotting various parameters\n",
|
||
|
"(i.e. temperature), keeping track of the location, formatting, and even the units for use in\n",
|
||
|
"the station plot. This makes it easy (if using standardized names) to re-use a given layout\n",
|
||
|
"of a station plot.\n",
|
||
|
"\n"
|
||
|
]
|
||
|
},
|
||
|
{
|
||
|
"cell_type": "markdown",
|
||
|
"metadata": {},
|
||
|
"source": [
|
||
|
"The setup\n",
|
||
|
"---------\n",
|
||
|
"\n",
|
||
|
"First read in the data. We use `numpy.loadtxt` to read in the data and use a structured\n",
|
||
|
"`numpy.dtype` to allow different types for the various columns. This allows us to handle\n",
|
||
|
"the columns with string data.\n",
|
||
|
"\n"
|
||
|
]
|
||
|
},
|
||
|
{
|
||
|
"cell_type": "code",
|
||
|
"execution_count": 2,
|
||
|
"metadata": {},
|
||
|
"outputs": [],
|
||
|
"source": [
|
||
|
"from awips.dataaccess import DataAccessLayer\n",
|
||
|
"from dynamicserialize.dstypes.com.raytheon.uf.common.time import TimeRange\n",
|
||
|
"from datetime import datetime, timedelta\n",
|
||
|
"import numpy as np\n",
|
||
|
"\n",
|
||
|
"import cartopy.crs as ccrs\n",
|
||
|
"import cartopy.feature as cfeature\n",
|
||
|
"import matplotlib.pyplot as plt\n",
|
||
|
"import pandas as pd\n",
|
||
|
"\n",
|
||
|
"from metpy.calc import wind_components\n",
|
||
|
"from metpy.cbook import get_test_data\n",
|
||
|
"from metpy.plots import (add_metpy_logo, simple_layout, StationPlot,\n",
|
||
|
" StationPlotLayout, wx_code_map)\n",
|
||
|
"from metpy.units import units\n",
|
||
|
"\n",
|
||
|
"def get_cloud_cover(code):\n",
|
||
|
" if 'OVC' in code:\n",
|
||
|
" return 1.0\n",
|
||
|
" elif 'BKN' in code:\n",
|
||
|
" return 6.0/8.0\n",
|
||
|
" elif 'SCT' in code:\n",
|
||
|
" return 4.0/8.0\n",
|
||
|
" elif 'FEW' in code:\n",
|
||
|
" return 2.0/8.0\n",
|
||
|
" else:\n",
|
||
|
" return 0\n",
|
||
|
"\n",
|
||
|
"# Pull out these specific stations (prepend K for AWIPS identifiers)\n",
|
||
|
"selected = ['PDX', 'OKC', 'ICT', 'GLD', 'MEM', 'BOS', 'MIA', 'MOB', 'ABQ', 'PHX', 'TTF',\n",
|
||
|
" 'ORD', 'BIL', 'BIS', 'CPR', 'LAX', 'ATL', 'MSP', 'SLC', 'DFW', 'NYC', 'PHL',\n",
|
||
|
" 'PIT', 'IND', 'OLY', 'SYR', 'LEX', 'CHS', 'TLH', 'HOU', 'GJT', 'LBB', 'LSV',\n",
|
||
|
" 'GRB', 'CLT', 'LNK', 'DSM', 'BOI', 'FSD', 'RAP', 'RIC', 'JAN', 'HSV', 'CRW',\n",
|
||
|
" 'SAT', 'BUY', '0CO', 'ZPC', 'VIH', 'BDG', 'MLF', 'ELY', 'WMC', 'OTH', 'CAR',\n",
|
||
|
" 'LMT', 'RDM', 'PDT', 'SEA', 'UIL', 'EPH', 'PUW', 'COE', 'MLP', 'PIH', 'IDA', \n",
|
||
|
" 'MSO', 'ACV', 'HLN', 'BIL', 'OLF', 'RUT', 'PSM', 'JAX', 'TPA', 'SHV', 'MSY',\n",
|
||
|
" 'ELP', 'RNO', 'FAT', 'SFO', 'NYL', 'BRO', 'MRF', 'DRT', 'FAR', 'BDE', 'DLH',\n",
|
||
|
" 'HOT', 'LBF', 'FLG', 'CLE', 'UNV']\n",
|
||
|
"selected = ['K{0}'.format(id) for id in selected]\n",
|
||
|
"data_arr = []"
|
||
|
]
|
||
|
},
|
||
|
{
|
||
|
"cell_type": "code",
|
||
|
"execution_count": 3,
|
||
|
"metadata": {},
|
||
|
"outputs": [],
|
||
|
"source": [
|
||
|
"# EDEX Request\n",
|
||
|
"edexServer = \"edex-cloud.unidata.ucar.edu\"\n",
|
||
|
"DataAccessLayer.changeEDEXHost(edexServer)\n",
|
||
|
"request = DataAccessLayer.newDataRequest(\"obs\")\n",
|
||
|
"availableProducts = DataAccessLayer.getAvailableParameters(request)\n",
|
||
|
"\n",
|
||
|
"single_value_params = [\"timeObs\", \"stationName\", \"longitude\", \"latitude\", \n",
|
||
|
" \"temperature\", \"dewpoint\", \"windDir\",\n",
|
||
|
" \"windSpeed\", \"seaLevelPress\"]\n",
|
||
|
"multi_value_params = [\"presWeather\", \"skyCover\", \"skyLayerBase\"]\n",
|
||
|
"pres_weather, sky_cov, sky_layer_base = [],[],[]\n",
|
||
|
"params = single_value_params + multi_value_params\n",
|
||
|
"obs = dict({params: [] for params in params})\n",
|
||
|
"\n",
|
||
|
"request.setParameters(*(params))\n",
|
||
|
"request.setLocationNames(*(selected))"
|
||
|
]
|
||
|
},
|
||
|
{
|
||
|
"cell_type": "markdown",
|
||
|
"metadata": {},
|
||
|
"source": [
|
||
|
"Here we use the Python-AWIPS class **TimeRange** to prepare a beginning and end time span for requesting observations (the last hour):"
|
||
|
]
|
||
|
},
|
||
|
{
|
||
|
"cell_type": "code",
|
||
|
"execution_count": 4,
|
||
|
"metadata": {},
|
||
|
"outputs": [],
|
||
|
"source": [
|
||
|
"# Time range\n",
|
||
|
"lastHourDateTime = datetime.utcnow() - timedelta(hours = 1)\n",
|
||
|
"start = lastHourDateTime.strftime('%Y-%m-%d %H')\n",
|
||
|
"beginRange = datetime.strptime( start + \":00:00\", \"%Y-%m-%d %H:%M:%S\")\n",
|
||
|
"endRange = datetime.strptime( start + \":59:59\", \"%Y-%m-%d %H:%M:%S\")\n",
|
||
|
"timerange = TimeRange(beginRange, endRange)\n",
|
||
|
"\n",
|
||
|
"response = DataAccessLayer.getGeometryData(request,timerange)"
|
||
|
]
|
||
|
},
|
||
|
{
|
||
|
"cell_type": "code",
|
||
|
"execution_count": 5,
|
||
|
"metadata": {},
|
||
|
"outputs": [],
|
||
|
"source": [
|
||
|
"station_names = []\n",
|
||
|
"for ob in response:\n",
|
||
|
" avail_params = [x.decode('utf-8') for x in ob.getParameters()]\n",
|
||
|
" if \"presWeather\" in avail_params:\n",
|
||
|
" pres_weather.append(ob.getString(\"presWeather\"))\n",
|
||
|
" elif \"skyCover\" in avail_params and \"skyLayerBase\" in avail_params:\n",
|
||
|
" sky_cov.append(ob.getString(\"skyCover\"))\n",
|
||
|
" sky_layer_base.append(ob.getNumber(\"skyLayerBase\"))\n",
|
||
|
" else:\n",
|
||
|
" # If we already have a record for this stationName, skip\n",
|
||
|
" if ob.getString('stationName') not in station_names:\n",
|
||
|
" station_names.append(ob.getString('stationName'))\n",
|
||
|
" for param in single_value_params: \n",
|
||
|
" if param in avail_params:\n",
|
||
|
" if param == 'timeObs':\n",
|
||
|
" obs[param].append(datetime.fromtimestamp(ob.getNumber(param)/1000.0))\n",
|
||
|
" else:\n",
|
||
|
" try:\n",
|
||
|
" obs[param].append(ob.getNumber(param))\n",
|
||
|
" except TypeError:\n",
|
||
|
" obs[param].append(ob.getString(param))\n",
|
||
|
" else:\n",
|
||
|
" obs[param].append(None)\n",
|
||
|
" \n",
|
||
|
" obs['presWeather'].append(pres_weather);\n",
|
||
|
" obs['skyCover'].append(sky_cov);\n",
|
||
|
" obs['skyLayerBase'].append(sky_layer_base);\n",
|
||
|
" pres_weather = []\n",
|
||
|
" sky_cov = []\n",
|
||
|
" sky_layer_base = []"
|
||
|
]
|
||
|
},
|
||
|
{
|
||
|
"cell_type": "markdown",
|
||
|
"metadata": {},
|
||
|
"source": [
|
||
|
"Next grab the simple variables out of the data we have (attaching correct units), and\n",
|
||
|
"put them into a dictionary that we will hand the plotting function later:\n",
|
||
|
"\n",
|
||
|
"- Get wind components from speed and direction\n",
|
||
|
"- Convert cloud fraction values to integer codes [0 - 8]\n",
|
||
|
"- Map METAR weather codes to WMO codes for weather symbols"
|
||
|
]
|
||
|
},
|
||
|
{
|
||
|
"cell_type": "code",
|
||
|
"execution_count": 6,
|
||
|
"metadata": {},
|
||
|
"outputs": [],
|
||
|
"source": [
|
||
|
"data = dict()\n",
|
||
|
"data['stid'] = np.array(obs['stationName'])\n",
|
||
|
"data['latitude'] = np.array(obs['latitude'])\n",
|
||
|
"data['longitude'] = np.array(obs['longitude'])\n",
|
||
|
"data['air_temperature'] = np.array(obs['temperature'], dtype=float)* units.degC\n",
|
||
|
"data['dew_point_temperature'] = np.array(obs['dewpoint'], dtype=float)* units.degC\n",
|
||
|
"data['air_pressure_at_sea_level'] = np.array(obs['seaLevelPress'])* units('mbar')\n",
|
||
|
"\n",
|
||
|
"direction = np.array(obs['windDir'])\n",
|
||
|
"direction[direction == -9999.0] = 'nan'\n",
|
||
|
"\n",
|
||
|
"u, v = wind_components(np.array(obs['windSpeed']) * units('knots'),\n",
|
||
|
" direction * units.degree)\n",
|
||
|
"data['eastward_wind'], data['northward_wind'] = u, v\n",
|
||
|
"data['cloud_coverage'] = [int(get_cloud_cover(x)*8) for x in obs['skyCover']]\n",
|
||
|
"data['present_weather'] = obs['presWeather']"
|
||
|
]
|
||
|
},
|
||
|
{
|
||
|
"cell_type": "markdown",
|
||
|
"metadata": {},
|
||
|
"source": [
|
||
|
"## MetPy Surface Obs Plot"
|
||
|
]
|
||
|
},
|
||
|
{
|
||
|
"cell_type": "code",
|
||
|
"execution_count": 8,
|
||
|
"metadata": {},
|
||
|
"outputs": [
|
||
|
{
|
||
|
"data": {
|
||
|
"image/png": "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
|
||
|
"text/plain": [
|
||
|
"<Figure size 1440x720 with 1 Axes>"
|
||
|
]
|
||
|
},
|
||
|
"metadata": {
|
||
|
"needs_background": "light"
|
||
|
},
|
||
|
"output_type": "display_data"
|
||
|
}
|
||
|
],
|
||
|
"source": [
|
||
|
"proj = ccrs.LambertConformal(central_longitude=-95, central_latitude=35,\n",
|
||
|
" standard_parallels=[35])\n",
|
||
|
"# Change the DPI of the figure\n",
|
||
|
"plt.rcParams['savefig.dpi'] = 255\n",
|
||
|
"\n",
|
||
|
"\n",
|
||
|
"# Create the figure and an axes set to the projection\n",
|
||
|
"fig = plt.figure(figsize=(20, 10))\n",
|
||
|
"add_metpy_logo(fig, 1080, 290, size='large')\n",
|
||
|
"ax = fig.add_subplot(1, 1, 1, projection=proj)\n",
|
||
|
"# Add some various map elements to the plot to make it recognizable\n",
|
||
|
"ax.add_feature(cfeature.LAND)\n",
|
||
|
"ax.add_feature(cfeature.OCEAN)\n",
|
||
|
"ax.add_feature(cfeature.LAKES)\n",
|
||
|
"ax.add_feature(cfeature.COASTLINE)\n",
|
||
|
"ax.add_feature(cfeature.STATES)\n",
|
||
|
"ax.add_feature(cfeature.BORDERS, linewidth=2)\n",
|
||
|
"# Set plot bounds\n",
|
||
|
"ax.set_extent((-118, -73, 23, 50))\n",
|
||
|
"ax.set_title(str(ob.getDataTime()) + \" | METAR | \" + edexServer)\n",
|
||
|
"\n",
|
||
|
"# Just winds, temps, and dewpoint, colored, with station id\n",
|
||
|
"custom_layout = StationPlotLayout()\n",
|
||
|
"custom_layout.add_barb('eastward_wind', 'northward_wind', units='knots')\n",
|
||
|
"custom_layout.add_value('NW', 'air_temperature', fmt='.0f', units='degF', color='darkred')\n",
|
||
|
"custom_layout.add_value('SW', 'dew_point_temperature', fmt='.0f', units='degF', color='darkgreen')\n",
|
||
|
"custom_layout.add_value('E', 'precipitation', fmt='0.1f', units='inch', color='blue')\n",
|
||
|
"stationplot = StationPlot(ax, data['longitude'], data['latitude'], clip_on=True,\n",
|
||
|
" transform=ccrs.PlateCarree(), fontsize=10)\n",
|
||
|
"stationplot.plot_text((2, 0), data['stid'])\n",
|
||
|
"custom_layout.plot(stationplot, data)"
|
||
|
]
|
||
|
}
|
||
|
],
|
||
|
"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.6.6"
|
||
|
}
|
||
|
},
|
||
|
"nbformat": 4,
|
||
|
"nbformat_minor": 1
|
||
|
}
|