Exemple #1
0
def data_kind(data, x=None, y=None, z=None):
    """
    Check what kind of data is provided to a module.

    Possible types:

    * a file name provided as 'data'
    * an xarray.DataArray provided as 'data'
    * a matrix provided as 'data'
    * 1D arrays x and y (and z, optionally)

    Arguments should be ``None`` if not used. If doesn't fit any of these
    categories (or fits more than one), will raise an exception.

    Parameters
    ----------
    data : str, xarray.DataArray, 2d array, or None
       Data file name, xarray.DataArray or numpy array.
    x/y : 1d arrays or None
        x and y columns as numpy arrays.
    z : 1d array or None
        z column as numpy array. To be used optionally when x and y
        are given.

    Returns
    -------
    kind : str
        One of: ``'file'``, ``'grid'``, ``'matrix'``, ``'vectors'``.

    Examples
    --------

    >>> import numpy as np
    >>> import xarray as xr
    >>> data_kind(data=None, x=np.array([1, 2, 3]), y=np.array([4, 5, 6]))
    'vectors'
    >>> data_kind(data=np.arange(10).reshape((5, 2)), x=None, y=None)
    'matrix'
    >>> data_kind(data="my-data-file.txt", x=None, y=None)
    'file'
    >>> data_kind(data=xr.DataArray(np.random.rand(4, 3)))
    'grid'

    """
    if data is None and x is None and y is None:
        raise GMTInvalidInput("No input data provided.")
    if data is not None and (x is not None or y is not None or z is not None):
        raise GMTInvalidInput("Too much data. Use either data or x and y.")
    if data is None and (x is None or y is None):
        raise GMTInvalidInput("Must provided both x and y.")

    if isinstance(data, str):
        kind = "file"
    elif isinstance(data, xr.DataArray):
        kind = "grid"
    elif data is not None:
        kind = "matrix"
    else:
        kind = "vectors"
    return kind
Exemple #2
0
def _blockm(block_method, table, outfile, **kwargs):
    r"""
    Block average (x,y,z) data tables by mean or median estimation.

    Reads arbitrarily located (x,y,z) triples [or optionally weighted
    quadruples (x,y,z,w)] from a table and writes to the output a mean or
    median (depending on ``block_method``) position and value for every
    non-empty block in a grid region defined by the ``region`` and ``spacing``
    parameters.

    Parameters
    ----------
    block_method : str
        Name of the GMT module to call. Must be "blockmean" or "blockmedian".

    Returns
    -------
    output : pandas.DataFrame or None
        Return type depends on whether the ``outfile`` parameter is set:

        - :class:`pandas.DataFrame` table with (x, y, z) columns if ``outfile``
          is not set
        - None if ``outfile`` is set (filtered output will be stored in file
          set by ``outfile``)
    """

    kind = data_kind(table)
    with GMTTempFile(suffix=".csv") as tmpfile:
        with Session() as lib:
            if kind == "matrix":
                if not hasattr(table, "values"):
                    raise GMTInvalidInput(
                        f"Unrecognized data type: {type(table)}")
                file_context = lib.virtualfile_from_matrix(table.values)
            elif kind == "file":
                if outfile is None:
                    raise GMTInvalidInput("Please pass in a str to 'outfile'")
                file_context = dummy_context(table)
            else:
                raise GMTInvalidInput(f"Unrecognized data type: {type(table)}")

            with file_context as infile:
                if outfile is None:
                    outfile = tmpfile.name
                arg_str = " ".join(
                    [infile, build_arg_string(kwargs), "->" + outfile])
                lib.call_module(module=block_method, args=arg_str)

        # Read temporary csv output to a pandas table
        if outfile == tmpfile.name:  # if user did not set outfile, return pd.DataFrame
            result = pd.read_csv(tmpfile.name, sep="\t", names=table.columns)
        elif outfile != tmpfile.name:  # return None if outfile set, output in outfile
            result = None

    return result
Exemple #3
0
 def gtype(self, value):
     if value in (0, 1):
         self._gtype = value
     else:
         raise GMTInvalidInput(
             f"Invalid coordinate system type: {value}, should be a boolean of "
             "either 0 for Cartesian or 1 for Geographic")
Exemple #4
0
def legend(self, spec=None, position="JTR+jTR+o0.2c", box="+gwhite+p1p", **kwargs):
    r"""
    Plot legends on maps.

    Makes legends that can be overlaid on maps. Reads specific
    legend-related information from an input file, or automatically creates
    legend entries from plotted symbols that have labels. Unless otherwise
    noted, annotations will be made using the primary annotation font and
    size in effect (i.e., FONT_ANNOT_PRIMARY).

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

    {aliases}

    Parameters
    ----------
    spec : None or str
        Either ``None`` [default] for using the automatically generated legend
        specification file, or a *filename* pointing to the legend
        specification file.
    {J}
    {R}
    position : str
        [**g**\|\ **j**\|\ **J**\|\ **n**\|\ **x**]\ *refpoint*\
        **+w**\ *width*\ [/*height*]\ [**+j**\ *justify*]\ [**+l**\ *spacing*]\
        [**+o**\ *dx*\ [/*dy*]].
        Defines the reference point on the map for the
        legend. By default, uses **JTR**\ +\ **jTR**\ +\ **o**\ *0.2c* which
        places the legend at the top-right corner inside the map frame, with a
        0.2 cm offset.
    box : bool or str
        [**+c**\ *clearances*][**+g**\ *fill*][**+i**\ [[*gap*/]\ *pen*]]\
        [**+p**\ [*pen*]][**+r**\ [*radius*]][**+s**\ [[*dx*/*dy*/][*shade*]]].
        Without further arguments, draws a rectangular border around the legend
        using :gmt-term:`MAP_FRAME_PEN`. By default, uses
        **+g**\ white\ **+p**\ 1p which draws a box around the legend using a
        1p black pen and adds a white background.
    {V}
    {XY}
    {c}
    {p}
    {t}
    """
    kwargs = self._preprocess(**kwargs)  # pylint: disable=protected-access

    if "D" not in kwargs:
        kwargs["D"] = position

        if "F" not in kwargs:
            kwargs["F"] = box

    with Session() as lib:
        if spec is None:
            specfile = ""
        elif data_kind(spec) == "file":
            specfile = spec
        else:
            raise GMTInvalidInput("Unrecognized data type: {}".format(type(spec)))
        arg_str = " ".join([specfile, build_arg_string(kwargs)])
        lib.call_module("legend", arg_str)
Exemple #5
0
 def registration(self, value):
     if value in (0, 1):
         self._registration = value
     else:
         raise GMTInvalidInput(
             f"Invalid grid registration value: {value}, should be a boolean of "
             "either 0 for Gridline registration or 1 for Pixel registration"
         )
Exemple #6
0
    def show(self, dpi=300, width=500, method="static"):
        """
        Display a preview of the figure.

        Inserts the preview in the Jupyter notebook output. You will need to
        have IPython installed for this to work. You should have it if you are
        using the notebook.

        If ``method='external'``, makes PDF preview instead and opens it in the
        default viewer for your operating system (falls back to the default web
        browser). Note that the external viewer does not block the current
        process, so this won't work in a script.

        Parameters
        ----------
        dpi : int
            The image resolution (dots per inch).
        width : int
            Width of the figure shown in the notebook in pixels. Ignored if
            ``method='external'``.
        method : str
            How the figure will be displayed. Options are (1) ``'static'``: PNG
            preview (default); (2) ``'external'``: PDF preview in an external
            program.

        Returns
        -------
        img : IPython.display.Image
            Only if ``method != 'external'``.
        """
        # Module level variable to know which figures had their show method
        # called. Needed for the sphinx-gallery scraper.
        SHOWED_FIGURES.append(self)

        if method not in ["static", "external"]:
            raise GMTInvalidInput("Invalid show method '{}'.".format(method))
        if method == "external":
            pdf = self._preview(fmt="pdf",
                                dpi=dpi,
                                anti_alias=False,
                                as_bytes=False)
            launch_external_viewer(pdf)
            img = None
        elif method == "static":
            png = self._preview(fmt="png",
                                dpi=dpi,
                                anti_alias=True,
                                as_bytes=True,
                                transparent=True)
            if Image is None:
                raise GMTError(" ".join([
                    "Cannot find IPython.",
                    "Make sure you have it installed",
                    "or use 'method=\"external\"' to open in an external viewer.",
                ]))
            img = Image(data=png, width=width)
        return img
Exemple #7
0
def grdfill(grid, **kwargs):
    r"""
    Fill blank areas from a grid file.

    Read a grid that presumably has unfilled holes that the user
    wants to fill in some fashion. Holes are identified by NaN values but
    this criteria can be changed. There are several different algorithms that
    can be used to replace the hole values.

    Full option list at :gmt-docs:`grdfill.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.
    mode : str
        Specify the hole-filling algorithm to use.  Choose from **c** for
        constant fill and append the constant value, **n** for nearest
        neighbor (and optionally append a search radius in
        pixels [default radius is :math:`r^2 = \sqrt{{ X^2 + Y^2 }}`,
        where (*X,Y*) are the node dimensions of the grid]), or
        **s** for bicubic spline (optionally append a *tension*
        parameter [Default is no tension]).

    {R}
    {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 "A" not in kwargs and "L" not in kwargs:
        raise GMTInvalidInput(
            "At least parameter 'mode' or 'L' 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("grdfill", arg_str)

        return load_dataarray(outgrid) if outgrid == tmpfile.name else None
Exemple #8
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}
    {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 "I" not in kwargs.keys() or "R" not in kwargs.keys():
        raise GMTInvalidInput("Both 'region' and 'spacing' must be specified.")

    with GMTTempFile(suffix=".nc") as tmpfile:
        with Session() as lib:
            if "G" not in kwargs.keys(
            ):  # 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)

        if outgrid == tmpfile.name:  # if user did not set outgrid, return DataArray
            with xr.open_dataarray(outgrid) as dataarray:
                result = dataarray.load()
                _ = result.gmt  # load GMTDataArray accessor information
        else:
            result = None  # if user sets an outgrid, return None

        return result
Exemple #9
0
 def new_module(*args, **kwargs):
     """
     New module that parses and replaces the registered aliases.
     """
     for arg, alias in aliases.items():
         if alias in kwargs and arg in kwargs:
             raise GMTInvalidInput(
                 f"Arguments in short-form ({arg}) and long-form ({alias}) can't coexist"
             )
         if alias in kwargs:
             kwargs[arg] = kwargs.pop(alias)
     return module_func(*args, **kwargs)
Exemple #10
0
def basemap(self, **kwargs):
    r"""
    Plot base maps and frames for the figure.

    Creates a basic or fancy basemap with axes, fill, and titles. Several
    map projections are available, and the user may specify separate
    tick-mark intervals for boundary annotation, ticking, and [optionally]
    gridlines. A simple map scale or directional rose may also be plotted.

    At least one of the parameters ``frame``, ``map_scale``, ``rose`` or
    ``compass`` must be specified.

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

    {aliases}

    Parameters
    ----------
    {J}
    zscale/zsize : float or str
        Set z-axis scaling or z-axis size.
    {R}
        *Required if this is the first plot command.*
    {B}
    map_scale : str
        [**g**\|\ **j**\|\ **J**\|\ **n**\|\ **x**]\ *refpoint*\
        **+w**\ *length*.
        Draws a simple map scale centered on the reference point specified.
    rose : str
        Draws a map directional rose on the map at the location defined by
        the reference and anchor points.
    compass : str
        Draws a map magnetic rose on the map at the location defined by the
        reference and anchor points
    {U}
    {V}
    {XY}
    {c}
    {f}
    {p}
    {t}
    """
    kwargs = self._preprocess(**kwargs)  # pylint: disable=protected-access
    if not args_in_kwargs(args=["B", "L", "Td", "Tm", "c"], kwargs=kwargs):
        raise GMTInvalidInput(
            "At least one of frame, map_scale, compass, rose, or panel must be specified."
        )
    with Session() as lib:
        lib.call_module("basemap", build_arg_string(kwargs))
Exemple #11
0
 def new_module(*args, **kwargs):
     """
     New module instance that converts old parameters to new parameters.
     """
     if oldname in kwargs:
         if newname in kwargs:
             raise GMTInvalidInput(
                 f"Can't provide both '{newname}' and '{oldname}'.")
         msg = (
             f"The '{oldname}' parameter has been deprecated since {deprecate_version}"
             f" and will be removed in {remove_version}."
             f" Please use '{newname}' instead.")
         warnings.warn(msg, category=FutureWarning, stacklevel=2)
         kwargs[newname] = kwargs.pop(oldname)
     return module_func(*args, **kwargs)
Exemple #12
0
 def new_module(*args, **kwargs):
     """
     New module that parses and replaces the registered aliases.
     """
     for short_param, long_alias in aliases.items():
         if long_alias in kwargs and short_param in kwargs:
             raise GMTInvalidInput(
                 f"Parameters in short-form ({short_param}) and "
                 f"long-form ({long_alias}) can't coexist.")
         if long_alias in kwargs:
             kwargs[short_param] = kwargs.pop(long_alias)
         elif short_param in kwargs:
             msg = (
                 f"Short-form parameter ({short_param}) is not recommended. "
                 f"Use long-form parameter '{long_alias}' instead.")
             warnings.warn(msg, category=SyntaxWarning, stacklevel=2)
     return module_func(*args, **kwargs)
Exemple #13
0
def set_display(method=None):
    """
    Set the display method.

    Parameters
    ----------
    method : str or None
        The method to display an image. Choose from:

        - **external**: PDF preview in an external program [default]
        - **notebook**: PNG preview [default in Jupyter notebooks]
        - **none**: Disable image preview
    """
    if method in ["notebook", "external", "none"]:
        SHOW_CONFIG["method"] = method
    elif method is not None:
        raise GMTInvalidInput(
            (f"Invalid display mode '{method}', "
             "should be either 'notebook', 'external' or 'none'."))
Exemple #14
0
def load_sample_data(name):
    """
    Load an example dataset from the GMT server.

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

    Parameters
    ----------
    name : str
        Name of the dataset to load.

    Returns
    -------
    :class:`pandas.DataFrame` or :class:`xarray.DataArray`
        Sample dataset loaded as a pandas.DataFrame for tabular data or
        xarray.DataArray for raster data.

    See Also
    --------
    list_sample_data : Report datasets available for tests and documentation
        examples.
    """
    names = list_sample_data()
    if name not in names:
        raise GMTInvalidInput(f"Invalid dataset name '{name}'.")

    load_func = {
        "bathymetry": load_sample_bathymetry,
        "fractures": load_fractures_compilation,
        "hotspots": load_hotspots,
        "japan_quakes": load_japan_quakes,
        "mars_shape": load_mars_shape,
        "ocean_ridge_points": load_ocean_ridge_points,
        "usgs_quakes": load_usgs_quakes,
    }

    data = load_func[name](suppress_warning=True)

    return data
Exemple #15
0
def grdinfo(grid, **kwargs):
    """
    Get information about a grid.

    Can read the grid from a file or given as an xarray.DataArray grid.

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

    Parameters
    ----------
    grid : str or xarray.DataArray
        The file name of the input grid or the grid loaded as a DataArray.

    {V}

    Returns
    -------
    info : str
        A string with information about the grid.

    """
    kind = data_kind(grid, None, None)
    with GMTTempFile() as outfile:
        with Session() as lib:
            if kind == "file":
                file_context = dummy_context(grid)
            elif kind == "grid":
                file_context = lib.virtualfile_from_grid(grid)
            else:
                raise GMTInvalidInput("Unrecognized data type: {}".format(
                    type(grid)))
            with file_context as infile:
                arg_str = " ".join(
                    [infile,
                     build_arg_string(kwargs), "->" + outfile.name])
                lib.call_module("grdinfo", arg_str)
        result = outfile.read()
    return result
Exemple #16
0
def contour(self, x=None, y=None, z=None, data=None, **kwargs):
    r"""
    Contour table data by direct triangulation.

    Takes a matrix, (x,y,z) pairs, or a file name as input and plots lines,
    polygons, or symbols at those locations on a map.

    Must provide either ``data`` or ``x``/``y``/``z``.

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

    {aliases}

    Parameters
    ----------
    x/y/z : 1d arrays
        Arrays of x and y coordinates and values z of the data points.
    data : str or 2d array
        Either a data file name or a 2d numpy array with the tabular data.
    {J}
    {R}
    annotation : str or int
        Specify or disable annotated contour levels, modifies annotated
        contours specified in ``interval``.

        - Specify a fixed annotation interval *annot_int* or a
          single annotation level +\ *annot_int*.
    {B}
    levels : str or int
        Specify the contour lines to generate.

        - The filename of a CPT file where the color boundaries will
          be used as contour levels.
        - The filename of a 2 (or 3) column file containing the contour
          levels (col 1), (**C**)ontour or (**A**)nnotate (col 2), and optional
          angle (col 3)
        - A fixed contour interval *cont_int* or a single contour with
          +\ *cont_int*
    D : str
        Dump contour coordinates.
    E : str
        Network information.
    label_placement : str
        Placement of labels.
    I : bool
        Color the triangles using CPT.
    triangular_mesh_pen : str
        Pen to draw the underlying triangulation [Default is none].
    no_clip : bool
        Do NOT clip contours or image at the boundaries [Default will clip
        to fit inside region].
    Q : float or str
        [*cut*][**+z**].
        Do not draw contours with less than cut number of points.
    skip : bool or str
        [**p**\|\ **t**].
        Skip input points outside region.
    {W}
    label : str
        Add a legend entry for the contour being plotted. Normally, the
        annotated contour is selected for the legend. You can select the
        regular contour instead, or both of them, by considering the label
        to be of the format [*annotcontlabel*][/*contlabel*]. If either
        label contains a slash (/) character then use ``|`` as the
        separator for the two labels instead.
    {V}
    {XY}
    {c}
    {p}
    {t}
    """
    kwargs = self._preprocess(**kwargs)  # pylint: disable=protected-access

    kind = data_kind(data, x, y, z)
    if kind == "vectors" and z is None:
        raise GMTInvalidInput("Must provided both x, y, and z.")

    with Session() as lib:
        # Choose how data will be passed in to the module
        if kind == "file":
            file_context = dummy_context(data)
        elif kind == "matrix":
            file_context = lib.virtualfile_from_matrix(data)
        elif kind == "vectors":
            file_context = lib.virtualfile_from_vectors(x, y, z)

        with file_context as fname:
            arg_str = " ".join([fname, build_arg_string(kwargs)])
            lib.call_module("contour", arg_str)
Exemple #17
0
def kwargs_to_strings(**conversions):
    """
    Decorator to convert given keyword arguments to strings.

    The strings are what GMT expects from command line arguments.

    Boolean arguments and None are not converted and will be processed in the
    ``build_arg_string`` function.

    You can also specify other conversions to specific arguments.

    Conversions available:

    * 'sequence': transforms a sequence (list, tuple) into a ``'/'`` separated
      string
    * 'sequence_comma': transforms a sequence into a ``','`` separated string
    * 'sequence_plus': transforms a sequence into a ``'+'`` separated string
    * 'sequence_space': transforms a sequence into a ``' '`` separated string

    Parameters
    ----------
    conversions : keyword arguments
        Keyword arguments specifying other kinds of conversions that should be
        performed. The keyword is the name of the argument and the value is the
        conversion type (see list above).

    Examples
    --------

    >>> @kwargs_to_strings(
    ...     R="sequence", i="sequence_comma", files="sequence_space"
    ... )
    ... def module(*args, **kwargs):
    ...     "A module that prints the arguments it received"
    ...     print("{", end="")
    ...     print(
    ...         ", ".join(
    ...             "'{}': {}".format(k, repr(kwargs[k]))
    ...             for k in sorted(kwargs)
    ...         ),
    ...         end="",
    ...     )
    ...     print("}")
    ...     if args:
    ...         print("args:", " ".join("{}".format(x) for x in args))
    >>> module(R=[1, 2, 3, 4])
    {'R': '1/2/3/4'}
    >>> # It's already a string, do nothing
    >>> module(R="5/6/7/8")
    {'R': '5/6/7/8'}
    >>> module(P=True)
    {'P': True}
    >>> module(P=False)
    {'P': False}
    >>> module(P=None)
    {'P': None}
    >>> module(i=[1, 2])
    {'i': '1,2'}
    >>> module(files=["data1.txt", "data2.txt"])
    {'files': 'data1.txt data2.txt'}
    >>> # Other non-boolean arguments are passed along as they are
    >>> module(123, bla=(1, 2, 3), foo=True, A=False, i=(5, 6))
    {'A': False, 'bla': (1, 2, 3), 'foo': True, 'i': '5,6'}
    args: 123
    >>> import datetime
    >>> module(
    ...     R=[
    ...         np.datetime64("2010-01-01T16:00:00"),
    ...         datetime.datetime(2020, 1, 1, 12, 23, 45),
    ...     ]
    ... )
    {'R': '2010-01-01T16:00:00/2020-01-01T12:23:45.000000'}
    >>> import pandas as pd
    >>> import xarray as xr
    >>> module(
    ...     R=[
    ...         xr.DataArray(data=np.datetime64("2005-01-01T08:00:00")),
    ...         pd.Timestamp("2015-01-01T12:00:00.123456789"),
    ...     ]
    ... )
    {'R': '2005-01-01T08:00:00.000000000/2015-01-01T12:00:00.123456'}
    """
    valid_conversions = [
        "sequence",
        "sequence_comma",
        "sequence_plus",
        "sequence_space",
    ]

    for arg, fmt in conversions.items():
        if fmt not in valid_conversions:
            raise GMTInvalidInput(
                "Invalid conversion type '{}' for argument '{}'.".format(
                    fmt, arg))

    separators = {
        "sequence": "/",
        "sequence_comma": ",",
        "sequence_plus": "+",
        "sequence_space": " ",
    }

    # Make the actual decorator function
    def converter(module_func):
        """
        The decorator that creates our new function with the conversions.
        """
        @functools.wraps(module_func)
        def new_module(*args, **kwargs):
            """
            New module instance that converts the arguments first.
            """
            for arg, fmt in conversions.items():
                if arg in kwargs:
                    value = kwargs[arg]
                    issequence = fmt in separators
                    if issequence and is_nonstr_iter(value):
                        for index, item in enumerate(value):
                            try:
                                # check if there is a space " " when converting
                                # a pandas.Timestamp/xr.DataArray to a string.
                                # If so, use np.datetime_as_string instead.
                                assert " " not in str(item)
                            except AssertionError:
                                # convert datetime-like item to ISO 8601
                                # string format like YYYY-MM-DDThh:mm:ss.ffffff
                                value[index] = np.datetime_as_string(
                                    np.asarray(item, dtype=np.datetime64))
                        kwargs[arg] = separators[fmt].join(f"{item}"
                                                           for item in value)
            # Execute the original function and return its output
            return module_func(*args, **kwargs)

        return new_module

    return converter
Exemple #18
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.

    spacing : str
        *xinc*\[\ *unit*\][**+e**\|\ **n**]
        [/*yinc*\ [*unit*][**+e**\|\ **n**]].
        *xinc* [and optionally *yinc*] is the grid spacing.
    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}

    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``)

    Examples
    --------
    >>> 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")
    """
    kind = data_kind(grid)

    with GMTTempFile(suffix=".nc") as tmpfile:
        with Session() as lib:
            if kind == "file":
                file_context = dummy_context(grid)
            elif kind == "grid":
                file_context = lib.virtualfile_from_grid(grid)
            else:
                raise GMTInvalidInput("Unrecognized data type: {}".format(
                    type(grid)))

            with file_context as infile:
                if "G" not in kwargs.keys(
                ):  # 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)

        if outgrid == tmpfile.name:  # if user did not set outgrid, return DataArray
            with xr.open_dataarray(outgrid) as dataarray:
                result = dataarray.load()
                _ = result.gmt  # load GMTDataArray accessor information
        else:
            result = None  # if user sets an outgrid, return None

        return result
Exemple #19
0
def grdtrack(points, grid, newcolname=None, outfile=None, **kwargs):
    r"""
    Sample grids at specified (x,y) locations.

    Reads one or more grid files and a table (from file or an array input; but
    see ``profile`` for exception) with (x,y) [or (lon,lat)] positions in the
    first two columns (more columns may be present). It interpolates the
    grid(s) at the positions in the table and writes out the table with the
    interpolated values added as (one or more) new columns. Alternatively
    (``crossprofile``), the input is considered to be line-segments and we
    create orthogonal cross-profiles at each data point or with an equidistant
    separation and sample the grid(s) along these profiles. A bicubic
    [Default], bilinear, B-spline or nearest-neighbor interpolation is used,
    requiring boundary conditions at the limits of the region (see
    ``interpolation``; Default uses "natural" conditions (second partial
    derivative normal to edge is zero) unless the grid is automatically
    recognized as periodic.)

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

    {aliases}

    Parameters
    ----------
    points : str or {table-like}
        Pass in either a file name to an ASCII data table, a 2D
        {table-classes}.

    grid : xarray.DataArray or str
        Gridded array from which to sample values from, or a filename (netcdf
        format).

    newcolname : str
        Required if ``points`` is a :class:`pandas.DataFrame`. The name for the
        new column in the track :class:`pandas.DataFrame` table where the
        sampled values will be placed.

    outfile : str
        The file name for the output ASCII file.

    resample : str
        **f**\|\ **p**\|\ **m**\|\ **r**\|\ **R**\ [**+l**]
        For track resampling (if ``crossprofile`` or ``profile`` are set) we
        can select how this is to be performed. Append **f** to keep original
        points, but add intermediate points if needed [Default], **m** as
        **f**, but first follow meridian (along y) then parallel (along x),
        **p** as **f**, but first follow parallel (along y) then meridian
        (along x), **r** to resample at equidistant locations; input points are
        not necessarily included in the output, and **R** as **r**, but adjust
        given spacing to fit the track length exactly. Finally, append
        **+l** if geographic distances should be measured along rhumb lines
        (loxodromes) instead of great circles. Ignored unless ``crossprofile``
        is used.
    crossprofile : str
        *length*/\ *ds*\ [*/spacing*][**+a**\|\ **+v**][**l**\|\ **r**].
        Use input line segments to create an equidistant and (optionally)
        equally-spaced set of crossing profiles along which we sample the
        grid(s) [Default simply samples the grid(s) at the input locations].
        Specify two length scales that control how the sampling is done:
        *length* sets the full length of each cross-profile, while *ds* is
        the sampling spacing along each cross-profile. Optionally, append
        **/**\ *spacing* for an equidistant spacing between cross-profiles
        [Default erects cross-profiles at the input coordinates]; see
        ``resample`` for how resampling the input track is controlled. By
        default, all cross-profiles have the same direction (left to right
        as we look in the direction of the input line segment). Append **+a**
        to alternate the direction of cross-profiles, or **v** to enforce
        either a "west-to-east" or "south-to-north" view. By default the entire
        profiles are output. Choose to only output the left or right halves
        of the profiles by appending **+l** or **+r**, respectively.  Append
        suitable units to *length*; it sets the unit used for *ds* [and
        *spacing*] (See :gmt-docs:`Units <grdtrack.html#units>`). The default
        unit for geographic grids is meter while Cartesian grids implies the
        user unit.  The output columns will be *lon*, *lat*, *dist*, *azimuth*,
        *z1*, *z2*, ..., *zn* (The *zi* are the sampled values for each of the
        *n* grids).
    dfile : str
        In concert with ``crossprofile`` we can save the (possibly resampled)
        original lines to *dfile* [Default only saves the cross-profiles]. The
        columns will be *lon*, *lat*, *dist*, *azimuth*, *z1*, *z2*, ...
        (sampled value for each grid).
    profile : str
        *line*\ [,\ *line*,...][**+a**\ *az*][**+c**][**+d**][**+g**]\
        [**+i**\ *inc*][**+l**\ *length*][**+n**\ *np*][**+o**\ *az*]\
        [**+r**\ *radius*].
        Instead of reading input track coordinates, specify profiles via
        coordinates and modifiers. The format of each *line* is
        *start*/*stop*, where *start* or *stop* are either *lon*/*lat* (*x*/*y*
        for Cartesian data) or a 2-character XY key that uses the
        :gmt-docs:`text <text.html>`-style justification format to specify
        a point on the map as [LCR][BMT]. Each line will be a separate segment
        unless **+c** is used which will connect segments with shared joints
        into a single segment. In addition to line coordinates, you can use Z-,
        Z+ to mean the global minimum and maximum locations in the grid (only
        available if a single grid is given via **outfile**). You may append
        **+i**\ *inc* to set the sampling interval; if not given then we
        default to half the minimum grid interval. For a *line* along parallels
        or meridians you can add **+g** to report degrees of longitude or
        latitude instead of great circle distances starting at zero. Instead of
        two coordinates you can specify an origin and one of **+a**, **+o**, or
        **+r**. The **+a** sets the azimuth of a profile of given length
        starting at the given origin, while **+o** centers the profile on the
        origin; both require **+l**. For circular sampling specify **+r** to
        define a circle of given radius centered on the origin; this option
        requires either **+n** or **+i**.  The **+n**\ *np* modifier sets the
        desired number of points, while **+l**\ *length* gives the total length
        of the profile. Append **+d** to output the along-track distances after
        the coordinates. **Note**: No track file will be read. Also note that
        only one distance unit can be chosen. Giving different units will
        result in an error. If no units are specified we default to great
        circle distances in km (if geographic). If working with geographic data
        you can use ``distcalc`` to control distance calculation mode [Default
        is Great Circle]. **Note**: If ``crossprofile`` is set and *spacing* is
        given then that sampling scheme overrules any modifier set in
        ``profile``.
    critical : str
        [**+b**][**+n**][**+r**][**+z**\ *z0*].
        Find critical points along each cross-profile as a function of
        along-track distance. Requires ``crossprofile`` and a single input grid
        (*z*). We examine each cross-profile generated and report (*dist*,
        *lonc*, *latc*, *distc*, *azimuthc*, *zc*) at the center peak of
        maximum *z* value, (*lonl*, *latl*, *distl*) and (*lonr*, *latr*,
        *distr*) at the first and last non-NaN point whose *z*-value exceeds
        *z0*, respectively, and the *width* based on the two extreme points
        found. Here, *dist* is the distance along the original input
        ``points`` and the other 12 output columns are a function of that
        distance.  When searching for the center peak and the extreme first and
        last values that exceed the threshold we assume the profile is positive
        up. If we instead are looking for a trough then you must use **+n** to
        temporarily flip the profile to positive. The threshold *z0* value is
        always given as >= 0; use **+z** to change it [Default is 0].
        Alternatively, use **+b** to determine the balance point and standard
        deviation of the profile; this is the weighted mean and weighted
        standard deviation of the distances, with *z* acting as the weight.
        Finally, use **+r** to obtain the weighted rms about the cross-track
        center (*distc* == 0). **Note**: We round the exact results to the
        nearest distance nodes along the cross-profiles. We write 13 output
        columns per track: *dist, lonc, latc, distc, azimuthc, zc, lonl, latl,
        distl, lonr, latr, distr, width*.
    {R}
    no_skip : bool
        Do *not* skip points that fall outside the domain of the grid(s)
        [Default only output points within grid domain].
    stack : str or list
        *method*/*modifiers*.
        In conjunction with ``crossprofile``, compute a single stacked profile
        from all profiles across each segment. Choose how stacking should be
        computed [Default method is **a**]:

        - **a** = mean (average)
        - **m** = median
        - **p** = mode (maximum likelihood)
        - **l** = lower
        - **L** = lower but only consider positive values
        - **u** = upper
        - **U** = upper but only consider negative values.

        The *modifiers* control the output; choose one or more among these
        choices:

        - **+a** : Append stacked values to all cross-profiles.
        - **+d** : Append stack deviations to all cross-profiles.
        - **+r** : Append data residuals (data - stack) to all cross-profiles.
        - **+s**\ [*file*] : Save stacked profile to *file* [Default filename
          is grdtrack_stacked_profile.txt].
        - **+c**\ *fact* : Compute envelope on stacked profile as
          ±\ *fact* \*\ *deviation* [Default fact value is 2].

        Notes:

        1. Deviations depend on *method* and are st.dev (**a**), L1 scale,
           i.e., 1.4826 \* median absolute deviation (MAD) (for **m** and
           **p**), or half-range (upper-lower)/2.
        2. The stacked profile file contains a leading column plus groups of
           4-6 columns, with one group for each sampled grid. The leading
           column holds cross distance, while the first four columns in a group
           hold stacked value, deviation, min value, and max value,
           respectively. If *method* is one of **a**\|\ **m**\|\ **p** then we
           also write the lower and upper confidence bounds (see **+c**). When
           one or more of **+a**, **+d**, and **+r** are used then we also
           append the stacking results to the end of each row, for all
           cross-profiles. The order is always stacked value (**+a**), followed
           by deviations (**+d**) and finally residuals (**+r**). When more
           than one grid is sampled this sequence of 1-3 columns is repeated
           for each grid.
    radius : bool or int or float or str
        [*radius*][**+e**\|\ **p**].
        To be used with normal grid sampling, and limited to a single, non-IMG
        grid. If the nearest node to the input point is NaN, search outwards
        until we find the nearest non-NaN node and report that value instead.
        Optionally specify a search radius which limits the consideration to
        points within this distance from the input point. To report the
        location of the nearest node and its distance from the input point,
        append **+e**. The default unit for geographic grid distances is
        spherical degrees. Use *radius* to change the unit and give *radius* =
        0 if you do not want to limit the radius search. To instead replace the
        input point with the coordinates of the nearest node, append **+p**.
    {V}
    z_only : bool
        Only write out the sampled z-values [Default writes all columns].
    {a}
    {b}
    {d}
    {e}
    {f}
    {g}
    {h}
    {i}
    {j}
    {n}
    {o}
    {s}
    {w}

    Returns
    -------
    track: pandas.DataFrame or None
        Return type depends on whether the ``outfile`` parameter is set:

        - :class:`pandas.DataFrame` table with (x, y, ..., newcolname) if
          ``outfile`` is not set
        - None if ``outfile`` is set (track output will be stored in file set
          by ``outfile``)

    Example
    -------
    >>> import pygmt
    >>> # Load a grid of @earth_relief_30m data, with an x-range of -118 to
    >>> # -107, and a y-range of -49 to -42
    >>> grid = pygmt.datasets.load_earth_relief(
    ...     resolution="30m", region=[-118, -107, -49, -42]
    ... )
    >>> # Load a pandas dataframe with ocean ridge points
    >>> points = pygmt.datasets.load_sample_data(name="ocean_ridge_points")
    >>> # Create a pandas dataframe from an input grid and set of points
    >>> # The output dataframe adds a column named "bathymetry"
    >>> output_dataframe = pygmt.grdtrack(
    ...     points=points, grid=grid, newcolname="bathymetry"
    ... )
    """
    if hasattr(points, "columns") and newcolname is None:
        raise GMTInvalidInput("Please pass in a str to 'newcolname'")

    with GMTTempFile(suffix=".csv") 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=points)
            # Store the xarray.DataArray grid in virtualfile
            grid_context = lib.virtualfile_from_data(check_kind="raster",
                                                     data=grid)

            # Run grdtrack on the temporary (csv) points table
            # and (netcdf) grid virtualfile
            with table_context as csvfile:
                with grid_context as grdfile:
                    kwargs.update({"G": grdfile})
                    if outfile is None:  # Output to tmpfile if outfile is not set
                        outfile = tmpfile.name
                    lib.call_module(
                        module="grdtrack",
                        args=build_arg_string(kwargs,
                                              infile=csvfile,
                                              outfile=outfile),
                    )

        # Read temporary csv output to a pandas table
        if outfile == tmpfile.name:  # if user did not set outfile, return pd.DataFrame
            try:
                column_names = points.columns.to_list() + [newcolname]
                result = pd.read_csv(tmpfile.name,
                                     sep="\t",
                                     names=column_names)
            except AttributeError:  # 'str' object has no attribute 'columns'
                result = pd.read_csv(tmpfile.name,
                                     sep="\t",
                                     header=None,
                                     comment=">")
        elif outfile != tmpfile.name:  # return None if outfile set, output in outfile
            result = None

    return result
Exemple #20
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-docs:`datasets/remote-data.html#global-earth-seafloor-crustal-age-grids`
    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).

    Notes
    -----
    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
Exemple #21
0
def grdview(self, grid, **kwargs):
    r"""
    Create 3-D perspective image or surface mesh from a grid.

    Reads a 2-D grid file and produces a 3-D perspective plot by drawing a
    mesh, painting a colored/gray-shaded surface made up of polygons, or by
    scanline conversion of these polygons to a raster image. Options
    include draping a data set on top of a surface, plotting of contours on
    top of the surface, and apply artificial illumination based on
    intensities provided in a separate grid file.

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

    {aliases}

    Parameters
    ----------
    grid : str or xarray.DataArray
        The file name of the input relief grid or the grid loaded as a
        DataArray.
    region : str or list
        *xmin/xmax/ymin/ymax*\ [**+r**][**+u**\ *unit*].
        Specify the :doc:`region </tutorials/basics/regions>` of interest.
        When used with ``perspective``, optionally append */zmin/zmax* to
        indicate the range to use for the 3-D axes [Default is the region in
        the input grid].
    {J}
    zscale/zsize : float or str
        Set z-axis scaling or z-axis size.
    {B}
    cmap : str
        The name of the color palette table to use.
    drapegrid : str or xarray.DataArray
        The file name or a DataArray of the image grid to be draped on top
        of the relief provided by grid. [Default determines colors from
        grid]. Note that ``zscale`` and ``plane`` always refers to the grid.
        The drapegrid only provides the information pertaining to colors, which
        (if drapegrid is a grid) will be looked-up via the CPT (see ``cmap``).
    plane : float or str
        *level*\ [**+g**\ *fill*].
        Draws a plane at this z-level. If the optional color is provided
        via the **+g** modifier, and the projection is not oblique, the frontal
        facade between the plane and the data perimeter is colored.
    surftype : str
        Specifies cover type of the grid.
        Select one of following settings:

        - **m** - mesh plot [Default].
        - **mx** or **my** - waterfall plots (row or column profiles).
        - **s** - surface plot, and optionally append **m** to have mesh lines
          drawn on top of the surface.
        - **i** - image plot.
        - **c** - Same as **i** but will make nodes with z = NaN transparent.

        For any of these choices, you may force a monochrome image by
        appending the modifier **+m**.
    contourpen : str
        Draw contour lines on top of surface or mesh (not image). Append
        pen attributes used for the contours.
    meshpen : str
        Sets the pen attributes used for the mesh. You must also select
        ``surftype`` of **m** or **sm** for meshlines to be drawn.
    facadepen :str
        Sets the pen attributes used for the facade. You must also select
        ``plane`` for the facade outline to be drawn.
    shading : str
        Provide the name of a grid file with intensities in the (-1,+1)
        range, or a constant intensity to apply everywhere (affects the
        ambient light). Alternatively, derive an intensity grid from the
        input data grid reliefgrid via a call to ``grdgradient``; append
        **+a**\ *azimuth*, **+n**\ *args*, and **+m**\ *ambient* to specify
        azimuth, intensity, and ambient arguments for that method, or just give
        **+d** to select the default arguments
        [Default is **+a**\ -45\ **+nt**\ 1\ **+m**\ 0].
    {V}
    {XY}
    {c}
    {f}
    {n}
    {p}
    {t}
    """
    kwargs = self._preprocess(**kwargs)  # pylint: disable=protected-access
    with Session() as lib:
        file_context = lib.virtualfile_from_data(check_kind="raster",
                                                 data=grid)

        with contextlib.ExitStack() as stack:
            if kwargs.get("G") is not None:
                # deal with kwargs["G"] if drapegrid is xr.DataArray
                drapegrid = kwargs["G"]
                if data_kind(drapegrid) in ("file", "grid"):
                    if data_kind(drapegrid) == "grid":
                        drape_context = lib.virtualfile_from_grid(drapegrid)
                        kwargs["G"] = stack.enter_context(drape_context)
                else:
                    raise GMTInvalidInput(
                        f"Unrecognized data type for drapegrid: {type(drapegrid)}"
                    )
            fname = stack.enter_context(file_context)
            lib.call_module(module="grdview",
                            args=build_arg_string(kwargs, infile=fname))
Exemple #22
0
    def savefig(self,
                fname,
                transparent=False,
                crop=True,
                anti_alias=True,
                show=False,
                **kwargs):
        """
        Save the figure to a file.

        This method implements a matplotlib-like interface for
        :meth:`pygmt.Figure.psconvert`.

        Supported formats: PNG (``.png``), JPEG (``.jpg``), PDF (``.pdf``),
        BMP (``.bmp``), TIFF (``.tif``), EPS (``.eps``), and KML (``.kml``).
        The KML output generates a companion PNG file.

        You can pass in any keyword arguments that
        :meth:`pygmt.Figure.psconvert` accepts.

        Parameters
        ----------
        fname : str
            The desired figure file name, including the extension. See the list
            of supported formats and their extensions above.
        transparent : bool
            If True, will use a transparent background for the figure. Only
            valid for PNG format.
        crop : bool
            If True, will crop the figure canvas (page) to the plot area.
        anti_alias: bool
            If True, will use anti aliasing when creating raster images (PNG,
            JPG, TIFF). More specifically, it passes arguments ``t2``
            and ``g2`` to the ``anti_aliasing`` parameter of
            :meth:`pygmt.Figure.psconvert`. Ignored if creating vector
            graphics.
        show: bool
            If True, will open the figure in an external viewer.
        dpi : int
            Set raster resolution in dpi. Default is 720 for PDF, 300 for
            others.
        """
        # All supported formats
        fmts = dict(png="g",
                    pdf="f",
                    jpg="j",
                    bmp="b",
                    eps="e",
                    tif="t",
                    kml="g")

        prefix, ext = os.path.splitext(fname)
        ext = ext[1:]  # Remove the .
        if ext not in fmts:
            raise GMTInvalidInput("Unknown extension '.{}'".format(ext))
        fmt = fmts[ext]
        if transparent:
            if fmt != "g":
                raise GMTInvalidInput(
                    "Transparency unavailable for '{}', only for png.".format(
                        ext))
            fmt = fmt.upper()
        if anti_alias:
            kwargs["Qt"] = 2
            kwargs["Qg"] = 2
        if ext == "kml":
            kwargs["W"] = "+k"

        self.psconvert(prefix=prefix, fmt=fmt, crop=crop, **kwargs)
        if show:
            launch_external_viewer(fname)
Exemple #23
0
def blockmedian(table, outfile=None, **kwargs):
    r"""
    Block average (x,y,z) data tables by median estimation.

    Reads arbitrarily located (x,y,z) triples [or optionally weighted
    quadruples (x,y,z,w)] from a table and writes to the output a median
    position and value for every non-empty block in a grid region defined by
    the region and spacing arguments.

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

    {aliases}

    Parameters
    ----------
    table : pandas.DataFrame or str
        Either a pandas dataframe with (x, y, z) or (longitude, latitude,
        elevation) values in the first three columns, or a file name to an
        ASCII data table.

    spacing : str
        *xinc*\[\ *unit*\][**+e**\|\ **n**]
        [/*yinc*\ [*unit*][**+e**\|\ **n**]].
        *xinc* [and optionally *yinc*] is the grid spacing.

    region : str or list
        *xmin/xmax/ymin/ymax*\[\ **+r**\][**+u**\ *unit*].
        Specify the region of interest.

    outfile : str
        Required if ``table`` is a file. The file name for the output ASCII
        file.

    {V}

    Returns
    -------
    output : pandas.DataFrame or None
        Return type depends on whether the ``outfile`` parameter is set:

        - :class:`pandas.DataFrame` table with (x, y, z) columns if ``outfile``
          is not set
        - None if ``outfile`` is set (filtered output will be stored in file
          set by ``outfile``)
    """
    kind = data_kind(table)
    with GMTTempFile(suffix=".csv") as tmpfile:
        with Session() as lib:
            if kind == "matrix":
                if not hasattr(table, "values"):
                    raise GMTInvalidInput(
                        f"Unrecognized data type: {type(table)}")
                file_context = lib.virtualfile_from_matrix(table.values)
            elif kind == "file":
                if outfile is None:
                    raise GMTInvalidInput("Please pass in a str to 'outfile'")
                file_context = dummy_context(table)
            else:
                raise GMTInvalidInput(f"Unrecognized data type: {type(table)}")

            with file_context as infile:
                if outfile is None:
                    outfile = tmpfile.name
                arg_str = " ".join(
                    [infile, build_arg_string(kwargs), "->" + outfile])
                lib.call_module(module="blockmedian", args=arg_str)

        # Read temporary csv output to a pandas table
        if outfile == tmpfile.name:  # if user did not set outfile, return pd.DataFrame
            result = pd.read_csv(tmpfile.name, sep="\t", names=table.columns)
        elif outfile != tmpfile.name:  # return None if outfile set, output in outfile
            result = None

    return result
Exemple #24
0
def plot3d(self,
           data=None,
           x=None,
           y=None,
           z=None,
           size=None,
           direction=None,
           **kwargs):
    r"""
    Plot lines, polygons, and symbols in 3-D.

    Takes a matrix, (x,y,z) triplets, or a file name as input and plots
    lines, polygons, or symbols at those locations in 3-D.

    Must provide either ``data`` or ``x``/``y``/``z``.

    If providing data through ``x/y/z``, ``color`` can be a 1d array
    that will be mapped to a colormap.

    If a symbol is selected and no symbol size given, then plot3d will
    interpret the fourth column of the input data as symbol size. Symbols
    whose size is <= 0 are skipped. If no symbols are specified then the
    symbol code (see ``style`` below) must be present as last column in the
    input. If ``style`` is not used, a line connecting the data points will
    be drawn instead. To explicitly close polygons, use ``close``. Select a
    fill with ``color``. If ``color`` is set, ``pen`` will control whether the
    polygon outline is drawn or not. If a symbol is selected, ``color`` and
    ``pen`` determines the fill and outline/no outline, respectively.

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

    {aliases}

    Parameters
    ----------
    data : str or {table-like}
        Either a data file name, a 2d {table-classes}.
        Optionally, use parameter ``incols`` to specify which columns are x, y,
        z, color, and size, respectively.
    x/y/z : float or 1d arrays
        The x, y, and z coordinates, or arrays of x, y and z coordinates of
        the data points
    size : 1d array
        The size of the data points in units specified in ``style``.
        Only valid if using ``x``/``y``/``z``.
    direction : list of two 1d arrays
        If plotting vectors (using ``style='V'`` or ``style='v'``), then
        should be a list of two 1d arrays with the vector directions. These
        can be angle and length, azimuth and length, or x and y components,
        depending on the style options chosen.
    {J}
    zscale/zsize : float or str
        Set z-axis scaling or z-axis size.
    {R}
    straight_line : bool or str
        [**m**\|\ **p**\|\ **x**\|\ **y**].
        By default, geographic line segments are drawn as great circle
        arcs. To draw them as straight lines, use ``straight_line``.
        Alternatively, add **m** to draw the line by first following a
        meridian, then a parallel. Or append **p** to start following a
        parallel, then a meridian. (This can be practical to draw a line
        along parallels, for example). For Cartesian data, points are
        simply connected, unless you append **x** or **y** to draw
        stair-case curves that whose first move is along *x* or *y*,
        respectively. **Note**: The ``straight_line`` parameter requires
        constant *z*-coordinates.
    {B}
    {CPT}
    offset : str
        *dx*/*dy*\ [/*dz*].
        Offset the plot symbol or line locations by the given amounts
        *dx*/*dy*\ [/*dz*] [Default is no offset].
    {G}
        *color* can be a 1d array, but it is only valid if using ``x``/``y``
        and ``cmap=True`` is also required.
    intensity : float or bool or 1d array
        Provide an *intensity* value (nominally in the -1 to +1 range) to
        modulate the fill color by simulating illumination. If using
        ``intensity=True``, we will instead read *intensity* from the first
        data column after the symbol parameters (if given). *intensity* can
        also be a 1d array to set varying intensity for symbols, but it is only
        valid for ``x``/``y``/``z``.

    close : str
        [**+b**\|\ **d**\|\ **D**][**+xl**\|\ **r**\|\ *x0*]\
        [**+yl**\|\ **r**\|\ *y0*][**+p**\ *pen*].
        Force closed polygons. Full documentation is at
        :gmt-docs:`plot3d.html#l`.
    no_clip : bool or str
        [**c**\|\ **r**].
        Do NOT clip symbols that fall outside map border [Default plots
        points whose coordinates are strictly inside the map border only].
        This parameter does not apply to lines and polygons which are always
        clipped to the map region. For periodic (360-longitude) maps we
        must plot all symbols twice in case they are clipped by the
        repeating boundary. ``no_clip=True`` will turn off clipping and not
        plot repeating symbols. Use ``no_clip="r"`` to turn off clipping
        but retain the plotting of such repeating symbols, or use
        ``no_clip="c"`` to retain clipping but turn off plotting of
        repeating symbols.
    no_sort : bool
        Turn off the automatic sorting of items based on their distance
        from the viewer. The default is to sort the items so that items in
        the foreground are plotted after items in the background.
    style : str
        Plot symbols. Full documentation is at :gmt-docs:`plot3d.html#s`.
    {U}
    {V}
    {W}
    {XY}
    zvalue : str
        *value*\|\ *file*.
        Instead of specifying a symbol or polygon fill and outline color
        via ``color`` and ``pen``, give both a *value* via **zvalue** and a
        color lookup table via ``cmap``.  Alternatively, give the name of a
        *file* with one z-value (read from the last column) for each
        polygon in the input data. To apply it to the fill color, use
        ``color='+z'``. To apply it to the pen color, append **+z** to
        ``pen``.
    {a}
    {b}
    {c}
    {d}
    {e}
    {f}
    {g}
    {h}
    {i}
    {l}
    {p}
    {t}
        *transparency* can also be a 1d array to set varying transparency
        for symbols, but this option is only valid if using x/y/z.
    {w}
    """
    # pylint: disable=too-many-locals
    kwargs = self._preprocess(**kwargs)  # pylint: disable=protected-access

    kind = data_kind(data, x, y, z)

    extra_arrays = []
    if kwargs.get("S") is not None and kwargs["S"][
            0] in "vV" and direction is not None:
        extra_arrays.extend(direction)
    elif (
            kwargs.get("S") is None and kind == "geojson"
            and data.geom_type.isin(["Point", "MultiPoint"]).all()
    ):  # checking if the geometry of a geoDataFrame is Point or MultiPoint
        kwargs["S"] = "u0.2c"
    elif kwargs.get("S") is None and kind == "file" and str(data).endswith(
            ".gmt"):
        # checking that the data is a file path to set default style
        try:
            with open(which(data), mode="r", encoding="utf8") as file:
                line = file.readline()
            if "@GMULTIPOINT" in line or "@GPOINT" in line:
                # if the file is gmt style and geometry is set to Point
                kwargs["S"] = "u0.2c"
        except FileNotFoundError:
            pass
    if kwargs.get("G") is not None and is_nonstr_iter(kwargs["G"]):
        if kind != "vectors":
            raise GMTInvalidInput(
                "Can't use arrays for color if data is matrix or file.")
        extra_arrays.append(kwargs["G"])
        del kwargs["G"]
    if size is not None:
        if kind != "vectors":
            raise GMTInvalidInput(
                "Can't use arrays for 'size' if data is a matrix or a file.")
        extra_arrays.append(size)

    for flag in ["I", "t"]:
        if kwargs.get(flag) is not None and is_nonstr_iter(kwargs[flag]):
            if kind != "vectors":
                raise GMTInvalidInput(
                    f"Can't use arrays for {plot3d.aliases[flag]} if data is matrix or file."
                )
            extra_arrays.append(kwargs[flag])
            kwargs[flag] = ""

    with Session() as lib:
        # Choose how data will be passed in to the module
        file_context = lib.virtualfile_from_data(
            check_kind="vector",
            data=data,
            x=x,
            y=y,
            z=z,
            extra_arrays=extra_arrays,
            required_z=True,
        )

        with file_context as fname:
            lib.call_module(module="plot3d",
                            args=build_arg_string(kwargs, infile=fname))
Exemple #25
0
def info(table, **kwargs):
    r"""
    Get information about data tables.

    Reads from files and finds the extreme values in each of the columns
    reported as min/max pairs. It recognizes NaNs and will print warnings if
    the number of columns vary from record to record. As an option, it will
    find the extent of the first two columns rounded up and down to the nearest
    multiple of the supplied increments given by ``spacing``. Such output will
    be in a numpy.ndarray form [*w*, *e*, *s*, *n*], which can be used
    directly as the ``region`` parameter for other modules (hence only *dx*
    and *dy* are needed). If the ``per_column`` parameter is combined with
    ``spacing``, then the numpy.ndarray output will be rounded up/down for as
    many columns as there are increments provided in ``spacing``. A similar
    parameter ``nearest_multiple`` will provide a numpy.ndarray in the form
    of [*zmin*, *zmax*, *dz*] for makecpt.

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

    {aliases}

    Parameters
    ----------
    table : str or np.ndarray or pandas.DataFrame or xarray.Dataset
        Pass in either a file name to an ASCII data table, a 1D/2D numpy array,
        a pandas dataframe, or an xarray dataset made up of 1D xarray.DataArray
        data variables.
    per_column : bool
        Report the min/max values per column in separate columns.
    spacing : str
        [**b**\|\ **p**\|\ **f**\|\ **s**]\ *dx*\[/*dy*\[/*dz*...]].
        Report the min/max of the first n columns to the nearest multiple of
        the provided increments and output results in the form
        ``[w, e, s, n]``.
    nearest_multiple : str
        **dz**\[\ **+c**\ *col*].
        Report the min/max of the first (0'th) column to the nearest multiple
        of dz and output this in the form ``[zmin, zmax, dz]``.

    {V}

    Returns
    -------
    output : np.ndarray or str
        Return type depends on whether any of the ``per_column``,
        ``spacing``, or ``nearest_multiple`` parameters are set.

        - :class:`numpy.ndarray` if either of the above parameters are used.
        - str if none of the above parameters are used.
    """
    kind = data_kind(table)
    with Session() as lib:
        if kind == "file":
            file_context = dummy_context(table)
        elif kind == "matrix":
            try:
                # pandas.DataFrame and xarray.Dataset types
                arrays = [array for _, array in table.items()]
            except AttributeError:
                # Python lists, tuples, and numpy ndarray types
                arrays = np.atleast_2d(np.asanyarray(table).T)
            file_context = lib.virtualfile_from_vectors(*arrays)
        else:
            raise GMTInvalidInput(f"Unrecognized data type: {type(table)}")

        with GMTTempFile() as tmpfile:
            with file_context as fname:
                arg_str = " ".join(
                    [fname,
                     build_arg_string(kwargs), "->" + tmpfile.name])
                lib.call_module("info", arg_str)
            result = tmpfile.read()

        if any(arg in kwargs for arg in ["C", "I", "T"]):
            # Converts certain output types into a numpy array
            # instead of a raw string that is less useful.
            if result.startswith(("-R", "-T")):  # e.g. -R0/1/2/3 or -T0/9/1
                result = result[2:].replace("/", " ")
            result = np.loadtxt(result.splitlines())

        return result
Exemple #26
0
def surface(x=None, y=None, z=None, data=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
    ----------
    x/y/z : 1d arrays
        Arrays of x and y coordinates and values z of the data points.
    data : str or 2d array
        Either a data file name or a 2d numpy array with the tabular data.

    spacing : str
        *xinc*\[\ *unit*\][**+e**\|\ **n**]\
        [/*yinc*\ [*unit*][**+e**\|\ **n**]].
        *xinc* [and optionally *yinc*] is the grid spacing.

    region : str or list
        *xmin/xmax/ymin/ymax*\[**+r**][**+u**\ *unit*].
        Specify the region of interest.

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

    {V}
    {a}
    {f}
    {r}

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

        - :class:`xarray.DataArray`: if ``outfile`` is not set
        - None if ``outfile`` is set (grid output will be stored in file set by
          ``outfile``)
    """
    kind = data_kind(data, x, y, z)
    if kind == "vectors" and z is None:
        raise GMTInvalidInput("Must provide z with x and y.")

    with GMTTempFile(suffix=".nc") as tmpfile:
        with Session() as lib:
            if kind == "file":
                file_context = dummy_context(data)
            elif kind == "matrix":
                file_context = lib.virtualfile_from_matrix(data)
            elif kind == "vectors":
                file_context = lib.virtualfile_from_vectors(x, y, z)
            else:
                raise GMTInvalidInput("Unrecognized data type: {}".format(
                    type(data)))
            with file_context as infile:
                if "G" not in kwargs.keys(
                ):  # if outfile is unset, output to tmpfile
                    kwargs.update({"G": tmpfile.name})
                outfile = kwargs["G"]
                arg_str = " ".join([infile, build_arg_string(kwargs)])
                lib.call_module(module="surface", args=arg_str)

        if outfile == tmpfile.name:  # if user did not set outfile, return DataArray
            with xr.open_dataarray(outfile) as dataarray:
                result = dataarray.load()
                _ = result.gmt  # load GMTDataArray accessor information
        elif outfile != tmpfile.name:  # if user sets an outfile, return None
            result = None

    return result
Exemple #27
0
def grdtrack(points, grid, newcolname=None, outfile=None, **kwargs):
    """
    Sample grids at specified (x,y) locations.

    Grdtrack reads one or more grid files and a table with (x,y) [or (lon,lat)]
    positions in the first two columns (more columns may be present). It
    interpolates the grid(s) at the positions in the table and writes out the
    table with the interpolated values added as (one or more) new columns. A
    bicubic [Default], bilinear, B-spline or nearest-neighbor interpolation is
    used, requiring boundary conditions at the limits of the region (see
    *interpolation*; Default uses “natural” conditions (second partial
    derivative normal to edge is zero) unless the grid is automatically
    recognized as periodic.)

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

    {aliases}

    Parameters
    ----------
    points : pandas.DataFrame or str
        Either a table with (x, y) or (lon, lat) values in the first two
        columns, or a filename (e.g. csv, txt format). More columns may be
        present.

    grid : xarray.DataArray or str
        Gridded array from which to sample values from, or a filename (netcdf
        format).

    newcolname : str
        Required if 'points' is a pandas.DataFrame. The name for the new column
        in the track pandas.DataFrame table where the sampled values will be
        placed.

    outfile : str
        Required if 'points' is a file. The file name for the output ASCII
        file.

    {V}

    {n}

    Returns
    -------
    track: pandas.DataFrame or None
        Return type depends on whether the outfile parameter is set:

        - pandas.DataFrame table with (x, y, ..., newcolname) if outfile is not
          set
        - None if outfile is set (track output will be stored in outfile)
    """

    with GMTTempFile(suffix=".csv") as tmpfile:
        with Session() as lib:
            # Store the pandas.DataFrame points table in virtualfile
            if data_kind(points) == "matrix":
                if newcolname is None:
                    raise GMTInvalidInput(
                        "Please pass in a str to 'newcolname'")
                table_context = lib.virtualfile_from_matrix(points.values)
            elif data_kind(points) == "file":
                if outfile is None:
                    raise GMTInvalidInput("Please pass in a str to 'outfile'")
                table_context = dummy_context(points)
            else:
                raise GMTInvalidInput(f"Unrecognized data type {type(points)}")

            # Store the xarray.DataArray grid in virtualfile
            if data_kind(grid) == "grid":
                grid_context = lib.virtualfile_from_grid(grid)
            elif data_kind(grid) == "file":
                grid_context = dummy_context(grid)
            else:
                raise GMTInvalidInput(f"Unrecognized data type {type(grid)}")

            # Run grdtrack on the temporary (csv) points table
            # and (netcdf) grid virtualfile
            with table_context as csvfile:
                with grid_context as grdfile:
                    kwargs.update({"G": grdfile})
                    if outfile is None:  # Output to tmpfile if outfile is not set
                        outfile = tmpfile.name
                    arg_str = " ".join(
                        [csvfile,
                         build_arg_string(kwargs), "->" + outfile])
                    lib.call_module(module="grdtrack", args=arg_str)

        # Read temporary csv output to a pandas table
        if outfile == tmpfile.name:  # if user did not set outfile, return pd.DataFrame
            column_names = points.columns.to_list() + [newcolname]
            result = pd.read_csv(tmpfile.name, sep="\t", names=column_names)
        elif outfile != tmpfile.name:  # return None if outfile set, output in outfile
            result = None

    return result
Exemple #28
0
def plot(self, x=None, y=None, data=None, size=None, direction=None, **kwargs):
    r"""
    Plot lines, polygons, and symbols in 2-D.

    Takes a matrix, (x,y) pairs, or a file name as input and plots lines,
    polygons, or symbols at those locations on a map.

    Must provide either ``data`` or ``x``/``y``.

    If providing data through ``x``/``y``, ``color`` can be a 1d array that
    will be mapped to a colormap.

    If a symbol is selected and no symbol size given, then plot will
    interpret the third column of the input data as symbol size. Symbols
    whose size is <= 0 are skipped. If no symbols are specified then the
    symbol code (see ``style`` below) must be present as last column in the
    input. If ``style`` is not used, a line connecting the data points will
    be drawn instead. To explicitly close polygons, use ``close``. Select a
    fill with ``color``. If ``color`` is set, ``pen`` will control whether the
    polygon outline is drawn or not. If a symbol is selected, ``color`` and
    ``pen`` determines the fill and outline/no outline, respectively.

    Full parameter list at :gmt-docs:`plot.html`

    {aliases}

    Parameters
    ----------
    x/y : float or 1d arrays
        The x and y coordinates, or arrays of x and y coordinates of the
        data points
    data : str or {table-like}
        Pass in either a file name to an ASCII data table, a 2D
        {table-classes}.
        Use parameter ``columns`` to choose which columns are x, y, color, and
        size, respectively.
    size : 1d array
        The size of the data points in units specified using ``style``.
        Only valid if using ``x``/``y``.
    direction : list of two 1d arrays
        If plotting vectors (using ``style='V'`` or ``style='v'``), then
        should be a list of two 1d arrays with the vector directions. These
        can be angle and length, azimuth and length, or x and y components,
        depending on the style options chosen.
    {J}
    {R}
    straight_line : bool or str
        [**m**\|\ **p**\|\ **x**\|\ **y**].
        By default, geographic line segments are drawn as great circle
        arcs. To draw them as straight lines, use ``straight_line``.
        Alternatively, add **m** to draw the line by first following a
        meridian, then a parallel. Or append **p** to start following a
        parallel, then a meridian. (This can be practical to draw a line
        along parallels, for example). For Cartesian data, points are
        simply connected, unless you append **x** or **y** to draw
        stair-case curves that whose first move is along *x* or *y*,
        respectively.
    {B}
    {CPT}
    offset : str
        *dx*/*dy*.
        Offset the plot symbol or line locations by the given amounts
        *dx/dy* [Default is no offset]. If *dy* is not given it is set
        equal to *dx*.
    error_bar : bool or str
        [**+b**\|\ **d**\|\ **D**][**+xl**\|\ **r**\|\ *x0*]\
        [**+yl**\|\ **r**\|\ *y0*][**+p**\ *pen*].
        Draw symmetrical error bars. Full documentation is at
        :gmt-docs:`plot.html#e`.
    connection : str
        [**c**\|\ **n**\|\ **r**]\
        [**a**\|\ **f**\|\ **s**\|\ **r**\|\ *refpoint*].
        Alter the way points are connected (by specifying a *scheme*) and
        data are grouped (by specifying a *method*). Append one of three
        line connection schemes:

        - **c** : Draw continuous line segments for each group [Default].
        - **r** : Draw line segments from a reference point reset for each
          group.
        - **n** : Draw networks of line segments between all points in
          each group.

        Optionally, append the one of four segmentation methods to define
        the group:

        - **a** : Ignore all segment headers, i.e., let all points belong
          to a single group, and set group reference point to the very
          first point of the first file.
        - **f** : Consider all data in each file to be a single separate
          group and reset the group reference point to the first point of
          each group.
        - **s** : Segment headers are honored so each segment is a group;
          the group reference point is reset to the first point of each
          incoming segment [Default].
        - **r** : Same as **s**, but the group reference point is reset
          after each record to the previous point (this method is only
          available with the ``connection='r'`` scheme).

        Instead of the codes **a**\|\ **f**\|\ **s**\|\ **r** you may append
        the coordinates of a *refpoint* which will serve as a fixed external
        reference point for all groups.
    {G}
        *color* can be a 1d array, but it is only valid if using ``x``/``y``
        and ``cmap=True`` is also required.
    intensity : float or bool or 1d array
        Provide an *intensity* value (nominally in the -1 to +1 range) to
        modulate the fill color by simulating illumination. If using
        ``intensity=True``, we will instead read *intensity* from the first
        data column after the symbol parameters (if given). *intensity* can
        also be a 1d array to set varying intensity for symbols, but it is only
        valid for ``x``/``y`` pairs.
    close : str
        [**+b**\|\ **d**\|\ **D**][**+xl**\|\ **r**\|\ *x0*]\
        [**+yl**\|\ **r**\|\ *y0*][**+p**\ *pen*].
        Force closed polygons. Full documentation is at
        :gmt-docs:`plot.html#l`.
    no_clip : bool or str
        [**c**\|\ **r**].
        Do NOT clip symbols that fall outside map border [Default plots
        points whose coordinates are strictly inside the map border only].
        The parameter does not apply to lines and polygons which are always
        clipped to the map region. For periodic (360-longitude) maps we
        must plot all symbols twice in case they are clipped by the
        repeating boundary. ``no_clip=True`` will turn off clipping and not
        plot repeating symbols. Use ``no_clip="r"`` to turn off clipping
        but retain the plotting of such repeating symbols, or use
        ``no_clip="c"`` to retain clipping but turn off plotting of
        repeating symbols.
    style : str
        Plot symbols (including vectors, pie slices, fronts, decorated or
        quoted lines).
    {W}
    {U}
    {V}
    {XY}
    zvalue : str
        *value*\|\ *file*.
        Instead of specifying a symbol or polygon fill and outline color
        via ``color`` and ``pen``, give both a *value* via ``zvalue`` and a
        color lookup table via ``cmap``.  Alternatively, give the name of a
        *file* with one z-value (read from the last column) for each
        polygon in the input data. To apply it to the fill color, use
        ``color='+z'``. To apply it to the pen color, append **+z** to
        ``pen``.
    {a}
    {c}
    {f}
    {i}
    label : str
        Add a legend entry for the symbol or line being plotted.

    {p}
    {t}
        *transparency* can also be a 1d array to set varying transparency
        for symbols, but this option is only valid if using x/y.
    """
    kwargs = self._preprocess(**kwargs)  # pylint: disable=protected-access

    kind = data_kind(data, x, y)

    extra_arrays = []
    if "S" in kwargs and kwargs["S"][0] in "vV" and direction is not None:
        extra_arrays.extend(direction)
    if "G" in kwargs and not isinstance(kwargs["G"], str):
        if kind != "vectors":
            raise GMTInvalidInput(
                "Can't use arrays for color if data is matrix or file."
            )
        extra_arrays.append(kwargs["G"])
        del kwargs["G"]
    if size is not None:
        if kind != "vectors":
            raise GMTInvalidInput(
                "Can't use arrays for 'size' if data is a matrix or file."
            )
        extra_arrays.append(size)

    for flag in ["I", "t"]:
        if flag in kwargs and is_nonstr_iter(kwargs[flag]):
            if kind != "vectors":
                raise GMTInvalidInput(
                    f"Can't use arrays for {plot.aliases[flag]} if data is matrix or file."
                )
            extra_arrays.append(kwargs[flag])
            kwargs[flag] = ""

    with Session() as lib:
        # Choose how data will be passed in to the module
        file_context = lib.virtualfile_from_data(
            check_kind="vector", data=data, x=x, y=y, extra_arrays=extra_arrays
        )

        with file_context as fname:
            arg_str = " ".join([fname, build_arg_string(kwargs)])
            lib.call_module("plot", arg_str)
Exemple #29
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-docs:`datasets/remote-data.html#global-earth-relief-grids`
    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.

    Notes
    -----
    The :class:`xarray.DataArray` grid doesn't support slice operation, for
    Earth relief data with resolutions higher than "05m", 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")
        with xr.open_dataarray(fname) as dataarray:
            grid = dataarray.load()
            _ = grid.gmt  # load GMTDataArray accessor information
    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
Exemple #30
0
def x2sys_cross(tracks=None, outfile=None, **kwargs):
    r"""
    Calculate crossovers between track data files.

    Determines all intersections between ("external cross-overs") or within
    ("internal cross-overs") tracks (Cartesian or geographic), and report the
    time, position, distance along track, heading and speed along each track
    segment, and the crossover error (COE) and mean values for all observables.
    By default, :meth:`pygmt.x2sys_cross` will look for both external and
    internal COEs. As an option, you may choose to project all data using one
    of the map projections prior to calculating the COE.

    Full option list at :gmt-docs:`supplements/x2sys/x2sys_cross.html`

    {aliases}

    Parameters
    ----------
    tracks : pandas.DataFrame or str or list
        A table or a list of tables with (x, y) or (lon, lat) values in the
        first two columns. Track(s) can be provided as pandas DataFrame tables
        or file names. Supported file formats are ASCII, native binary, or
        COARDS netCDF 1-D data. More columns may also be present.

        If the filenames are missing their file extension, we will append the
        suffix specified for this TAG. Track files will be searched for first
        in the current directory and second in all directories listed in
        $X2SYS_HOME/TAG/TAG_paths.txt (if it exists). [If $X2SYS_HOME is not
        set it will default to $GMT_SHAREDIR/x2sys]. (Note: MGD77 files will
        also be looked for via $MGD77_HOME/mgd77_paths.txt and .gmt files
        will be searched for via $GMT_SHAREDIR/mgg/gmtfile_paths).

    outfile : str
        Optional. The file name for the output ASCII txt file to store the
        table in.

    tag : str
        Specify the x2sys TAG which identifies the attributes of this data
        type.

    combitable : str
        Only process the pair-combinations found in the file *combitable*
        [Default process all possible combinations among the specified files].
        The file *combitable* is created by :gmt-docs:`x2sys_get's -L option
        <supplements/x2sys/x2sys_get.html#l>`.

    runtimes : bool or str
        Compute and append the processing run-time for each pair to the
        progress message (use ``runtimes=True``). Pass in a filename (e.g.
        ``runtimes="file.txt"``) to save these run-times to file. The idea here
        is to use the knowledge of run-times to split the main process in a
        number of sub-processes that can each be launched in a different
        processor of your multi-core machine. See the MATLAB function
        `split_file4coes.m
        <https://github.com/GenericMappingTools/gmt/blob/master/src/x2sys/>`_.

    override : bool or str
        **S**\|\ **N**.
        Control how geographic coordinates are handled (Cartesian data are
        unaffected). By default, we determine if the data are closer to one
        pole than the other, and then we use a cylindrical polar conversion to
        avoid problems with longitude jumps. You can turn this off entirely
        with ``override`` and then the calculations uses the original data (we
        have protections against longitude jumps). However, you can force the
        selection of the pole for the projection by appending **S** or **N**
        for the south or north pole, respectively. The conversion is used
        because the algorithm used to find crossovers is inherently a
        Cartesian algorithm that can run into trouble with data that has large
        longitudinal range at higher latitudes.

    interpolation : str
        **l**\|\ **a**\|\ **c**.
        Sets the interpolation mode for estimating values at the crossover.
        Choose among:

        - **l** - Linear interpolation [Default].
        - **a** - Akima spline interpolation.
        - **c** - Cubic spline interpolation.

    coe : str
        Use **e** for external COEs only, and **i** for internal COEs only
        [Default is all COEs].

    {R}

    speed : str or list
        **l**\|\ **u**\|\ **h**\ *speed*.
        Defines window of track speeds. If speeds are outside this window we do
        not calculate a COE. Specify:

        - **l** sets lower speed [Default is 0].
        - **u** sets upper speed [Default is infinity].
        - **h** does not limit the speed but sets a lower speed below which
          headings will not be computed (i.e., set to NaN) [Default
          calculates headings regardless of speed].

        For example, you can use ``speed=["l0", "u10", "h5"]`` to set a lower
        speed of 0, upper speed of 10, and disable heading calculations for
        speeds below 5.

    {V}

    numpoints : int
        Give the maximum number of data points on either side of the crossover
        to use in the spline interpolation [Default is 3].

    trackvalues : bool
        Report the values of each track at the crossover [Default reports the
        crossover value and the mean value].

    Returns
    -------
    crossover_errors : :class:`pandas.DataFrame` or None
        Table containing crossover error information.
        Return type depends on whether the ``outfile`` parameter is set:

        - :class:`pandas.DataFrame` with (x, y, ..., etc) if ``outfile`` is not
          set
        - None if ``outfile`` is set (track output will be stored in the set in
          ``outfile``)
    """
    with Session() as lib:
        file_contexts = []
        for track in tracks:
            kind = data_kind(track)
            if kind == "file":
                file_contexts.append(dummy_context(track))
            elif kind == "matrix":
                # find suffix (-E) of trackfiles used (e.g. xyz, csv, etc) from
                # $X2SYS_HOME/TAGNAME/TAGNAME.tag file
                lastline = (Path(
                    os.environ["X2SYS_HOME"], kwargs["T"],
                    f"{kwargs['T']}.tag").read_text().strip().split("\n")[-1]
                            )  # e.g. "-Dxyz -Etsv -I1/1"
                for item in sorted(
                        lastline.split()):  # sort list alphabetically
                    if item.startswith(
                        ("-E", "-D")):  # prefer -Etsv over -Dxyz
                        suffix = item[
                            2:]  # e.g. tsv (1st choice) or xyz (2nd choice)

                # Save pandas.DataFrame track data to temporary file
                file_contexts.append(
                    tempfile_from_dftrack(track=track, suffix=suffix))
            else:
                raise GMTInvalidInput(f"Unrecognized data type: {type(track)}")

        with GMTTempFile(suffix=".txt") as tmpfile:
            with contextlib.ExitStack() as stack:
                fnames = [stack.enter_context(c) for c in file_contexts]
                if outfile is None:
                    outfile = tmpfile.name
                arg_str = " ".join(
                    [*fnames,
                     build_arg_string(kwargs), "->" + outfile])
                lib.call_module(module="x2sys_cross", args=arg_str)

            # Read temporary csv output to a pandas table
            if outfile == tmpfile.name:  # if outfile isn't set, return pd.DataFrame
                # Read the tab-separated ASCII table
                table = pd.read_csv(
                    tmpfile.name,
                    sep="\t",
                    header=2,  # Column names are on 2nd row
                    comment=">",  # Skip the 3rd row with a ">"
                    parse_dates=[2, 3],  # Datetimes on 3rd and 4th column
                )
                # Remove the "# " from "# x" in the first column
                table = table.rename(
                    columns={table.columns[0]: table.columns[0][2:]})
            elif outfile != tmpfile.name:  # if outfile is set, output in outfile only
                table = None

    return table