Source code for DWR_plots.contour

# (C) British Crown Copyright 2017, Met Office
#
# This code is free software: you can redistribute it and/or modify it under
# the terms of the GNU Lesser General Public License as published by the
# Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This code is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU Lesser General Public License for more details.
#

# Plot reanalysis pressure and DWR observations

import iris
import iris.analysis
import matplotlib
import matplotlib.cm
import cartopy.crs as ccrs
import numpy
import pandas
import Meteorographica as mg
import collections

[docs]def plot_contour(ax,extent,dte,field,obs_r,dwr_obs,**kwargs): """Make a mslp contour plot with DWR observations Args: ax (:`cartopy.axes`): Axes to hold the plot extent (:obj:`list`) Plot extent (lon.min,lon.max,lat.min,lat.max) dte (:obj:`datetime.datetime`): Time of plot field (:obj:`iris.Cube.cube`): Reanalysis mslp ensemble obs_r (:obj:`pandas.DataFrame`): Reanalysis observations. dwr_obs (:obj:`pandas.DataFrame`): DWR observations. Kwargs: projection (:obj:`cartopy.crs`): Map projection to use, default UKV. obs_radius (:obj:`float`): Reanalysis obs plot size, default 0.15. contour_levels (:obj:`list`): Values to plot contours at, default numpy.arange(870,1050,10). contour_width (:obj:`float`): Width of member contour lines, default 0.1. contour_mask (:obj:`float`): Plot mean contours where spread < this, default 3. n_contours (:obj:`int`): Max. number of member contour to plot, default None - all members. label_mean_contour (:obj:`bool`): Label the mean contour lines? Default=True. dwr_color (:obj:`str`): Either a color name, or the string 'anomaly' (default) to color by pressure anomaly. dwr_anomaly_range (:obj:`float`): Anomaly color scale factor, default 20. dwr_radius (:obj:`float`): DWR obs plot size, default 0.25. stations (:obj:`list`): Names (DWR format) of stations to be included, default is stations in dwr_obs. station_latlon (:obj:`dict`): Latitiudes and Longitudes of stations to be included, default is taken from dwr_obs. | """ # Set keyword argument defaults kwargs.setdefault('projection',ccrs.RotatedPole(pole_longitude=177.5, pole_latitude=35.5)) kwargs.setdefault('obs_radius',0.15) kwargs.setdefault('contour_levels',numpy.arange(870,1050,10)) kwargs.setdefault('contour_width',0.1) kwargs.setdefault('contour_mask',3.0) kwargs.setdefault('n_contours',None) kwargs.setdefault('label_mean_contour',True) if dwr_obs is not None: kwargs.setdefault('dwr_color','anomaly') kwargs.setdefault('dwr_anomaly_range',20.0) kwargs.setdefault('dwr_radius',0.25) kwargs.setdefault('stations',list(collections.OrderedDict.fromkeys( dwr_obs.loc[:,'name']).keys())) if 'station_latlon' not in kwargs: latlon={} for station in kwargs.get('stations'): latlon[station]=DWR.get_station_location(dwr_obs,station) kwargs['station_latlon']=latlon ax.set_axis_off() ax.set_extent(extent,crs=kwargs.get('projection')) ax.background_patch.set_facecolor(ax.get_figure().get_facecolor()) mg.background.add_grid(ax) land_img=ax.background_img(name='GreyT', resolution='low') # Plot the DWR obs if dwr_obs is not None: if kwargs.get('dwr_color')=='anomaly': cmap = matplotlib.cm.get_cmap('coolwarm') interpolator = iris.analysis.Linear().interpolator(field, ['latitude', 'longitude']) interpolated={} for station in kwargs.get('stations'): try: interpolated[station]=DWR.at_station_and_time( dwr_obs,station,dte) except Exception: interpolated[station]=None ensemble=interpolator([kwargs.get('station_latlon')[station]['latitude'], kwargs.get('station_latlon')[station]['longitude']]) if interpolated[station] is None: spoof=pandas.DataFrame(data={ 'latitude' : kwargs.get('station_latlon')[station]['latitude'], 'longitude': kwargs.get('station_latlon')[station]['longitude'], 'values' : 0},index=[0]) mg.observations.plot(ax,spoof, lat_label='latitude',lon_label='longitude', radius=kwargs.get('dwr_radius'), facecolor='grey',edgecolor='black') else: stn_diff=interpolated[station]-numpy.mean(ensemble.data) dfn=max(0.01,min(0.99, stn_diff/kwargs.get('dwr_anomaly_range')+0.5)) stn_color=cmap(dfn) mg.observations.plot(ax,dwr_obs[dwr_obs['name']==station], lat_label='latitude',lon_label='longitude', radius=kwargs.get('dwr_radius'), facecolor=stn_color,edgecolor='black', zorder=5) else: for station in kwargs.get('stations'): mg.observations.plot(ax,dwr_obs[dwr_obs['name']==station], lat_label='latitude',lon_label='longitude', radius=kwargs.get('dwr_radius'), facecolor=kwargs.get('dwr_color'),edgecolor='black', zorder=5) # Plot the 20CR obs if obs_r is not None: if 'Assimilation.indicator' in obs_r.index: # in V2 only obs_s=obs_r.loc[(obs_r['Assimilation.indicator']==1)] if not obs_s.empty: mg.observations.plot(ax,obs_s,radius=kwargs.get('obs_radius'), zorder=10) obs_s=obs_r.loc[(obs_r['Assimilation.indicator']==0)] if not obs_s.empty: mg.observations.plot(ax,obs_s,radius=kwargs.get('obs_radius'), facecolor='grey',edgecolor='yellow', zorder=100) else: if not obs_r.empty: mg.observations.plot(ax,obs_r,radius=kwargs.get('obs_radius'), zorder=100) # Contour spaghetti plot of ensemble members if kwargs.get('n_contours') is not None: field_r=field.extract(iris.Constraint(member= field.coord('member').points[0:kwargs.get('n_contours')])) else: field_r=field mg.pressure.plot(ax,field_r,type='spaghetti', resolution=0.25, levels=kwargs.get('contour_levels'), colors='blue', label=False, linewidths=kwargs.get('contour_width'), zorder=15) # Add the ensemble mean - with labels field_m=field.collapsed('member', iris.analysis.MEAN) field_s=field.collapsed('member', iris.analysis.STD_DEV) field_m.data[numpy.where(field_s.data>kwargs.get('contour_mask'))]=numpy.nan mg.pressure.plot(ax,field_m, resolution=0.25, levels=kwargs.get('contour_levels'), colors='black', label=kwargs.get('label_mean_contour'), linewidths=2, zorder=20)