ncfile = "swan.four.nc" lon0 = -5.1 lon1 = -4.9 lat0 = 48.35 lat1 = 48.55 # Imports from vcmq import cdms2, data_sample, N, transect, curve2, code_file_name, os, \ add_map_lines, P, add_shadow # Read data f = cdms2.open(data_sample(ncfile)) hs = f('HS', squeeze=1) f.close() # Compute transect hst, lons, lats = transect(hs, (lon0,lon1), (lat0,lat1), getcoords=True) # Plot along time s = curve2(hst, figsize=(8,3), title='Spatial transect on curved grid', show=False, top=0.85) # Add a small map to show the transect positions o = add_map_lines(hs, lons, lats, map_bgcolor='w', map_bbox= [.6, .2, .3, .5], map_anchor='W') # Save figfile = code_file_name(ext='png') if os.path.exists(figfile): os.remove(figfile) s.savefig(figfile, pdf=True)
def plot_scattered_locs(lons, lats, depths, slice_type=None, interval=None, plotter=None, lon=None, lat=None, level=None, label='', lon_bounds_margin=.1, lat_bounds_margin=.1, data=None, warn=True, bathy=None, xybathy=None, secbathy=None, size=20, color='#2ca02c', linewidth=0.4, edgecolor='k', add_profile_line=None, add_bathy=True, add_minimap=True, add_section_bathy=True, fig=None, title="{long_name}", register_sm=True, depthshade=False, legend=False, colorbar=True, **kwargs): """Plot scattered localisations Parameters ---------- lons: n-D array lats: n-D array depths: n-D array slice_type: one of "3d"/None, "2d", "zonal", "meridional", "horizontal" The way to slice the observations. "3d"/"2d" are 3D/2D view of all observations. Other slices make a selection with a range (``interval``). interval: None, tuple of float Interval for selecting valid data Required if slice_type is not "3d"/None/"2d". map_<param>: <param> is passed to :func:`create_map` section_<param>: <param> is passed to :func:`vacumm.misc.plot.section2` minimap_<param>: <param> is passed to :func:`vacumm.misc.plot.add_map_box` Todo ---- Add time support. """ # Inits if cdms2.isVariable(data): data = data.asma() kwmap = kwfilter(kwargs, 'map_') kwminimap = kwfilter(kwargs, 'minimap_') kwsecbat = kwfilter(kwargs, 'section_bathy_') kwsection = kwfilter(kwargs, 'section_') kwplt = kwfilter(kwargs, 'plotter_') dict_check_defaults(kwmap, **kwplt) dict_check_defaults(kwsection, **kwplt) kwpf = kwfilter(kwargs, 'add_profile_line') kwleg = kwfilter(kwargs, 'legend') kwcb = kwfilter(kwargs, 'colorbar') long_name = get_long_name(data) units = getattr(data, 'units', '') if long_name is None: long_name = "Locations" if not title: title = None elif title is True: title = long_name else: title = title.format(**locals()) # Slice type if slice_type is None: slice_type = "3d" else: slice_type = str(slice_type).lower() valid_slice_types = [ '3d', "2d", 'zonal', 'merid', 'horiz', 'bottom', 'surf' ] assert slice_type in valid_slice_types, ('Invalid slice type. ' 'It must be one of: ' + ', '.join(valid_slice_types)) # Numeric horizontal coordinates xx = lons[:].copy() yy = lats[:].copy() # Profiles? profiles = (not isinstance(depths, str) and (isaxis(depths) or N.shape(depths) != N.shape(xx) or (data is not None and data.ndim == 2))) # Force some options if not profiles or slice_type not in ('3d', 'merid', 'zonal'): add_profile_line = False elif add_profile_line is None: add_profile_line = True # Bathymetry need_xybathy = int(add_profile_line) if depths == 'bottom' and slice_type not in ('bottom', '2d'): need_xybathy = 2 if need_xybathy and xybathy is not None: if bathy is not None: xybathy = grid2xy(bathy, lons, lats) if xybathy.mask.all(): if warn: sonat_warn( 'Bathymetry is fully masked at bottom locs. Skipping...' ) if need_xybathy == 2: return xybathy = None elif need_xybathy == 2 and warn: # we really need it sonat_warn('Bathymetry is needed at obs locations. Skipping...') return if xybathy is None: add_profile_line = False # Special depths: surf and bottom indepths = depths if (depths == 'surf' and slice_type != 'surf'): # surface depths = N.zeros(len(lons)) elif (depths == 'bottom' and slice_type not in ('bottom', '2d')): # bottom depths = -xybathy if interval is not None and N.isscalar(interval[0]): interval = (depths + interval[0], depths + interval[1]) # Numeric vertical coordinates strdepths = isinstance(depths, str) if not strdepths: zz = N.array(depths[:], copy=True) # Shape if data is not None: dshape = data.shape elif not profiles or strdepths: dshape = xx.shape elif zz.ndim == 2: dshape = zz.shape else: dshape = zz.shape + xx.shape # Masking outside interval if (slice_type != '3d' and slice_type != '2d' and (slice_type != 'surf' or depths != 'surf') and (slice_type != 'bottom' or depths != 'bottom')): assert interval is not None, ( 'You must provide a valid ' '"interval" for slicing scattered locations') stype = 'horiz' if slice_type in ('surf', 'bottom') else slice_type data = mask_scattered_locs(xx, yy, depths, stype, interval, data=data) if data is None: return # Get the full mask: (np), or (nz, np) for profiles # - mask with data if data is not None: if data.dtype.char == '?': mask = data data = None else: mask = N.ma.getmaskarray(data) else: mask = N.zeros(dshape) # - mask with coordinates if N.ma.isMA(xx) or N.ma.isMA(yy): # lons/lats xymask = N.ma.getmaskarray(xx) | N.ma.getmaskarray(yy) mask |= N.resize(mask, dshape) if not strdepths and N.ma.isMA(zz): # depths if profiles: zmask = N.ma.getmaskarray(zz) if zz.ndim == 1: zmask = N.repeat(N.ma.resize(N.ma.getmaskarray(zmask), (-1, 1)), xx.size, axis=1) mask |= zmask else: mask |= N.ma.getmaskarray(zz) # - check if mask.all(): if warn: sonat_warn('All your data are masked') return # - mask back xymask = mask if mask.ndim == 1 else mask.all(axis=0) xx = N.ma.masked_where(xymask, xx, copy=False) yy = N.ma.masked_where(xymask, yy, copy=False) if not strdepths: if mask.shape == zz.shape: zz = N.ma.masked_where(mask, zz, copy=False) elif zz.ndim == 1: zz = N.ma.masked_where(mask.all(axis=1), zz, copy=False) if data is not None: data = N.ma.masked_where(mask, data, copy=0) # Plotter as Axes if isinstance(plotter, P.Axes): ax = plotter fig = ax.get_figure() plotter = None elif plotter is None: ax = None elif isinstance(plotter, Plot): ax = plotter.axes else: raise SONATError('Plotter must be matplotlib Axes instance or ' 'a vacumm Plot instance') if slice_type == '3d': if ax is None: ax = '3d' elif not isinstance(ax, Axes3D): sonat_warn("Requesting 3D plot but provided axes are not 3D." " Skipping...") axes = None # Coordinate bounds if level is None and slice_type in ['3d', 'zonal', 'merid']: if strdepths or zz.min() == 0: level_min = -200 # Fall back to this min depth else: level_min = 1.1 * zz.min() level = (level_min, 0) if (lon is None and slice_type in ['3d', "2d", "horiz", 'surf', 'bottom', 'zonal']): lon = rescale_itv((xx.min(), xx.max()), 1.1) if (lat is None and slice_type in ['3d', "2d", "horiz", 'surf', 'bottom', 'merid']): lat = rescale_itv((yy.min(), yy.max()), 1.1) # Get the plotter if slice_type in ['3d', "2d", "horiz", 'surf', 'bottom']: # map # Map if plotter is None: plotter = create_map(lon, lat, level=level, bathy=bathy, add_bathy=add_bathy, fig=fig, axes=ax, **kwmap) ax = plotter.axes # Projection xx, yy = plotter(xx, yy) else: # sections if plotter is None: # Base plot kwsection.update(fig=fig, axes=ax, show=False, close=False) if add_minimap: dict_check_defaults(kwsection, top=.9, right=.9) if slice_type == 'merid': plotter = section(data=None, xaxis=MV2.array(lat, id='lat'), yaxis=MV2.array(level, id='dep'), **kwsection) else: plotter = section(data=None, xaxis=MV2.array(lon, id='lon'), yaxis=MV2.array(level, id='dep'), **kwsection) ax = plotter.axes # Add minimap if add_minimap: if slice_type == 'merid': xlim = interval ylim = plotter.axes.get_xlim() else: xlim = plotter.axes.get_xlim() ylim = interval extents = dict(x=xlim, y=ylim) dict_check_defaults(kwminimap, map_square=True, map_zoom=.5, map_res=None, map_arcgisimage="ocean", map_epsg=3395, linewidth=.6) kwminimap['map_fig'] = ax.figure add_map_box((xx, yy), extents, **kwminimap) # Bathy profile if add_section_bathy and bathy is not None or secbathy is not None: if secbathy is None: # interpolate if slice_type == 'merid': secbathy = transect( bathy, [0.5 * (interval[0] + interval[1])] * 2, ylim, outaxis='lat') else: secbathy = transect( bathy, xlim, [0.5 * (interval[0] + interval[1])] * 2, outaxis='lon') tx = secbathy.getAxis(0)[:] tb = secbathy.asma() axis_bounds = ax.axis() dict_check_defaults(kwsecbat, facecolor="0.7") ax.fill_between(tx, ax.get_ylim()[0], tb, **kwsecbat) ax.axis(axis_bounds) axis_bounds = ax.axis() # Plot params for scatter kwargs.update(linewidth=linewidth, s=size, edgecolor=edgecolor) # Data kwargs if data is not None: dict_check_defaults(kwargs, vmin=data.min(), vmax=data.max()) # 3D pp = [] if slice_type == "3d": kwargs['depthshade'] = depthshade # Depth labels zfmtfunc = lambda x, pos: deplab(x, nosign=True) ax.zaxis.set_major_formatter(FuncFormatter(zfmtfunc)) # Scatter plots if not profiles: # fully scattered # Points if data is not None: kwargs['c'] = data else: kwargs['c'] = color pp.append(ax.scatter(xx, yy, depths, label=label, **kwargs)) # Profile lines if add_profile_line: for ip, (x, y) in enumerate(zip(xx, yy)): plot_profile_line_3d(ax, x, y, xybathy[ip], zorder=pp[-1].get_zorder() - 0.01, **kwpf) else: # profiles for ip, (x, y) in enumerate(zip(xx, yy)): # Skip fully masked if mask[:, ip].all(): # if warn: # sonat_warn('Profile fully masked') continue # Points if zz.ndim == 2: z = depths[:, ip] else: z = zz z = N.ma.masked_where(mask[:, ip], z, copy=False) if data is not None: kwargs['c'] = data[..., ip] else: kwargs['c'] = color pp.append( ax.scatter([x] * len(z), [y] * len(z), z, label=label, **kwargs)) label = '_' + str(label) # Profile line if add_profile_line: plot_profile_line_3d(ax, x, y, -xybathy[ip], zorder=pp[-1].get_zorder() - 0.01, **kwpf) # Horizontal elif slice_type in ['2d', 'surf', 'bottom', 'horiz']: # Barotropic case if data is not None and data.ndim != 1: data = data.mean(axis=0) # Scatter plot if data is not None: kwargs['c'] = data else: kwargs['c'] = color pp.append(ax.scatter(xx, yy, label=label, **kwargs)) if pp[-1].norm.vmin is None: pass # Sections else: # X axis data if slice_type == 'zonal': xdata = xx else: xdata = yy # Scatter plots if not profiles: # scattered if data is not None: kwargs['c'] = data else: kwargs['c'] = color pp.append(ax.scatter(xdata, depths, label=label, **kwargs)) else: # profiles for ip, x in enumerate(xdata): # Skip fully masked if mask[:, ip].all(): # if warn: # sonat_warn('Profile fully masked') continue # Points if depths[:].ndim == 2: z = zz[:, ip] else: z = zz z = N.ma.masked_where(mask[:, ip], z, copy=False) if data is not None: kwargs['c'] = data[:, ip] else: kwargs['c'] = color pp.append(ax.scatter([x] * len(z), z, label=label, **kwargs)) label = '_' + str(label) # Profile line if add_profile_line: plot_profile_line_3d(ax, x, -xybathy[ip], zorder=pp[-1].get_zorder() - 0.01, **kwpf) # Finalise ax.axis(axis_bounds) if title: ax.set_title(title) if legend: plotter.legend(**kwleg) if colorbar and data is not None: add_colorbar(plotter, pp, units=units, **kwcb) if data is not None and register_sm: register_scalar_mappable(ax, pp, units=units) register_scatter(ax, pp, label) return plotter
# Imports from vcmq import cdms2, data_sample, N, transect, stick2, code_file_name, os, \ transect_specs, add_map_lines, create_time, IterDates, P # Read data f = cdms2.open(data_sample(ncfile)) u = f('u') v = f('v') f.close() # Transect specs tlons, tlats = transect_specs(u.getGrid(), lon0, lat0, lon1, lat1) ttimes = (time0, time1) # Compute transect tu = transect(u, tlons, tlats, times=ttimes) tv = transect(v, tlons, tlats, times=ttimes) # Plot along time s = stick2(tu, tv, figsize=(8, 3), title='Space-time transect of speed', show=False, top=0.85, quiver_width=0.002) # Add a small map to show the transect positions add_map_lines(u.getGrid(), tlons, tlats, map_zoom=0.5) # Save
lon0 = -5.4 lon1 = -4.7 lat0 = 48.1 lat1 = 48.6 time0 = "2008-08-15 07:00" time1 = "2008-08-15 16:00" splits = [None, 3, -3, (3, 'hour'), 3600*3.] # Imports from vcmq import (cdms2, data_sample, N, transect, stick2, code_file_name, os, transect_specs, add_map_lines, create_time, IterDates, P) # Read data f = cdms2.open(data_sample(ncfile)) u = f('u') v = f('v') f.close() # Transect specs tlons, tlats = transect_specs(u.getGrid(), lon0, lat0, lon1, lat1) ttimes = create_time(IterDates((time0, time1), len(tlons), closed=True)) # Compute reference transect tt = [transect(u, tlons, tlats, times=ttimes, split=split) for split in splits] # Unittest for ts in tt[1:]: N.testing.assert_allclose(tt[0], ts)
# Compute MLD mld = mixed_layer_depth(dens, depth=depth, mode='deltadens', format_axes=True) del dens # Compute transect tlons = (lon0, lon1) tlats = (lat0, lat1) tlons = N.concatenate( [N.linspace(lon0, lon1, 100.), N.linspace(lon1, lon1, 100.)]) tlats = N.concatenate( [N.linspace(lat0, lat1, 100.), N.linspace(lat1, lat0, 100.)]) xtemp, xlons, xlats = transect(temp, tlons, tlats, getcoords=True, outaxis='dist') xdepth = transect(depth, tlons, tlats) xmld = transect(mld, tlons, tlats) xmld[:] *= -1 # Plot temperature s = section2( xtemp, yaxis=xdepth, ymin=-800, fill='contourf', nmax=20, contour_linewidths=0.7, bgcolor='0.5',
lon0 = -5.1 lon1 = -4.9 lat0 = 48.35 lat1 = 48.55 # Imports from vcmq import cdms2, data_sample, N, transect, curve2, code_file_name, os, \ add_map_lines, P, add_shadow # Read data f = cdms2.open(data_sample(ncfile)) hs = f('HS', squeeze=1) f.close() # Compute transect hst, lons, lats = transect(hs, (lon0, lon1), (lat0, lat1), getcoords=True) # Plot along time s = curve2(hst, figsize=(8, 3), title='Spatial transect on curved grid', show=False, top=0.85) # Add a small map to show the transect positions o = add_map_lines(hs, lons, lats, map_bgcolor='w', map_bbox=[.6, .2, .3, .5], map_anchor='W')
# Imports from vcmq import cdms2, data_sample, N, transect, stick2, code_file_name, os, \ transect_specs, add_map_lines, create_time, IterDates, P # Read data f = cdms2.open(data_sample(ncfile)) u = f('u') v = f('v') f.close() # Transect specs tlons, tlats = transect_specs(u.getGrid(), lon0, lat0, lon1, lat1) ttimes = create_time(IterDates((time0, time1), len(tlons), closed=True)) # Compute transect tu = transect(u, tlons, tlats, times=ttimes) tv = transect(v, tlons, tlats, times=ttimes) # Plot along time s = stick2(tu, tv, figsize=(8,3), title='Space-time transect of speed', show=False, top=0.85, quiver_width=0.002) # Add a small map to show the transect positions add_map_lines(u.getGrid(), tlons, tlats, map_zoom=0.5) # Save figfile = code_file_name(ext='png') if os.path.exists(figfile): os.remove(figfile) s.savefig(figfile, pdf=True)
# Inits ncfile = "mars2d.xyt.nc" lon0 = -5.4 lon1 = -4.7 lat0 = 48.1 lat1 = 48.6 time0 = "2008-08-15 07:00" time1 = "2008-08-15 16:00" splits = [None, 3, -3, (3, 'hour'), 3600 * 3.] # Imports from vcmq import (cdms2, data_sample, N, transect, stick2, code_file_name, os, transect_specs, add_map_lines, create_time, IterDates, P) # Read data f = cdms2.open(data_sample(ncfile)) u = f('u') v = f('v') f.close() # Transect specs tlons, tlats = transect_specs(u.getGrid(), lon0, lat0, lon1, lat1) ttimes = create_time(IterDates((time0, time1), len(tlons), closed=True)) # Compute reference transect tt = [transect(u, tlons, tlats, times=ttimes, split=split) for split in splits] # Unittest for ts in tt[1:]: N.testing.assert_allclose(tt[0], ts)
# Read data ds = DS(data_sample(ncfile), 'mars', logger_level='critical') temp = ds.get_temp(squeeze=True) dens = ds.get_dens(squeeze=True) depth = ds.get_depth(squeeze=True) # Compute MLD mld = mixed_layer_depth(dens, depth=depth, mode='deltadens', format_axes=True) del dens # Compute transect tlons = (lon0,lon1) tlats = (lat0,lat1) tlons = N.concatenate([N.linspace(lon0,lon1,100.),N.linspace(lon1,lon1,100.)]) tlats = N.concatenate([N.linspace(lat0,lat1,100.),N.linspace(lat1,lat0,100.)]) xtemp, xlons, xlats = transect(temp, tlons, tlats, getcoords=True, outaxis='dist') xdepth = transect(depth, tlons, tlats) xmld = transect(mld, tlons, tlats) xmld[:]*=-1 # Plot temperature s = section2(xtemp, yaxis=xdepth, ymin=-800, fill='contourf', nmax=20, contour_linewidths=0.7, bgcolor='0.5', figsize=(7,4), cmap='vacumm_rnb2_hymex', title='%(long_name)s (dens) along temp transect', show=False) # Plot MLD curve2(xmld, 'w-', linewidth=2, show=False) # Add a small map to show the transect positions add_map_lines(temp[-1], xlons, xlats, map_zoom=0.7, color='k')