Example #1
0
def surface(data=None, x=None, y=None, z=None, **kwargs):
    r"""
    Grids table data using adjustable tension continuous curvature splines.

    Surface reads randomly-spaced (x,y,z) triples and produces gridded values
    z(x,y) by solving:

    .. math::    (1 - t)\nabla^2(z)+t\nabla(z) = 0

    where :math:`t` is a tension factor between 0 and 1, and :math:`\nabla`
    indicates the Laplacian operator.

    Takes a matrix, xyz triples, or a file name as input.

    Must provide either ``data`` or ``x``, ``y``, and ``z``.

    Full option list at :gmt-docs:`surface.html`

    {aliases}

    Parameters
    ----------
    data : str or {table-like}
        Pass in (x, y, z) or (longitude, latitude, elevation) values by
        providing a file name to an ASCII data table, a 2D
        {table-classes}.
    x/y/z : 1d arrays
        Arrays of x and y coordinates and values z of the data points.

    {I}

    {R}

    outgrid : str
        Optional. The file name for the output netcdf file with extension .nc
        to store the grid in.

    {V}
    {a}
    {b}
    {d}
    {e}
    {f}
    {h}
    {i}
    {r}
    {w}

    Returns
    -------
    ret: xarray.DataArray or None
        Return type depends on whether the ``outgrid`` parameter is set:

        - :class:`xarray.DataArray`: if ``outgrid`` is not set
        - None if ``outgrid`` is set (grid output will be stored in file set by
          ``outgrid``)
    """
    with GMTTempFile(suffix=".nc") as tmpfile:
        with Session() as lib:
            # Choose how data will be passed into the module
            file_context = lib.virtualfile_from_data(
                check_kind="vector", data=data, x=x, y=y, z=z, required_z=True
            )
            with file_context as infile:
                if "G" not in kwargs:  # if outgrid is unset, output to tmpfile
                    kwargs.update({"G": tmpfile.name})
                outgrid = kwargs["G"]
                arg_str = " ".join([infile, build_arg_string(kwargs)])
                lib.call_module(module="surface", args=arg_str)

        return load_dataarray(outgrid) if outgrid == tmpfile.name else None
Example #2
0
def grdproject(grid, **kwargs):
    r"""
    Change projection of gridded data between geographical and rectangular.

    This module will project a geographical gridded data set onto a
    rectangular grid. If ``inverse`` is ``True``, it will project a
    rectangular coordinate system to a geographic system. To obtain the value
    at each new node, its location is inversely projected back onto the input
    grid after which a value is interpolated between the surrounding input
    grid values. By default bi-cubic interpolation is used. Aliasing is
    avoided by also forward projecting the input grid nodes. If two or more
    nodes are projected onto the same new node, their average will dominate in
    the calculation of the new node value. Interpolation and aliasing is
    controlled with the ``interpolation`` option. The new node spacing may be
    determined in one of several ways by specifying the grid spacing, number
    of nodes, or resolution. Nodes not constrained by input data are set to
    NaN. The ``region`` parameter can be used to select a map region larger or
    smaller than that implied by the extent of the grid file.

    {aliases}

    Parameters
    ----------
    grid : str or xarray.DataArray
        The file name of the input grid or the grid loaded as a DataArray.
    outgrid : str or None
        The name of the output netCDF file with extension .nc to store the grid
        in.
    inverse : bool
        When set to ``True`` transforms grid from rectangular to
        geographical [Default is False].
    {J}
    {R}
    center : str or list
        [*dx*, *dy*].
        Let projected coordinates be relative to projection center [Default
        is relative to lower left corner]. Optionally, add offsets in the
        projected units to be added (or subtracted when ``inverse`` is set) to
        (from) the projected coordinates, such as false eastings and
        northings for particular projection zones [0/0].
    {I}
    dpi : int
        Set the resolution for the new grid in dots per inch.
    scaling : str
        [**c**\|\ **i**\|\ **p**\|\ **e**\|\ **f**\|\
        **k**\|\ **M**\|\ **n**\|\ **u**].
        Force 1:1 scaling, i.e., output or output data are in actual projected
        meters [**e**]. To specify other units, append **f** (foot),
        **k** (km), **M** (statute mile), **n** (nautical mile), **u**
        (US survey foot), **i** (inch), **c** (cm), or **p** (point).
    unit : str
        Append **c**, **i**, or **p** to indicate that cm, inch, or point
        should be the projected measure unit. Cannot be used with ``scaling``.
    {V}
    {n}
    {r}

    Returns
    -------
    ret: xarray.DataArray or None
        Return type depends on whether the ``outgrid`` parameter is set:

        - :class:`xarray.DataArray` if ``outgrid`` is not set
        - None if ``outgrid`` is set (grid output will be stored in file set by
          ``outgrid``)
    """
    if "J" not in kwargs:
        raise GMTInvalidInput("The projection must be specified.")
    with GMTTempFile(suffix=".nc") as tmpfile:
        with Session() as lib:
            file_context = lib.virtualfile_from_data(check_kind="raster",
                                                     data=grid)
            with file_context as infile:
                if "G" not in kwargs:  # if outgrid is unset, output to tempfile
                    kwargs.update({"G": tmpfile.name})
                outgrid = kwargs["G"]
                arg_str = " ".join([infile, build_arg_string(kwargs)])
                lib.call_module("grdproject", arg_str)

        return load_dataarray(outgrid) if outgrid == tmpfile.name else None
Example #3
0
def grdclip(grid, **kwargs):
    r"""
    Sets values in a grid that meet certain criteria to a new value.

    Produce a clipped ``outgrid`` or :class:`xarray.DataArray` version of the
    input ``grid`` file.

    The parameters ``above`` and ``below`` allow for a given value to be set
    for values above or below a set amount, respectively. This allows for
    extreme values in a grid, such as points below a certain depth when
    plotting Earth relief, to all be set to the same value.

    Full option list at :gmt-docs:`grdclip.html`

    {aliases}

    Parameters
    ----------
    grid : str or xarray.DataArray
        The file name of the input grid or the grid loaded as a DataArray.
    outgrid : str or None
        The name of the output netCDF file with extension .nc to store the grid
        in.
    {R}
    above : str or list or tuple
        [*high*, *above*].
        Set all data[i] > *high* to *above*.
    below : str or list or tuple
        [*low*, *below*].
        Set all data[i] < *low* to *below*.
    between : str or list or tuple
        [*low*, *high*, *between*].
        Set all data[i] >= *low* and <= *high* to *between*.
    new : str or list or tuple
        [*old*, *new*].
        Set all data[i] == *old* to *new*. This is mostly useful when
        your data are known to be integer values.
    {V}

    Returns
    -------
    ret: xarray.DataArray or None
        Return type depends on whether the ``outgrid`` parameter is set:

        - :class:`xarray.DataArray` if ``outgrid`` is not set
        - None if ``outgrid`` is set (grid output will be stored in file set by
          ``outgrid``)

    Example
    -------
    >>> import pygmt
    >>> # Load a grid of @earth_relief_30m data, with an x-range of 10 to 30,
    >>> # and a y-range of 15 to 25
    >>> grid = pygmt.datasets.load_earth_relief(
    ...     resolution="30m", region=[10, 30, 15, 25]
    ... )
    >>> # Report the minimum and maximum data values
    >>> [grid.data.min(), grid.data.max()]
    [179.0, 2103.0]
    >>> # Create a new grid from an input grid. Set all values below 1,000 to
    >>> # 0 and all values above 1,500 to 10,000
    >>> new_grid = pygmt.grdclip(
    ...     grid=grid, below=[1000, 0], above=[1500, 10000]
    ... )
    >>> # Report the minimum and maximum data values
    >>> [new_grid.data.min(), new_grid.data.max()]
    [0.0, 10000.0]
    """
    with GMTTempFile(suffix=".nc") as tmpfile:
        with Session() as lib:
            file_context = lib.virtualfile_from_data(check_kind="raster",
                                                     data=grid)
            with file_context as infile:
                if (outgrid := kwargs.get("G")) is None:
                    kwargs["G"] = outgrid = tmpfile.name  # output to tmpfile
                lib.call_module(module="grdclip",
                                args=build_arg_string(kwargs, infile=infile))

        return load_dataarray(outgrid) if outgrid == tmpfile.name else None
Example #4
0
def grdlandmask(**kwargs):
    r"""
    Create a grid file with set values for land and water.

    Read the selected shoreline database and create a grid to specify which
    nodes in the specified grid are over land or over water. The nodes defined
    by the selected region and lattice spacing
    will be set according to one of two criteria: (1) land vs water, or
    (2) the more detailed (hierarchical) ocean vs land vs lake
    vs island vs pond.

    Full option list at :gmt-docs:`grdlandmask.html`

    {aliases}

    Parameters
    ----------
    outgrid : str or None
        The name of the output netCDF file with extension .nc to store the grid
        in.
    {I}
    {R}
    {A}
    resolution : str
        *res*\[\ **+f**\]. Selects the resolution of the data set to use
        ((**f**)ull, (**h**)igh, (**i**)ntermediate, (**l**)ow, or
        (**c**)rude). The resolution drops off by ~80% between data sets.
        [Default is **l**]. Append **+f** to automatically select a lower
        resolution should the one requested not be available
        [abort if not found]. Alternatively, choose (**a**)uto to automatically
        select the best resolution given the chosen region. Note that because
        the coastlines differ in details a node in a mask file using one
        resolution is not guaranteed to remain inside [or outside] when a
        different resolution is selected.
    bordervalues : bool or str or float or list
        Nodes that fall exactly on a polygon boundary should be
        considered to be outside the polygon [Default considers them to be
        inside]. Alternatively, append either a list of four values
        [*cborder*, *lborder*, *iborder*, *pborder*] or just the single value
        *bordervalue* (for the case when they should all be the same value).
        This turns on the line-tracking mode. Now, after setting the mask
        values specified via ``maskvalues`` we trace the lines and change the
        node values for all cells traversed by a line to the corresponding
        border value. Here, *cborder* is used for cells traversed by the
        coastline, *lborder* for cells traversed by a lake outline, *iborder*
        for islands-in-lakes outlines, and *pborder* for
        ponds-in-islands-in-lakes outlines [Default is no line tracing].
    maskvalues : str or list
        [*wet*, *dry*] or [*ocean*, *land*, *lake*, *island*, *pond*].
        Sets the values that will be assigned to nodes. Values can
        be any number, including the textstring NaN
        [Default is [0, 1, 0, 1, 0] (i.e., [0, 1])]. Also select
        ``bordervalues`` to let nodes exactly on feature boundaries be
        considered outside [Default is inside].
    {V}
    {r}

    Returns
    -------
    ret: xarray.DataArray or None
        Return type depends on whether the ``outgrid`` parameter is set:

        - :class:`xarray.DataArray` if ``outgrid`` is not set
        - None if ``outgrid`` is set (grid output will be stored in file set by
          ``outgrid``)

    Example
    -------
    >>> import pygmt  # doctest: +SKIP
    >>> # Create a landmask grid with an x-range of 125 to 130,
    >>> # and a y-range of 30 to 35
    >>> landmask = pygmt.grdlandmask(
    ...     spacing=1, region=[125, 130, 30, 35]
    ... )  # doctest: +SKIP
    """
    if "I" not in kwargs or "R" not in kwargs:
        raise GMTInvalidInput("Both 'region' and 'spacing' must be specified.")

    with GMTTempFile(suffix=".nc") as tmpfile:
        with Session() as lib:
            if "G" not in kwargs:  # if outgrid is unset, output to tempfile
                kwargs.update({"G": tmpfile.name})
            outgrid = kwargs["G"]
            arg_str = build_arg_string(kwargs)
            lib.call_module("grdlandmask", arg_str)

        return load_dataarray(outgrid) if outgrid == tmpfile.name else None
Example #5
0
def grdfilter(grid, **kwargs):
    r"""
    Filter a grid in the space (or time) domain.

    Filter a grid file in the time domain using one of the selected convolution
    or non-convolution isotropic or rectangular filters and compute distances
    using Cartesian or Spherical geometries. The output grid file can
    optionally be generated as a sub-region of the input (via ``region``)
    and/or with new increment (via ``spacing``) or registration
    (via ``toggle``). In this way, one may have "extra space" in the input
    data so that the edges will not be used and the output can be within one
    half-width of the input edges. If the filter is low-pass, then the output
    may be less frequently sampled than the input.

    Full option list at :gmt-docs:`grdfilter.html`

    {aliases}

    Parameters
    ----------
    grid : str or xarray.DataArray
        The file name of the input grid or the grid loaded as a DataArray.
    outgrid : str or None
        The name of the output netCDF file with extension .nc to store the grid
        in.
    filter : str
        **b**\|\ **c**\|\ **g**\|\ **o**\|\ **m**\|\ **p**\|\ **h**\ *xwidth*\
        [/*width2*\][*modifiers*].
        Name of filter type you which to apply, followed by the width:

        b: Box Car

        c: Cosine Arch

        g: Gaussian

        o: Operator

        m: Median

        p: Maximum Likelihood probability

        h: histogram
    distance : str
        Distance *flag* tells how grid (x,y) relates to filter width as
        follows:

        p: grid (px,py) with *width* an odd number of pixels; Cartesian
        distances.

        0: grid (x,y) same units as *width*, Cartesian distances.

        1: grid (x,y) in degrees, *width* in kilometers, Cartesian distances.

        2: grid (x,y) in degrees, *width* in km, dx scaled by cos(middle y),
        Cartesian distances.

        The above options are fastest because they allow weight matrix to be
        computed only once. The next three options are slower because they
        recompute weights for each latitude.

        3: grid (x,y) in degrees, *width* in km, dx scaled by cosine(y),
        Cartesian distance calculation.

        4: grid (x,y) in degrees, *width* in km, Spherical distance
        calculation.

        5: grid (x,y) in Mercator ``projection='m1'`` img units, *width* in km,
        Spherical distance calculation.

    {I}
    nans : str or float
        **i**\|\ **p**\|\ **r**.
        Determine how NaN-values in the input grid affects the filtered output.
    {R}
    toggle : bool
        Toggle the node registration for the output grid so as to become the
        opposite of the input grid. [Default gives the same registration as the
        input grid].
    {V}
    {f}
    {r}

    Returns
    -------
    ret: xarray.DataArray or None
        Return type depends on whether the ``outgrid`` parameter is set:

        - :class:`xarray.DataArray` if ``outgrid`` is not set
        - None if ``outgrid`` is set (grid output will be stored in file set by
          ``outgrid``)

    Example
    -------
    >>> import os
    >>> import pygmt

    >>> # Apply a filter of 600km (full width) to the @earth_relief_30m file
    >>> # and return a filtered field (saved as netcdf)
    >>> pygmt.grdfilter(
    ...     grid="@earth_relief_30m",
    ...     filter="m600",
    ...     distance="4",
    ...     region=[150, 250, 10, 40],
    ...     spacing=0.5,
    ...     outgrid="filtered_pacific.nc",
    ... )
    >>> os.remove("filtered_pacific.nc")  # cleanup file

    >>> # Apply a gaussian smoothing filter of 600 km in the input data array,
    >>> # and returns a filtered data array with the smoothed field.
    >>> grid = pygmt.datasets.load_earth_relief()
    >>> smooth_field = pygmt.grdfilter(grid=grid, filter="g600", distance="4")
    """
    with GMTTempFile(suffix=".nc") as tmpfile:
        with Session() as lib:
            file_context = lib.virtualfile_from_data(check_kind="raster",
                                                     data=grid)
            with file_context as infile:
                if "G" not in kwargs:  # if outgrid is unset, output to tempfile
                    kwargs.update({"G": tmpfile.name})
                outgrid = kwargs["G"]
                arg_str = " ".join([infile, build_arg_string(kwargs)])
                lib.call_module("grdfilter", arg_str)

        return load_dataarray(outgrid) if outgrid == tmpfile.name else None
Example #6
0
def test_io_load_dataarray_cache():
    """
    Check that load_dataarray fails when the cache argument is used.
    """
    with pytest.raises(TypeError):
        _ = load_dataarray("somefile.nc", cache=True)
Example #7
0
def grdgradient(grid, **kwargs):
    r"""
    Compute the directional derivative of the vector gradient of the data.

    Can accept ``azimuth``, ``direction``, and ``radiance`` input to create
    the resulting gradient.

    Full option list at :gmt-docs:`grdgradient.html`

    {aliases}

    Parameters
    ----------
    grid : str or xarray.DataArray
        The file name of the input grid or the grid loaded as a DataArray.
    outgrid : str or None
        The name of the output netCDF file with extension .nc to store the grid
        in.
    azimuth : int or float or str or list
        *azim*\ [/*azim2*].
        Azimuthal direction for a directional derivative; *azim* is the
        angle in the x,y plane measured in degrees positive clockwise from
        north (the +y direction) toward east (the +x direction). The
        negative of the directional derivative,
        :math:`-(\frac{{dz}}{{dx}}\sin(\mbox{{azim}}) + \
        \frac{{dz}}{{dy}}\cos(\mbox{{azim}}))`, is found; negation yields
        positive values when the slope of :math:`z(x,y)` is downhill in the
        *azim* direction, the correct sense for shading the illumination of an
        image by a light source above the x,y plane shining from the *azim*
        direction. Optionally, supply two azimuths, *azim*/*azim2*, in which
        case the gradients in each of these directions are calculated and the
        one larger in magnitude is retained; this is useful for illuminating
        data with two directions of lineated structures, e.g., *0*/*270*
        illuminates from the north (top) and west (left).  Finally, if *azim*
        is a file it must be a grid of the same domain, spacing and
        registration as *grid* that will update the azimuth at each output
        node when computing the directional derivatives.
    direction : str
        [**a**][**c**][**o**][**n**].
        Find the direction of the positive (up-slope) gradient of the data.
        The following options are supported:

        - **a** - Find the aspect (i.e., the down-slope direction)
        - **c** - Use the conventional Cartesian angles measured
          counterclockwise from the positive x (east) direction.
        - **o** - Report orientations (0-180) rather than directions (0-360).
        - **n** - Add 90 degrees to all angles (e.g., to give local strikes of
          the surface).
    radiance : str or list
        [**m**\|\ **s**\|\ **p**]\ *azim/elev*\ [**+a**\ *ambient*][**+d**\
        *diffuse*][**+p**\ *specular*][**+s**\ *shine*].
        Compute Lambertian radiance appropriate to use with
        :doc:`pygmt.Figure.grdimage` and :doc:`pygmt.Figure.grdview`. The
        Lambertian Reflection assumes an ideal surface that reflects all the
        light that strikes it and the surface appears
        equally bright from all viewing directions. Here, *azim* and *elev* are
        the azimuth and elevation of the light vector. Optionally, supply
        *ambient* [0.55], *diffuse* [0.6], *specular* [0.4], or *shine* [10],
        which are parameters that control the reflectance properties of the
        surface. Default values are given in the brackets. Use **s** for a
        simpler Lambertian algorithm. Note that with this form you only have
        to provide azimuth and elevation. Alternatively, use **p** for
        the Peucker piecewise linear approximation (simpler but faster
        algorithm; in this case *azim* and *elev* are hardwired to 315
        and 45 degrees. This means that even if you provide other values
        they will be ignored.).
    normalize : str or bool
        [**e**\|\ **t**][*amp*][**+a**\ *ambient*][**+s**\ *sigma*]\
        [**+o**\ *offset*].
        The actual gradients :math:`g` are offset and scaled to produce
        normalized gradients :math:`g_n` with a maximum output magnitude of
        *amp*. If *amp* is not given, default *amp* = 1. If *offset* is not
        given, it is set to the average of :math:`g`. The following forms are
        supported:

        - **True** - Normalize using :math:`g_n = \mbox{{amp}}\
          (\frac{{g - \mbox{{offset}}}}{{max(|g - \mbox{{offset}}|)}})`
        - **e** - Normalize using a cumulative Laplace distribution yielding:
          :math:`g_n = \mbox{{amp}}(1 - \
          \exp{{(\sqrt{{2}}\frac{{g - \mbox{{offset}}}}{{\sigma}}))}}`, where
          :math:`\sigma` is estimated using the L1 norm of
          :math:`(g - \mbox{{offset}})` if it is not given.
        - **t** - Normalize using a cumulative Cauchy distribution yielding:
          :math:`g_n = \
          \frac{{2(\mbox{{amp}})}}{{\pi}}(\tan^{{-1}}(\frac{{g - \
          \mbox{{offset}}}}{{\sigma}}))` where :math:`\sigma` is estimated
          using the L2 norm of :math:`(g - \mbox{{offset}})` if it is not
          given.

        As a final option, you may add **+a**\ *ambient* to add *ambient* to
        all nodes after gradient calculations are completed.
    tiles : str
        **c**\|\ **r**\|\ **R**.
        Controls how normalization via ``normalize`` is carried out.  When
        multiple  grids should be normalized the same way (i.e., with the same
        *offset*  and/or *sigma*),
        we must pass these values via ``normalize``.  However, this is
        inconvenient if we compute these values from a grid.  Use **c** to
        save  the results  of *offset* and *sigma* to a statistics file; if
        grid output is not  needed for this run then do not specify
        ``outgrid``. For  subsequent runs,  just use **r** to read these
        values.  Using **R**  will read then delete the statistics file.
    {R}
    slope_file : str
        Name of output grid file with scalar magnitudes of gradient vectors.
        Requires ``direction`` but makes ``outgrid`` optional.
    {V}
    {f}
    {n}

    Returns
    -------
    ret: xarray.DataArray or None
        Return type depends on whether the ``outgrid`` parameter is set:

        - :class:`xarray.DataArray` if ``outgrid`` is not set
        - None if ``outgrid`` is set (grid output will be stored in file set by
          ``outgrid``)


    Example
    -------
    >>> import pygmt
    >>> # Load a grid of @earth_relief_30m data, with an x-range of 10 to 30,
    >>> # and a y-range of 15 to 25
    >>> grid = pygmt.datasets.load_earth_relief(
    ...     resolution="30m", region=[10, 30, 15, 25]
    ... )
    >>> # Create a new grid from an input grid, set the azimuth to 10 degrees,
    >>> new_grid = pygmt.grdgradient(grid=grid, azimuth=10)
    """
    with GMTTempFile(suffix=".nc") as tmpfile:
        if kwargs.get("Q") is not None and kwargs.get("N") is None:
            raise GMTInvalidInput("""Must specify normalize if tiles is specified.""")
        if not args_in_kwargs(args=["A", "D", "E"], kwargs=kwargs):
            raise GMTInvalidInput(
                """At least one of the following parameters must be specified:
                azimuth, direction, or radiance"""
            )
        with Session() as lib:
            file_context = lib.virtualfile_from_data(check_kind="raster", data=grid)
            with file_context as infile:
                if (outgrid := kwargs.get("G")) is None:
                    kwargs["G"] = outgrid = tmpfile.name  # output to tmpfile
                lib.call_module(
                    module="grdgradient", args=build_arg_string(kwargs, infile=infile)
                )

        return load_dataarray(outgrid) if outgrid == tmpfile.name else None
Example #8
0
    def _grdhisteq(grid, output_type, **kwargs):
        r"""
        Perform histogram equalization for a grid.

        Must provide ``outfile`` or ``outgrid``.

        Full option list at :gmt-docs:`grdhisteq.html`

        {aliases}

        Parameters
        ----------
        grid : str or xarray.DataArray
            The file name of the input grid or the grid loaded as a DataArray.
        outgrid : str or bool or None
            The name of the output netCDF file with extension .nc to store the
            grid in.
        outfile : str or bool or None
            The name of the output ASCII file to store the results of the
            histogram equalization in.
        output_type: str
            Determines the output type. Use "file", "xarray", "pandas", or
            "numpy".
        divisions : int
            Set the number of divisions of the data range [Default is 16].

        {R}
        {V}
        {h}

        Returns
        -------
        ret: pandas.DataFrame or xarray.DataArray or None
            Return type depends on whether the ``outgrid`` parameter is set:

            - xarray.DataArray if ``output_type`` is "xarray""
            - numpy.ndarray if ``output_type`` is "numpy"
            - pandas.DataFrame if ``output_type`` is "pandas"
            - None if ``output_type`` is "file" (output is stored in
              ``outgrid`` or ``outfile``)

        See Also
        -------
        :meth:`pygmt.grd2cpt`
        """

        with Session() as lib:
            file_context = lib.virtualfile_from_data(check_kind="raster", data=grid)
            with file_context as infile:
                lib.call_module(
                    module="grdhisteq", args=build_arg_string(kwargs, infile=infile)
                )

        if output_type == "file":
            return None
        if output_type == "xarray":
            return load_dataarray(kwargs["G"])

        result = pd.read_csv(
            filepath_or_buffer=kwargs["D"],
            sep="\t",
            header=None,
            names=["start", "stop", "bin_id"],
            dtype={
                "start": np.float32,
                "stop": np.float32,
                "bin_id": np.uint32,
            },
        )
        if output_type == "numpy":
            return result.to_numpy()

        return result.set_index("bin_id")
Example #9
0
def grdcut(grid, **kwargs):
    r"""
    Extract subregion from a grid.

    Produce a new ``outgrid`` file which is a subregion of ``grid``. The
    subregion is specified with ``region``; the specified range must not exceed
    the range of ``grid`` (but see ``extend``). If in doubt, run
    :meth:`pygmt.grdinfo` to check range. Alternatively, define the subregion
    indirectly via a range check on the node values or via distances from a
    given point. Finally, you can give ``projection`` for oblique projections
    to determine the corresponding rectangular ``region`` that will give a grid
    that fully covers the oblique domain.

    Full option list at :gmt-docs:`grdcut.html`

    {aliases}

    Parameters
    ----------
    grid : str or xarray.DataArray
        The file name of the input grid or the grid loaded as a DataArray.
    outgrid : str or None
        The name of the output netCDF file with extension .nc to store the grid
        in.
    {J}
    {R}
    extend : bool or int or float
        Allow grid to be extended if new ``region`` exceeds existing
        boundaries. Give a value to initialize nodes outside current region.
    circ_subregion : str
        *lon/lat/radius*\[\ *unit*\][**+n**].
        Specify an origin (*lon* and *lat*) and *radius*; append a distance
        *unit* and we determine the corresponding rectangular region so that
        all grid nodes on or inside the circle are contained in the subset.
        If **+n** is appended we set all nodes outside the circle to NaN.
    z_subregion : str
        [*min/max*\][**+n**\|\ **N**\|\ **r**].
        Determine a new rectangular region so that all nodes outside this
        region are also outside the given z-range [-inf/+inf]. To indicate no
        limit on *min* or *max* only, specify a hyphen (-). Normally, any NaNs
        encountered are simply skipped and not considered in the
        range-decision. Append **+n** to consider a NaN to be outside the given
        z-range. This means the new subset will be NaN-free. Alternatively,
        append **+r** to consider NaNs to be within the data range. In this
        case we stop shrinking the boundaries once a NaN is found [Default
        simply skips NaNs when making the range decision]. Finally, if your
        core subset grid is surrounded by rows and/or columns that are all
        NaNs, append **+N** to strip off such columns before (optionally)
        considering the range of the core subset for further reduction of the
        area.

    {V}
    {f}

    Returns
    -------
    ret: xarray.DataArray or None
        Return type depends on whether the ``outgrid`` parameter is set:

        - :class:`xarray.DataArray` if ``outgrid`` is not set
        - None if ``outgrid`` is set (grid output will be stored in file set by
          ``outgrid``)
    """
    with GMTTempFile(suffix=".nc") as tmpfile:
        with Session() as lib:
            file_context = lib.virtualfile_from_data(check_kind="raster", data=grid)
            with file_context as infile:
                if "G" not in kwargs:  # if outgrid is unset, output to tempfile
                    kwargs.update({"G": tmpfile.name})
                outgrid = kwargs["G"]
                arg_str = " ".join([infile, build_arg_string(kwargs)])
                lib.call_module("grdcut", arg_str)

        return load_dataarray(outgrid) if outgrid == tmpfile.name else None
Example #10
0
def xyz2grd(data=None, x=None, y=None, z=None, **kwargs):
    r"""
    Create a grid file from table data.

    Reads one or more tables with *x, y, z* columns and creates a binary grid
    file. xyz2grd will report if some of the nodes are not filled in with
    data. Such unconstrained nodes are set to a value specified by the user
    [Default is NaN]. Nodes with more than one value will be set to the mean
    value.

    Full option list at :gmt-docs:`xyz2grd.html`

    {aliases}

    Parameters
    ----------
    data : str or {table-like}
        Pass in (x, y, z) or (longitude, latitude, elevation) values by
        providing a file name to an ASCII data table, a 2D {table-classes}.
    x/y/z : 1d arrays
        The arrays of x and y coordinates and z data points.
    outgrid : str or None
        Optional. The name of the output netCDF file with extension .nc to
        store the grid in.
    duplicate : str
        [**d**\|\ **f**\|\ **l**\|\ **m**\|\ **n**\|\
        **r**\|\ **S**\|\ **s**\|\ **u**\|\ **z**].
        By default we will calculate mean values if multiple entries fall on
        the same node. Use **-A** to change this behavior, except it is
        ignored if **-Z** is given. Append **f** or **s** to simply keep the
        first or last data point that was assigned to each node. Append
        **l** or **u** or **d** to find the lowest (minimum) or upper (maximum)
        value or the difference between the maximum and miminum value
        at each node, respectively. Append **m** or **r** or **S** to compute
        mean or RMS value or standard deviation at each node, respectively.
        Append **n** to simply count the number of data points that were
        assigned to each node (this only requires two input columns *x* and
        *y* as *z* is not consulted). Append **z** to sum multiple values that
        belong to the same node.
    {I}
    {J}
    {R}
    {V}
    convention : str
        [*flags*].
        Read a 1-column ASCII [or binary] table. This assumes that all the
        nodes are present and sorted according to specified ordering
        convention contained in *flags*. If incoming data represents rows,
        make *flags* start with **T**\ (op) if first row is y
        = ymax or **B**\ (ottom) if first row is y = ymin.
        Then, append **L** or **R** to indicate that first element is at
        left or right end of row. Likewise for column formats: start with
        **L** or **R** to position first column, and then append **T** or
        **B** to position first element in a row. **Note**: These two
        row/column indicators are only required for grids; for other tables
        they do not apply. For gridline registered grids: If data are periodic
        in x but the incoming data do not contain the (redundant) column at
        x = xmax, append **x**. For data periodic in y without redundant row at
        y = ymax, append **y**. Append **s**\ *n* to skip the first *n* number
        of bytes (probably a header). If the byte-order or the words needs
        to be swapped, append **w**. Select one of several data types (all
        binary except **a**):

        - **A** ASCII representation of one or more floating point values per
          record
        - **a** ASCII representation of a single item per record
        - **c** int8_t, signed 1-byte character
        - **u** uint8_t, unsigned 1-byte character
        - **h** int16_t, signed 2-byte integer
        - **H** uint16_t, unsigned 2-byte integer
        - **i** int32_t, signed 4-byte integer
        - **I** uint32_t, unsigned 4-byte integer
        - **l** int64_t, long (8-byte) integer
        - **L** uint64_t, unsigned long (8-byte) integer
        - **f** 4-byte floating point single precision
        - **d** 8-byte floating point double precision

        [Default format is scanline orientation of ASCII numbers: **La**].
        The difference between **A** and **a** is that the latter can decode
        both *date*\ **T**\ *clock* and *ddd:mm:ss[.xx]* formats but expects
        each input record to have a single value, while the former can handle
        multiple values per record but can only parse regular floating point
        values. Translate incoming *z*-values via the ``incols`` parameter.
    {b}
    {d}
    {e}
    {f}
    {h}
    {i}
    {r}
    {w}

    Returns
    -------
    ret: xarray.DataArray or None
        Return type depends on whether the ``outgrid`` parameter is set:

        - :class:`xarray.DataArray`: if ``outgrid`` is not set
        - None if ``outgrid`` is set (grid output will be stored in file set by
          ``outgrid``)

    Example
    -------
    >>> import numpy as np
    >>> import pygmt
    >>> # generate a grid for z=x**2+y**2, with an x-range of 0 to 3,
    >>> # and a y-range of 10.5 to 12.5. The x- and y-spacing are 1.0 and 0.5.
    >>> x, y = np.meshgrid([0, 1, 2, 3], [10.5, 11.0, 11.5, 12.0, 12.5])
    >>> z = x**2 + y**2
    >>> xx, yy, zz = x.flatten(), y.flatten(), z.flatten()
    >>> grid = pygmt.xyz2grd(
    ...     x=xx, y=yy, z=zz, spacing=(1.0, 0.5), region=[0, 3, 10, 13]
    ... )
    """
    if kwargs.get("I") is None or kwargs.get("R") is None:
        raise GMTInvalidInput("Both 'region' and 'spacing' must be specified.")

    with GMTTempFile(suffix=".nc") as tmpfile:
        with Session() as lib:
            file_context = lib.virtualfile_from_data(
                check_kind="vector", data=data, x=x, y=y, z=z, required_z=True
            )
            with file_context as infile:
                if (outgrid := kwargs.get("G")) is None:
                    kwargs["G"] = outgrid = tmpfile.name  # output to tmpfile
                lib.call_module(
                    module="xyz2grd", args=build_arg_string(kwargs, infile=infile)
                )

        return load_dataarray(outgrid) if outgrid == tmpfile.name else None
Example #11
0
def nearneighbor(data=None, x=None, y=None, z=None, **kwargs):
    r"""
    Grid table data using a "Nearest neighbor" algorithm

    **nearneighbor** reads arbitrarily located (*x,y,z*\ [,\ *w*]) triples
    [quadruplets] and uses a nearest neighbor algorithm to assign a weighted
    average value to each node that has one or more data points within a search
    radius centered on the node with adequate coverage across a subset of the
    chosen sectors. The node value is computed as a weighted mean of the
    nearest point from each sector inside the search radius. The weighting
    function and the averaging used is given by:

    .. math::
        w(r_i) = \frac{{w_i}}{{1 + d(r_i) ^ 2}},
        \quad d(r) = \frac {{3r}}{{R}},
        \quad \bar{{z}} = \frac{{\sum_i^n w(r_i) z_i}}{{\sum_i^n w(r_i)}}

    where :math:`n` is the number of data points that satisfy the selection
    criteria and :math:`r_i` is the distance from the node to the *i*'th data
    point. If no data weights are supplied then :math:`w_i = 1`.

    .. figure:: https://docs.generic-mapping-tools.org/dev/_images/GMT_nearneighbor.png # noqa: W505
       :width: 300 px
       :align: center

       Search geometry includes the search radius (R) which limits the points
       considered and the number of sectors (here 4), which restricts how
       points inside the search radius contribute to the value at the node.
       Only the closest point in each sector (red circles) contribute to the
       weighted estimate.

    Takes a matrix, xyz triples, or a file name as input.

    Must provide either ``data`` or ``x``, ``y``, and ``z``.

    Full option list at :gmt-docs:`nearneighbor.html`

    {aliases}

    Parameters
    ----------
    data : str or {table-like}
        Pass in (x, y, z) or (longitude, latitude, elevation) values by
        providing a file name to an ASCII data table, a 2D
        {table-classes}.
    x/y/z : 1d arrays
        Arrays of x and y coordinates and values z of the data points.

    {I}

    {R}

    search_radius : str
        Sets the search radius that determines which data points are considered
        close to a node.

    outgrid : str
        Optional. The file name for the output netcdf file with extension .nc
        to store the grid in.

    empty : str
        Optional. Set the value assigned to empty nodes. Defaults to NaN.

    sectors : str
        *sectors*\ [**+m**\ *min_sectors*]\|\ **n**.
        Optional. The circular search area centered on each node is divided
        into *sectors* sectors. Average values will only be computed if there
        is *at least* one value inside each of at least *min_sectors* of the
        sectors for a given node. Nodes that fail this test are assigned the
        value NaN (but see ``empty``). If **+m** is omitted then *min_sectors*
        is set to be at least 50% of *sectors* (i.e., rounded up to next
        integer) [Default is a quadrant search with 100% coverage, i.e.,
        *sectors* = *min_sectors* = 4]. Note that only the nearest value per
        sector enters into the averaging; the more distant points are ignored.
        Alternatively, use ``sectors="n"`` to call GDAL's nearest neighbor
        algorithm instead.

    {V}
    {a}
    {b}
    {d}
    {e}
    {f}
    {g}
    {h}
    {i}
    {r}
    {w}

    Returns
    -------
    ret: xarray.DataArray or None
        Return type depends on whether the ``outgrid`` parameter is set:

        - :class:`xarray.DataArray`: if ``outgrid`` is not set
        - None if ``outgrid`` is set (grid output will be stored in file set by
          ``outgrid``)
    """
    with GMTTempFile(suffix=".nc") as tmpfile:
        with Session() as lib:
            # Choose how data will be passed into the module
            table_context = lib.virtualfile_from_data(check_kind="vector",
                                                      data=data,
                                                      x=x,
                                                      y=y,
                                                      z=z,
                                                      required_z=True)
            with table_context as infile:
                if "G" not in kwargs:  # if outgrid is unset, output to tmpfile
                    kwargs.update({"G": tmpfile.name})
                outgrid = kwargs["G"]
                arg_str = " ".join([infile, build_arg_string(kwargs)])
                lib.call_module(module="nearneighbor", args=arg_str)

        return load_dataarray(outgrid) if outgrid == tmpfile.name else None
Example #12
0
def load_earth_age(resolution="01d", region=None, registration=None):
    r"""
    Load Earth seafloor crustal ages in various resolutions.

    The grids are downloaded to a user data directory
    (usually ``~/.gmt/server/earth/earth_age/``) the first time you invoke
    this function. Afterwards, it will load the grid from the data directory.
    So you'll need an internet connection the first time around.

    These grids can also be accessed by passing in the file name
    **@earth_age**\_\ *res*\[_\ *reg*] to any grid plotting/processing
    function. *res* is the grid resolution (see below), and *reg* is grid
    registration type (**p** for pixel registration or **g** for gridline
    registration).

    Refer to :gmt-datasets:`earth-age.html` for more details.

    Parameters
    ----------
    resolution : str
        The grid resolution. The suffix ``d`` and ``m`` stand for
        arc-degree, arc-minute and arc-second. It can be ``'01d'``, ``'30m'``,
        ``'20m'``, ``'15m'``, ``'10m'``, ``'06m'``, ``'05m'``, ``'04m'``,
        ``'03m'``, ``'02m'``, or ``'01m'``.

    region : str or list
        The subregion of the grid to load, in the forms of a list
        [*xmin*, *xmax*, *ymin*, *ymax*] or a string *xmin/xmax/ymin/ymax*.
        Required for grids with resolutions higher than 5
        arc-minute (i.e., ``05m``).

    registration : str
        Grid registration type. Either ``pixel`` for pixel registration or
        ``gridline`` for gridline registration. Default is ``None``, where
        a pixel-registered grid is returned unless only the
        gridline-registered grid is available.

    Returns
    -------
    grid : :class:`xarray.DataArray`
        The Earth seafloor crustal age grid. Coordinates are latitude and
        longitude in degrees. Age is in millions of years (Myr).

    Note
    ----
    The :class:`xarray.DataArray` grid doesn't support slice operation, for
    Earth seafloor crustal age with resolutions of 5 arc-minutes or higher,
    which are stored as smaller tiles.
    """

    # earth seafloor crust age data stored as single grids for low resolutions
    non_tiled_resolutions = ["01d", "30m", "20m", "15m", "10m", "06m"]
    # earth seafloor crust age data stored as tiles for high resolutions
    tiled_resolutions = ["05m", "04m", "03m", "02m", "01m"]

    if registration in ("pixel", "gridline", None):
        # If None, let GMT decide on Pixel/Gridline type
        reg = f"_{registration[0]}" if registration else ""
    else:
        raise GMTInvalidInput(
            f"Invalid grid registration: '{registration}', should be either "
            "'pixel', 'gridline' or None. Default is None, where a "
            "pixel-registered grid is returned unless only the "
            "gridline-registered grid is available."
        )

    if resolution not in non_tiled_resolutions + tiled_resolutions:
        raise GMTInvalidInput(f"Invalid Earth relief resolution '{resolution}'.")

    # Choose earth relief data prefix
    earth_age_prefix = "earth_age_"

    # different ways to load tiled and non-tiled earth relief data
    # Known issue: tiled grids don't support slice operation
    # See https://github.com/GenericMappingTools/pygmt/issues/524
    if region is None:
        if resolution not in non_tiled_resolutions:
            raise GMTInvalidInput(
                f"'region' is required for Earth age resolution '{resolution}'."
            )
        fname = which(f"@earth_age_{resolution}{reg}", download="a")
        grid = load_dataarray(fname, engine="netcdf4")
    else:
        grid = grdcut(f"@{earth_age_prefix}{resolution}{reg}", region=region)

    # Add some metadata to the grid
    grid.name = "seafloor_age"
    grid.attrs["long_name"] = "age of seafloor crust"
    grid.attrs["units"] = "Myr"
    grid.attrs["vertical_datum"] = "EMG96"
    grid.attrs["horizontal_datum"] = "WGS84"
    # Remove the actual range because it gets outdated when indexing the grid,
    # which causes problems when exporting it to netCDF for usage on the
    # command-line.
    grid.attrs.pop("actual_range")
    for coord in grid.coords:
        grid[coord].attrs.pop("actual_range")
    return grid
Example #13
0
def dimfilter(grid, **kwargs):
    r"""
    Filter a grid by dividing the filter circle.

    Filter a grid in the space (or time) domain by
    dividing the given filter circle into the given number of sectors,
    applying one of the selected primary convolution or non-convolution
    filters to each sector, and choosing the final outcome according to the
    selected secondary filter. It computes distances using Cartesian or
    Spherical geometries. The output grid can optionally be generated as a
    subregion of the input and/or with a new increment using ``spacing``,
    which may add an "extra space" in the input data to prevent edge
    effects for the output grid. If the filter is low-pass, then the output
    may be less frequently sampled than the input. **dimfilter** will not
    produce a smooth output as other spatial filters
    do because it returns a minimum median out of *N* medians of *N*
    sectors. The output can be rough unless the input data is noise-free.
    Thus, an additional filtering (e.g., Gaussian via :func:`pygmt.grdfilter`)
    of the DiM-filtered data is generally recommended.

    Full option list at :gmt-docs:`dimfilter.html`

    {aliases}

    Parameters
    ----------
    grid : str or xarray.DataArray
        The file name of the input grid or the grid loaded as a DataArray.
    outgrid : str or None
        The name of the output netCDF file with extension .nc to store the grid
        in.
    distance : int or str
        Distance flag tells how grid (x,y) relates to filter width, as follows:

        - **0**\ : grid (x,y) in same units as *width*, Cartesian distances.
        - **1**\ : grid (x,y) in degrees, *width* in kilometers, Cartesian
          distances.
        - **2**\ : grid (x,y) in degrees, *width* in km, dx scaled by
          cos(middle y), Cartesian distances.

        The above options are fastest because they allow weight matrix to be
        computed only once. The next two options are slower because they
        recompute weights for each latitude.

        - **3**\ : grid (x,y) in degrees, *width* in km, dx scaled by
          cosine(y), Cartesian distance calculation.
        - **4**\ : grid (x,y) in degrees, *width* in km, Spherical distance
          calculation.
    filter : str
        **x**\ *width*\ [**+l**\|\ **u**].
        Sets the primary filter type. Choose among convolution and
        non-convolution filters. Use the filter code **x** followed by
        the full diameter *width*. Available convolution filters are:

        - (**b**) Boxcar: All weights are equal.
        - (**c**) Cosine Arch: Weights follow a cosine arch curve.
        - (**g**) Gaussian: Weights are given by the Gaussian function.

        Non-convolution filters are:

        - (**m**) Median: Returns median value.
        - (**p**) Maximum likelihood probability (a mode estimator): Return
          modal value. If more than one mode is found we return their average
          value. Append **+l** or **+h** to the filter width if you want
          to return the smallest or largest of each sector's modal values.
    sectors : str
        **x**\ *sectors*\ [**+l**\|\ **u**]
        Sets the secondary filter type **x** and the number of bow-tie sectors.
        *sectors* must be integer and larger than 0. When *sectors* is
        set to 1, the secondary filter is not effective. Available secondary
        filters **x** are:

        - (**l**) Lower: Return the minimum of all filtered values.
        - (**u**) Upper: Return the maximum of all filtered values.
        - (**a**) Average: Return the mean of all filtered values.
        - (**m**) Median: Return the median of all filtered values.
        - (**p**) Mode: Return the mode of all filtered values:
          If more than one mode is found we return their average
          value. Append **+l** or **+h** to the sectors if you rather want to
          return the smallest or largest of the modal values.
    spacing : str or list
        *x_inc* [and optionally *y_inc*] is the output Increment. Append
        **m** to indicate minutes, or **c** to indicate seconds. If the new
        *x_inc*, *y_inc* are NOT integer multiples of the old ones (in the
        input data), filtering will be considerably slower. [Default: Same
        as input.]
    region : str or list
        [*xmin*, *xmax*, *ymin*, *ymax*].
        Defines the region of the output points. [Default: Same as input.]
    {V}

    Returns
    -------
    ret: xarray.DataArray or None
        Return type depends on whether the ``outgrid`` parameter is set:

        - :class:`xarray.DataArray` if ``outgrid`` is not set
        - None if ``outgrid`` is set (grid output will be stored in file set by
          ``outgrid``)
    """
    if not all(arg in kwargs for arg in ["D", "F", "N"]) and "Q" not in kwargs:
        raise GMTInvalidInput(
            """At least one of the following parameters must be specified:
            distance, filters, or sectors.""")

    with GMTTempFile(suffix=".nc") as tmpfile:
        with Session() as lib:
            file_context = lib.virtualfile_from_data(check_kind=None,
                                                     data=grid)
            with file_context as infile:
                if (outgrid := kwargs.get("G")) is None:
                    kwargs["G"] = outgrid = tmpfile.name  # output to tmpfile
                lib.call_module(module="dimfilter",
                                args=build_arg_string(kwargs, infile=infile))

        return load_dataarray(outgrid) if outgrid == tmpfile.name else None
Example #14
0
def load_earth_relief(resolution="01d",
                      region=None,
                      registration=None,
                      use_srtm=False):
    r"""
    Load Earth relief grids (topography and bathymetry) in various resolutions.

    The grids are downloaded to a user data directory
    (usually ``~/.gmt/server/earth/earth_relief/``) the first time you invoke
    this function. Afterwards, it will load the grid from the data directory.
    So you'll need an internet connection the first time around.

    These grids can also be accessed by passing in the file name
    **@earth_relief**\_\ *res*\[_\ *reg*] to any grid plotting/processing
    function. *res* is the grid resolution (see below), and *reg* is grid
    registration type (**p** for pixel registration or **g** for gridline
    registration).

    Refer to :gmt-datasets:`earth-relief.html` for more details.

    Parameters
    ----------
    resolution : str
        The grid resolution. The suffix ``d``, ``m`` and ``s`` stand for
        arc-degree, arc-minute and arc-second. It can be ``'01d'``, ``'30m'``,
        ``'20m'``, ``'15m'``, ``'10m'``, ``'06m'``, ``'05m'``, ``'04m'``,
        ``'03m'``, ``'02m'``, ``'01m'``, ``'30s'``, ``'15s'``, ``'03s'``,
        or ``'01s'``.

    region : str or list
        The subregion of the grid to load, in the forms of a list
        [*xmin*, *xmax*, *ymin*, *ymax*] or a string *xmin/xmax/ymin/ymax*.
        Required for Earth relief grids with resolutions higher than 5
        arc-minute (i.e., ``05m``).

    registration : str
        Grid registration type. Either ``pixel`` for pixel registration or
        ``gridline`` for gridline registration. Default is ``None``, where
        a pixel-registered grid is returned unless only the
        gridline-registered grid is available.

    use_srtm : bool
        By default, the land-only SRTM tiles from NASA are used to generate the
        ``'03s'`` and ``'01s'`` grids, and the missing ocean values are filled
        by up-sampling the SRTM15+V2.1 tiles which have a resolution of 15
        arc-second (i.e., ``'15s'``). If True, will only load the original
        land-only SRTM tiles.

    Returns
    -------
    grid : :class:`xarray.DataArray`
        The Earth relief grid. Coordinates are latitude and longitude in
        degrees. Relief is in meters.

    Note
    ----
    The :class:`xarray.DataArray` grid doesn't support slice operation, for
    Earth relief data with resolutions of 5 arc-minutes or higher, which are
    stored as smaller tiles.

    Examples
    --------

    >>> # load the default grid (pixel-registered 01d grid)
    >>> grid = load_earth_relief()
    >>> # load the 30m grid with "gridline" registration
    >>> grid = load_earth_relief("30m", registration="gridline")
    >>> # load high-resolution grid for a specific region
    >>> grid = load_earth_relief(
    ...     "05m", region=[120, 160, 30, 60], registration="gridline"
    ... )
    >>> # load the original 3 arc-second land-only SRTM tiles from NASA
    >>> grid = load_earth_relief(
    ...     "03s",
    ...     region=[135, 136, 35, 36],
    ...     registration="gridline",
    ...     use_srtm=True,
    ... )
    """

    # earth relief data stored as single grids for low resolutions
    non_tiled_resolutions = ["01d", "30m", "20m", "15m", "10m", "06m"]
    # earth relief data stored as tiles for high resolutions
    tiled_resolutions = [
        "05m", "04m", "03m", "02m", "01m", "30s", "15s", "03s", "01s"
    ]
    # resolutions of original land-only SRTM tiles from NASA
    land_only_srtm_resolutions = ["03s", "01s"]

    if registration in ("pixel", "gridline", None):
        # If None, let GMT decide on Pixel/Gridline type
        reg = f"_{registration[0]}" if registration else ""
    else:
        raise GMTInvalidInput(
            f"Invalid grid registration: '{registration}', should be either "
            "'pixel', 'gridline' or None. Default is None, where a "
            "pixel-registered grid is returned unless only the "
            "gridline-registered grid is available.")

    if resolution not in non_tiled_resolutions + tiled_resolutions:
        raise GMTInvalidInput(
            f"Invalid Earth relief resolution '{resolution}'.")

    # Check combination of resolution and registration.
    if (resolution == "15s"
            and registration == "gridline") or (resolution in ("03s", "01s")
                                                and registration == "pixel"):
        raise GMTInvalidInput(
            f"{registration}-registered Earth relief data for "
            f"resolution '{resolution}' is not supported.")

    # Choose earth relief data prefix
    earth_relief_prefix = "earth_relief_"
    if use_srtm and resolution in land_only_srtm_resolutions:
        earth_relief_prefix = "srtm_relief_"

    # different ways to load tiled and non-tiled earth relief data
    # Known issue: tiled grids don't support slice operation
    # See https://github.com/GenericMappingTools/pygmt/issues/524
    if region is None:
        if resolution not in non_tiled_resolutions:
            raise GMTInvalidInput(
                f"'region' is required for Earth relief resolution '{resolution}'."
            )
        fname = which(f"@earth_relief_{resolution}{reg}", download="a")
        grid = load_dataarray(fname, engine="netcdf4")
    else:
        grid = grdcut(f"@{earth_relief_prefix}{resolution}{reg}",
                      region=region)

    # Add some metadata to the grid
    grid.name = "elevation"
    grid.attrs["long_name"] = "elevation relative to the geoid"
    grid.attrs["units"] = "meters"
    grid.attrs["vertical_datum"] = "EMG96"
    grid.attrs["horizontal_datum"] = "WGS84"
    # Remove the actual range because it gets outdated when indexing the grid,
    # which causes problems when exporting it to netCDF for usage on the
    # command-line.
    grid.attrs.pop("actual_range")
    for coord in grid.coords:
        grid[coord].attrs.pop("actual_range")
    return grid
Example #15
0
class triangulate:  # pylint: disable=invalid-name
    """
    Delaunay triangulation or Voronoi partitioning and gridding of Cartesian
    data.

    Triangulate reads in x,y[,z] data and performs Delaunay triangulation,
    i.e., it finds how the points should be connected to give the most
    equilateral triangulation possible. If a map projection (give ``region``
    and ``projection``) is chosen then it is applied before the triangulation
    is calculated. By default, the output is triplets of point id numbers that
    make up each triangle. The id numbers refer to the points position (line
    number, starting at 0 for the first line) in the input file. If ``outgrid``
    and ``spacing`` are set a grid will be calculated based on the surface
    defined by the planar triangles. The actual algorithm used in the
    triangulations is either that of Watson [1982] or Shewchuk [1996] [Default
    is Shewchuk if installed; type ``gmt get GMT_TRIANGULATE`` on the command
    line to see which method is selected]. Furthermore, if the Shewchuk
    algorithm is installed then you can also perform the calculation of Voronoi
    polygons and optionally grid your data via the natural nearest neighbor
    algorithm.

    Note
    ----
    For geographic data with global or very large extent you should consider
    :gmt-docs:`sphtriangulate <sphtriangulate.html>` instead since
    ``triangulate`` is a Cartesian or small-geographic area operator and is
    unaware of periodic or polar boundary conditions.
    """
    @staticmethod
    @fmt_docstring
    @use_alias(
        G="outgrid",
        I="spacing",
        J="projection",
        R="region",
        V="verbose",
        b="binary",
        d="nodata",
        e="find",
        f="coltypes",
        h="header",
        i="incols",
        r="registration",
        s="skiprows",
        w="wrap",
    )
    @kwargs_to_strings(I="sequence", R="sequence", i="sequence_comma")
    def _triangulate(data=None,
                     x=None,
                     y=None,
                     z=None,
                     *,
                     output_type,
                     outfile=None,
                     **kwargs):
        """
        Delaunay triangulation or Voronoi partitioning and gridding of
        Cartesian data.

        Must provide ``outfile`` or ``outgrid``.

        Full option list at :gmt-docs:`triangulate.html`

        {aliases}

        Parameters
        ----------
        x/y/z : np.ndarray
            Arrays of x and y coordinates and values z of the data points.
        data : str or {table-like}
            Pass in (x, y, z) or (longitude, latitude, elevation) values by
            providing a file name to an ASCII data table, a 2D
            {table-classes}.
        {J}
        {R}
        {I}
        outgrid : bool or str
            The name of the output netCDF file with extension .nc to store the
            grid in. The interpolation is performed in the original
            coordinates, so if your triangles are close to the poles you are
            better off projecting all data to a local coordinate system before
            using ``triangulate`` (this is true of all gridding routines) or
            instead select :gmt-docs:`sphtriangulate <sphtriangulate.html>`.
        outfile : str or bool or None
            The name of the output ASCII file to store the results of the
            histogram equalization in.
        output_type: str
            Determines the output type. Use "file", "xarray", "pandas", or
            "numpy".
        {V}
        {b}
        {d}
        {e}
        {f}
        {h}
        {i}
        {r}
            Only valid with ``outgrid``.
        {s}
        {w}

        Returns
        -------
        ret: numpy.ndarray or pandas.DataFrame or xarray.DataArray or None
            Return type depends on the ``output_type`` parameter:

            - numpy.ndarray if ``output_type`` is "numpy"
            - pandas.DataFrame if ``output_type`` is "pandas"
            - xarray.DataArray if ``output_type`` is "xarray""
            - None if ``output_type`` is "file" (output is stored in
              ``outgrid`` or ``outfile``)
        """
        with Session() as lib:
            # Choose how data will be passed into the module
            table_context = lib.virtualfile_from_data(check_kind="vector",
                                                      data=data,
                                                      x=x,
                                                      y=y,
                                                      z=z,
                                                      required_z=False)
            with table_context as infile:
                # table output if outgrid is unset, else output to outgrid
                if (outgrid := kwargs.get("G")) is None:
                    kwargs.update({">": outfile})
                lib.call_module(module="triangulate",
                                args=build_arg_string(kwargs, infile=infile))

        if output_type == "file":
            return None
        if output_type == "xarray":
            return load_dataarray(outgrid)

        result = pd.read_csv(outfile, sep="\t", header=None)
        if output_type == "numpy":
            return result.to_numpy()
        return result
Example #16
0
def sphdistance(data=None, x=None, y=None, **kwargs):
    r"""
    Create Voronoi distance, node, or natural nearest-neighbor grid on a
    sphere.

    Reads a table containing *lon, lat* columns and performs
    the construction of Voronoi polygons. These polygons are
    then processed to calculate the nearest distance to each
    node of the lattice and written to the specified grid.

    Full option list at :gmt-docs:`sphdistance.html`

    {aliases}

    Parameters
    ----------
    data : str or {table-like}
        Pass in (x, y) or (longitude, latitude) values by
        providing a file name to an ASCII data table, a 2D
        {table-classes}.
    x/y : 1d arrays
        Arrays of x and y coordinates.
    outgrid : str or None
        The name of the output netCDF file with extension .nc to store the grid
        in.
    {I}
    {R}
    {V}
    single_form : bool
        For large data sets you can save some memory (at the expense of more
        processing) by only storing one form of location coordinates
        (geographic or Cartesian 3-D vectors) at any given time, translating
        from one form to the other when necessary [Default keeps both arrays
        in memory]. Not applicable with ``voronoi``.
    duplicate : bool
        Used to skip duplicate points since the algorithm cannot handle them.
        [Default assumes there are no duplicates].
    quantity : str
        **d**\|\ **n**\|\ **z**\ [*dist*].
        Specify the quantity that should be assigned to the grid nodes [Default
        is **d**]:

        - **d** - compute distances to the nearest data point
        - **n** - assign the ID numbers of the Voronoi polygons that each
          grid node is inside
        - **z** - assign all nodes inside the polygon the z-value of the center
          node for a natural nearest-neighbor grid.

        Optionally, append the resampling interval along Voronoi arcs in
        spherical degrees.
    unit : str
        Specify the unit used for distance calculations. Choose among **d**
        (spherical degree), **e** (m), **f** (feet), **k** (km), **M**
        (mile), **n** (nautical mile) or **u** survey foot.
    node_table : str
        Read the information pertaining to each Voronoi
        polygon (the unique node lon, lat and polygon area) from a separate
        file [Default acquires this information from the ASCII segment
        headers of the output file]. Required if binary input via `voronoi`
        is used.
    voronoi : str
        Append the name of a file with pre-calculated Voronoi polygons
        [Default performs the Voronoi construction on input data].
    Returns
    -------
    ret: xarray.DataArray or None
        Return type depends on whether the ``outgrid`` parameter is set:

        - :class:`xarray.DataArray` if ``outgrid`` is not set
        - None if ``outgrid`` is set (grid output will be stored in file set by
          ``outgrid``)
    """
    if "I" not in kwargs or "R" not in kwargs:
        raise GMTInvalidInput("Both 'region' and 'spacing' must be specified.")
    with GMTTempFile(suffix=".nc") as tmpfile:
        with Session() as lib:
            file_context = lib.virtualfile_from_data(check_kind="vector",
                                                     data=data,
                                                     x=x,
                                                     y=y)
            with file_context as infile:
                if "G" not in kwargs:  # if outgrid is unset, output to tempfile
                    kwargs.update({"G": tmpfile.name})
                outgrid = kwargs["G"]
                arg_str = build_arg_string(kwargs)
                arg_str = " ".join([infile, arg_str])
                lib.call_module("sphdistance", arg_str)

        return load_dataarray(outgrid) if outgrid == tmpfile.name else None