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)
Exemplo n.º 2
0
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
Exemplo n.º 3
0
# 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
Exemplo n.º 4
0
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)

Exemplo n.º 5
0
# 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',
Exemplo n.º 6
0
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')
Exemplo n.º 7
0
# 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)
Exemplo n.º 8
0
# 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)
Exemplo n.º 9
0
# 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')