Source code for pyrad.graph.plots_vol

"""
pyrad.graph.plots_vol
=====================

Functions to plot radar volume data

.. autosummary::
    :toctree: generated/

    plot_ray
    plot_ppi
    plot_ppi_map
    plot_rhi
    plot_bscope
    plot_time_range
    plot_fixed_rng
    plot_fixed_rng_span
    plot_cappi
    plot_traj
    plot_rhi_contour
    plot_ppi_contour
    plot_roi_contour
    plot_rhi_profile
    plot_along_coord
    plot_field_coverage

"""
from warnings import warn

import numpy as np
from netCDF4 import num2date

try:
    import cartopy
    from cartopy.io.img_tiles import Stamen
    _CARTOPY_AVAILABLE = True
except ImportError:
    _CARTOPY_AVAILABLE = False

try:
    import shapely
    _SHAPELY_AVAILABLE = True
except ImportError:
    warn('shapely not available')
    _SHAPELY_AVAILABLE = False

import matplotlib as mpl
mpl.use('Agg')

# Increase a bit font size
mpl.rcParams.update({'font.size': 16})
mpl.rcParams.update({'font.family':  "sans-serif"})

import matplotlib.pyplot as plt

import pyart

from .plots_aux import get_colobar_label, get_norm, generate_fixed_rng_title
from .plots_aux import generate_fixed_rng_span_title
from .plots_aux import generate_complex_range_Doppler_title
from .plots import plot_quantiles, plot_histogram, _plot_time_range

from ..util.radar_utils import compute_quantiles_sweep, find_ang_index
from ..util.radar_utils import compute_histogram_sweep


[docs]def plot_ray(radar, field_name, ind_ray, prdcfg, fname_list, titl=None, vmin=None, vmax=None, save_fig=True): """ plots a ray Parameters ---------- radar : Radar object object containing the radar data to plot field_name : str name of the radar field to plot ind_ray : int ray index to plot prdcfg : dict dictionary containing the product configuration fname_list : list of str list of names of the files where to store the plot plot_type : str type of plot (PPI, QUANTILES or HISTOGRAM) titl : str Plot title vmin, vmax : float min and max values of the y axis save_fig : bool if true save the figure. If false it does not close the plot and returns the handle to the figure Returns ------- fname_list : list of str or fig, ax : tupple list of names of the saved plots or handle of the figure an axes """ rng_km = radar.range['data']/1000. dpi = prdcfg['ppiImageConfig'].get('dpi', 72) xsize = prdcfg['ppiImageConfig']['xsize'] ysize = prdcfg['ppiImageConfig']['ysize'] fig = plt.figure(figsize=[xsize, ysize], dpi=dpi) if titl is None: titl = generate_complex_range_Doppler_title( radar, field_name, ind_ray) labely = get_colobar_label(radar.fields[field_name], field_name) ax = fig.add_subplot(111) ax.plot(rng_km, radar.fields[field_name]['data'][ind_ray, :], marker='x') ax.set_title(titl) ax.set_xlabel('Range (km)') ax.set_ylabel(labely) ax.set_ylim(bottom=vmin, top=vmax) ax.set_xlim([rng_km[0], rng_km[-1]]) # Turn on the grid ax.grid() # Make a tight layout fig.tight_layout() if save_fig: for fname in fname_list: fig.savefig(fname, dpi=dpi) plt.close(fig) return fname_list return (fig, ax)
[docs]def plot_ppi(radar, field_name, ind_el, prdcfg, fname_list, plot_type='PPI', titl=None, vmin=None, vmax=None, step=None, quantiles=None, save_fig=True): """ plots a PPI Parameters ---------- radar : Radar object object containing the radar data to plot field_name : str name of the radar field to plot ind_el : int sweep index to plot prdcfg : dict dictionary containing the product configuration fname_list : list of str list of names of the files where to store the plot plot_type : str type of plot (PPI, QUANTILES or HISTOGRAM) titl : str Plot title vmin, vmax : float The minimum and maximum value. If None the scale is going to be obtained from the Py-ART config file. step : float step for histogram plotting quantiles : float array quantiles to plot save_fig : bool if true save the figure. If false it does not close the plot and returns the handle to the figure Returns ------- fname_list : list of str or fig, ax : tupple list of names of the saved plots or handle of the figure an axes """ if plot_type == 'PPI': dpi = prdcfg['ppiImageConfig'].get('dpi', 72) norm = None ticks = None ticklabs = None if vmin is None or vmax is None: norm, ticks, ticklabs = get_norm(field_name) vmin = None vmax = None xsize = prdcfg['ppiImageConfig']['xsize'] ysize = prdcfg['ppiImageConfig']['ysize'] fig = plt.figure(figsize=[xsize, ysize], dpi=dpi) ax = fig.add_subplot(111, aspect='equal') display = pyart.graph.RadarDisplay(radar) display.plot_ppi( field_name, title=titl, sweep=ind_el, norm=norm, ticks=ticks, vmin=vmin, vmax=vmax, ticklabs=ticklabs, fig=fig, ax=ax) display.set_limits( ylim=[prdcfg['ppiImageConfig']['ymin'], prdcfg['ppiImageConfig']['ymax']], xlim=[prdcfg['ppiImageConfig']['xmin'], prdcfg['ppiImageConfig']['xmax']], ax=ax) if 'rngRing' in prdcfg['ppiImageConfig']: if prdcfg['ppiImageConfig']['rngRing'] > 0: display.plot_range_rings(np.arange( 0., radar.range['data'][-1]/1000., prdcfg['ppiImageConfig']['rngRing']), ax=ax) display.plot_cross_hair(5., ax=ax) # Turn on the grid ax.grid() # Make a tight layout fig.tight_layout() if save_fig: for fname in fname_list: fig.savefig(fname, dpi=dpi) plt.close(fig) return fname_list return (fig, ax) if plot_type == 'QUANTILES': quantiles, values = compute_quantiles_sweep( radar.fields[field_name]['data'], radar.sweep_start_ray_index['data'][ind_el], radar.sweep_end_ray_index['data'][ind_el], quantiles=quantiles) titl = pyart.graph.common.generate_title(radar, field_name, ind_el) labely = get_colobar_label(radar.fields[field_name], field_name) plot_quantiles(quantiles, values, fname_list, labelx='quantile', labely=labely, titl=titl) elif plot_type == 'HISTOGRAM': bins, values = compute_histogram_sweep( radar.fields[field_name]['data'], radar.sweep_start_ray_index['data'][ind_el], radar.sweep_end_ray_index['data'][ind_el], field_name, step=step) titl = pyart.graph.common.generate_title(radar, field_name, ind_el) labelx = get_colobar_label(radar.fields[field_name], field_name) plot_histogram(bins, values, fname_list, labelx=labelx, labely='Number of Samples', titl=titl) else: warn('Unknown plot type '+plot_type) return fname_list
[docs]def plot_ppi_map(radar, field_name, ind_el, prdcfg, fname_list, save_fig=True): """ plots a PPI on a geographic map Parameters ---------- radar : Radar object object containing the radar data to plot field_name : str name of the radar field to plot ind_el : int sweep index to plot prdcfg : dict dictionary containing the product configuration fname_list : list of str list of names of the files where to store the plot save_fig : bool if true save the figure. If false it does not close the plot and returns the handle to the figure Returns ------- fname_list : list of str or fig, ax, display : tupple list of names of the saved plots or handle of the figure an axes """ dpi = prdcfg['ppiImageConfig'].get('dpi', 72) norm, ticks, ticklabs = get_norm(field_name) xsize = prdcfg['ppiMapImageConfig']['xsize'] ysize = prdcfg['ppiMapImageConfig']['ysize'] lonstep = prdcfg['ppiMapImageConfig'].get('lonstep', 0.5) latstep = prdcfg['ppiMapImageConfig'].get('latstep', 0.5) min_lon = prdcfg['ppiMapImageConfig'].get('lonmin', 2.5) max_lon = prdcfg['ppiMapImageConfig'].get('lonmax', 12.5) min_lat = prdcfg['ppiMapImageConfig'].get('latmin', 43.5) max_lat = prdcfg['ppiMapImageConfig'].get('latmax', 49.5) resolution = prdcfg['ppiMapImageConfig'].get('mapres', '110m') if resolution not in ('110m', '50m', '10m'): warn('Unknown map resolution: '+resolution) resolution = '110m' background_zoom = prdcfg['ppiMapImageConfig'].get('background_zoom', 8) lon_lines = np.arange(np.floor(min_lon), np.ceil(max_lon)+1, lonstep) lat_lines = np.arange(np.floor(min_lat), np.ceil(max_lat)+1, latstep) fig = plt.figure(figsize=[xsize, ysize], dpi=dpi) ax = fig.add_subplot(111) display_map = pyart.graph.RadarMapDisplay(radar) display_map.plot_ppi_map( field_name, sweep=ind_el, norm=norm, ticks=ticks, ticklabs=ticklabs, min_lon=min_lon, max_lon=max_lon, min_lat=min_lat, max_lat=max_lat, resolution=resolution, background_zoom=background_zoom, lat_lines=lat_lines, lon_lines=lon_lines, maps_list=prdcfg['ppiMapImageConfig']['maps'], ax=ax, fig=fig, colorbar_flag=True, alpha=1) ax = display_map.ax if 'rngRing' in prdcfg['ppiMapImageConfig']: if prdcfg['ppiMapImageConfig']['rngRing'] > 0: rng_rings = np.arange( 0., radar.range['data'][-1]/1000., prdcfg['ppiMapImageConfig']['rngRing']) for rng_ring in rng_rings: display_map.plot_range_ring(rng_ring, ax=ax) if save_fig: for fname in fname_list: fig.savefig(fname, dpi=dpi) plt.close(fig) return fname_list return (fig, ax, display_map)
[docs]def plot_rhi(radar, field_name, ind_az, prdcfg, fname_list, plot_type='RHI', titl=None, vmin=None, vmax=None, step=None, quantiles=None, save_fig=True): """ plots an RHI Parameters ---------- radar : Radar object object containing the radar data to plot field_name : str name of the radar field to plot ind_az : int sweep index to plot prdcfg : dict dictionary containing the product configuration fname_list : list of str list of names of the files where to store the plot plot_type : str type of plot (PPI, QUANTILES or HISTOGRAM) titl : str Plot title vmin, vmax : float The minimum and maximum value. If None the scale is going to be obtained from the Py-ART config file. step : float step for histogram plotting quantiles : float array quantiles to plot save_fig : bool if true save the figure. If false it does not close the plot and returns the handle to the figure Returns ------- fname_list : list of str or fig, ax : tupple list of names of the saved plots or handle of the figure an axes """ if plot_type == 'RHI': dpi = prdcfg['ppiImageConfig'].get('dpi', 72) norm = None ticks = None ticklabs = None if vmin is None or vmax is None: norm, ticks, ticklabs = get_norm(field_name) vmin = None vmax = None xsize = prdcfg['rhiImageConfig']['xsize'] ysize = prdcfg['rhiImageConfig']['ysize'] fig = plt.figure(figsize=[xsize, ysize], dpi=dpi) ax = fig.add_subplot(111, aspect='equal') display = pyart.graph.RadarDisplay(radar) display.plot_rhi( field_name, title=titl, sweep=ind_az, norm=norm, ticks=ticks, ticklabs=ticklabs, vmin=vmin, vmax=vmax, colorbar_orient='horizontal', reverse_xaxis=False, fig=fig, ax=ax) display.set_limits( ylim=[prdcfg['rhiImageConfig']['ymin'], prdcfg['rhiImageConfig']['ymax']], xlim=[prdcfg['rhiImageConfig']['xmin'], prdcfg['rhiImageConfig']['xmax']], ax=ax) display.plot_cross_hair(5., ax=ax) # Turn on the grid ax.grid() # Make a tight layout fig.tight_layout() if save_fig: for fname in fname_list: fig.savefig(fname, dpi=dpi) plt.close(fig) return fname_list return (fig, ax) if plot_type == 'QUANTILES': quantiles, values = compute_quantiles_sweep( radar.fields[field_name]['data'], radar.sweep_start_ray_index['data'][ind_az], radar.sweep_end_ray_index['data'][ind_az], quantiles=quantiles) if titl is None: titl = pyart.graph.common.generate_title( radar, field_name, ind_az) labely = get_colobar_label(radar.fields[field_name], field_name) plot_quantiles(quantiles, values, fname_list, labelx='quantile', labely=labely, titl=titl) elif plot_type == 'HISTOGRAM': bins, values = compute_histogram_sweep( radar.fields[field_name]['data'], radar.sweep_start_ray_index['data'][ind_az], radar.sweep_end_ray_index['data'][ind_az], field_name, step=step) if titl is None: titl = pyart.graph.common.generate_title( radar, field_name, ind_az) labelx = get_colobar_label(radar.fields[field_name], field_name) plot_histogram(bins, values, fname_list, labelx=labelx, labely='Number of Samples', titl=titl) else: warn('Unknown plot type '+plot_type) return fname_list
[docs]def plot_bscope(radar, field_name, ind_sweep, prdcfg, fname_list, vmin=None, vmax=None, ray_dim='ang', xaxis_rng=True): """ plots a B-Scope (angle-range representation) Parameters ---------- radar : Radar object object containing the radar data to plot field_name : str name of the radar field to plot ind_sweep : int sweep index to plot prdcfg : dict dictionary containing the product configuration fname_list : list of str list of names of the files where to store the plot vmin, vmax : float Min and max values of the colorbar ray_dim : str the ray dimension. Can be 'ang' or 'time' xaxis : bool if true the range will be in the x-axis. Otherwise it will be in the y-axis. Returns ------- fname_list : list of str list of names of the created plots """ norm = None ticks = None ticklabs = None if vmin is None or vmax is None: norm, ticks, ticklabs = get_norm(field_name) if norm is None: # if norm is set do not override with vmin/vmax vmin, vmax = pyart.config.get_field_limits(field_name) radar_aux = radar.extract_sweeps([ind_sweep]) if ray_dim == 'ang': if radar_aux.scan_type == 'ppi': ray = np.sort(radar_aux.azimuth['data']) ind_ray = np.argsort(radar_aux.azimuth['data']) field = radar_aux.fields[field_name]['data'][ind_ray, :] ray_label = 'azimuth angle (degrees)' elif radar_aux.scan_type == 'rhi': ray = np.sort(radar_aux.elevation['data']) ind_ray = np.argsort(radar_aux.elevation['data']) field = radar_aux.fields[field_name]['data'][ind_ray, :] ray_label = 'elevation angle (degrees)' else: field = radar_aux.fields[field_name]['data'] ray = np.array(range(radar_aux.nrays)) ray_label = 'ray number' else: ray = np.sort(radar_aux.time['data']) start_time = ray[0] ray -= start_time ind_ray = np.argsort(radar_aux.time['data']) field = radar_aux.fields[field_name]['data'][ind_ray, :] sweep_start_time = num2date( start_time, radar_aux.time['units'], radar_aux.time['calendar']) ray_label = ( 'time [s from ' + sweep_start_time.strftime('%Y-%m-%d %H:%M:%S')+' UTC]') # display data titl = pyart.graph.common.generate_title(radar_aux, field_name, 0) label = get_colobar_label(radar_aux.fields[field_name], field_name) dpi = prdcfg['ppiImageConfig'].get('dpi', 72) fig = plt.figure(figsize=[prdcfg['ppiImageConfig']['xsize'], prdcfg['ppiImageConfig']['ysize']], dpi=dpi) ax = fig.add_subplot(111) if radar_aux.ngates == 1: ax.plot(ray, field, 'bx', figure=fig) ax.set_xlabel(ray_label) ax.set_ylabel(label) ax.set_title(titl) else: cmap = pyart.config.get_field_colormap(field_name) rng_aux = radar_aux.range['data']/1000. rng_res = rng_aux[1]-rng_aux[0] rng_aux = np.append(rng_aux-rng_res/2., rng_aux[-1]+rng_res/2.) rng_label = 'Range (km)' ray_res = np.ma.median(ray[1:]-ray[:-1]) ray_aux = np.append(ray-ray_res/2, ray[-1]+ray_res/2) if xaxis_rng: cax = ax.pcolormesh( rng_aux, ray_aux, field, cmap=cmap, vmin=vmin, vmax=vmax, norm=norm) ax.set_xlabel(rng_label) ax.set_ylabel(ray_label) else: cax = ax.pcolormesh( ray_aux, rng_aux, np.ma.transpose(field), cmap=cmap, vmin=vmin, vmax=vmax, norm=norm) ax.set_xlabel(ray_label) ax.set_ylabel(rng_label) ax.set_title(titl) cb = fig.colorbar(cax) if ticks is not None: cb.set_ticks(ticks) if ticklabs: cb.set_ticklabels(ticklabs) cb.set_label(label) # Make a tight layout fig.tight_layout() for fname in fname_list: fig.savefig(fname, dpi=dpi) plt.close(fig) return fname_list
[docs]def plot_time_range(radar, field_name, ind_sweep, prdcfg, fname_list, vmin=None, vmax=None, ylabel='range (Km)'): """ plots a time-range plot Parameters ---------- radar : Radar object object containing the radar data to plot field_name : str name of the radar field to plot ind_sweep : int sweep index to plot prdcfg : dict dictionary containing the product configuration fname_list : list of str list of names of the files where to store the plot vmin, vmax : float Min and max values of the colorbar ylabel : str The y-axis label Returns ------- fname_list : list of str list of names of the created plots """ radar_aux = radar.extract_sweeps([ind_sweep]) field = radar_aux.fields[field_name]['data'] # display data titl = pyart.graph.common.generate_title(radar_aux, field_name, ind_sweep) dpi = prdcfg['ppiImageConfig'].get('dpi', 72) xsize = prdcfg['ppiImageConfig'].get('xsize', 10) ysize = prdcfg['ppiImageConfig'].get('ysize', 8) rng_aux = radar_aux.range['data'] if ylabel == 'range (Km)': rng_aux /= 1000. rng_res = rng_aux[1]-rng_aux[0] rng_aux = np.append(rng_aux-rng_res/2., rng_aux[-1]+rng_res/2.) time_res = np.mean(radar_aux.time['data'][1:]-radar_aux.time['data'][0:-1]) time_aux = np.append( radar_aux.time['data'], radar_aux.time['data'][-1]+time_res) return _plot_time_range( time_aux, rng_aux, field, field_name, fname_list, titl=titl, ylabel=ylabel, vmin=vmin, vmax=vmax, figsize=[xsize, ysize], dpi=dpi)
[docs]def plot_fixed_rng(radar, field_name, prdcfg, fname_list, azi_res=None, ele_res=None, ang_tol=1., vmin=None, vmax=None): """ plots a fixed range plot Parameters ---------- radar : radar object The radar object containing the fixed range data field_name : str The name of the field to plot prdcfg : dict dictionary containing the product configuration fname_list : list of str list of names of the files where to store the plot azi_res, ele_res : float The nominal azimuth and elevation angle resolution [deg] ang_tol : float The tolerance between the nominal and the actual radar angle vmin, vmax : float Min and Max values of the color scale. If None it is going to be taken from the Py-ART config files Returns ------- fname_list : list of str list of names of the created plots """ # Get radar azimuth angles within limits taking as reference # the first elevation angle fixed_rng = radar.range['data'][0] if radar.scan_type == 'ppi': ele_vec = np.sort(radar.fixed_angle['data']) azi_vec = np.sort( radar.azimuth['data'][radar.sweep_start_ray_index['data'][0]: radar.sweep_end_ray_index['data'][0]+1]) else: ele_vec = np.sort( radar.elevation['data'][radar.sweep_start_ray_index['data'][0]: radar.sweep_end_ray_index['data'][0]+1]) azi_vec = np.sort(radar.fixed_angle['data']) # put data in a regular 2D grid field_2D = np.ma.masked_all((azi_vec.size, ele_vec.size)) sweep_start_inds = radar.sweep_start_ray_index['data'] sweep_end_inds = radar.sweep_end_ray_index['data'] if radar.scan_type == 'ppi': for j, ele in enumerate(ele_vec): field_1D = radar.fields[field_name]['data'][ sweep_start_inds[j]:sweep_end_inds[j]+1] azi_1D = radar.azimuth['data'][ sweep_start_inds[j]:sweep_end_inds[j]+1] for i, azi in enumerate(azi_vec): ind = find_ang_index(azi_1D, azi, ang_tol=ang_tol) if ind is None: continue field_2D[i, j] = field_1D[ind] else: for i, azi in enumerate(azi_vec): field_1D = radar.fields[field_name]['data'][ sweep_start_inds[i]:sweep_end_inds[i]+1] ele_1D = radar.elevation['data'][ sweep_start_inds[i]:sweep_end_inds[i]+1] for j, ele in enumerate(ele_vec): ind = find_ang_index(ele_1D, ele, ang_tol=ang_tol) if ind is None: continue field_2D[i, j] = field_1D[ind] # get limits of angle bins if radar.scan_type == 'ppi': if azi_res is None: azi_res = np.median(azi_vec[1:]-azi_vec[0:-1]) if radar.ray_angle_res is not None: azi_res = np.min( [radar.ray_angle_res['data'][0], azi_res]) azi_vec = np.append(azi_vec-azi_res/2., azi_vec[-1]+azi_res/2.) if ele_res is None: ele_res = np.median(ele_vec[1:]-ele_vec[0:-1]) if radar.instrument_parameters is not None: if 'radar_beam_width_h' in radar.instrument_parameters: bwidth = radar.instrument_parameters[ 'radar_beam_width_h']['data'][0] ele_res = np.min([bwidth, ele_res]) elif 'radar_beam_width_v' in radar.instrument_parameters: bwidth = radar.instrument_parameters[ 'radar_beam_width_v']['data'][0] ele_res = np.min([bwidth, ele_res]) ele_vec = np.append(ele_vec-ele_res/2., ele_vec[-1]+ele_res/2.) else: if ele_res is None: ele_res = np.median(ele_vec[1:]-ele_vec[0:-1]) if radar.ray_angle_res is not None: ele_res = np.min( [radar.ray_angle_res['data'][0], ele_res]) ele_vec = np.append(ele_vec-ele_res/2., ele_vec[-1]+ele_res/2.) if azi_res is None: azi_res = np.median(azi_vec[1:]-azi_vec[0:-1]) if radar.instrument_parameters is not None: if 'radar_beam_width_h' in radar.instrument_parameters: bwidth = radar.instrument_parameters[ 'radar_beam_width_h']['data'][0] azi_res = np.min([bwidth, azi_res]) elif 'radar_beam_width_v' in radar.instrument_parameters: bwidth = radar.instrument_parameters[ 'radar_beam_width_v']['data'][0] azi_res = np.min([bwidth, azi_res]) azi_vec = np.append(azi_vec-azi_res/2., azi_vec[-1]+azi_res/2.) titl = generate_fixed_rng_title(radar, field_name, fixed_rng) dpi = prdcfg['ppiImageConfig'].get('dpi', 72) xsize = prdcfg['ppiImageConfig'].get('xsize', 10) ysize = prdcfg['ppiImageConfig'].get('ysize', 8) return _plot_time_range( azi_vec, ele_vec, field_2D, field_name, fname_list, titl=titl, xlabel='azimuth (deg)', ylabel='elevation (deg)', figsize=[xsize, ysize], vmin=vmin, vmax=vmax, dpi=dpi)
[docs]def plot_fixed_rng_span(radar, field_name, prdcfg, fname_list, azi_res=None, ele_res=None, ang_tol=1., stat='max'): """ plots a fixed range plot Parameters ---------- radar : radar object The radar object containing the fixed range data field_name : str The name of the field to plot prdcfg : dict dictionary containing the product configuration fname_list : list of str list of names of the files where to store the plot azi_res, ele_res : float The nominal azimuth and elevation angle resolution [deg] ang_tol : float The tolerance between the nominal and the actual radar angle Returns ------- fname_list : list of str list of names of the created plots """ # Get radar azimuth angles within limits taking as reference # the first elevation angle if radar.scan_type == 'ppi': ele_vec = np.sort(radar.fixed_angle['data']) azi_vec = np.sort( radar.azimuth['data'][radar.sweep_start_ray_index['data'][0]: radar.sweep_end_ray_index['data'][0]+1]) else: ele_vec = np.sort( radar.elevation['data'][radar.sweep_start_ray_index['data'][0]: radar.sweep_end_ray_index['data'][0]+1]) azi_vec = np.sort(radar.fixed_angle['data']) # put data in a regular 2D grid field_2D = np.ma.masked_all((azi_vec.size, ele_vec.size)) rng_2D = np.ma.masked_all((azi_vec.size, ele_vec.size)) sweep_start_inds = radar.sweep_start_ray_index['data'] sweep_end_inds = radar.sweep_end_ray_index['data'] if radar.scan_type == 'ppi': for j, ele in enumerate(ele_vec): field = radar.fields[field_name]['data'][ sweep_start_inds[j]:sweep_end_inds[j]+1, :] if stat == 'max': field_1D = np.ma.max(field, axis=-1) ind = np.ma.argmax(field, axis=-1) rng_1D = radar.range['data'][ind] elif stat == 'min': field_1D = np.ma.min(field, axis=-1) ind = np.ma.argmin(field, axis=-1) rng_1D = radar.range['data'][ind] elif stat == 'mean': field_1D = np.ma.mean(field, axis=-1) mid_rng = radar.range['data'][int(radar.ngates/2)] rng_1D = np.ma.zeros(np.shape(field_1D))+mid_rng elif stat == 'median': field_1D = np.ma.median(field, axis=-1) mid_rng = radar.range['data'][int(radar.ngates/2)] rng_1D = np.ma.zeros(np.shape(field_1D))+mid_rng azi_1D = radar.azimuth['data'][ sweep_start_inds[j]:sweep_end_inds[j]+1] for i, azi in enumerate(azi_vec): ind = find_ang_index(azi_1D, azi, ang_tol=ang_tol) if ind is None: continue field_2D[i, j] = field_1D[ind] rng_2D[i, j] = rng_1D[ind] else: for i, azi in enumerate(azi_vec): field = radar.fields[field_name]['data'][ sweep_start_inds[i]:sweep_end_inds[i]+1, :] if stat == 'max': field_1D = np.ma.max(field, axis=-1) ind = np.ma.argmax(field, axis=-1) rng_1D = radar.range['data'][ind] elif stat == 'min': field_1D = np.ma.min(field, axis=-1) ind = np.ma.argmin(field, axis=-1) rng_1D = radar.range['data'][ind] elif stat == 'mean': field_1D = np.ma.mean(field, axis=-1) mid_rng = radar.range['data'][int(radar.ngates/2)] rng_1D = np.ma.zeros(np.shape(field_1D))+mid_rng elif stat == 'median': field_1D = np.ma.median(field, axis=-1) mid_rng = radar.range['data'][int(radar.ngates/2)] rng_1D = np.ma.zeros(np.shape(field_1D))+mid_rng ele_1D = radar.elevation['data'][ sweep_start_inds[i]:sweep_end_inds[i]+1] for j, ele in enumerate(ele_vec): ind = find_ang_index(ele_1D, ele, ang_tol=ang_tol) if ind is None: continue field_2D[i, j] = field_1D[ind] rng_2D[i, j] = rng_1D[ind] # get limits of angle bins if radar.scan_type == 'ppi': if azi_res is None: azi_res = np.median(azi_vec[1:]-azi_vec[0:-1]) if radar.ray_angle_res is not None: azi_res = np.min( [radar.ray_angle_res['data'][0], azi_res]) azi_vec = np.append(azi_vec-azi_res/2., azi_vec[-1]+azi_res/2.) if ele_res is None: ele_res = np.median(ele_vec[1:]-ele_vec[0:-1]) if radar.instrument_parameters is not None: if 'radar_beam_width_h' in radar.instrument_parameters: bwidth = radar.instrument_parameters[ 'radar_beam_width_h']['data'][0] ele_res = np.min([bwidth, ele_res]) elif 'radar_beam_width_v' in radar.instrument_parameters: bwidth = radar.instrument_parameters[ 'radar_beam_width_v']['data'][0] ele_res = np.min([bwidth, ele_res]) ele_vec = np.append(ele_vec-ele_res/2., ele_vec[-1]+ele_res/2.) else: if ele_res is None: ele_res = np.median(ele_vec[1:]-ele_vec[0:-1]) if radar.ray_angle_res is not None: ele_res = np.min( [radar.ray_angle_res['data'][0], ele_res]) ele_vec = np.append(ele_vec-ele_res/2., ele_vec[-1]+ele_res/2.) if azi_res is None: azi_res = np.median(azi_vec[1:]-azi_vec[0:-1]) if radar.instrument_parameters is not None: if 'radar_beam_width_h' in radar.instrument_parameters: bwidth = radar.instrument_parameters[ 'radar_beam_width_h']['data'][0] azi_res = np.min([bwidth, azi_res]) elif 'radar_beam_width_v' in radar.instrument_parameters: bwidth = radar.instrument_parameters[ 'radar_beam_width_v']['data'][0] azi_res = np.min([bwidth, azi_res]) azi_vec = np.append(azi_vec-azi_res/2., azi_vec[-1]+azi_res/2.) titl = generate_fixed_rng_span_title(radar, field_name, stat) dpi = prdcfg['ppiImageConfig'].get('dpi', 72) xsize = prdcfg['ppiImageConfig'].get('xsize', 10) ysize = prdcfg['ppiImageConfig'].get('ysize', 8) fname_rng_list = [] for fname in fname_list: fname_rng_list.append( fname.rsplit('.', 1)[0]+'_RNG.'+fname.rsplit('.', 1)[1]) _plot_time_range( azi_vec, ele_vec, rng_2D, 'radar_range', fname_rng_list, titl=titl, xlabel='azimuth (deg)', ylabel='elevation (deg)', figsize=[xsize, ysize], dpi=dpi) return _plot_time_range( azi_vec, ele_vec, field_2D, field_name, fname_list, titl=titl, xlabel='azimuth (deg)', ylabel='elevation (deg)', figsize=[xsize, ysize], dpi=dpi)
[docs]def plot_cappi(radar, field_name, altitude, prdcfg, fname_list, beamwidth=1., beam_spacing=1., save_fig=True): """ plots a Constant Altitude Plan Position Indicator CAPPI Parameters ---------- radar : Radar object object containing the radar data to plot field_name : str name of the radar field to plot altitude : float the altitude [m MSL] to be plotted prdcfg : dict dictionary containing the product configuration fname_list : list of str list of names of the files where to store the plot beamwidth : float The radar beamwidth beam_spacing : float the ray angle resolution save_fig : bool if true save the figure. If false it does not close the plot and returns the handle to the figure Returns ------- fname_list : list of str or fig, ax : tupple list of names of the saved plots or handle of the figure an axes """ norm, ticks, ticklabs = get_norm(field_name) xmin = prdcfg['ppiImageConfig']['xmin'] xmax = prdcfg['ppiImageConfig']['xmax'] ymin = prdcfg['ppiImageConfig']['ymin'] ymax = prdcfg['ppiImageConfig']['ymax'] wfunc = prdcfg.get('wfunc', 'NEAREST') cappi_res = prdcfg.get('res', 500.) # number of grid points in cappi ny = int((ymax-ymin)*1000./cappi_res)+1 nx = int((xmax-xmin)*1000./cappi_res)+1 # parameters to determine the gates to use for each grid point if (radar.instrument_parameters is not None and 'radar_beam_width_h' in radar.instrument_parameters): beamwidth = radar.instrument_parameters[ 'radar_beam_width_h']['data'][0] if radar.ray_angle_res is not None: beam_spacing = radar.ray_angle_res['data'][0] lat = float(radar.latitude['data']) lon = float(radar.longitude['data']) alt = 0. # cartesian mapping grid = pyart.map.grid_from_radars( (radar,), gridding_algo='map_to_grid', weighting_function=wfunc, roi_func='dist_beam', h_factor=1.0, nb=beamwidth, bsp=beam_spacing, min_radius=cappi_res/2., grid_shape=(1, ny, nx), grid_limits=((altitude, altitude), (ymin*1000., ymax*1000.), (xmin*1000., xmax*1000.)), grid_origin=(lat, lon), grid_origin_alt=alt, fields=[field_name]) # display data dpi = prdcfg['ppiImageConfig'].get('dpi', 72) fig = plt.figure(figsize=[prdcfg['ppiImageConfig']['xsize'], prdcfg['ppiImageConfig']['ysize']], dpi=dpi) ax = fig.add_subplot(111, aspect='equal') cmap = pyart.config.get_field_colormap(field_name) vmin = vmax = None if norm is None: # if norm is set do not override with vmin/vmax vmin, vmax = pyart.config.get_field_limits(field_name) titl = pyart.graph.common.generate_grid_title(grid, field_name, 0) cax = ax.imshow( grid.fields[field_name]['data'][0], extent=(xmin, xmax, ymin, ymax), origin='lower', cmap=cmap, vmin=vmin, vmax=vmax, norm=norm, interpolation='none') ax.set_xlabel('East West distance from radar(km)') ax.set_ylabel('North South distance from radar(km)') ax.set_title(titl) # plot the colorbar and set the label. cb = fig.colorbar(cax) if ticks is not None: cb.set_ticks(ticks) if ticklabs: cb.set_ticklabels(ticklabs) label = get_colobar_label(grid.fields[field_name], field_name) cb.set_label(label) # Make a tight layout fig.tight_layout() if save_fig: for fname in fname_list: fig.savefig(fname, dpi=dpi) plt.close(fig) return fname_list return (fig, ax)
[docs]def plot_traj(rng_traj, azi_traj, ele_traj, time_traj, prdcfg, fname_list, rad_alt=None, rad_tstart=None, ax=None, fig=None, save_fig=True): """ plots a trajectory on a Cartesian surface Parameters ---------- rng_traj, azi_traj, ele_traj : float array antenna coordinates of the trajectory [m and deg] time_traj : datetime array trajectory time prdcfg : dict dictionary containing the product configuration fname_list : list of str list of names of the files where to store the plot rad_alt : float or None radar altitude [m MSL] rad_tstart : datetime object or None start time of the radar scan surface_alt : float surface altitude [m MSL] color_ref : str What the color code represents. Can be 'None', 'rel_altitude', 'altitude' or 'time' fig : Figure Figure to add the colorbar to. If none a new figure will be created ax : Axis Axis to plot on. if fig is None a new axis will be created save_fig : bool if true save the figure if false it does not close the plot and returns the handle to the figure Returns ------- fname_list : list of str or fig, ax : tupple list of names of the saved plots or handle of the figure an axes """ color_ref = prdcfg.get('color_ref', 'None') if 'altitude' not in prdcfg and color_ref == 'rel_altitude': warn('Unable to plot trajectory relative to surface altitude. ' + 'Unknown surface altitude.') color_ref = 'None' if rad_tstart is None and color_ref == 'time': warn('Unable to plot trajectory relative to radar scan start time. ' + 'Unknown radar scan start time.') color_ref = 'None' if rad_alt is None and color_ref in ('rel_altitude', 'altitude'): warn('Unable to plot trajectory altitude. ' + 'Unknown radar altitude.') color_ref = 'None' x, y, z = pyart.core.antenna_to_cartesian( rng_traj/1000., azi_traj, ele_traj) if color_ref == 'rel_altitude': h = z+rad_alt h_rel = h-prdcfg['altitude'] marker = 'x' col = h_rel cmap = 'coolwarm' norm = plt.Normalize(-2000., 2000.) cb_label = 'Altitude relative to CAPPI [m]' plot_cb = True elif color_ref == 'altitude': h = z+rad_alt marker = 'x' col = h cmap = 'Greys' norm = plt.Normalize(h.min(), h.max()) cb_label = 'Altitude [m MSL]' plot_cb = True elif color_ref == 'time': td_vec = time_traj-rad_tstart tt_s = [] for td in td_vec: tt_s.append(td.total_seconds()) tt_s = np.asarray(tt_s) marker = 'x' col = tt_s cmap = 'Greys' norm = plt.Normalize(tt_s.min(), tt_s.max()) cb_label = 'Time from start of radar scan [s]' plot_cb = True else: col = 'k' marker = 'x' cmap = None plot_cb = False # display data dpi = prdcfg['ppiImageConfig'].get('dpi', 72) if fig is None: fig = plt.figure(figsize=[prdcfg['ppiImageConfig']['xsize'], prdcfg['ppiImageConfig']['ysize']], dpi=dpi) ax = fig.add_subplot(111, aspect='equal') else: ax.autoscale(False) cax = ax.scatter( x/1000., y/1000., c=col, marker=marker, alpha=0.5, cmap=cmap, norm=norm) # plot colorbar if plot_cb: cb = fig.colorbar(cax, orientation='horizontal') cb.set_label(cb_label) if save_fig: for fname in fname_list: fig.savefig(fname, dpi=dpi) plt.close(fig) return fname_list return (fig, ax)
[docs]def plot_rhi_contour(radar, field_name, ind_az, prdcfg, fname_list, contour_values=None, linewidths=1.5, ax=None, fig=None, save_fig=True): """ plots contour data on an RHI Parameters ---------- radar : Radar object object containing the radar data to plot field_name : str name of the radar field to plot ind_az : int sweep index to plot prdcfg : dict dictionary containing the product configuration fname_list : list of str list of names of the files where to store the plot contour_values : float array list of contours to plot linewidths : float width of the contour lines fig : Figure Figure to add the colorbar to. If none a new figure will be created ax : Axis Axis to plot on. if fig is None a new axis will be created save_fig : bool if true save the figure if false it does not close the plot and returns the handle to the figure Returns ------- fname_list : list of str or fig, ax : tupple list of names of the saved plots or handle of the figure an axes """ dpi = prdcfg['ppiImageConfig'].get('dpi', 72) # get contour intervals if contour_values is None: field_dict = pyart.config.get_metadata(field_name) if 'boundaries' in field_dict: vmin = field_dict['boundaries'][0] vmax = field_dict['boundaries'][-1] num = len(field_dict['boundaries']) else: vmin, vmax = pyart.config.get_field_limits(field_name) num = 10 contour_values = np.linspace(vmin, vmax, num=num) # get data and position display = pyart.graph.RadarDisplay(radar) data = display._get_data(field_name, ind_az, None, True, None) x_edges, y_edges, z_edges = display._get_x_y_z(ind_az, True, True) delta_x = x_edges[1:, 1:]-x_edges[:-1, :-1] delta_y = y_edges[1:, 1:]-y_edges[:-1, :-1] delta_z = z_edges[1:, 1:]-z_edges[:-1, :-1] x = x_edges[:-1, :-1]+delta_x/2. y = y_edges[:-1, :-1]+delta_y/2. z = z_edges[:-1, :-1]+delta_z/2. R = np.sqrt(x ** 2 + y ** 2) * np.sign(x) # display data if fig is None: xsize = prdcfg['rhiImageConfig']['xsize'] ysize = prdcfg['rhiImageConfig']['ysize'] fig = plt.figure(figsize=[xsize, ysize], dpi=dpi) ax = fig.add_subplot(111, aspect='equal') ax.contour(R, z, data, contour_values, colors='k', linewidths=linewidths) display._set_title(field_name, ind_az, None, ax) display._label_axes_rhi((None, None), ax) display.set_limits( ylim=[prdcfg['rhiImageConfig']['ymin'], prdcfg['rhiImageConfig']['ymax']], xlim=[prdcfg['rhiImageConfig']['xmin'], prdcfg['rhiImageConfig']['xmax']], ax=ax) display.plot_cross_hair(5., ax=ax) # Turn on the grid ax.grid() # Make a tight layout fig.tight_layout() else: ax.autoscale(False) ax.contour(R, z, data, contour_values, colors='k', linewidths=linewidths) if save_fig: for fname in fname_list: fig.savefig(fname, dpi=dpi) plt.close(fig) return fname_list return (fig, ax)
[docs]def plot_ppi_contour(radar, field_name, ind_el, prdcfg, fname_list, contour_values=None, linewidths=1.5, ax=None, fig=None, save_fig=True): """ plots contour data on a PPI Parameters ---------- radar : Radar object object containing the radar data to plot field_name : str name of the radar field to plot ind_el : int sweep index to plot prdcfg : dict dictionary containing the product configuration fname_list : list of str list of names of the files where to store the plot contour_values : float array list of contours to plot linewidths : float width of the contour lines fig : Figure Figure to add the colorbar to. If none a new figure will be created ax : Axis Axis to plot on. if fig is None a new axis will be created save_fig : bool if true save the figure if false it does not close the plot and returns the handle to the figure Returns ------- fname_list : list of str or fig, ax : tupple list of names of the saved plots or handle of the figure an axes """ dpi = prdcfg['ppiImageConfig'].get('dpi', 72) # get contour intervals if contour_values is None: field_dict = pyart.config.get_metadata(field_name) if 'boundaries' in field_dict: vmin = field_dict['boundaries'][0] vmax = field_dict['boundaries'][-1] num = len(field_dict['boundaries']) else: vmin, vmax = pyart.config.get_field_limits(field_name) num = 10 contour_values = np.linspace(vmin, vmax, num=num) # get data and position display = pyart.graph.RadarDisplay(radar) data = display._get_data(field_name, ind_el, None, True, None) x_edges, y_edges = display._get_x_y(ind_el, True, True) delta_x = x_edges[1:, 1:]-x_edges[:-1, :-1] delta_y = y_edges[1:, 1:]-y_edges[:-1, :-1] x = x_edges[:-1, :-1]+delta_x/2. y = y_edges[:-1, :-1]+delta_y/2. # display data if fig is None: xsize = prdcfg['ppiImageConfig']['xsize'] ysize = prdcfg['ppiImageConfig']['ysize'] fig = plt.figure(figsize=[xsize, ysize], dpi=dpi) ax = fig.add_subplot(111, aspect='equal') ax.contour(x, y, data, contour_values, colors='k', linewidths=linewidths) display._set_title(field_name, ind_el, None, ax) display._label_axes_ppi((None, None), ax) display.set_limits( ylim=[prdcfg['ppiImageConfig']['ymin'], prdcfg['ppiImageConfig']['ymax']], xlim=[prdcfg['ppiImageConfig']['xmin'], prdcfg['ppiImageConfig']['xmax']], ax=ax) display.plot_cross_hair(5., ax=ax) # Turn on the grid ax.grid() # Make a tight layout fig.tight_layout() else: ax.autoscale(False) ax.contour(x, y, data, contour_values, colors='k', linewidths=linewidths) if save_fig: for fname in fname_list: fig.savefig(fname, dpi=dpi) plt.close(fig) return fname_list return (fig, ax)
[docs]def plot_roi_contour(roi_dict, prdcfg, fname_list, plot_center=True, xlabel='Lon [Deg]', ylabel='Lat [Deg]', titl='TRT cell position', ax=None, fig=None, save_fig=True): """ plots the contour of a region of interest on a map Parameters ---------- roi_dict : dict dictionary containing lon_roi, lat_roi, the points defining the contour prdcfg : dict dictionary containing the product configuration fname_list : list of str list of names of the files where to store the plot plot_center : bool If True a marked with the center of the roi is plotted fig : Figure Figure to add the colorbar to. If none a new figure will be created ax : Axis Axis to plot on. if fig is None a new axis will be created save_fig : bool if true save the figure if false it does not close the plot and returns the handle to the figure Returns ------- fname_list : list of str or fig, ax : tupple list of names of the saved plots or handle of the figure an axes """ if not _SHAPELY_AVAILABLE or not _CARTOPY_AVAILABLE: warn('Unable to plot ROI contour: Missing shapely and/or' ' cartopy modules') return None dpi = prdcfg['ppiMapImageConfig'].get('dpi', 72) # create polygon to plot polygon = shapely.geometry.Polygon(list(zip( roi_dict['lon'], roi_dict['lat']))) # display data if fig is None: xsize = prdcfg['ppiMapImageConfig']['xsize'] ysize = prdcfg['ppiMapImageConfig']['ysize'] lonstep = prdcfg['ppiMapImageConfig'].get('lonstep', 0.5) latstep = prdcfg['ppiMapImageConfig'].get('latstep', 0.5) min_lon = prdcfg['ppiMapImageConfig'].get('lonmin', 2.5) max_lon = prdcfg['ppiMapImageConfig'].get('lonmax', 12.5) min_lat = prdcfg['ppiMapImageConfig'].get('latmin', 43.5) max_lat = prdcfg['ppiMapImageConfig'].get('latmax', 49.5) resolution = prdcfg['ppiMapImageConfig'].get('mapres', '110m') if resolution not in ('110m', '50m', '10m'): warn('Unknown map resolution: '+resolution) resolution = '110m' background_zoom = prdcfg['ppiMapImageConfig'].get( 'background_zoom', 8) lon_lines = np.arange(np.floor(min_lon), np.ceil(max_lon)+1, lonstep) lat_lines = np.arange(np.floor(min_lat), np.ceil(max_lat)+1, latstep) limits = [min_lon, max_lon, min_lat, max_lat] # get background map instance stamen_terrain = Stamen('terrain-background') projection = cartopy.crs.PlateCarree() fig = plt.figure(figsize=[xsize, ysize], dpi=dpi) # draw background ax = fig.add_subplot(111, projection=stamen_terrain.crs) ax.set_extent(limits, crs=projection) ax.add_image(stamen_terrain, background_zoom) # add countries countries = cartopy.feature.NaturalEarthFeature( category='cultural', name='admin_0_countries', scale=resolution, facecolor='none') ax.add_feature(countries, edgecolor='black') # draw grid lines and labels gl = ax.gridlines(xlocs=lon_lines, ylocs=lat_lines, draw_labels=True) gl.xlabels_top = False gl.ylabels_right = False ax.text(0.5, -0.2, xlabel, va='bottom', ha='center', rotation='horizontal', rotation_mode='anchor', transform=ax.transAxes) ax.text(-0.1, 0.55, ylabel, va='bottom', ha='center', rotation='vertical', rotation_mode='anchor', transform=ax.transAxes) ax.set_title(titl) else: ax.autoscale(False) ax.add_geometries( [polygon], cartopy.crs.PlateCarree(), facecolor='none', edgecolor='k') if 'lon_center' in roi_dict and 'lat_center' in roi_dict and plot_center: ax.scatter( [roi_dict['lon_center']], [roi_dict['lat_center']], c='k', marker='x', transform=cartopy.crs.PlateCarree()) if save_fig: for fname in fname_list: fig.savefig(fname, dpi=dpi) plt.close(fig) return fname_list return (fig, ax)
[docs]def plot_rhi_profile(data_list, hvec, fname_list, labelx='Value', labely='Height (m MSL)', labels=['Mean'], title='RHI profile', colors=None, linestyles=None, vmin=None, vmax=None, hmin=None, hmax=None, dpi=72): """ plots an RHI profile Parameters ---------- data_list : list of float array values of the profile hvec : float array height points of the profile fname_list : list of str list of names of the files where to store the plot labelx : str The label of the X axis labely : str The label of the Y axis labels : array of str The label of the legend title : str The figure title colors : array of str Specifies the colors of each line linestyles : array of str Specifies the line style of each line vmin, vmax: float Lower/Upper limit of data values hmin, hmax: float Lower/Upper limit of altitude dpi : int dots per inch Returns ------- fname_list : list of str list of names of the created plots """ fig, ax = plt.subplots(figsize=[10, 6], dpi=dpi) lab = None col = None lstyle = None for i, data in enumerate(data_list): if labels is not None: lab = labels[i] if colors is not None: col = colors[i] if linestyles is not None: lstyle = linestyles[i] ax.plot( data, hvec, label=lab, color=col, linestyle=lstyle, marker='x') ax.set_title(title) ax.set_xlabel(labelx) ax.set_ylabel(labely) ax.set_xlim(left=vmin, right=vmax) ax.set_ylim(bottom=hmin, top=hmax) ax.legend(loc='best') # Turn on the grid ax.grid() for fname in fname_list: fig.savefig(fname, dpi=dpi) plt.close(fig) return fname_list
[docs]def plot_along_coord(xval_list, yval_list, fname_list, labelx='coord', labely='Value', labels=None, title='Plot along coordinate', colors=None, linestyles=None, ymin=None, ymax=None, dpi=72): """ plots data along a certain radar coordinate Parameters ---------- xval_list : list of float arrays the x values, range, azimuth or elevation yval_list : list of float arrays the y values. Parameter to plot fname_list : list of str list of names of the files where to store the plot labelx : str The label of the X axis labely : str The label of the Y axis labels : array of str The label of the legend title : str The figure title colors : array of str Specifies the colors of each line linestyles : array of str Specifies the line style of each line ymin, ymax: float Lower/Upper limit of y axis dpi : int dots per inch Returns ------- fname_list : list of str list of names of the created plots """ fig, ax = plt.subplots(figsize=[10, 6], dpi=dpi) lab = None col = None lstyle = None for i, xval in enumerate(xval_list): yval = yval_list[i] if labels is not None: lab = labels[i] if colors is not None: col = colors[i] if linestyles is not None: lstyle = linestyles[i] ax.plot(xval, yval, label=lab, color=col, linestyle=lstyle) ax.set_title(title) ax.set_xlabel(labelx) ax.set_ylabel(labely) ax.set_ylim(bottom=ymin, top=ymax) ax.legend(loc='best') for fname in fname_list: fig.savefig(fname, dpi=dpi) plt.close(fig) return fname_list
[docs]def plot_field_coverage(xval_list, yval_list, fname_list, labelx='Azimuth (deg)', labely='Range extension [m]', labels=None, title='Field coverage', ymin=None, ymax=None, xmeanval=None, ymeanval=None, labelmeanval=None, dpi=72): """ plots a time series Parameters ---------- xval_list : list of float arrays the x values, azimuth yval_list : list of float arrays the y values. Range extension fname_list : list of str list of names of the files where to store the plot labelx : str The label of the X axis labely : str The label of the Y axis labels : array of str The label of the legend title : str The figure title ymin, ymax : float Lower/Upper limit of y axis xmeanval, ymeanval : float array the x and y values of a mean along elevation labelmeanval : str the label of the mean dpi : int dots per inch Returns ------- fname_list : list of str list of names of the created plots """ fig, ax = plt.subplots(figsize=[10, 6], dpi=dpi) lab = None for i, xval in enumerate(xval_list): yval = yval_list[i] if labels is not None: lab = labels[i] ax.plot(xval, yval, label=lab, linestyle='None', marker='o', fillstyle='full') if xmeanval is not None and ymeanval is not None: ax.plot(xmeanval, ymeanval, label=labelmeanval, linestyle='-', color='r', marker='x') ax.set_title(title) ax.set_xlabel(labelx) ax.set_ylabel(labely) ax.set_ylim(bottom=ymin, top=ymax) if labels is not None: ax.legend(loc='best') for fname in fname_list: fig.savefig(fname, dpi=dpi) plt.close(fig) return fname_list