python-awips/examples/notebooks/Regional_Surface_Obs_Plot.ipynb

443 lines
433 KiB
Text
Raw Normal View History

{
"cells": [
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [],
"source": [
"%matplotlib inline"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"\n",
"Surface Obs Regional Plot\n",
"=====================\n",
"\n",
"This exercise creates a surface observsation station plot for the state of Colorado, using both METAR (datatype *obs*) and Synoptic (datatype *sfcobs*). Because we are using the AWIPS Map Database for state and county boundaries, there is no use of Cartopy `cfeature` in this exercise."
]
},
{
"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",
"import cartopy.crs as ccrs\n",
"from cartopy.mpl.gridliner import LONGITUDE_FORMATTER, LATITUDE_FORMATTER\n",
"from cartopy.feature import ShapelyFeature\n",
"from shapely.ops import cascaded_union\n",
"import matplotlib.pyplot as plt\n",
"from metpy.units import units\n",
"from metpy.calc import wind_components\n",
"from metpy.plots import (simple_layout, StationPlot,\n",
" StationPlotLayout, wx_code_map)\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"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Found 1 MultiPolygon\n",
"Florida FL 28.67402 -82.50934 (-87.63429260299995, 24.521051616000022, -80.03199876199994, 31.001012802000048)\n",
"\n",
"Found 6 MultiPolygons\n",
"Florida FL 28.67402 -82.50934\n",
"Georgia GA 32.65155 -83.44848\n",
"Louisiana LA 31.0891 -92.02905\n",
"Alabama AL 32.79354 -86.82676\n",
"Mississippi MS 32.75201 -89.66553\n",
"South Carolina SC 33.93574 -80.89899\n"
]
}
],
"source": [
"# EDEX request for a single state\n",
"edexServer = \"edex-cloud.unidata.ucar.edu\"\n",
"DataAccessLayer.changeEDEXHost(edexServer)\n",
"request = DataAccessLayer.newDataRequest('maps')\n",
"request.addIdentifier('table', 'mapdata.states')\n",
"request.addIdentifier('state', 'FL')\n",
"request.addIdentifier('geomField', 'the_geom')\n",
"request.setParameters('state','name','lat','lon')\n",
"response = DataAccessLayer.getGeometryData(request)\n",
"record = response[0]\n",
"print(\"Found \" + str(len(response)) + \" MultiPolygon\")\n",
"state={}\n",
"state['name'] = record.getString('name')\n",
"state['state'] = record.getString('state')\n",
"state['lat'] = record.getNumber('lat')\n",
"state['lon'] = record.getNumber('lon')\n",
"#state['geom'] = record.getGeometry()\n",
"state['bounds'] = record.getGeometry().bounds\n",
"print(state['name'], state['state'], state['lat'], state['lon'], state['bounds'])\n",
"print()\n",
"\n",
"# EDEX request for multiple states\n",
"request = DataAccessLayer.newDataRequest('maps')\n",
"request.addIdentifier('table', 'mapdata.states')\n",
"request.addIdentifier('geomField', 'the_geom')\n",
"request.addIdentifier('inLocation', 'true')\n",
"request.addIdentifier('locationField', 'state')\n",
"request.setParameters('state','name','lat','lon')\n",
"request.setLocationNames('FL','GA','MS','AL','SC','LA')\n",
"response = DataAccessLayer.getGeometryData(request)\n",
"print(\"Found \" + str(len(response)) + \" MultiPolygons\")\n",
"\n",
"# Append each geometry to a numpy array\n",
"states = np.array([])\n",
"for ob in response:\n",
" print(ob.getString('name'), ob.getString('state'), ob.getNumber('lat'), ob.getNumber('lon'))\n",
" states = np.append(states,ob.getGeometry())"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Now make sure we can plot the states with a lat/lon grid. "
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"<cartopy.mpl.feature_artist.FeatureArtist at 0x11fc149e8>"
]
},
"execution_count": 4,
"metadata": {},
"output_type": "execute_result"
},
{
"data": {
"image/png": "iVBORw0KGgoAAAANSUhEUgAAA7YAAAKPCAYAAABZ+FZJAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADl0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uIDIuMi4yLCBodHRwOi8vbWF0cGxvdGxpYi5vcmcvhp/UCwAAIABJREFUeJzs3Xd4U2X7B/DvSdNd2jLa0oJsZMjmFZQlOFhly1CGLEGmigiCKCgIKCIoIL6AILh4Qfay7DKVDRVkI6NllEJbutM0z++Pes4voS1N2iQnTb6f6zoXJydn3MnThNznWZIQAkRERERERERFlUbtAIiIiIiIiIgKg4ktERERERERFWlMbImIiIiIiKhIY2JLRERERERERRoTWyIiIiIiIirSmNgSERERERFRkcbEloiIiIiIiIo0JrZERERERERUpDGxJSIiIiIioiKNiS0REREREREVaVq1AyiMChUqiBs3bqgdBhEREREREdnGDSFEhfx2KtI1tjdu3IAQwuGX+/fvqx4Dl9yXWbNmAQACAgJYrlxYrnZePD09AQCzZs1iuXJhuTrZMnHiRJPfbJs3by4yZbt8+XKT2Ldt24ZDhw7l+B26e/du1KtXDwAwdOhQpKSkqP6+O/rCz6xzLrYuVwDlzckNi3RiS1RYV69eBQAEBgaqHAmR63F3dwcATJ06FR9//LHK0RCRNc2YMcPkcUJCgkqRWK5///4YNGiQ8rhdu3Zo0qQJfvnlF0ydOhURERF49dVXMXToULz00ktIS0vDokWL4OPjo2LURMTEllzatWvXAABBQUEqR0LkesaMGQMASE5OxmeffYaTJ0+qHBERWYterzd53LdvX5UiKZjXX39dWT9z5gwAoHfv3vj444/Rpk0bpKSkICYmBuvXry9SSTuRM2NiSy4tOjoaAFChQgV1AyFyQVOnTsW3336rPP7+++9VjIaIrEmj0UCSJABAeHi4ytFY7uWXX8bAgQMBAPXq1cvx/bRu3Tq0bdsWnTt3RqlSpdQIkYgew8SWXFpsbCwAoHr16ipHQuSaPvroI2V96NChKkZCRNak0WiUhHbr1q345ptvVI7IcoMHD1bWhwwZoiTqAODt7Y3169djzpw50GqL9FisRE6DiS25tEePHgGAMvgDEdlPdHQ04uPjlcf8HBI5l40bNyo3jt99912Vo7FcnTp1cmx7vIk1ETkOJrbkslJTU5GZmQkAaNq0qcrRELkeuY87ETknjUaDsWPHKo+nTp2qYjSW+3c0VhOsnSVyXExsyWUdPXoUAODm5obSpUurHA2R69m6dauy3qFDBxUjISJbGTBggLI+ZcoUPPPMM3j48KF6AVnA398flStXVh5Pnz5dxWiIKD9MbMllySOwcnh+IvtbtGiRMo90pUqVsHnzZpUjIiJb0Gq1JnPa/v333yhXrhzS09NVjMp8VapUUdbfeustFSMhovwwsSWXdf78eQBAiRIlVI6EyPWsXr1aWR8yZAj7rRE5sRkzZqBRo0bK45SUFGWMC0cWFRWF7du3K4/lll5E5JiY2JLLkvv3sRkykf117dpVWZ84cSK8vLzQqFEjrFmzRsWoiMhWjhw5YjJljqO20khPT0evXr0gSRLq1q2rbG/SpAl+/PFHFSMjovwwsSWXFRMTAwCoWLGiypEQuZ5Ro0bhp59+QrNmzeDm5oasrCwcO3YMPXr0wMiRI9UOj4hs4NVXX1XW1RhIatGiRQgNDcXixYtzPCeEwE8//YQqVarkaFFSq1Yt6HQ6k4GwiMjxcGg3cllxcXEAgKpVq6ocCZFr6tu3L/r27Qu9Xo/vvvsOCxYswKVLl7Bw4UIcO3YMO3bsQGBgoNphEpGV6HQ6Zf327dt2v/6wYcMAZPeV7dmzJw4fPoz//ve/SEhIwIEDB5T9goODodfrcfXqVeU7SAhhMo8tETkeJrbkspKSkgDkPk8dEdmPVqvF6NGjMXr0aLRo0QIHDhzAsWPHEBISglu3biE4OFjtEInICkJDQ5V1tce3KF68eK7blyxZgkGDBkGjMW3UyKSWyPGxKTK5JIPBoNw5fvbZZ1WOhohkly5dUtZ1Oh02bNigYjREZC0rVqyAwWBQHp87d87uMZQsWTLHtvLly6Njx45Yu3YtMjIy8Oabb+ZIaomoaOAnl1zSxYsXlfXy5curGAkRyQwGA+7du6c8bt26NQYNGqRiRERkLXPmzFHWk5KSUKpUKauePzIyEqGhoTh79myuzxsMBrz44osm2/bu3Yvr169j06ZN6NatGzw8PKwaExHZFxNbckmRkZEAOIctkdoOHToEf39/uLm5wdPTU9n+7rvvYvv27dBq2WOGyBkYdyno0qWLVc65YMECdO/eHfv27UOrVq1w9+5d1K5dG8nJySb7CSEwZswY/Pbbb8o2d3d3PPfcc1aJg4gcAxNbckl///03gLz72BCRfbz55ptISkqCwWBQ5rKtVKkS5s6dq3JkRGRNo0ePVvqp7t69Gz169CjU+dLT0/HOO+9g7dq1aNmypclzxjfJDAYD3nzzTcybN0/ZFhQUhJUrV8LLy6tQMRCRY2FiSy7p8uXLADiHLZFajhw5ghYtWuDChQvKtoYNG+LUqVO4evWqipERkS106tQJDx8+VB6vWbMGjx49KvD5vLy8lFGOH+fu7q6sf/jhh1i2bJnyuFWrVrhw4YLJ1ENE5ByY2JJLun79OoDsmiEisq8tW7agadOmJtNrlCtXDitXrkS9evVUjIyIbCkwMNBkdOHNmzcX6nzffvsttm7dmufzmzdvxhdffAGtVosdO3ZACIE9e/aoPiIzEdkGE1tySffv3wcAPPPMMypHQuRajh07hi5duiArKwu+vr748MMP8eDBA9y4cYNzShO5ACGEsm5pd6BJkyZBkiT06tULDx8+xMKFCxEeHm6yT7ly5QAAERER6NOnDwBgxowZeOWVVwoZORE5Oo7KQS5JnsO2fv36KkdC5Dq+//57jBw5EllZWfDz88M///xj9ZFRicix+fr6IiUlBQAs6uO6Y8cOzJgxAwCwevVqrF69Otf9Fi1ahH79+uHnn38GALz++usYO3ZsIaMmoqKAiS25HL1ej8zMTADgiIhEdqLX6zFkyBAA2f3fTp8+zaSWyAUVL15cSWybNGli1jFRUVFo06ZNju1BQUFKCyxZu3btAGQPIDV58mRMmDCB89ISuQh+0snlyHPcSZJkMv0AEdmORqNRpu555513ULlyZZUjIiI1fPPNN8p6aGgoTp8+bfL8+fPncezYMZNtCxYsyHGewYMH488//8yx3cvLC8OHD8fZs2fx4YcfMqklciH8tJPLOXr0KADA29tb5UiIXIdGo8Gzzz4LAPj9999VjoaI1NKlSxflJldCQgLq16+PF154AZGRkRgwYABq1qyJRo0amYyYPn78ePTu3Vt57O3tja+//tqk1YeXlxc+++wzXL9+HQsXLkSVKlXs96KIyCEwsSWXc+bMGQCcw5bI3mrVqgUAOHfuHFJTU1WOhojUoNFokJGRgTfeeEPZtn//frRq1QorVqxQtqWkpOC5557Dxo0bUaVKFSxcuFB5Li0tDcWKFUNWVhaaNGmCGjVq4MiRI5g0aRJCQkLs+nqIyHGwjy25HHkO29DQUJUjIXItcrNBDw8PiwaNISLnotFosGLFCqxYsQKff/45vvrqK8THx8PNzQ3dunVTxsE4cuQIunTpgnr16qF27doICAhAYmKicp4TJ07g0KFDar0MInIwTGzJ5dy8eRMA2MePyM7u3bsHILtvHPu9EREATJgwARMmTMix/dy5c6hatSouX76M06dP5+iLu2/fPjRv3txeYRJREcBfFuRyYmNjAQA1atRQORIi1xIXFwcA0Ol0KkdCRI4uJCQEly5dwpgxY3J93tvbG5s3b1Zqd4mImNiSy5HnsG3UqJHKkRC5FoPBAABYuXKlypEQUVExZ84cfPTRR5AkyWR7o0aN0LlzZ9StW1elyIjI0TCxJZei0+mg1+sBAI0bN1Y5GiLXkZCQoKyzfy0RWWLatGkwGAy4f/9+jmn6zp8
"text/plain": [
"<Figure size 1152x864 with 1 Axes>"
]
},
"metadata": {
"needs_background": "light"
},
"output_type": "display_data"
}
],
"source": [
"def make_map(bbox, proj=ccrs.PlateCarree()):\n",
" fig, ax = plt.subplots(figsize=(16,12),subplot_kw=dict(projection=proj))\n",
" ax.set_extent(bbox)\n",
" gl = ax.gridlines(draw_labels=True, color='#e7e7e7')\n",
" gl.xlabels_top = gl.ylabels_right = False\n",
" gl.xformatter = LONGITUDE_FORMATTER\n",
" gl.yformatter = LATITUDE_FORMATTER\n",
" return fig, ax\n",
"\n",
"# buffer our bounds by +/i degrees lat/lon\n",
"bounds = state['bounds']\n",
"bbox=[bounds[0]-3,bounds[2]+3,bounds[1]-1.5,bounds[3]+1.5]\n",
"\n",
"fig, ax = make_map(bbox=bbox)\n",
"shape_feature = ShapelyFeature(states,ccrs.PlateCarree(), \n",
" facecolor='none', linestyle=\"-\",edgecolor='#000000',linewidth=2)\n",
"ax.add_feature(shape_feature)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Plot METAR\n",
"\n",
"Here we use a spatial envelope to limit the request to the boundary or our plot. Without such a filter you may be requesting many tens of thousands of records."
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Found 2448 records\n"
]
}
],
"source": [
"from shapely.geometry import Polygon\n",
"# Create envelope geometry\n",
"envelope = Polygon([(bbox[0],bbox[2]),(bbox[0],bbox[3]),\n",
" (bbox[1], bbox[3]),(bbox[1],bbox[2]),\n",
" (bbox[0],bbox[2])])\n",
"\n",
"# New obs request\n",
"DataAccessLayer.changeEDEXHost(edexServer)\n",
"request = DataAccessLayer.newDataRequest(\"obs\", envelope=envelope)\n",
"availableProducts = DataAccessLayer.getAvailableParameters(request)\n",
"single_value_params = [\"timeObs\", \"stationName\", \"longitude\", \"latitude\", \n",
" \"temperature\", \"dewpoint\", \"windDir\",\n",
" \"windSpeed\", \"seaLevelPress\"]\n",
"multi_value_params = [\"presWeather\", \"skyCover\", \"skyLayerBase\"]\n",
"params = single_value_params + multi_value_params\n",
"request.setParameters(*(params))\n",
"\n",
"# Time range\n",
"lastHourDateTime = datetime.utcnow() - timedelta(minutes = 60)\n",
"start = lastHourDateTime.strftime('%Y-%m-%d %H:%M:%S')\n",
"end = datetime.utcnow().strftime('%Y-%m-%d %H:%M:%S')\n",
"\n",
"beginRange = datetime.strptime( start , \"%Y-%m-%d %H:%M:%S\")\n",
"endRange = datetime.strptime( end , \"%Y-%m-%d %H:%M:%S\")\n",
"timerange = TimeRange(beginRange, endRange)\n",
"# Get response\n",
"response = DataAccessLayer.getGeometryData(request,timerange)\n",
"# function getMetarObs was added in python-awips 18.1.4\n",
"obs = DataAccessLayer.getMetarObs(response)\n",
"print(\"Found \" + str(len(response)) + \" records\")"
]
},
{
"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",
"tmp = np.array(obs['temperature'], dtype=float)\n",
"dpt = np.array(obs['dewpoint'], dtype=float)\n",
"tmp[tmp == -9999.0] = 'nan'\n",
"dpt[dpt == -9999.] = 'nan' \n",
"data['air_temperature'] = tmp * units.degC\n",
"data['dew_point_temperature'] = dpt * units.degC\n",
"data['air_pressure_at_sea_level'] = np.array(obs['seaLevelPress'])* units('mbar')\n",
"direction = np.array(obs['windDir'])\n",
"direction[direction == -9999.0] = 'nan'\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": 7,
"metadata": {},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"/Users/mjames/miniconda3/envs/python3-awips/lib/python3.6/site-packages/metpy/plots/station_plot.py:299: RuntimeWarning: invalid value encountered in less\n",
" u, v = self.ax.projection.transform_vectors(trans, self.x, self.y, u, v)\n",
"/Users/mjames/miniconda3/envs/python3-awips/lib/python3.6/site-packages/metpy/plots/station_plot.py:299: RuntimeWarning: invalid value encountered in greater\n",
" u, v = self.ax.projection.transform_vectors(trans, self.x, self.y, u, v)\n"
]
},
{
"data": {
"image/png": "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
"text/plain": [
"<Figure size 1152x864 with 1 Axes>"
]
},
"execution_count": 7,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"proj = ccrs.LambertConformal(central_longitude=state['lon'], central_latitude=state['lat'],\n",
" standard_parallels=[35])\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",
"ax.set_title(str(ob.getDataTime()) + \" | METAR | \" + edexServer)\n",
"stationplot = StationPlot(ax, data['longitude'], data['latitude'], clip_on=True,\n",
" transform=ccrs.PlateCarree(), fontsize=10)\n",
"custom_layout.plot(stationplot, data)\n",
"fig"
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Found 337 records\n"
]
}
],
"source": [
"# New sfcobs/SYNOP request\n",
"DataAccessLayer.changeEDEXHost(edexServer)\n",
"request = DataAccessLayer.newDataRequest(\"sfcobs\", envelope=envelope)\n",
"availableProducts = DataAccessLayer.getAvailableParameters(request)\n",
"# (sfcobs) uses stationId, while (obs) uses stationName,\n",
"# the rest of these parameters are the same.\n",
"single_value_params = [\"timeObs\", \"stationId\", \"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",
"request.setParameters(*(params))\n",
"\n",
"# Time range\n",
"lastHourDateTime = datetime.utcnow() - timedelta(minutes = 60)\n",
"start = lastHourDateTime.strftime('%Y-%m-%d %H:%M:%S')\n",
"end = datetime.utcnow().strftime('%Y-%m-%d %H:%M:%S')\n",
"\n",
"beginRange = datetime.strptime( start , \"%Y-%m-%d %H:%M:%S\")\n",
"endRange = datetime.strptime( end , \"%Y-%m-%d %H:%M:%S\")\n",
"timerange = TimeRange(beginRange, endRange)\n",
"\n",
"# Get response\n",
"response = DataAccessLayer.getGeometryData(request,timerange)\n",
"# function getSynopticObs was added in python-awips 18.1.4\n",
"sfcobs = DataAccessLayer.getSynopticObs(response)\n",
"print(\"Found \" + str(len(response)) + \" records\")"
]
},
{
"cell_type": "code",
"execution_count": 9,
"metadata": {},
"outputs": [],
"source": [
"data = dict()\n",
"data['stid'] = np.array(sfcobs['stationId'])\n",
"data['lat'] = np.array(sfcobs['latitude'])\n",
"data['lon'] = np.array(sfcobs['longitude'])\n",
"\n",
"# Synop/sfcobs temps are stored in kelvin (degC for METAR/obs)\n",
"tmp = np.array(sfcobs['temperature'], dtype=float)\n",
"dpt = np.array(sfcobs['dewpoint'], dtype=float)\n",
"direction = np.array(sfcobs['windDir'])\n",
"# Account for missing values\n",
"tmp[tmp == -9999.0] = 'nan'\n",
"dpt[dpt == -9999.] = 'nan'\n",
"direction[direction == -9999.0] = 'nan'\n",
"\n",
"data['air_temperature'] = tmp * units.kelvin\n",
"data['dew_point_temperature'] = dpt * units.kelvin\n",
"data['air_pressure_at_sea_level'] = np.array(sfcobs['seaLevelPress'])* units('mbar')\n",
"try:\n",
" data['eastward_wind'], data['northward_wind'] = wind_components(\n",
" np.array(sfcobs['windSpeed']) * units('knots'),direction * units.degree)\n",
" data['present_weather'] = sfcobs['presWeather']\n",
"except ValueError:\n",
" pass"
]
},
{
"cell_type": "code",
"execution_count": 10,
"metadata": {},
"outputs": [
{
"data": {
"image/png": "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
"text/plain": [
"<Figure size 1152x864 with 1 Axes>"
]
},
"execution_count": 10,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"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",
"ax.set_title(str(ob.getDataTime()) + \" | SYNOP/METAR Surface Obs | \" + edexServer)\n",
"stationplot = StationPlot(ax, data['lon'], data['lat'], clip_on=True,\n",
" transform=ccrs.PlateCarree(), fontsize=10)\n",
"custom_layout.plot(stationplot, data)\n",
"fig"
]
}
],
"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
}