diff --git a/doc/api/index.rst b/doc/api/index.rst index 646fb49886a..ac14604f2bb 100644 --- a/doc/api/index.rst +++ b/doc/api/index.rst @@ -206,6 +206,15 @@ Miscellaneous print_clib_info show_versions +Common Parameters +----------------- + +.. autosummary:: + :toctree: generated + + params.Box + + .. currentmodule:: pygmt Datasets diff --git a/pygmt/params/__init__.py b/pygmt/params/__init__.py new file mode 100644 index 00000000000..1b46e4117b5 --- /dev/null +++ b/pygmt/params/__init__.py @@ -0,0 +1,5 @@ +""" +Classes for common parameters. +""" + +from pygmt.params.box import Box diff --git a/pygmt/params/base.py b/pygmt/params/base.py new file mode 100644 index 00000000000..ba570308cb8 --- /dev/null +++ b/pygmt/params/base.py @@ -0,0 +1,75 @@ +""" +General class for PyGMT parameters. +""" + +from __future__ import annotations + +from typing import NamedTuple + +from pygmt.helpers import is_nonstr_iter + + +class Alias(NamedTuple): + """ + Alias PyGMT long-form parameter to GMT single-letter option flag. + """ + + name: str + modifier: str + separator: str | None = None + + +class BaseParams: + """ + Base class for PyGMT parameters. + + Examples + -------- + >>> import dataclasses + >>> from pygmt.params.base import BaseParams + >>> + >>> @dataclasses.dataclass(repr=False) + ... class Test(BaseParams): + ... attr1: Any = None + ... attr2: Any = None + ... attr3: Any = None + ... + ... __aliases__ = [ + ... Alias("attr1", ""), + ... Alias("attr2", "+a"), + ... Alias("attr3", "+b", "/"), + ... ] + >>> var = Test(attr1="val1") + >>> str(var) + 'val1' + >>> repr(var) + "Test(attr1='val1')" + """ + + def __str__(self): + """ + String representation of the object that can be passed to GMT directly. + """ + values = [] + for alias in self.__aliases__: + value = getattr(self, alias.name) + if value in (None, False): + continue + if value is True: + value = "" + elif is_nonstr_iter(value): + value = alias.separator.join(map(str, value)) + values.append(f"{alias.modifier}{value}") + return "".join(values) + + def __repr__(self): + """ + String representation of the object. + """ + string = [] + for alias in self.__aliases__: + value = getattr(self, alias.name) + if value is None or value is False: + continue + string.append(f"{alias.name}={value!r}") + return f"{self.__class__.__name__}({', '.join(string)})" diff --git a/pygmt/params/box.py b/pygmt/params/box.py new file mode 100644 index 00000000000..014b7a3270e --- /dev/null +++ b/pygmt/params/box.py @@ -0,0 +1,45 @@ +""" +Class for the box around GMT embellishments. +""" + +from collections.abc import Sequence +from dataclasses import dataclass +from typing import ClassVar + +from pygmt.params.base import Alias, BaseParams + + +@dataclass(repr=False) +class Box(BaseParams): + """ + Class for the box around GMT embellishments. + + Attributes + ---------- + clearance + Set clearances between the embellishment and the box border. Can be either a + scalar value or a list of two/four values. + + - a scalar value means a uniform clearance in all four directions. + - a list of two values means separate clearances in x- and y- directions. + - a list of four values means separate clearances for left/right/bottom/top. + fill + Fill for the box. None means no fill. + + """ + + clearance: float | str | Sequence[float | str] | None = None + fill: str | None = None + innerborder: str | Sequence | None = None + pen: str | None = None + radius: float | bool | None = False + shading: str | Sequence | None = None + + __aliases__: ClassVar = [ + Alias("clearance", "+c", "/"), + Alias("fill", "+g"), + Alias("innerborder", "+i", "/"), + Alias("pen", "+p"), + Alias("radius", "+r"), + Alias("shading", "+s", "/"), + ] diff --git a/pygmt/src/logo.py b/pygmt/src/logo.py index bab9c5dcd36..7c83153df2a 100644 --- a/pygmt/src/logo.py +++ b/pygmt/src/logo.py @@ -4,6 +4,7 @@ from pygmt.clib import Session from pygmt.helpers import build_arg_list, fmt_docstring, kwargs_to_strings, use_alias +from pygmt.params import Box @fmt_docstring @@ -18,7 +19,7 @@ t="transparency", ) @kwargs_to_strings(R="sequence", c="sequence_comma", p="sequence") -def logo(self, **kwargs): +def logo(self, box: bool | Box = False, **kwargs): # noqa: ARG001 r""" Plot the GMT logo. @@ -39,7 +40,7 @@ def logo(self, **kwargs): [**g**\|\ **j**\|\ **J**\|\ **n**\|\ **x**]\ *refpoint*\ **+w**\ *width*\ [**+j**\ *justify*]\ [**+o**\ *dx*\ [/*dy*]]. Set reference point on the map for the image. - box : bool or str + box If set to ``True``, draw a rectangular border around the GMT logo. style : str