Source code for DWR_plots.scatter_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.
#

# Combination scatter+contour plot

import iris
import DWR
import numpy
import collections
import matplotlib
from matplotlib.patches import Circle
import cartopy
import cartopy.crs as ccrs
import Meteorographica as mg

from .scatter import plot_scatter
from .contour import plot_contour

[docs]def plot_scatter_contour(fig,field,obs_r,dwr_obs,dte,**kwargs): """Make a combined contour-plot and scatter plot Args: fig (:`matplotlib.figure`): Figure to hold the plot field (:obj:`iris.Cube.cube`): Reanalysis mslp ensemble obs_r (:obj:`pandas.DataFrame`): Reanalysis observations. dwr_obs (:obj:`pandas.DataFrame`): DWR observations. dte (:obj:`datetime.datetime`): Time of data to plot Kwargs: projection (:obj:`cartopy.crs`): Map projection to use, default UKV. scale (:obj:`float`): Map scale - latitude range, default 20. pressure_range (:obj:`list`): (min,max) pressure for scatterplot, default [945,1045]. 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. 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. xlabel (:obj:`str`): x-axis label for scatter plot, default 'MSLP (hPa)'. scatter_point_size (:obj:`float`): Size of ensemble dots in scatter plot (pts), default 25. scatter_alpha (:obj:`float`): Alpha transparency of ensemble dots in scatter plot (pts), default 0.5. stations (:obj:`list`): Names of DWR stations to plot, if missing, taken from dwr_obs. station_latlon (:obj:`dict`): Positions of DWR stations to plot (each station entry a dictionary with 'latitude' and 'longitude'), if missing, taken from dwr_obs. | """ # Set keyword argument defaults kwargs.setdefault('projection',ccrs.RotatedPole(pole_longitude=177.5, pole_latitude=35.5)) kwargs.setdefault('scale',20.0) kwargs.setdefault('stations',list(collections.OrderedDict.fromkeys( dwr_obs.loc[:,'name']).keys())) 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_map=fig.add_axes([0.01,0.01,0.485,0.98], projection=kwargs.get('projection')) aspect=fig.get_size_inches()[1]/(fig.get_size_inches()[0]/2.0) extent=[kwargs.get('scale')*-1,kwargs.get('scale'), kwargs.get('scale')*-1*aspect,kwargs.get('scale')*aspect] if kwargs.get('stations') is None: stations=list(collections.OrderedDict.fromkeys( dwr_obs.loc[:,'name']).keys()) plot_contour(ax_map,extent,dte,field,obs_r,dwr_obs,**kwargs) # Label with the date mg.utils.plot_label(ax_map, '%04d-%02d-%02d:%02d' % (dte.year,dte.month, dte.day,dte.hour), facecolor=fig.get_facecolor(), x_fraction=0.02, horizontalalignment='left') ax_scp=fig.add_axes([0.6,0.06,0.39,0.93]) plot_scatter(ax_scp,field,dwr_obs,dte,**kwargs) # Join each station name to its location on the map # Need another axes, filling the whole fig ax_full=fig.add_axes([0,0,1,1]) ax_full.patch.set_alpha(0.0) # Transparent background # Map location of a station in ax_full coordinates def pos_left(idx): station=kwargs.get('stations')[idx] latlon=kwargs.get('station_latlon')[station] rp=ax_map.projection.transform_points(ccrs.PlateCarree(), numpy.asarray(latlon['longitude']), numpy.asarray(latlon['latitude'])) new_lon=rp[:,0] new_lat=rp[:,1] result={} scale=kwargs.get('scale') result['x']=0.01+0.485*((new_lon-(scale*-1))/(scale*2)) result['y']=0.01+0.98*((new_lat-(scale*aspect*-1))/ (scale*2*aspect)) return result # Label location of a station in ax_full coordinates def pos_right(idx): result={} result['x']=0.51 result['y']=0.06+(0.93/len(kwargs.get('stations')))*(idx+0.5) return result for i in range(0,len(kwargs.get('stations'))): p_left=pos_left(i) p_right=pos_right(i) ax_full.add_patch(Circle((p_right['x'], p_right['y']), radius=0.001, facecolor=(1,0,0,1), edgecolor=(0,0,0,1), alpha=1, zorder=1)) ax_full.add_line(matplotlib.lines.Line2D( xdata=(p_left['x'],p_right['x']), ydata=(p_left['y'],p_right['y']), linestyle='solid', linewidth=0.2, color=(1,0,0,0.5), zorder=1))