From 7718f6233c5b14ae5e3f9bcd515a91c247f10367 Mon Sep 17 00:00:00 2001 From: Dongdong Tian Date: Tue, 16 Jan 2024 01:07:23 +0800 Subject: [PATCH 01/10] New alias system --- pygmt/alias.py | 83 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 83 insertions(+) create mode 100644 pygmt/alias.py diff --git a/pygmt/alias.py b/pygmt/alias.py new file mode 100644 index 00000000000..e4474e4c432 --- /dev/null +++ b/pygmt/alias.py @@ -0,0 +1,83 @@ +""" +Alias system to convert PyGMT parameters to GMT options. +""" +import inspect +from collections import defaultdict +from typing import NamedTuple + +from pygmt.helpers import is_nonstr_iter + + +class Alias(NamedTuple): + """ + Alias system for mapping a PyGMT parameter to its equivalent GMT option string. + + Attributes + ---------- + name : str + PyGMT parameter name. + flag : str + GMT single-letter option flag. + modifier : str + GMT option modifier. Can be None. + separator : str + Separator to join the iterable argument into a string. + """ + + name: str + flag: str + modifier: str + separator: str + + +def convert_aliases(): + """ + Convert PyGMT parameters to GMT options. + + The caller function must have the special variable ``_aliases`` defined. + + Examples + -------- + >>> def module_func(**kwargs): + ... _aliases = [ + ... Alias("par1", "A", "", ""), + ... Alias("par2", "B", "", "/"), + ... Alias("par3", "C", "", ","), + ... Alias("pard1", "D", "", ""), + ... Alias("pard2", "D", "+a", ""), + ... Alias("pard3", "D", "+b", ","), + ... Alias("pard4", "D", "+c", "/"), + ... ] + ... options = convert_aliases() + ... print(options) + >>> + >>> module_func( + ... par1="value1", + ... par2=[1, 2, 3, 4], + ... par3=[0, 1], + ... pard1="value2", + ... pard2="value3", + ... pard3=[1, 2, 3, 4], + ... pard4=[1, 2, 3, 4], + ... ) + {'A': 'value1', 'B': '1/2/3/4', 'C': '0,1', 'D': 'value2+avalue3+b1,2,3,4+c1/2/3/4'} + """ + # Get the local namespace of the caller function + p_locals = inspect.currentframe().f_back.f_locals + params = p_locals.pop("kwargs", {}) | p_locals + + # Define a dict to store GMT option flags and arguments + kwdict = defaultdict(str) # default value is an empty string + for alias in p_locals.get("_aliases"): + value = params.get(alias.name) + if is_nonstr_iter(value): + if alias.separator != "": + value = alias.separator.join(str(item) for item in value) + else: + value = "" + elif value in (None, False): # None or False are skipped + continue + elif value is True: # Convert True to an empty string + value = "" + kwdict[alias.flag] += f"{alias.modifier}{value}" + return dict(kwdict) From fef7c00347350dbc5e147f108b6cf65a1d6675f5 Mon Sep 17 00:00:00 2001 From: Dongdong Tian Date: Tue, 16 Jan 2024 01:08:55 +0800 Subject: [PATCH 02/10] Update pygmt.info --- pygmt/src/info.py | 46 ++++++++++++++++++++++++++++------------------ 1 file changed, 28 insertions(+), 18 deletions(-) diff --git a/pygmt/src/info.py b/pygmt/src/info.py index 71fc96cdf35..7775114ca78 100644 --- a/pygmt/src/info.py +++ b/pygmt/src/info.py @@ -2,29 +2,28 @@ info - Get information about data tables. """ import numpy as np +from pygmt.alias import Alias, convert_aliases from pygmt.clib import Session from pygmt.helpers import ( GMTTempFile, build_arg_string, fmt_docstring, - kwargs_to_strings, - use_alias, ) @fmt_docstring -@use_alias( - C="per_column", - I="spacing", - T="nearest_multiple", - V="verbose", - a="aspatial", - f="coltypes", - i="incols", - r="registration", -) -@kwargs_to_strings(I="sequence", i="sequence_comma") -def info(data, **kwargs): +def info( + data, + per_column=None, + spacing=None, + nearest_multiple=None, + verbose=None, + aspatial=None, + coltypes=None, + incols=None, + registration=None, + **kwargs, +): r""" Get information about data tables. @@ -43,8 +42,6 @@ def info(data, **kwargs): Full option list at :gmt-docs:`gmtinfo.html` - {aliases} - Parameters ---------- data : str, {table-like} @@ -79,17 +76,30 @@ def info(data, **kwargs): - :class:`numpy.ndarray` if either of the above parameters are used. - str if none of the above parameters are used. """ + _aliases = [ + Alias("per_column", "C", "", ""), + Alias("spacing", "I", "", "/"), + Alias("nearest_multiple", "T", "", ""), + Alias("verbose", "V", "", ""), + Alias("aspatial", "a", "", ""), + Alias("coltypes", "f", "", ""), + Alias("incols", "i", "", ","), + Alias("registration", "r", "", ""), + ] + + options = convert_aliases() + with Session() as lib: file_context = lib.virtualfile_from_data(check_kind="vector", data=data) with GMTTempFile() as tmpfile: with file_context as fname: lib.call_module( module="info", - args=build_arg_string(kwargs, infile=fname, outfile=tmpfile.name), + args=build_arg_string(options, infile=fname, outfile=tmpfile.name), ) result = tmpfile.read() - if any(kwargs.get(arg) is not None for arg in ["C", "I", "T"]): + if any(arg is not None for arg in (per_column, spacing, nearest_multiple)): # 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 From eb32c4032c2add85c1428a0f05b4b437cd2d685b Mon Sep 17 00:00:00 2001 From: Dongdong Tian Date: Tue, 16 Jan 2024 01:09:06 +0800 Subject: [PATCH 03/10] Update legend --- pygmt/src/legend.py | 39 +++++++++++++++++---------------------- 1 file changed, 17 insertions(+), 22 deletions(-) diff --git a/pygmt/src/legend.py b/pygmt/src/legend.py index 8f58112d6d7..dcff97162b5 100644 --- a/pygmt/src/legend.py +++ b/pygmt/src/legend.py @@ -2,30 +2,18 @@ legend - Plot a legend. """ +from pygmt.alias import Alias, convert_aliases from pygmt.clib import Session from pygmt.exceptions import GMTInvalidInput from pygmt.helpers import ( build_arg_string, data_kind, fmt_docstring, - kwargs_to_strings, - use_alias, ) @fmt_docstring -@use_alias( - R="region", - J="projection", - D="position", - F="box", - V="verbose", - c="panel", - p="perspective", - t="transparency", -) -@kwargs_to_strings(R="sequence", c="sequence_comma", p="sequence") -def legend(self, spec=None, position="JTR+jTR+o0.2c", box="+gwhite+p1p", **kwargs): +def legend(self, spec=None, position="JTR+jTR+o0.2c", box="+gwhite+p1p", **kwargs): # noqa: ARG001 r""" Plot legends on maps. @@ -37,8 +25,6 @@ def legend(self, spec=None, position="JTR+jTR+o0.2c", box="+gwhite+p1p", **kwarg Full option list at :gmt-docs:`legend.html` - {aliases} - Parameters ---------- spec : None or str @@ -67,12 +53,19 @@ def legend(self, spec=None, position="JTR+jTR+o0.2c", box="+gwhite+p1p", **kwarg {perspective} {transparency} """ - kwargs = self._preprocess(**kwargs) + _aliases = [ + Alias("region", "R", "", "/"), + Alias("projection", "J", "", ""), + Alias("position", "D", "", ""), + Alias("box", "F", "", ""), + Alias("verbose", "v", "", ""), + Alias("panel", "c", "", ","), + Alias("perspective", "p", "", "/"), + Alias("transparency", "t", "", ""), + ] - if kwargs.get("D") is None: - kwargs["D"] = position - if kwargs.get("F") is None: - kwargs["F"] = box + kwargs = self._preprocess(**kwargs) + options = convert_aliases() with Session() as lib: if spec is None: @@ -81,4 +74,6 @@ def legend(self, spec=None, position="JTR+jTR+o0.2c", box="+gwhite+p1p", **kwarg specfile = spec else: raise GMTInvalidInput(f"Unrecognized data type: {type(spec)}") - lib.call_module(module="legend", args=build_arg_string(kwargs, infile=specfile)) + lib.call_module( + module="legend", args=build_arg_string(options, infile=specfile) + ) From e01962f1748de30399709c6bb85fc2bb5a98e52a Mon Sep 17 00:00:00 2001 From: Dongdong Tian Date: Tue, 16 Jan 2024 01:09:18 +0800 Subject: [PATCH 04/10] Update plot --- pygmt/src/plot.py | 123 +++++++++++++++++++++++++--------------------- 1 file changed, 68 insertions(+), 55 deletions(-) diff --git a/pygmt/src/plot.py b/pygmt/src/plot.py index 2eb73d3b4b4..3c9d9b9366a 100644 --- a/pygmt/src/plot.py +++ b/pygmt/src/plot.py @@ -1,6 +1,7 @@ """ plot - Plot in two dimensions. """ +from pygmt.alias import Alias, convert_aliases from pygmt.clib import Session from pygmt.exceptions import GMTInvalidInput from pygmt.helpers import ( @@ -9,48 +10,24 @@ deprecate_parameter, fmt_docstring, is_nonstr_iter, - kwargs_to_strings, - use_alias, ) from pygmt.src.which import which @fmt_docstring @deprecate_parameter("color", "fill", "v0.8.0", remove_version="v0.12.0") -@use_alias( - A="straight_line", - B="frame", - C="cmap", - D="offset", - E="error_bar", - F="connection", - G="fill", - I="intensity", - J="projection", - L="close", - N="no_clip", - R="region", - S="style", - V="verbose", - W="pen", - Z="zvalue", - a="aspatial", - b="binary", - c="panel", - d="nodata", - e="find", - f="coltypes", - g="gap", - h="header", - i="incols", - l="label", - p="perspective", - t="transparency", - w="wrap", -) -@kwargs_to_strings(R="sequence", c="sequence_comma", i="sequence_comma", p="sequence") def plot( # noqa: PLR0912 - self, data=None, x=None, y=None, size=None, direction=None, **kwargs + self, + data=None, + x=None, + y=None, + size=None, + direction=None, + style=None, + fill=None, + transparency=None, + intensity=None, + **kwargs, ): r""" Plot lines, polygons, and symbols in 2-D. @@ -75,8 +52,6 @@ def plot( # noqa: PLR0912 Full option list at :gmt-docs:`plot.html` - {aliases} - Parameters ---------- data : str, {table-like} @@ -207,54 +182,92 @@ def plot( # noqa: PLR0912 """ kwargs = self._preprocess(**kwargs) + _aliases = [ + Alias("straight_line", "A", "", ""), + Alias("frame", "B", "", ""), + Alias("cmap", "C", "", ""), + Alias("offset", "D", "", ""), + Alias("error_bar", "E", "", ""), + Alias("connection", "F", "", ""), + Alias("fill", "G", "", ""), + Alias("intensity", "I", "", ""), + Alias("projection", "J", "", ""), + Alias("close", "L", "", ""), + Alias("no_clip", "N", "", ""), + Alias("region", "R", "", "/"), + Alias("style", "S", "", ""), + Alias("verbose", "V", "", ""), + Alias("pen", "W", "", ""), + Alias("zvalue", "Z", "", ""), + Alias("aspatial", "a", "", ""), + Alias("binary", "b", "", ""), + Alias("panel", "c", "", ","), + Alias("find", "e", "", ""), + Alias("coltypes", "f", "", ""), + Alias("gap", "g", "", ""), + Alias("header", "h", "", ""), + Alias("incols", "i", "", ","), + Alias("lable", "l", "", ""), + Alias("perspective", "p", "", "/"), + Alias("transparency", "t", "", ""), + Alias("wrap", "w", "", ""), + ] + kind = data_kind(data, x, y) extra_arrays = [] - if kwargs.get("S") is not None and kwargs["S"][0] in "vV" and direction is not None: + if style is not None and style[0] in "vV" and direction is not None: extra_arrays.extend(direction) elif ( - kwargs.get("S") is None + style 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"] = "s0.2c" - elif kwargs.get("S") is None and kind == "file" and str(data).endswith(".gmt"): + style = "s0.2c" + elif style 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), 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"] = "s0.2c" + style = "s0.2c" except FileNotFoundError: pass - if is_nonstr_iter(kwargs.get("G")): + + if is_nonstr_iter(fill): if kind != "vectors": raise GMTInvalidInput( "Can't use arrays for fill if data is matrix or file." ) - extra_arrays.append(kwargs["G"]) - del kwargs["G"] + extra_arrays.append(fill) + fill = None 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 is_nonstr_iter(kwargs.get(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] = "" + if is_nonstr_iter(intensity): + if kind != "vectors": + raise GMTInvalidInput( + "Can't use arrays for intensity if data is matrix or file." + ) + extra_arrays.append(intensity) + intensity = True + if is_nonstr_iter(transparency): + if kind != "vectors": + raise GMTInvalidInput( + "Can't use arrays for transparency if data is matrix or file." + ) + extra_arrays.append(transparency) + transparency = True with Session() as lib: file_context = lib.virtualfile_from_data( check_kind="vector", data=data, x=x, y=y, extra_arrays=extra_arrays ) + options = convert_aliases() with file_context as fname: - lib.call_module(module="plot", args=build_arg_string(kwargs, infile=fname)) + lib.call_module(module="plot", args=build_arg_string(options, infile=fname)) From 5ad2935a338cdb0a2f689b29502846b0729c701f Mon Sep 17 00:00:00 2001 From: Dongdong Tian Date: Tue, 16 Jan 2024 01:09:26 +0800 Subject: [PATCH 05/10] Update text --- pygmt/src/text.py | 99 +++++++++++++++++++++-------------------------- 1 file changed, 45 insertions(+), 54 deletions(-) diff --git a/pygmt/src/text.py b/pygmt/src/text.py index c386f89e81a..65652ccfa2f 100644 --- a/pygmt/src/text.py +++ b/pygmt/src/text.py @@ -2,6 +2,7 @@ text - Plot text on a figure. """ import numpy as np +from pygmt.alias import Alias, convert_aliases from pygmt.clib import Session from pygmt.exceptions import GMTInvalidInput from pygmt.helpers import ( @@ -11,38 +12,12 @@ is_nonstr_iter, kwargs_to_strings, non_ascii_to_octal, - use_alias, ) @fmt_docstring -@use_alias( - R="region", - J="projection", - B="frame", - C="clearance", - D="offset", - G="fill", - N="no_clip", - V="verbose", - W="pen", - a="aspatial", - c="panel", - e="find", - f="coltypes", - h="header", - it="use_word", - p="perspective", - t="transparency", - w="wrap", -) -@kwargs_to_strings( - R="sequence", - textfiles="sequence_space", - c="sequence_comma", - p="sequence", -) -def text_( # noqa: PLR0912 +@kwargs_to_strings(textfiles="sequence_space") +def text_( # noqa: PLR0913 self, textfiles=None, x=None, @@ -52,6 +27,9 @@ def text_( # noqa: PLR0912 angle=None, font=None, justify=None, + projection=None, # noqa: ARG001 + region=None, # noqa: ARG001 + transparency=None, **kwargs, ): r""" @@ -71,8 +49,6 @@ def text_( # noqa: PLR0912 Full option list at :gmt-docs:`text.html` - {aliases} - Parameters ---------- textfiles : str or list @@ -182,6 +158,31 @@ def text_( # noqa: PLR0912 """ kwargs = self._preprocess(**kwargs) + _aliases = [ + Alias("position", "F", "+c", ""), + Alias("angle", "F", "+a", ""), + Alias("font", "F", "+f", ""), + Alias("justify", "F", "+j", ""), + Alias("region", "R", "", "/"), + Alias("projection", "J", "", ""), + Alias("transparency", "t", "", ""), + Alias("frame", "B", "", ""), + Alias("clearance", "C", "", ""), + Alias("offset", "D", "", ""), + Alias("fill", "G", "", ""), + Alias("no_clip", "N", "", ""), + Alias("verbose", "V", "", ""), + Alias("pen", "W", "", ""), + Alias("aspatial", "a", "", ""), + Alias("panel", "c", "", ","), + Alias("find", "e", "", ""), + Alias("coltypes", "f", "", ""), + Alias("header", "h", "", ""), + Alias("use_word", "it", "", ""), + Alias("perspective", "p", "", "/"), + Alias("wrap", "w", "", ""), + ] + # Ensure inputs are either textfiles, x/y/text, or position/text if position is None: if (x is not None or y is not None) and textfiles is not None: @@ -201,33 +202,22 @@ def text_( # noqa: PLR0912 kind = None textfiles = "" - # Build the -F option in gmt text. - if kwargs.get("F") is None and any( - v is not None for v in (position, angle, font, justify) - ): - kwargs.update({"F": ""}) + # special handling with the position parameter + if position is not None: + position += f"+t{text}" extra_arrays = [] - for arg, flag in [(angle, "+a"), (font, "+f"), (justify, "+j")]: - if arg is True: - kwargs["F"] += flag - elif is_nonstr_iter(arg): - kwargs["F"] += flag - if flag == "+a": # angle is numeric type - extra_arrays.append(np.atleast_1d(arg)) - else: # font or justify is str type - extra_arrays.append(np.atleast_1d(arg).astype(str)) - elif isinstance(arg, (int, float, str)): - kwargs["F"] += f"{flag}{arg}" - - if isinstance(position, str): - kwargs["F"] += f"+c{position}+t{text}" - + # angle is numeric type + if is_nonstr_iter(angle): + extra_arrays.append(np.atleast_1d(angle)) + # font or justify is str type + for arg in (font, justify): + if is_nonstr_iter(arg): + extra_arrays.append(np.atleast_1d(arg).astype(str)) # noqa: PERF401 # If an array of transparency is given, GMT will read it from # the last numerical column per data record. - if is_nonstr_iter(kwargs.get("t")): - extra_arrays.append(kwargs["t"]) - kwargs["t"] = "" + if is_nonstr_iter(transparency): + extra_arrays.append(transparency) # Append text at last column. Text must be passed in as str type. if kind == "vectors": @@ -239,5 +229,6 @@ def text_( # noqa: PLR0912 file_context = lib.virtualfile_from_data( check_kind="vector", data=textfiles, x=x, y=y, extra_arrays=extra_arrays ) + options = convert_aliases() with file_context as fname: - lib.call_module(module="text", args=build_arg_string(kwargs, infile=fname)) + lib.call_module(module="text", args=build_arg_string(options, infile=fname)) From a37f9deed20c8b2d77d581ebca3ec3d72779e186 Mon Sep 17 00:00:00 2001 From: Dongdong Tian Date: Tue, 16 Jan 2024 01:09:36 +0800 Subject: [PATCH 06/10] Updte timestamp --- pygmt/src/timestamp.py | 40 ++++++++++++++++++++++++---------------- 1 file changed, 24 insertions(+), 16 deletions(-) diff --git a/pygmt/src/timestamp.py b/pygmt/src/timestamp.py index 96c816a67d9..aa750152ce5 100644 --- a/pygmt/src/timestamp.py +++ b/pygmt/src/timestamp.py @@ -7,8 +7,9 @@ from typing import TYPE_CHECKING from packaging.version import Version +from pygmt.alias import Alias, convert_aliases from pygmt.clib import Session, __gmt_version__ -from pygmt.helpers import build_arg_string, kwargs_to_strings +from pygmt.helpers import build_arg_string, is_nonstr_iter if TYPE_CHECKING: from collections.abc import Sequence @@ -17,7 +18,6 @@ __doctest_skip__ = ["timestamp"] -@kwargs_to_strings(offset="sequence") def timestamp( self, text: str | None = None, @@ -82,17 +82,22 @@ def timestamp( """ self._preprocess() - # Build the options passed to the "plot" module - kwdict: dict = {"T": True, "U": ""} - if label is not None: - kwdict["U"] += f"{label}" - kwdict["U"] += f"+j{justification}" - - if Version(__gmt_version__) <= Version("6.4.0") and "/" not in str(offset): - # Giving a single offset doesn't work in GMT <= 6.4.0. - # See https://github.com/GenericMappingTools/gmt/issues/7107. - offset = f"{offset}/{offset}" - kwdict["U"] += f"+o{offset}" + # Aliases from PyGMT parameters to GMT options + _aliases = [ + Alias("label", "U", "", ""), + Alias("justification", "U", "+j", ""), + Alias("offset", "U", "+o", "/"), + Alias("text", "U", "+t", ""), + ] + + # Giving a single offset doesn't work in GMT <= 6.4.0. + # See https://github.com/GenericMappingTools/gmt/issues/7107. + if ( + Version(__gmt_version__) <= Version("6.4.0") + and not is_nonstr_iter(offset) + and "/" not in str(offset) + ): + offset = (offset, offset) # The +t modifier was added in GMT 6.5.0. # See https://github.com/GenericMappingTools/gmt/pull/7127. @@ -106,13 +111,16 @@ def timestamp( if Version(__gmt_version__) <= Version("6.4.0"): # workaround for GMT<=6.4.0 by overriding the 'timefmt' parameter timefmt = text[:64] - else: - kwdict["U"] += f"+t{text}" + text = None # reset 'text' to None + + # Build the options passed to the "plot" module + options = convert_aliases() + options["T"] = True with Session() as lib: lib.call_module( module="plot", args=build_arg_string( - kwdict, confdict={"FONT_LOGO": font, "FORMAT_TIME_STAMP": timefmt} + options, confdict={"FONT_LOGO": font, "FORMAT_TIME_STAMP": timefmt} ), ) From 9c988530892e9c0cfdc423149776e9356db8be62 Mon Sep 17 00:00:00 2001 From: Dongdong Tian Date: Tue, 16 Jan 2024 01:09:44 +0800 Subject: [PATCH 07/10] Update xyz2grd --- pygmt/src/xyz2grd.py | 74 ++++++++++++++++++++++++++++---------------- 1 file changed, 47 insertions(+), 27 deletions(-) diff --git a/pygmt/src/xyz2grd.py b/pygmt/src/xyz2grd.py index 693d9f0eab7..bdc24e8b212 100644 --- a/pygmt/src/xyz2grd.py +++ b/pygmt/src/xyz2grd.py @@ -1,14 +1,13 @@ """ xyz2grd - Convert data table to a grid. """ +from pygmt.alias import Alias, convert_aliases from pygmt.clib import Session from pygmt.exceptions import GMTInvalidInput from pygmt.helpers import ( GMTTempFile, build_arg_string, fmt_docstring, - kwargs_to_strings, - use_alias, ) from pygmt.io import load_dataarray @@ -16,25 +15,28 @@ @fmt_docstring -@use_alias( - A="duplicate", - G="outgrid", - I="spacing", - J="projection", - R="region", - V="verbose", - Z="convention", - b="binary", - d="nodata", - e="find", - f="coltypes", - h="header", - i="incols", - r="registration", - w="wrap", -) -@kwargs_to_strings(I="sequence", R="sequence") -def xyz2grd(data=None, x=None, y=None, z=None, **kwargs): +def xyz2grd( + data=None, + x=None, + y=None, + z=None, + outgrid=None, + spacing=None, + duplicate=None, + projection=None, + region=None, + verbose=None, + convention=None, + binary=None, + nodata=None, + find=None, + coltypes=None, + header=None, + incols=None, + registration=None, + wrap=None, + **kwargs, +): r""" Create a grid file from table data. @@ -46,8 +48,6 @@ def xyz2grd(data=None, x=None, y=None, z=None, **kwargs): Full option list at :gmt-docs:`xyz2grd.html` - {aliases} - Parameters ---------- data : str, {table-like} @@ -146,7 +146,25 @@ def xyz2grd(data=None, x=None, y=None, z=None, **kwargs): ... x=xx, y=yy, z=zz, spacing=(1.0, 0.5), region=[0, 3, 10, 13] ... ) """ - if kwargs.get("I") is None or kwargs.get("R") is None: + _aliases = [ + Alias("duplicate", "A", "", ""), + Alias("outgrid", "G", "", ""), + Alias("spacing", "I", "", "/"), + Alias("projection", "J", "", ""), + Alias("region", "R", "", "/"), + Alias("verbose", "V", "", ""), + Alias("convention", "Z", "", ""), + Alias("binary", "b", "", ""), + Alias("nodata", "d", "", ""), + Alias("find", "e", "", ""), + Alias("coltypes", "f", "", ""), + Alias("header", "h", "", ""), + Alias("incols", "i", "", ""), + Alias("registration", "r", "", ""), + Alias("wrap", "w", "", ""), + ] + + if spacing is None or region is None: raise GMTInvalidInput("Both 'region' and 'spacing' must be specified.") with GMTTempFile(suffix=".nc") as tmpfile: @@ -155,10 +173,12 @@ def xyz2grd(data=None, x=None, y=None, z=None, **kwargs): check_kind="vector", data=data, x=x, y=y, z=z, required_z=True ) with file_context as infile: - if (outgrid := kwargs.get("G")) is None: - kwargs["G"] = outgrid = tmpfile.name # output to tmpfile + if outgrid is None: + outgrid = tmpfile.name + + options = convert_aliases() lib.call_module( - module="xyz2grd", args=build_arg_string(kwargs, infile=infile) + module="xyz2grd", args=build_arg_string(options, infile=infile) ) return load_dataarray(outgrid) if outgrid == tmpfile.name else None From 20a041da7507c336d4604eb1b60027e9163afc4d Mon Sep 17 00:00:00 2001 From: Dongdong Tian Date: Tue, 16 Jan 2024 17:35:21 +0800 Subject: [PATCH 08/10] alias: deal with deprecated -U/timestamp parameter --- pygmt/alias.py | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/pygmt/alias.py b/pygmt/alias.py index e4474e4c432..6635d2d0bce 100644 --- a/pygmt/alias.py +++ b/pygmt/alias.py @@ -2,6 +2,7 @@ Alias system to convert PyGMT parameters to GMT options. """ import inspect +import warnings from collections import defaultdict from typing import NamedTuple @@ -64,7 +65,8 @@ def convert_aliases(): """ # Get the local namespace of the caller function p_locals = inspect.currentframe().f_back.f_locals - params = p_locals.pop("kwargs", {}) | p_locals + p_kwargs = p_locals.get("kwargs", {}) + params = p_locals | p_kwargs # Define a dict to store GMT option flags and arguments kwdict = defaultdict(str) # default value is an empty string @@ -80,4 +82,15 @@ def convert_aliases(): elif value is True: # Convert True to an empty string value = "" kwdict[alias.flag] += f"{alias.modifier}{value}" + + # Handling of deprecated common options. + # timestamp (U) is deprecated since v0.9.0. + if "U" in p_kwargs or "timestamp" in p_kwargs: + msg = ( + "Parameters 'U' and 'timestamp' are deprecated since v0.9.0 and will be " + "removed in v0.12.0. Use Figure.timestamp() instead." + ) + warnings.warn(msg, category=SyntaxWarning, stacklevel=2) + kwdict["U"] = p_kwargs["U"] if "U" in p_kwargs else p_kwargs["timestamp"] + return dict(kwdict) From 6abd4fb471dad5d6641686187df6b49b49042ad7 Mon Sep 17 00:00:00 2001 From: Dongdong Tian Date: Tue, 16 Jan 2024 17:35:29 +0800 Subject: [PATCH 09/10] Update timestamp --- pygmt/src/timestamp.py | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/pygmt/src/timestamp.py b/pygmt/src/timestamp.py index aa750152ce5..a14c8374642 100644 --- a/pygmt/src/timestamp.py +++ b/pygmt/src/timestamp.py @@ -90,13 +90,11 @@ def timestamp( Alias("text", "U", "+t", ""), ] + gmt_older_than_640 = Version(__gmt_version__) <= Version("6.4.0") + # Giving a single offset doesn't work in GMT <= 6.4.0. # See https://github.com/GenericMappingTools/gmt/issues/7107. - if ( - Version(__gmt_version__) <= Version("6.4.0") - and not is_nonstr_iter(offset) - and "/" not in str(offset) - ): + if gmt_older_than_640 and not is_nonstr_iter(offset) and "/" not in str(offset): offset = (offset, offset) # The +t modifier was added in GMT 6.5.0. @@ -108,19 +106,19 @@ def timestamp( "The given text string will be truncated to 64 characters." ) warnings.warn(message=msg, category=RuntimeWarning, stacklevel=2) - if Version(__gmt_version__) <= Version("6.4.0"): + if gmt_older_than_640: # workaround for GMT<=6.4.0 by overriding the 'timefmt' parameter timefmt = text[:64] text = None # reset 'text' to None # Build the options passed to the "plot" module - options = convert_aliases() - options["T"] = True + kwdict = convert_aliases() + kwdict["T"] = True with Session() as lib: lib.call_module( module="plot", args=build_arg_string( - options, confdict={"FONT_LOGO": font, "FORMAT_TIME_STAMP": timefmt} + kwdict, confdict={"FONT_LOGO": font, "FORMAT_TIME_STAMP": timefmt} ), ) From edbe9fa32a33db42304ff226cfe36d8e6d0952e2 Mon Sep 17 00:00:00 2001 From: Dongdong Tian Date: Tue, 16 Jan 2024 17:40:19 +0800 Subject: [PATCH 10/10] Update xyz2grd --- pygmt/src/xyz2grd.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pygmt/src/xyz2grd.py b/pygmt/src/xyz2grd.py index bdc24e8b212..d5723792c88 100644 --- a/pygmt/src/xyz2grd.py +++ b/pygmt/src/xyz2grd.py @@ -176,9 +176,9 @@ def xyz2grd( if outgrid is None: outgrid = tmpfile.name - options = convert_aliases() + kwdict = convert_aliases() lib.call_module( - module="xyz2grd", args=build_arg_string(options, infile=infile) + module="xyz2grd", args=build_arg_string(kwdict, infile=infile) ) return load_dataarray(outgrid) if outgrid == tmpfile.name else None