diff --git a/pygmt/alias.py b/pygmt/alias.py index 339a0d20803..52033172f35 100644 --- a/pygmt/alias.py +++ b/pygmt/alias.py @@ -14,6 +14,7 @@ def _to_string( value: Any, prefix: str = "", # Default to an empty string to simplify the code logic. + suffix: str = "", # Default to an empty string to simplify the code logic. mapping: Mapping | None = None, sep: Literal["/", ","] | None = None, size: int | Sequence[int] | None = None, @@ -38,13 +39,13 @@ def _to_string( GMT's short-form argument ``"h"``). An optional prefix (e.g., `"+o"`) can be added to the beginning of the converted - string. + string, and an optional suffix (e.g., `"+l"`) can be added to the end. To avoid extra overhead, this function does not validate parameter combinations. For example, if ``value`` is a sequence but ``sep`` is not specified, the function will - return a sequence of strings. In this case, ``prefix`` has no effect, but the - function does not check for such inconsistencies. The maintainer should ensure that - the parameter combinations are valid. + return a sequence of strings. In this case, ``prefix`` and ``suffix`` have no + effect, but the function does not check for such inconsistencies. The maintainer + should ensure that the parameter combinations are valid. Parameters ---------- @@ -52,6 +53,8 @@ def _to_string( The value to convert. prefix The string to add as a prefix to the returned value. + suffix + The string to add as a suffix to the returned value. mapping A mapping dictionary to map PyGMT's long-form arguments to GMT's short-form. sep @@ -90,6 +93,13 @@ def _to_string( >>> _to_string(False, prefix="+a") >>> _to_string(None, prefix="+a") + >>> _to_string("blue", suffix="+l") + 'blue+l' + >>> _to_string("red", suffix="+r") + 'red+r' + >>> _to_string(True, suffix="+l") + '+l' + >>> _to_string("mean", mapping={"mean": "a", "mad": "d", "full": "g"}) 'a' >>> _to_string("invalid", mapping={"mean": "a", "mad": "d", "full": "g"}) @@ -135,9 +145,9 @@ def _to_string( # None and False are converted to None. if value is None or value is False: return None - # True is converted to an empty string with the optional prefix. + # True is converted to an empty string with the optional prefix and suffix. if value is True: - return f"{prefix}" + return f"{prefix}{suffix}" # Any non-sequence value is converted to a string. if not is_nonstr_iter(value): if mapping: @@ -148,16 +158,16 @@ def _to_string( choices=mapping.keys(), ) value = mapping.get(value, value) - return f"{prefix}{value}" + return f"{prefix}{value}{suffix}" # Return the sequence if separator is not specified for options like '-B'. # True in a sequence will be converted to an empty string. if sep is None: return [str(item) if item is not True else "" for item in value] # Join the sequence of values with the separator. - # "prefix" and "mapping" are ignored. We can enable them when needed. + # "prefix", "suffix", and "mapping" are ignored. We can enable them when needed. _value = sequence_join(value, sep=sep, size=size, ndim=ndim, name=name) - return _value if is_nonstr_iter(_value) else f"{prefix}{_value}" + return _value if is_nonstr_iter(_value) else f"{prefix}{_value}{suffix}" class Alias: @@ -172,6 +182,8 @@ class Alias: The name of the parameter to be used in the error message. prefix The string to add as a prefix to the returned value. + suffix + The string to add as a suffix to the returned value. mapping A mapping dictionary to map PyGMT's long-form arguments to GMT's short-form. sep @@ -189,6 +201,10 @@ class Alias: >>> par._value '+o3.0/3.0' + >>> par = Alias("blue", suffix="+l") + >>> par._value + 'blue+l' + >>> par = Alias("mean", mapping={"mean": "a", "mad": "d", "full": "g"}) >>> par._value 'a' @@ -203,6 +219,7 @@ def __init__( value: Any, name: str | None = None, prefix: str = "", + suffix: str = "", mapping: Mapping | None = None, sep: Literal["/", ","] | None = None, size: int | Sequence[int] | None = None, @@ -210,10 +227,12 @@ def __init__( ): self.name = name self.prefix = prefix + self.suffix = suffix self._value = _to_string( value=value, name=name, prefix=prefix, + suffix=suffix, mapping=mapping, sep=sep, size=size, @@ -283,8 +302,12 @@ def __init__(self, **kwargs): # The value of each key in kwargs is an Alias object or a sequence of Alias # objects. If it is a single Alias object, we will use its _value property. If - # it is a sequence of Alias objects, we will concatenate their _value properties - # into a single string. + # it is a sequence of Alias objects, we will check if any have suffix: + # + # - If any Alias has a suffix, return a list of values, for repeated GMT options + # like -Cblue+l -Cred+r + # - Otherwise, concatenate into a single string for combined modifiers like + # -BWSen+ttitle+gblue. # # Note that alias._value is converted by the _to_string method and can only be # None, string or sequence of strings. @@ -296,7 +319,13 @@ def __init__(self, **kwargs): if isinstance(aliases, Sequence): # A sequence of Alias objects. values = [alias._value for alias in aliases if alias._value is not None] if values: - kwdict[option] = "".join(values) + # Check if any alias has suffix - if so, return as list + has_suffix = any(alias.suffix for alias in aliases) + # If has suffix and multiple values, return as list; + # else concatenate into a single string. + kwdict[option] = ( + values if has_suffix and len(values) > 1 else "".join(values) + ) elif aliases._value is not None: # A single Alias object and not None. kwdict[option] = aliases._value super().__init__(kwdict) diff --git a/pygmt/src/wiggle.py b/pygmt/src/wiggle.py index dd407acb9b1..1d6ade94987 100644 --- a/pygmt/src/wiggle.py +++ b/pygmt/src/wiggle.py @@ -11,33 +11,6 @@ from pygmt.helpers import build_arg_list, fmt_docstring, use_alias -def _parse_fills(fillpositive, fillnegative): - """ - Parse the fillpositive and fillnegative parameters. - - >>> _parse_fills("red", "blue") - ['red+p', 'blue+n'] - >>> _parse_fills(None, "blue") - 'blue+n' - >>> _parse_fills("red", None) - 'red+p' - >>> _parse_fills(None, None) - """ - _fills = [] - if fillpositive is not None: - _fills.append(fillpositive + "+p") - if fillnegative is not None: - _fills.append(fillnegative + "+n") - - match len(_fills): - case 0: - return None - case 1: - return _fills[0] - case 2: - return _fills - - @fmt_docstring @use_alias( D="position", @@ -138,10 +111,11 @@ def wiggle( # noqa: PLR0913 """ self._activate_figure() - _fills = _parse_fills(fillpositive, fillnegative) - aliasdict = AliasSystem( - G=Alias(_fills, name="fillpositive/fillnegative"), + G=[ + Alias(fillpositive, name="fillpositive", suffix="+p"), + Alias(fillnegative, name="fillnegative", suffix="+n"), + ], ).add_common( B=frame, J=projection,