Based on the MetPy example "Station Plot with Layout"
import datetime
import matplotlib.pyplot as plt
import numpy as np
import pprint
from awips.dataaccess import DataAccessLayer
from dynamicserialize.dstypes.com.raytheon.uf.common.time import TimeRange
from datetime import datetime, timedelta
from metpy.calc import get_wind_components
from metpy.cbook import get_test_data
from metpy.plots.wx_symbols import sky_cover, current_weather
from metpy.plots import StationPlot, StationPlotLayout, simple_layout
from metpy.units import units
import cartopy.crs as ccrs
import cartopy.feature as feat
from matplotlib import rcParams
%matplotlib inline
def get_cloud_cover(code):
if 'OVC' in code:
return 1.0
elif 'BKN' in code:
return 6.0/8.0
elif 'SCT' in code:
return 4.0/8.0
elif 'FEW' in code:
return 2.0/8.0
else:
return 0
state_capital_wx_stations = {'Washington':'KOLM', 'Oregon':'KSLE', 'California':'KSAC',
'Nevada':'KCXP', 'Idaho':'KBOI', 'Montana':'KHLN',
'Utah':'KSLC', 'Arizona':'KDVT', 'New Mexico':'KSAF',
'Colorado':'KBKF', 'Wyoming':'KCYS', 'North Dakota':'KBIS',
'South Dakota':'KPIR', 'Nebraska':'KLNK', 'Kansas':'KTOP',
'Oklahoma':'KPWA', 'Texas':'KATT', 'Louisiana':'KBTR',
'Arkansas':'KLIT', 'Missouri':'KJEF', 'Iowa':'KDSM',
'Minnesota':'KSTP', 'Wisconsin':'KMSN', 'Illinois':'KSPI',
'Mississippi':'KHKS', 'Alabama':'KMGM', 'Nashville':'KBNA',
'Kentucky':'KFFT', 'Indiana':'KIND', 'Michigan':'KLAN',
'Ohio':'KCMH', 'Georgia':'KFTY', 'Florida':'KTLH',
'South Carolina':'KCUB', 'North Carolina':'KRDU',
'Virginia':'KRIC', 'West Virginia':'KCRW',
'Pennsylvania':'KCXY', 'New York':'KALB', 'Vermont':'KMPV',
'New Hampshire':'KCON', 'Maine':'KAUG', 'Massachusetts':'KBOS',
'Rhode Island':'KPVD', 'Connecticut':'KHFD', 'New Jersey':'KTTN',
'Delaware':'KDOV', 'Maryland':'KNAK'}
single_value_params = ["timeObs", "stationName", "longitude", "latitude",
"temperature", "dewpoint", "windDir",
"windSpeed", "seaLevelPress"]
multi_value_params = ["presWeather", "skyCover", "skyLayerBase"]
pres_weather = []
sky_cov = []
sky_layer_base = []
all_params = single_value_params + multi_value_params
obs_dict = dict({all_params: [] for all_params in all_params})
# Create EDEX Request
DataAccessLayer.changeEDEXHost("edex-cloud.unidata.ucar.edu")
request = DataAccessLayer.newDataRequest()
request.setDatatype("obs")
request.setParameters(*(all_params))
request.setLocationNames(*(state_capital_wx_stations.values()))
lastHourDateTime = datetime.utcnow() - timedelta(hours = 1)
start = lastHourDateTime.strftime('%Y-%m-%d %H')
beginRange = datetime.strptime( start + ":00:00", "%Y-%m-%d %H:%M:%S")
endRange = datetime.strptime( start + ":59:59", "%Y-%m-%d %H:%M:%S")
timerange = TimeRange(beginRange, endRange)
response = DataAccessLayer.getGeometryData(request,timerange)
for ob in response:
avail_params = ob.getParameters()
if "presWeather" in avail_params:
pres_weather.append(ob.getString("presWeather"))
elif "skyCover" in avail_params and "skyLayerBase" in avail_params:
sky_cov.append(ob.getString("skyCover"))
sky_layer_base.append(ob.getNumber("skyLayerBase"))
else:
for param in single_value_params:
if param in avail_params:
if param == 'timeObs':
obs_dict[param].append(datetime.fromtimestamp(ob.getNumber(param)/1000.0))
else:
try:
obs_dict[param].append(ob.getNumber(param))
except TypeError:
obs_dict[param].append(ob.getString(param))
else:
obs_dict[param].append(None)
obs_dict['presWeather'].append(pres_weather);
obs_dict['skyCover'].append(sky_cov);
obs_dict['skyLayerBase'].append(sky_layer_base);
pres_weather = []
sky_cov = []
sky_layer_base = []
data = dict()
data['stid'] = np.array(df_recent["stationName"])
data['latitude'] = np.array(df_recent['latitude'])
data['longitude'] = np.array(df_recent['longitude'])
data['air_temperature'] = np.array(df_recent['temperature'], dtype=float)* units.degC
data['dew_point'] = np.array(df_recent['dewpoint'], dtype=float)* units.degC
data['slp'] = np.array(df_recent['seaLevelPress'])* units('mbar')
u, v = get_wind_components(np.array(df_recent['windSpeed']) * units('knots'),
np.array(df_recent['windDir']) * units.degree)
data['eastward_wind'], data['northward_wind'] = u, v
data['cloud_frac'] = [int(get_cloud_cover(x)*8) for x in df_recent['skyCover']]
rcParams['savefig.dpi'] = 100
proj = ccrs.LambertConformal(central_longitude=-95, central_latitude=35,
standard_parallels=[35])
state_boundaries = feat.NaturalEarthFeature(category='cultural',
name='admin_1_states_provinces_lines',
scale='110m', facecolor='none')
# Create the figure
fig = plt.figure(figsize=(20, 15))
ax = fig.add_subplot(1, 1, 1, projection=proj)
# Add map elements
ax.add_feature(feat.LAND, zorder=-1)
ax.add_feature(feat.OCEAN, zorder=-1)
ax.add_feature(feat.LAKES, zorder=-1)
ax.coastlines(resolution='110m', zorder=2, color='black')
ax.add_feature(state_boundaries)
ax.add_feature(feat.BORDERS, linewidth='2', edgecolor='black')
ax.set_extent((-120, -70, 20, 50))
# Start the station plot by specifying the axes to draw on, as well as the
# lon/lat of the stations (with transform). We also set the fontsize to 12 pt.
stationplot = StationPlot(ax, data['longitude'], data['latitude'],
transform=ccrs.PlateCarree(), fontsize=12)
# The layout knows where everything should go, and things are standardized using
# the names of variables. So the layout pulls arrays out of `data` and plots them
# using `stationplot`.
simple_layout.plot(stationplot, data)
# Plot the temperature and dew point to the upper and lower left, respectively, of
# the center point. Each one uses a different color.
stationplot.plot_parameter('NW', np.array(data['air_temperature']), color='red')
stationplot.plot_parameter('SW', np.array(data['dew_point']), color='darkgreen')
# A more complex example uses a custom formatter to control how the sea-level pressure
# values are plotted. This uses the standard trailing 3-digits of the pressure value
# in tenths of millibars.
stationplot.plot_parameter('NE', np.array(data['slp']),
formatter=lambda v: format(10 * v, '.0f')[-3:])
# Plot the cloud cover symbols in the center location. This uses the codes made above and
# uses the `sky_cover` mapper to convert these values to font codes for the
# weather symbol font.
stationplot.plot_symbol('C', data['cloud_frac'], sky_cover)
# Also plot the actual text of the station id. Instead of cardinal directions,
# plot further out by specifying a location of 2 increments in x and 0 in y.
stationplot.plot_text((2, 0), np.array(obs_dict["stationName"]))
plt.title("Most Recent Observations for State Capitals")
TextCollection
Error in callback <function post_execute at 0x111a21320> (for post_execute):
--------------------------------------------------------------------------- TypeError Traceback (most recent call last) /Users/mjames/miniconda2/envs/python-awips/lib/python2.7/site-packages/matplotlib/pyplot.pyc in post_execute() 147 def post_execute(): 148 if matplotlib.is_interactive(): --> 149 draw_all() 150 151 # IPython >= 2 /Users/mjames/miniconda2/envs/python-awips/lib/python2.7/site-packages/matplotlib/_pylab_helpers.pyc in draw_all(cls, force) 134 for f_mgr in cls.get_all_fig_managers(): 135 if force or f_mgr.canvas.figure.stale: --> 136 f_mgr.canvas.draw_idle() 137 138 atexit.register(Gcf.destroy_all) /Users/mjames/miniconda2/envs/python-awips/lib/python2.7/site-packages/matplotlib/backend_bases.pyc in draw_idle(self, *args, **kwargs) 2053 if not self._is_idle_drawing: 2054 with self._idle_draw_cntx(): -> 2055 self.draw(*args, **kwargs) 2056 2057 def draw_cursor(self, event): /Users/mjames/miniconda2/envs/python-awips/lib/python2.7/site-packages/matplotlib/backends/backend_agg.pyc in draw(self) 431 # if toolbar: 432 # toolbar.set_cursor(cursors.WAIT) --> 433 self.figure.draw(self.renderer) 434 # A GUI class may be need to update a window using this draw, so 435 # don't forget to call the superclass. /Users/mjames/miniconda2/envs/python-awips/lib/python2.7/site-packages/matplotlib/artist.pyc in draw_wrapper(artist, renderer, *args, **kwargs) 53 renderer.start_filter() 54 ---> 55 return draw(artist, renderer, *args, **kwargs) 56 finally: 57 if artist.get_agg_filter() is not None: /Users/mjames/miniconda2/envs/python-awips/lib/python2.7/site-packages/matplotlib/figure.pyc in draw(self, renderer) 1473 1474 mimage._draw_list_compositing_images( -> 1475 renderer, self, artists, self.suppressComposite) 1476 1477 renderer.close_group('figure') /Users/mjames/miniconda2/envs/python-awips/lib/python2.7/site-packages/matplotlib/image.pyc in _draw_list_compositing_images(renderer, parent, artists, suppress_composite) 139 if not_composite or not has_images: 140 for a in artists: --> 141 a.draw(renderer) 142 else: 143 # Composite any adjacent images together /Users/mjames/miniconda2/envs/python-awips/lib/python2.7/site-packages/matplotlib/artist.pyc in draw_wrapper(artist, renderer, *args, **kwargs) 53 renderer.start_filter() 54 ---> 55 return draw(artist, renderer, *args, **kwargs) 56 finally: 57 if artist.get_agg_filter() is not None: /Users/mjames/miniconda2/envs/python-awips/lib/python2.7/site-packages/cartopy/mpl/geoaxes.pyc in draw(self, renderer, inframe) 383 384 return matplotlib.axes.Axes.draw(self, renderer=renderer, --> 385 inframe=inframe) 386 387 def __str__(self): /Users/mjames/miniconda2/envs/python-awips/lib/python2.7/site-packages/matplotlib/artist.pyc in draw_wrapper(artist, renderer, *args, **kwargs) 53 renderer.start_filter() 54 ---> 55 return draw(artist, renderer, *args, **kwargs) 56 finally: 57 if artist.get_agg_filter() is not None: /Users/mjames/miniconda2/envs/python-awips/lib/python2.7/site-packages/matplotlib/axes/_base.pyc in draw(self, renderer, inframe) 2605 renderer.stop_rasterizing() 2606 -> 2607 mimage._draw_list_compositing_images(renderer, self, artists) 2608 2609 renderer.close_group('axes') /Users/mjames/miniconda2/envs/python-awips/lib/python2.7/site-packages/matplotlib/image.pyc in _draw_list_compositing_images(renderer, parent, artists, suppress_composite) 139 if not_composite or not has_images: 140 for a in artists: --> 141 a.draw(renderer) 142 else: 143 # Composite any adjacent images together /Users/mjames/miniconda2/envs/python-awips/lib/python2.7/site-packages/matplotlib/artist.pyc in draw_wrapper(artist, renderer, *args, **kwargs) 53 renderer.start_filter() 54 ---> 55 return draw(artist, renderer, *args, **kwargs) 56 finally: 57 if artist.get_agg_filter() is not None: /Users/mjames/miniconda2/envs/python-awips/lib/python2.7/site-packages/cartopy/mpl/feature_artist.pyc in draw(self, renderer, *args, **kwargs) 179 c.set_clip_path(ax.patch) 180 c.set_figure(ax.figure) --> 181 return c.draw(renderer) /Users/mjames/miniconda2/envs/python-awips/lib/python2.7/site-packages/matplotlib/artist.pyc in draw_wrapper(artist, renderer, *args, **kwargs) 53 renderer.start_filter() 54 ---> 55 return draw(artist, renderer, *args, **kwargs) 56 finally: 57 if artist.get_agg_filter() is not None: /Users/mjames/miniconda2/envs/python-awips/lib/python2.7/site-packages/matplotlib/collections.pyc in draw(self, renderer) 909 def draw(self, renderer): 910 self.set_sizes(self._sizes, self.figure.dpi) --> 911 Collection.draw(self, renderer) 912 913 /Users/mjames/miniconda2/envs/python-awips/lib/python2.7/site-packages/matplotlib/artist.pyc in draw_wrapper(artist, renderer, *args, **kwargs) 53 renderer.start_filter() 54 ---> 55 return draw(artist, renderer, *args, **kwargs) 56 finally: 57 if artist.get_agg_filter() is not None: /Users/mjames/miniconda2/envs/python-awips/lib/python2.7/site-packages/matplotlib/collections.pyc in draw(self, renderer) 335 self._linewidths, self._linestyles, 336 self._antialiaseds, self._urls, --> 337 self._offset_position) 338 339 gc.restore() /Users/mjames/miniconda2/envs/python-awips/lib/python2.7/site-packages/matplotlib/backends/backend_agg.pyc in draw_path_collection(self, *kl, **kw) 123 124 def draw_path_collection(self, *kl, **kw): --> 125 return self._renderer.draw_path_collection(*kl, **kw) 126 127 def _update_methods(self): TypeError: Cannot cast array data from dtype('S1') to dtype('float64') according to the rule 'safe'
--------------------------------------------------------------------------- TypeError Traceback (most recent call last) /Users/mjames/miniconda2/envs/python-awips/lib/python2.7/site-packages/IPython/core/formatters.pyc in __call__(self, obj) 332 pass 333 else: --> 334 return printer(obj) 335 # Finally look for special method names 336 method = get_real_method(obj, self.print_method) /Users/mjames/miniconda2/envs/python-awips/lib/python2.7/site-packages/IPython/core/pylabtools.pyc in <lambda>(fig) 239 240 if 'png' in formats: --> 241 png_formatter.for_type(Figure, lambda fig: print_figure(fig, 'png', **kwargs)) 242 if 'retina' in formats or 'png2x' in formats: 243 png_formatter.for_type(Figure, lambda fig: retina_figure(fig, **kwargs)) /Users/mjames/miniconda2/envs/python-awips/lib/python2.7/site-packages/IPython/core/pylabtools.pyc in print_figure(fig, fmt, bbox_inches, **kwargs) 123 124 bytes_io = BytesIO() --> 125 fig.canvas.print_figure(bytes_io, **kw) 126 data = bytes_io.getvalue() 127 if fmt == 'svg': /Users/mjames/miniconda2/envs/python-awips/lib/python2.7/site-packages/matplotlib/backend_bases.pyc in print_figure(self, filename, dpi, facecolor, edgecolor, orientation, format, **kwargs) 2210 orientation=orientation, 2211 dryrun=True, -> 2212 **kwargs) 2213 renderer = self.figure._cachedRenderer 2214 bbox_inches = self.figure.get_tightbbox(renderer) /Users/mjames/miniconda2/envs/python-awips/lib/python2.7/site-packages/matplotlib/backends/backend_agg.pyc in print_png(self, filename_or_obj, *args, **kwargs) 511 512 def print_png(self, filename_or_obj, *args, **kwargs): --> 513 FigureCanvasAgg.draw(self) 514 renderer = self.get_renderer() 515 original_dpi = renderer.dpi /Users/mjames/miniconda2/envs/python-awips/lib/python2.7/site-packages/matplotlib/backends/backend_agg.pyc in draw(self) 431 # if toolbar: 432 # toolbar.set_cursor(cursors.WAIT) --> 433 self.figure.draw(self.renderer) 434 # A GUI class may be need to update a window using this draw, so 435 # don't forget to call the superclass. /Users/mjames/miniconda2/envs/python-awips/lib/python2.7/site-packages/matplotlib/artist.pyc in draw_wrapper(artist, renderer, *args, **kwargs) 53 renderer.start_filter() 54 ---> 55 return draw(artist, renderer, *args, **kwargs) 56 finally: 57 if artist.get_agg_filter() is not None: /Users/mjames/miniconda2/envs/python-awips/lib/python2.7/site-packages/matplotlib/figure.pyc in draw(self, renderer) 1473 1474 mimage._draw_list_compositing_images( -> 1475 renderer, self, artists, self.suppressComposite) 1476 1477 renderer.close_group('figure') /Users/mjames/miniconda2/envs/python-awips/lib/python2.7/site-packages/matplotlib/image.pyc in _draw_list_compositing_images(renderer, parent, artists, suppress_composite) 139 if not_composite or not has_images: 140 for a in artists: --> 141 a.draw(renderer) 142 else: 143 # Composite any adjacent images together /Users/mjames/miniconda2/envs/python-awips/lib/python2.7/site-packages/matplotlib/artist.pyc in draw_wrapper(artist, renderer, *args, **kwargs) 53 renderer.start_filter() 54 ---> 55 return draw(artist, renderer, *args, **kwargs) 56 finally: 57 if artist.get_agg_filter() is not None: /Users/mjames/miniconda2/envs/python-awips/lib/python2.7/site-packages/cartopy/mpl/geoaxes.pyc in draw(self, renderer, inframe) 383 384 return matplotlib.axes.Axes.draw(self, renderer=renderer, --> 385 inframe=inframe) 386 387 def __str__(self): /Users/mjames/miniconda2/envs/python-awips/lib/python2.7/site-packages/matplotlib/artist.pyc in draw_wrapper(artist, renderer, *args, **kwargs) 53 renderer.start_filter() 54 ---> 55 return draw(artist, renderer, *args, **kwargs) 56 finally: 57 if artist.get_agg_filter() is not None: /Users/mjames/miniconda2/envs/python-awips/lib/python2.7/site-packages/matplotlib/axes/_base.pyc in draw(self, renderer, inframe) 2605 renderer.stop_rasterizing() 2606 -> 2607 mimage._draw_list_compositing_images(renderer, self, artists) 2608 2609 renderer.close_group('axes') /Users/mjames/miniconda2/envs/python-awips/lib/python2.7/site-packages/matplotlib/image.pyc in _draw_list_compositing_images(renderer, parent, artists, suppress_composite) 139 if not_composite or not has_images: 140 for a in artists: --> 141 a.draw(renderer) 142 else: 143 # Composite any adjacent images together /Users/mjames/miniconda2/envs/python-awips/lib/python2.7/site-packages/matplotlib/artist.pyc in draw_wrapper(artist, renderer, *args, **kwargs) 53 renderer.start_filter() 54 ---> 55 return draw(artist, renderer, *args, **kwargs) 56 finally: 57 if artist.get_agg_filter() is not None: /Users/mjames/miniconda2/envs/python-awips/lib/python2.7/site-packages/cartopy/mpl/feature_artist.pyc in draw(self, renderer, *args, **kwargs) 179 c.set_clip_path(ax.patch) 180 c.set_figure(ax.figure) --> 181 return c.draw(renderer) /Users/mjames/miniconda2/envs/python-awips/lib/python2.7/site-packages/matplotlib/artist.pyc in draw_wrapper(artist, renderer, *args, **kwargs) 53 renderer.start_filter() 54 ---> 55 return draw(artist, renderer, *args, **kwargs) 56 finally: 57 if artist.get_agg_filter() is not None: /Users/mjames/miniconda2/envs/python-awips/lib/python2.7/site-packages/matplotlib/collections.pyc in draw(self, renderer) 909 def draw(self, renderer): 910 self.set_sizes(self._sizes, self.figure.dpi) --> 911 Collection.draw(self, renderer) 912 913 /Users/mjames/miniconda2/envs/python-awips/lib/python2.7/site-packages/matplotlib/artist.pyc in draw_wrapper(artist, renderer, *args, **kwargs) 53 renderer.start_filter() 54 ---> 55 return draw(artist, renderer, *args, **kwargs) 56 finally: 57 if artist.get_agg_filter() is not None: /Users/mjames/miniconda2/envs/python-awips/lib/python2.7/site-packages/matplotlib/collections.pyc in draw(self, renderer) 335 self._linewidths, self._linestyles, 336 self._antialiaseds, self._urls, --> 337 self._offset_position) 338 339 gc.restore() /Users/mjames/miniconda2/envs/python-awips/lib/python2.7/site-packages/matplotlib/backends/backend_agg.pyc in draw_path_collection(self, *kl, **kw) 123 124 def draw_path_collection(self, *kl, **kw): --> 125 return self._renderer.draw_path_collection(*kl, **kw) 126 127 def _update_methods(self): TypeError: Cannot cast array data from dtype('S1') to dtype('float64') according to the rule 'safe'
<Figure size 1440x1080 with 1 Axes>