From 88bcf727b518a95b4f99156bc8197f75eb7555c4 Mon Sep 17 00:00:00 2001 From: Dongdong Tian Date: Tue, 11 Nov 2025 14:03:59 +0800 Subject: [PATCH 01/11] Implement the Perspective class for specifying viewpoint --- doc/api/index.rst | 1 + pygmt/params/__init__.py | 1 + pygmt/params/perspective.py | 67 ++++++++++++++++++++++++++ pygmt/tests/test_params_perspective.py | 36 ++++++++++++++ 4 files changed, 105 insertions(+) create mode 100644 pygmt/params/perspective.py create mode 100644 pygmt/tests/test_params_perspective.py diff --git a/doc/api/index.rst b/doc/api/index.rst index 3656bba286e..63585003996 100644 --- a/doc/api/index.rst +++ b/doc/api/index.rst @@ -214,6 +214,7 @@ Class-style Parameters Box Pattern + Perspective Enums ----- diff --git a/pygmt/params/__init__.py b/pygmt/params/__init__.py index b80b921407a..498c5a05bf3 100644 --- a/pygmt/params/__init__.py +++ b/pygmt/params/__init__.py @@ -4,3 +4,4 @@ from pygmt.params.box import Box from pygmt.params.pattern import Pattern +from pygmt.params.perspective import Perspective diff --git a/pygmt/params/perspective.py b/pygmt/params/perspective.py new file mode 100644 index 00000000000..70cb1914c33 --- /dev/null +++ b/pygmt/params/perspective.py @@ -0,0 +1,67 @@ +""" +The Perspective class for setting perspective view. +""" + +import dataclasses +from collections.abc import Sequence +from typing import Literal + +from pygmt.alias import Alias +from pygmt.exceptions import GMTInvalidInput +from pygmt.params.base import BaseParam + + +@dataclasses.dataclass(repr=False) +class Perspective(BaseParam): + """ + Class for setting perspective view. + """ + + #: Azimuth of the viewpoint in degress. Default is 180.0 (looking from south to + #: north). + azimuth: float + + #: Elevation angle of the viewpoint in degrees. Default is 90.0 (looking from + #: directly above). + elevation: float | None = None + + #: The z-level at which all 2D material, like the plot frame, is plotted (only valid + #: when used in consort with ``zsize``/``zscale`` [Default is at the bottom of the + #: z-axis]. + zlevel: float | None = None + + #: The plane to plot against the “wall” x = level (using x) or y = level (using y) + #: or the horizontal plain (using z) [default is z]. + plane: Literal["x", "y", "z"] | None = None + + #: For frames used for animation, the center of the data domain is fixed. Specify + #: another center using one of the following parameters: + + #: (*lon0*, *lat0*) or (*lon0*, *lat0*, *z0*). + #: Project the specified coordinate to the center of the page size. + center: Sequence[float] | None = None + + #: (*x0*, *y0*). Specify the center in the projected coordinate system. + viewpoint: Sequence[float] | None = None + + def __post_init__(self): + """ + Post-initialization processing to validate parameters. + """ + if self.center is not None and self.viewpoint is not None: + msg = "Parameters 'center' and 'viewpoint' are mutually exclusive." + raise GMTInvalidInput(msg) + + @property + def _aliases(self): + """ + Aliases for the parameters. + """ + return [ + Alias(self.plane, name="plane"), + Alias(self.azimuth, name="azimuth"), + Alias(self.elevation, name="elevation", prefix="/"), + Alias(self.zlevel, name="zlevel", prefix="/"), + Alias(self.center, name="center", prefix="+w", sep="/", size={2, 3}), + Alias(self.viewpoint, name="viewpoint", prefix="+v", sep="/", size=2), + ] diff --git a/pygmt/tests/test_params_perspective.py b/pygmt/tests/test_params_perspective.py new file mode 100644 index 00000000000..18b4cacbe00 --- /dev/null +++ b/pygmt/tests/test_params_perspective.py @@ -0,0 +1,36 @@ +""" +Test the Perspective class. +""" + +import pytest +from pygmt.exceptions import GMTInvalidInput +from pygmt.params import Perspective + + +def test_params_perspective(): + """ + Test the Perspective class. + """ + assert str(Perspective(azimuth=120)) == "120" + assert str(Perspective(azimuth=120, elevation=30)) == "120/30" + assert str(Perspective(azimuth=120, elevation=30, zlevel=1000)) == "120/30/1000" + assert str(Perspective(azimuth=120, elevation=30, center=[0, 0])) == "120/30+w0/0" + + pp = Perspective(azimuth=120, elevation=30, center=(10, 20, 30)) + assert str(pp) == "120/30+w10/20/30" + + pp = Perspective(azimuth=120, elevation=30, viewpoint=[0, 0]) + assert str(pp) == "120/30+v0/0" + assert str(Perspective(azimuth=120, elevation=30, plane="x")) == "x120/30" + assert str(Perspective(azimuth=120, elevation=30, plane="y")) == "y120/30" + assert str(Perspective(azimuth=120, elevation=30, plane="z")) == "z120/30" + + +def test_params_viewpoint_center_exclusive(): + """ + Test that center and viewpoint are mutually exclusive. + """ + with pytest.raises(GMTInvalidInput): + _ = str( + Perspective(azimuth=120, elevation=30, center=(10, 20), viewpoint=(0, 0)) + ) From 02ae33914bec713da5b30ae9df8afab06c351a0a Mon Sep 17 00:00:00 2001 From: Dongdong Tian Date: Wed, 12 Nov 2025 15:58:49 +0800 Subject: [PATCH 02/11] Improve docstrings --- pygmt/params/perspective.py | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/pygmt/params/perspective.py b/pygmt/params/perspective.py index 70cb1914c33..a2a72277fc8 100644 --- a/pygmt/params/perspective.py +++ b/pygmt/params/perspective.py @@ -25,23 +25,23 @@ class Perspective(BaseParam): #: directly above). elevation: float | None = None - #: The z-level at which all 2D material, like the plot frame, is plotted (only valid - #: when used in consort with ``zsize``/``zscale`` [Default is at the bottom of the - #: z-axis]. + #: The z-level at which all 2-D material, like the plot frame, is plotted (only + #: valid when used in consort with parameters ``zsize``/``zscale``. Default is at + #: the bottom of the z-axis]. zlevel: float | None = None - #: The plane to plot against the “wall” x = level (using x) or y = level (using y) - #: or the horizontal plain (using z) [default is z]. + #: The plane to plot against the "wall" x = level (using x) or y = level (using y) + #: or the horizontal plain (using z). Default is the z-plane. plane: Literal["x", "y", "z"] | None = None #: For frames used for animation, the center of the data domain is fixed. Specify - #: another center using one of the following parameters: - - #: (*lon0*, *lat0*) or (*lon0*, *lat0*, *z0*). - #: Project the specified coordinate to the center of the page size. + #: another center using either parameters ``center`` or ``viewpoint``. + #: + #: Project the coordinate (*lon0*, *lat0*) or (*lon0*, *lat0*, *z0*) to the center + #: of the page size. center: Sequence[float] | None = None - #: (*x0*, *y0*). Specify the center in the projected coordinate system. + #: Specify the coordinates (*x0*, *y0*) of the projected 2-D view point. viewpoint: Sequence[float] | None = None def __post_init__(self): From 3be6a08bb136e9d172a67a58fad98c19d5f6b4d8 Mon Sep 17 00:00:00 2001 From: Dongdong Tian Date: Wed, 12 Nov 2025 16:03:12 +0800 Subject: [PATCH 03/11] Add a doctest --- pygmt/params/perspective.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/pygmt/params/perspective.py b/pygmt/params/perspective.py index a2a72277fc8..0e776506672 100644 --- a/pygmt/params/perspective.py +++ b/pygmt/params/perspective.py @@ -15,6 +15,20 @@ class Perspective(BaseParam): """ Class for setting perspective view. + + Examples + -------- + >>> import pygmt + >>> from pygmt.params import Perspective + >>> fig = pygmt.Figure() + >>> fig.basemap( + ... region=[0, 10, 0, 10, 0, 20], + ... projection="X3c", + ... zsize="3c", + ... frame=["xafg", "yafg", "zafg", "wSEnZ"], + ... perspective=Perspective(azimuth=135, elevation=40, zlevel=10), + ... ) + >>> fig.show() """ #: Azimuth of the viewpoint in degress. Default is 180.0 (looking from south to From 202cf2207e95a8f2ba82a6fc671e85e539f7d502 Mon Sep 17 00:00:00 2001 From: Dongdong Tian Date: Sat, 15 Nov 2025 12:47:41 +0800 Subject: [PATCH 04/11] Improve the class --- pygmt/params/perspective.py | 17 +++++++++++++---- pygmt/tests/test_params_perspective.py | 25 +++++++++++++++++++------ 2 files changed, 32 insertions(+), 10 deletions(-) diff --git a/pygmt/params/perspective.py b/pygmt/params/perspective.py index 0e776506672..c67889eab50 100644 --- a/pygmt/params/perspective.py +++ b/pygmt/params/perspective.py @@ -33,15 +33,15 @@ class Perspective(BaseParam): #: Azimuth of the viewpoint in degress. Default is 180.0 (looking from south to #: north). - azimuth: float + azimuth: float | None = None - #: Elevation angle of the viewpoint in degrees. Default is 90.0 (looking from - #: directly above). + #: Elevation angle of the viewpoint in degrees. Default is 90.0 (looking straight + #: down at nadir). elevation: float | None = None #: The z-level at which all 2-D material, like the plot frame, is plotted (only #: valid when used in consort with parameters ``zsize``/``zscale``. Default is at - #: the bottom of the z-axis]. + #: the bottom of the z-axis. zlevel: float | None = None #: The plane to plot against the "wall" x = level (using x) or y = level (using y) @@ -62,10 +62,19 @@ def __post_init__(self): """ Post-initialization processing to validate parameters. """ + # Ensure that center and viewpoint are mutually exclusive. if self.center is not None and self.viewpoint is not None: msg = "Parameters 'center' and 'viewpoint' are mutually exclusive." raise GMTInvalidInput(msg) + # azimuth is required, so it must be set to the default if not specified. + if self.azimuth is None: + self.azimuth = 180.0 # Default azimuth is 180.0 + + # Set default elevation if zlevel is set but elevation is not. + if self.zlevel is not None and self.elevation is None: + self.elevation = 90.0 # Default elevation is 90.0 + @property def _aliases(self): """ diff --git a/pygmt/tests/test_params_perspective.py b/pygmt/tests/test_params_perspective.py index 18b4cacbe00..fddf02dc7c9 100644 --- a/pygmt/tests/test_params_perspective.py +++ b/pygmt/tests/test_params_perspective.py @@ -9,21 +9,36 @@ def test_params_perspective(): """ - Test the Perspective class. + Test the Perspective class with various parameters. """ + # Test azimuth, elevation, and zlevel separately assert str(Perspective(azimuth=120)) == "120" + assert str(Perspective(elevation=30)) == "180.0/30" + assert str(Perspective(zlevel=1000)) == "180.0/90.0/1000" + + # Test combinations of azimuth, elevation, and zlevel assert str(Perspective(azimuth=120, elevation=30)) == "120/30" assert str(Perspective(azimuth=120, elevation=30, zlevel=1000)) == "120/30/1000" - assert str(Perspective(azimuth=120, elevation=30, center=[0, 0])) == "120/30+w0/0" + assert str(Perspective(elevation=30, zlevel=1000)) == "180.0/30/1000" + # Test center parameter + assert str(Perspective(center=(10, 20))) == "180.0/90.0+w10/20" + assert str(Perspective(azimuth=120, elevation=30, center=(0, 0))) == "120/30+w0/0" pp = Perspective(azimuth=120, elevation=30, center=(10, 20, 30)) assert str(pp) == "120/30+w10/20/30" - pp = Perspective(azimuth=120, elevation=30, viewpoint=[0, 0]) + # Test viewpoint parameter + assert str(Perspective(viewpoint=(10, 20))) == "180.0+v10/20" + pp = Perspective(azimuth=120, elevation=30, viewpoint=(0, 0)) assert str(pp) == "120/30+v0/0" + + # Test plane parameter assert str(Perspective(azimuth=120, elevation=30, plane="x")) == "x120/30" assert str(Perspective(azimuth=120, elevation=30, plane="y")) == "y120/30" assert str(Perspective(azimuth=120, elevation=30, plane="z")) == "z120/30" + pp = Perspective(azimuth=120, elevation=30, plane="x", viewpoint=(0, 0)) + assert str(pp) == "x120/30+v0/0" + assert str(Perspective(plane="y")) == "y180.0" def test_params_viewpoint_center_exclusive(): @@ -31,6 +46,4 @@ def test_params_viewpoint_center_exclusive(): Test that center and viewpoint are mutually exclusive. """ with pytest.raises(GMTInvalidInput): - _ = str( - Perspective(azimuth=120, elevation=30, center=(10, 20), viewpoint=(0, 0)) - ) + _ = Perspective(azimuth=120, elevation=30, center=(10, 20), viewpoint=(0, 0)) From 9807b0b31d22b05d7941e2cb66973969ff065062 Mon Sep 17 00:00:00 2001 From: Dongdong Tian Date: Thu, 25 Jun 2026 20:36:55 +0800 Subject: [PATCH 05/11] Remove some parameters --- pygmt/params/perspective.py | 36 +++++++++----------------- pygmt/tests/test_params_perspective.py | 23 ++++------------ 2 files changed, 17 insertions(+), 42 deletions(-) diff --git a/pygmt/params/perspective.py b/pygmt/params/perspective.py index c67889eab50..98372ca7e7b 100644 --- a/pygmt/params/perspective.py +++ b/pygmt/params/perspective.py @@ -3,11 +3,10 @@ """ import dataclasses -from collections.abc import Sequence from typing import Literal from pygmt.alias import Alias -from pygmt.exceptions import GMTInvalidInput +from pygmt.exceptions import GMTValueError from pygmt.params.base import BaseParam @@ -31,7 +30,7 @@ class Perspective(BaseParam): >>> fig.show() """ - #: Azimuth of the viewpoint in degress. Default is 180.0 (looking from south to + #: Azimuth of the viewpoint in degrees. Default is 180.0 (looking from south to #: north). azimuth: float | None = None @@ -39,34 +38,20 @@ class Perspective(BaseParam): #: down at nadir). elevation: float | None = None - #: The z-level at which all 2-D material, like the plot frame, is plotted (only - #: valid when used in consort with parameters ``zsize``/``zscale``. Default is at + #: The z-level at which all 2-D material, like the plot frame, is plotted. Only + #: valid when used together with parameters ``zsize``/``zscale``. Default is at #: the bottom of the z-axis. zlevel: float | None = None - #: The plane to plot against the "wall" x = level (using x) or y = level (using y) - #: or the horizontal plain (using z). Default is the z-plane. + #: Set which constant-coordinate plane is used as the plotting plane. Use ``"x"`` + #: for the x-plane, ``"y"`` for the y-plane, or ``"z"`` for the horizontal z-plane + # [Default is ``"z"``]. plane: Literal["x", "y", "z"] | None = None - #: For frames used for animation, the center of the data domain is fixed. Specify - #: another center using either parameters ``center`` or ``viewpoint``. - #: - #: Project the coordinate (*lon0*, *lat0*) or (*lon0*, *lat0*, *z0*) to the center - #: of the page size. - center: Sequence[float] | None = None - - #: Specify the coordinates (*x0*, *y0*) of the projected 2-D view point. - viewpoint: Sequence[float] | None = None - def __post_init__(self): """ Post-initialization processing to validate parameters. """ - # Ensure that center and viewpoint are mutually exclusive. - if self.center is not None and self.viewpoint is not None: - msg = "Parameters 'center' and 'viewpoint' are mutually exclusive." - raise GMTInvalidInput(msg) - # azimuth is required, so it must be set to the default if not specified. if self.azimuth is None: self.azimuth = 180.0 # Default azimuth is 180.0 @@ -75,6 +60,11 @@ def __post_init__(self): if self.zlevel is not None and self.elevation is None: self.elevation = 90.0 # Default elevation is 90.0 + if self.plane is not None and self.plane not in {"x", "y", "z"}: + raise GMTValueError( + self.plane, description="plane", choices=["x", "y", "z"] + ) + @property def _aliases(self): """ @@ -85,6 +75,4 @@ def _aliases(self): Alias(self.azimuth, name="azimuth"), Alias(self.elevation, name="elevation", prefix="/"), Alias(self.zlevel, name="zlevel", prefix="/"), - Alias(self.center, name="center", prefix="+w", sep="/", size={2, 3}), - Alias(self.viewpoint, name="viewpoint", prefix="+v", sep="/", size=2), ] diff --git a/pygmt/tests/test_params_perspective.py b/pygmt/tests/test_params_perspective.py index fddf02dc7c9..6927ca835a9 100644 --- a/pygmt/tests/test_params_perspective.py +++ b/pygmt/tests/test_params_perspective.py @@ -3,7 +3,7 @@ """ import pytest -from pygmt.exceptions import GMTInvalidInput +from pygmt.exceptions import GMTValueError from pygmt.params import Perspective @@ -21,29 +21,16 @@ def test_params_perspective(): assert str(Perspective(azimuth=120, elevation=30, zlevel=1000)) == "120/30/1000" assert str(Perspective(elevation=30, zlevel=1000)) == "180.0/30/1000" - # Test center parameter - assert str(Perspective(center=(10, 20))) == "180.0/90.0+w10/20" - assert str(Perspective(azimuth=120, elevation=30, center=(0, 0))) == "120/30+w0/0" - pp = Perspective(azimuth=120, elevation=30, center=(10, 20, 30)) - assert str(pp) == "120/30+w10/20/30" - - # Test viewpoint parameter - assert str(Perspective(viewpoint=(10, 20))) == "180.0+v10/20" - pp = Perspective(azimuth=120, elevation=30, viewpoint=(0, 0)) - assert str(pp) == "120/30+v0/0" - # Test plane parameter assert str(Perspective(azimuth=120, elevation=30, plane="x")) == "x120/30" assert str(Perspective(azimuth=120, elevation=30, plane="y")) == "y120/30" assert str(Perspective(azimuth=120, elevation=30, plane="z")) == "z120/30" - pp = Perspective(azimuth=120, elevation=30, plane="x", viewpoint=(0, 0)) - assert str(pp) == "x120/30+v0/0" assert str(Perspective(plane="y")) == "y180.0" -def test_params_viewpoint_center_exclusive(): +def test_params_perspective_invalid_plane(): """ - Test that center and viewpoint are mutually exclusive. + Test that an invalid plane raises an error. """ - with pytest.raises(GMTInvalidInput): - _ = Perspective(azimuth=120, elevation=30, center=(10, 20), viewpoint=(0, 0)) + with pytest.raises(GMTValueError): + str(Perspective(plane="bad")) From e9aa78f5d10cae616285045a744238437c9ff258 Mon Sep 17 00:00:00 2001 From: Dongdong Tian Date: Thu, 25 Jun 2026 22:40:10 +0800 Subject: [PATCH 06/11] Rename zlevel to level --- pygmt/helpers/decorators.py | 4 ++-- pygmt/params/perspective.py | 16 ++++++++-------- pygmt/tests/test_params_perspective.py | 10 +++++----- 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/pygmt/helpers/decorators.py b/pygmt/helpers/decorators.py index 53c7e1f1d29..cd462dbaba7 100644 --- a/pygmt/helpers/decorators.py +++ b/pygmt/helpers/decorators.py @@ -278,13 +278,13 @@ Select perspective view and set the azimuth and elevation of the viewpoint. Accepts a single value or a sequence of two or three values: *azimuth*, - (*azimuth*, *elevation*), or (*azimuth*, *elevation*, *zlevel*). + (*azimuth*, *elevation*), or (*azimuth*, *elevation*, *level*). - *azimuth*: Azimuth angle of the viewpoint in degrees [Default is 180, i.e., looking from south to north]. - *elevation*: Elevation angle of the viewpoint above the horizon [Default is 90, i.e., looking straight down at nadir]. - - *zlevel*: Z-level at which 2-D elements (e.g., the plot frame) are drawn. + - *level*: Z-level at which 2-D elements (e.g., the plot frame) are drawn. Only applied when used together with ``zsize`` or ``zscale``. [Default is at the bottom of the z-axis]. diff --git a/pygmt/params/perspective.py b/pygmt/params/perspective.py index 98372ca7e7b..dc50ac0861b 100644 --- a/pygmt/params/perspective.py +++ b/pygmt/params/perspective.py @@ -25,7 +25,7 @@ class Perspective(BaseParam): ... projection="X3c", ... zsize="3c", ... frame=["xafg", "yafg", "zafg", "wSEnZ"], - ... perspective=Perspective(azimuth=135, elevation=40, zlevel=10), + ... perspective=Perspective(azimuth=135, elevation=40, level=10), ... ) >>> fig.show() """ @@ -38,10 +38,10 @@ class Perspective(BaseParam): #: down at nadir). elevation: float | None = None - #: The z-level at which all 2-D material, like the plot frame, is plotted. Only - #: valid when used together with parameters ``zsize``/``zscale``. Default is at - #: the bottom of the z-axis. - zlevel: float | None = None + #: The level at which all 2-D material, like the plot frame, is plotted. Only valid + #: when used together with parameters ``zsize``/``zscale``. Default is at the bottom + #: of the z-axis. + level: float | None = None #: Set which constant-coordinate plane is used as the plotting plane. Use ``"x"`` #: for the x-plane, ``"y"`` for the y-plane, or ``"z"`` for the horizontal z-plane @@ -56,8 +56,8 @@ def __post_init__(self): if self.azimuth is None: self.azimuth = 180.0 # Default azimuth is 180.0 - # Set default elevation if zlevel is set but elevation is not. - if self.zlevel is not None and self.elevation is None: + # Set default elevation if level is set but elevation is not. + if self.level is not None and self.elevation is None: self.elevation = 90.0 # Default elevation is 90.0 if self.plane is not None and self.plane not in {"x", "y", "z"}: @@ -74,5 +74,5 @@ def _aliases(self): Alias(self.plane, name="plane"), Alias(self.azimuth, name="azimuth"), Alias(self.elevation, name="elevation", prefix="/"), - Alias(self.zlevel, name="zlevel", prefix="/"), + Alias(self.level, name="level", prefix="/"), ] diff --git a/pygmt/tests/test_params_perspective.py b/pygmt/tests/test_params_perspective.py index 6927ca835a9..aed5a1560e9 100644 --- a/pygmt/tests/test_params_perspective.py +++ b/pygmt/tests/test_params_perspective.py @@ -11,15 +11,15 @@ def test_params_perspective(): """ Test the Perspective class with various parameters. """ - # Test azimuth, elevation, and zlevel separately + # Test azimuth, elevation, and level separately assert str(Perspective(azimuth=120)) == "120" assert str(Perspective(elevation=30)) == "180.0/30" - assert str(Perspective(zlevel=1000)) == "180.0/90.0/1000" + assert str(Perspective(level=1000)) == "180.0/90.0/1000" - # Test combinations of azimuth, elevation, and zlevel + # Test combinations of azimuth, elevation, and level assert str(Perspective(azimuth=120, elevation=30)) == "120/30" - assert str(Perspective(azimuth=120, elevation=30, zlevel=1000)) == "120/30/1000" - assert str(Perspective(elevation=30, zlevel=1000)) == "180.0/30/1000" + assert str(Perspective(azimuth=120, elevation=30, level=1000)) == "120/30/1000" + assert str(Perspective(elevation=30, level=1000)) == "180.0/30/1000" # Test plane parameter assert str(Perspective(azimuth=120, elevation=30, plane="x")) == "x120/30" From ad7e33875869b4e864c232d3cc303ac8162833d6 Mon Sep 17 00:00:00 2001 From: Dongdong Tian Date: Thu, 25 Jun 2026 22:51:32 +0800 Subject: [PATCH 07/11] Skip doctest and use _validate --- pygmt/params/perspective.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/pygmt/params/perspective.py b/pygmt/params/perspective.py index dc50ac0861b..6acde229c42 100644 --- a/pygmt/params/perspective.py +++ b/pygmt/params/perspective.py @@ -9,6 +9,8 @@ from pygmt.exceptions import GMTValueError from pygmt.params.base import BaseParam +__doctest_skip__ = ["Perspective"] + @dataclasses.dataclass(repr=False) class Perspective(BaseParam): @@ -48,7 +50,7 @@ class Perspective(BaseParam): # [Default is ``"z"``]. plane: Literal["x", "y", "z"] | None = None - def __post_init__(self): + def _validate(self): """ Post-initialization processing to validate parameters. """ From af31b7a561b6f8c89f4e4a6e7cfbda6c37be46e8 Mon Sep 17 00:00:00 2001 From: Dongdong Tian Date: Fri, 26 Jun 2026 00:13:05 +0800 Subject: [PATCH 08/11] Update type hints for the perspective parameter --- pygmt/helpers/decorators.py | 7 +++++-- pygmt/src/basemap.py | 4 ++-- pygmt/src/coast.py | 4 ++-- pygmt/src/colorbar.py | 4 ++-- pygmt/src/contour.py | 4 ++-- pygmt/src/directional_rose.py | 4 ++-- pygmt/src/fill_between.py | 4 ++-- pygmt/src/grdcontour.py | 4 ++-- pygmt/src/grdimage.py | 4 ++-- pygmt/src/grdview.py | 3 ++- pygmt/src/histogram.py | 4 ++-- pygmt/src/hlines.py | 3 ++- pygmt/src/image.py | 4 ++-- pygmt/src/legend.py | 4 ++-- pygmt/src/logo.py | 4 ++-- pygmt/src/magnetic_rose.py | 4 ++-- pygmt/src/meca.py | 3 ++- pygmt/src/plot.py | 4 ++-- pygmt/src/plot3d.py | 4 ++-- pygmt/src/rose.py | 4 ++-- pygmt/src/scalebar.py | 4 ++-- pygmt/src/solar.py | 4 ++-- pygmt/src/ternary.py | 4 ++-- pygmt/src/text.py | 10 ++++++++-- pygmt/src/tilemap.py | 4 ++-- pygmt/src/velo.py | 4 ++-- pygmt/src/vlines.py | 3 ++- pygmt/src/wiggle.py | 4 ++-- 28 files changed, 65 insertions(+), 52 deletions(-) diff --git a/pygmt/helpers/decorators.py b/pygmt/helpers/decorators.py index cd462dbaba7..c8f74a1380f 100644 --- a/pygmt/helpers/decorators.py +++ b/pygmt/helpers/decorators.py @@ -277,8 +277,9 @@ perspective Select perspective view and set the azimuth and elevation of the viewpoint. - Accepts a single value or a sequence of two or three values: *azimuth*, - (*azimuth*, *elevation*), or (*azimuth*, *elevation*, *level*). + Accepts a :class:`pygmt.params.Perspective` object, a single value, or a + sequence of two or three values: *azimuth*, (*azimuth*, *elevation*), or + (*azimuth*, *elevation*, *level*). - *azimuth*: Azimuth angle of the viewpoint in degrees [Default is 180, i.e., looking from south to north]. @@ -287,6 +288,8 @@ - *level*: Z-level at which 2-D elements (e.g., the plot frame) are drawn. Only applied when used together with ``zsize`` or ``zscale``. [Default is at the bottom of the z-axis]. + - :class:`pygmt.params.Perspective`: A class-style way to specify the same + perspective parameters. Alternatively, set ``perspective=True`` to reuse the perspective setting from the previous plotting method, or pass a string following the full diff --git a/pygmt/src/basemap.py b/pygmt/src/basemap.py index ccb24b7b713..074fe3856ad 100644 --- a/pygmt/src/basemap.py +++ b/pygmt/src/basemap.py @@ -9,7 +9,7 @@ from pygmt.alias import Alias, AliasSystem from pygmt.clib import Session from pygmt.helpers import build_arg_list, fmt_docstring, is_given, use_alias -from pygmt.params import Axis, Box, Frame +from pygmt.params import Axis, Box, Frame, Perspective @fmt_docstring @@ -28,7 +28,7 @@ def basemap( # noqa: PLR0913 rose: str | None = None, box: Box | str | bool = False, panel: int | Sequence[int] | bool = False, - perspective: float | Sequence[float] | str | bool = False, + perspective: Perspective | float | Sequence[float] | bool = False, transparency: float | None = None, **kwargs, ): diff --git a/pygmt/src/coast.py b/pygmt/src/coast.py index e359f28662a..1cbfc93271b 100644 --- a/pygmt/src/coast.py +++ b/pygmt/src/coast.py @@ -9,7 +9,7 @@ from pygmt.clib import Session from pygmt.exceptions import GMTParameterError from pygmt.helpers import args_in_kwargs, build_arg_list, fmt_docstring, use_alias -from pygmt.params import Axis, Box, Frame +from pygmt.params import Axis, Box, Frame, Perspective __doctest_skip__ = ["coast"] @@ -34,7 +34,7 @@ def coast( # noqa: PLR0913 verbose: Literal["quiet", "error", "warning", "timing", "info", "compat", "debug"] | bool = False, panel: int | Sequence[int] | bool = False, - perspective: float | Sequence[float] | str | bool = False, + perspective: Perspective | float | Sequence[float] | bool = False, transparency: float | None = None, **kwargs, ): diff --git a/pygmt/src/colorbar.py b/pygmt/src/colorbar.py index 8b4e4d7d7a3..161d54b2cf0 100644 --- a/pygmt/src/colorbar.py +++ b/pygmt/src/colorbar.py @@ -11,7 +11,7 @@ from pygmt.exceptions import GMTValueError from pygmt.helpers import build_arg_list, fmt_docstring, is_given, use_alias from pygmt.helpers.utils import is_nonstr_iter -from pygmt.params import Axis, Box, Frame, Position +from pygmt.params import Axis, Box, Frame, Perspective, Position from pygmt.src._common import _parse_position __doctest_skip__ = ["colorbar"] @@ -277,7 +277,7 @@ def colorbar( # noqa: PLR0913 verbose: Literal["quiet", "error", "warning", "timing", "info", "compat", "debug"] | bool = False, panel: int | Sequence[int] | bool = False, - perspective: float | Sequence[float] | str | bool = False, + perspective: Perspective | float | Sequence[float] | bool = False, transparency: float | None = None, **kwargs, ): diff --git a/pygmt/src/contour.py b/pygmt/src/contour.py index c0b2878e645..2f255bcb32e 100644 --- a/pygmt/src/contour.py +++ b/pygmt/src/contour.py @@ -14,7 +14,7 @@ is_nonstr_iter, use_alias, ) -from pygmt.params import Axis, Frame +from pygmt.params import Axis, Frame, Perspective @fmt_docstring @@ -46,7 +46,7 @@ def contour( # noqa: PLR0913 | bool = False, panel: int | Sequence[int] | bool = False, incols: int | str | Sequence[int | str] | None = None, - perspective: float | Sequence[float] | str | bool = False, + perspective: Perspective | float | Sequence[float] | bool = False, transparency: float | None = None, **kwargs, ): diff --git a/pygmt/src/directional_rose.py b/pygmt/src/directional_rose.py index fbeab2dc106..e690e7e60b7 100644 --- a/pygmt/src/directional_rose.py +++ b/pygmt/src/directional_rose.py @@ -9,7 +9,7 @@ from pygmt.alias import Alias, AliasSystem from pygmt.clib import Session from pygmt.helpers import build_arg_list, fmt_docstring -from pygmt.params import Box, Position +from pygmt.params import Box, Perspective, Position from pygmt.src._common import _parse_position __doctest_skip__ = ["directional_rose"] @@ -26,7 +26,7 @@ def directional_rose( verbose: Literal["quiet", "error", "warning", "timing", "info", "compat", "debug"] | bool = False, panel: int | Sequence[int] | bool = False, - perspective: float | Sequence[float] | str | bool = False, + perspective: Perspective | float | Sequence[float] | bool = False, transparency: float | None = None, ): """ diff --git a/pygmt/src/fill_between.py b/pygmt/src/fill_between.py index 2b280fe9e0b..dc69c41a5f5 100644 --- a/pygmt/src/fill_between.py +++ b/pygmt/src/fill_between.py @@ -10,7 +10,7 @@ from pygmt.clib import Session from pygmt.exceptions import GMTValueError from pygmt.helpers import build_arg_list, fmt_docstring -from pygmt.params import Axis, Frame +from pygmt.params import Axis, Frame, Perspective __doctest_skip__ = ["fill_between"] @@ -36,7 +36,7 @@ def fill_between( # noqa: PLR0913 verbose: Literal["quiet", "error", "warning", "timing", "info", "compat", "debug"] | bool = False, panel: int | Sequence[int] | bool = False, - perspective: float | Sequence[float] | str | bool = False, + perspective: Perspective | float | Sequence[float] | bool = False, transparency: float | None = None, ): """ diff --git a/pygmt/src/grdcontour.py b/pygmt/src/grdcontour.py index 07b9b144cc6..0011432cf93 100644 --- a/pygmt/src/grdcontour.py +++ b/pygmt/src/grdcontour.py @@ -17,7 +17,7 @@ kwargs_to_strings, use_alias, ) -from pygmt.params import Axis, Frame +from pygmt.params import Axis, Frame, Perspective __doctest_skip__ = ["grdcontour"] @@ -45,7 +45,7 @@ def grdcontour( verbose: Literal["quiet", "error", "warning", "timing", "info", "compat", "debug"] | bool = False, panel: int | Sequence[int] | bool = False, - perspective: float | Sequence[float] | str | bool = False, + perspective: Perspective | float | Sequence[float] | bool = False, transparency: float | None = None, **kwargs, ): diff --git a/pygmt/src/grdimage.py b/pygmt/src/grdimage.py index 59c3c10cdaa..3d875b91907 100644 --- a/pygmt/src/grdimage.py +++ b/pygmt/src/grdimage.py @@ -10,7 +10,7 @@ from pygmt.alias import Alias, AliasSystem from pygmt.clib import Session from pygmt.helpers import build_arg_list, fmt_docstring, use_alias -from pygmt.params import Axis, Frame +from pygmt.params import Axis, Frame, Perspective __doctest_skip__ = ["grdimage"] @@ -37,7 +37,7 @@ def grdimage( # noqa: PLR0913 verbose: Literal["quiet", "error", "warning", "timing", "info", "compat", "debug"] | bool = False, panel: int | Sequence[int] | bool = False, - perspective: float | Sequence[float] | str | bool = False, + perspective: Perspective | float | Sequence[float] | bool = False, transparency: float | None = None, cores: int | bool = False, **kwargs, diff --git a/pygmt/src/grdview.py b/pygmt/src/grdview.py index 5fae8666fec..7f96b0854dc 100644 --- a/pygmt/src/grdview.py +++ b/pygmt/src/grdview.py @@ -18,6 +18,7 @@ is_given, use_alias, ) +from pygmt.params import Perspective from pygmt.params import Axis, Frame from pygmt.src.grdinfo import grdinfo @@ -148,7 +149,7 @@ def grdview( # noqa: PLR0913 verbose: Literal["quiet", "error", "warning", "timing", "info", "compat", "debug"] | bool = False, panel: int | Sequence[int] | bool = False, - perspective: float | Sequence[float] | str | bool = False, + perspective: Perspective | float | Sequence[float] | bool = False, transparency: float | None = None, **kwargs, ): diff --git a/pygmt/src/histogram.py b/pygmt/src/histogram.py index f89b0b047ea..c8548bbccc6 100644 --- a/pygmt/src/histogram.py +++ b/pygmt/src/histogram.py @@ -16,7 +16,7 @@ kwargs_to_strings, use_alias, ) -from pygmt.params import Axis, Frame +from pygmt.params import Axis, Frame, Perspective @fmt_docstring @@ -55,7 +55,7 @@ def histogram( # noqa: PLR0913 | bool = False, panel: int | Sequence[int] | bool = False, incols: int | str | Sequence[int | str] | None = None, - perspective: float | Sequence[float] | str | bool = False, + perspective: Perspective | float | Sequence[float] | bool = False, transparency: float | None = None, **kwargs, ): diff --git a/pygmt/src/hlines.py b/pygmt/src/hlines.py index c5ae316c1e5..39b76dacc38 100644 --- a/pygmt/src/hlines.py +++ b/pygmt/src/hlines.py @@ -6,6 +6,7 @@ import numpy as np from pygmt.exceptions import GMTValueError +from pygmt.params import Perspective __doctest_skip__ = ["hlines"] @@ -18,7 +19,7 @@ def hlines( pen: str | None = None, label: str | None = None, no_clip: bool = False, - perspective: str | bool | None = None, + perspective: Perspective | float | Sequence[float] | bool | None = None, ): """ Plot one or multiple horizontal line(s). diff --git a/pygmt/src/image.py b/pygmt/src/image.py index 5ed843d0e55..37a2413c4da 100644 --- a/pygmt/src/image.py +++ b/pygmt/src/image.py @@ -9,7 +9,7 @@ from pygmt.alias import Alias, AliasSystem from pygmt.clib import Session from pygmt.helpers import build_arg_list, fmt_docstring, use_alias -from pygmt.params import Axis, Box, Frame, Position +from pygmt.params import Axis, Box, Frame, Perspective, Position from pygmt.src._common import _parse_position @@ -32,7 +32,7 @@ def image( # noqa: PLR0913 verbose: Literal["quiet", "error", "warning", "timing", "info", "compat", "debug"] | bool = False, panel: int | Sequence[int] | bool = False, - perspective: float | Sequence[float] | str | bool = False, + perspective: Perspective | float | Sequence[float] | bool = False, transparency: float | None = None, **kwargs, ): diff --git a/pygmt/src/legend.py b/pygmt/src/legend.py index 03cd1929094..a63c13c7526 100644 --- a/pygmt/src/legend.py +++ b/pygmt/src/legend.py @@ -11,7 +11,7 @@ from pygmt.clib import Session from pygmt.exceptions import GMTTypeError from pygmt.helpers import build_arg_list, data_kind, fmt_docstring, is_nonstr_iter -from pygmt.params import Axis, Box, Frame, Position +from pygmt.params import Axis, Box, Frame, Perspective, Position from pygmt.src._common import _parse_position @@ -31,7 +31,7 @@ def legend( # noqa: PLR0913 verbose: Literal["quiet", "error", "warning", "timing", "info", "compat", "debug"] | bool = False, panel: int | Sequence[int] | bool = False, - perspective: float | Sequence[float] | str | bool = False, + perspective: Perspective | float | Sequence[float] | bool = False, transparency: float | None = None, **kwargs, ): diff --git a/pygmt/src/logo.py b/pygmt/src/logo.py index b669ae6497c..1d640ca3293 100644 --- a/pygmt/src/logo.py +++ b/pygmt/src/logo.py @@ -10,7 +10,7 @@ from pygmt.clib import Session from pygmt.exceptions import GMTParameterError from pygmt.helpers import build_arg_list, fmt_docstring -from pygmt.params import Box, Position +from pygmt.params import Box, Perspective, Position from pygmt.src._common import _parse_position __doctest_skip__ = ["logo"] @@ -29,7 +29,7 @@ def logo( # noqa: PLR0913 verbose: Literal["quiet", "error", "warning", "timing", "info", "compat", "debug"] | bool = False, panel: int | Sequence[int] | bool = False, - perspective: float | Sequence[float] | str | bool = False, + perspective: Perspective | float | Sequence[float] | bool = False, transparency: float | None = None, **kwargs, ): diff --git a/pygmt/src/magnetic_rose.py b/pygmt/src/magnetic_rose.py index 41e8f751ab1..33f69479a08 100644 --- a/pygmt/src/magnetic_rose.py +++ b/pygmt/src/magnetic_rose.py @@ -10,7 +10,7 @@ from pygmt.clib import Session from pygmt.exceptions import GMTParameterError from pygmt.helpers import build_arg_list, fmt_docstring -from pygmt.params import Box, Position +from pygmt.params import Box, Perspective, Position from pygmt.src._common import _parse_position __doctest_skip__ = ["magnetic_rose"] @@ -31,7 +31,7 @@ def magnetic_rose( # noqa: PLR0913 verbose: Literal["quiet", "error", "warning", "timing", "info", "compat", "debug"] | bool = False, panel: int | Sequence[int] | bool = False, - perspective: float | Sequence[float] | str | bool = False, + perspective: Perspective | float | Sequence[float] | bool = False, transparency: float | None = None, ): """ diff --git a/pygmt/src/meca.py b/pygmt/src/meca.py index a0d35b7aa56..b5edfee6ba1 100644 --- a/pygmt/src/meca.py +++ b/pygmt/src/meca.py @@ -18,6 +18,7 @@ fmt_docstring, use_alias, ) +from pygmt.params import Perspective from pygmt.params import Axis, Frame from pygmt.src._common import _FocalMechanismConvention @@ -155,7 +156,7 @@ def meca( # noqa: PLR0913 | bool = False, panel: int | Sequence[int] | bool = False, transparency: float | None = None, - perspective: float | Sequence[float] | str | bool = False, + perspective: Perspective | float | Sequence[float] | bool = False, **kwargs, ): r""" diff --git a/pygmt/src/plot.py b/pygmt/src/plot.py index 2900296d7f7..92838e9b893 100644 --- a/pygmt/src/plot.py +++ b/pygmt/src/plot.py @@ -16,7 +16,7 @@ is_nonstr_iter, use_alias, ) -from pygmt.params import Axis, Frame +from pygmt.params import Axis, Frame, Perspective from pygmt.src._common import _data_geometry_is_point @@ -59,7 +59,7 @@ def plot( # noqa: PLR0912, PLR0913 | bool = False, panel: int | Sequence[int] | bool = False, incols: int | str | Sequence[int | str] | None = None, - perspective: float | Sequence[float] | str | bool = False, + perspective: Perspective | float | Sequence[float] | bool = False, transparency: float | Sequence[float] | bool | None = None, **kwargs, ): diff --git a/pygmt/src/plot3d.py b/pygmt/src/plot3d.py index 12ebd3ffa8c..e151ec5b9d6 100644 --- a/pygmt/src/plot3d.py +++ b/pygmt/src/plot3d.py @@ -16,7 +16,7 @@ is_nonstr_iter, use_alias, ) -from pygmt.params import Axis, Frame +from pygmt.params import Axis, Frame, Perspective from pygmt.src._common import _data_geometry_is_point @@ -61,7 +61,7 @@ def plot3d( # noqa: PLR0912, PLR0913 | bool = False, panel: int | Sequence[int] | bool = False, incols: int | str | Sequence[int | str] | None = None, - perspective: float | Sequence[float] | str | bool = False, + perspective: Perspective | float | Sequence[float] | bool = False, transparency: float | Sequence[float] | bool | None = None, **kwargs, ): diff --git a/pygmt/src/rose.py b/pygmt/src/rose.py index 6f77530f905..ab0b93562eb 100644 --- a/pygmt/src/rose.py +++ b/pygmt/src/rose.py @@ -9,7 +9,7 @@ from pygmt.alias import AliasSystem from pygmt.clib import Session from pygmt.helpers import build_arg_list, fmt_docstring, use_alias -from pygmt.params import Axis, Frame +from pygmt.params import Axis, Frame, Perspective @fmt_docstring @@ -46,7 +46,7 @@ def rose( # noqa: PLR0913 | bool = False, panel: int | Sequence[int] | bool = False, incols: int | str | Sequence[int | str] | None = None, - perspective: float | Sequence[float] | str | bool = False, + perspective: Perspective | float | Sequence[float] | bool = False, transparency: float | None = None, **kwargs, ): diff --git a/pygmt/src/scalebar.py b/pygmt/src/scalebar.py index 918d10bbcd5..186c28e0761 100644 --- a/pygmt/src/scalebar.py +++ b/pygmt/src/scalebar.py @@ -9,7 +9,7 @@ from pygmt.alias import Alias, AliasSystem from pygmt.clib import Session from pygmt.helpers import build_arg_list, fmt_docstring -from pygmt.params import Box, Position +from pygmt.params import Box, Perspective, Position from pygmt.src._common import _parse_position __doctest_skip__ = ["scalebar"] @@ -31,7 +31,7 @@ def scalebar( # noqa: PLR0913 verbose: Literal["quiet", "error", "warning", "timing", "info", "compat", "debug"] | bool = False, panel: int | Sequence[int] | bool = False, - perspective: float | Sequence[float] | str | bool = False, + perspective: Perspective | float | Sequence[float] | bool = False, transparency: float | None = None, ): """ diff --git a/pygmt/src/solar.py b/pygmt/src/solar.py index 93ac9057f11..532ebe31d63 100644 --- a/pygmt/src/solar.py +++ b/pygmt/src/solar.py @@ -10,7 +10,7 @@ from pygmt.clib import Session from pygmt.exceptions import GMTValueError from pygmt.helpers import build_arg_list, fmt_docstring -from pygmt.params import Axis, Frame +from pygmt.params import Axis, Frame, Perspective __doctest_skip__ = ["solar"] @@ -28,7 +28,7 @@ def solar( # noqa: PLR0913 verbose: Literal["quiet", "error", "warning", "timing", "info", "compat", "debug"] | bool = False, panel: int | Sequence[int] | bool = False, - perspective: float | Sequence[float] | str | bool = False, + perspective: Perspective | float | Sequence[float] | bool = False, transparency: float | None = None, **kwargs, ): diff --git a/pygmt/src/ternary.py b/pygmt/src/ternary.py index 23e75109689..bf715941682 100644 --- a/pygmt/src/ternary.py +++ b/pygmt/src/ternary.py @@ -10,7 +10,7 @@ from pygmt.clib import Session from pygmt.exceptions import GMTValueError from pygmt.helpers import build_arg_list, fmt_docstring, use_alias -from pygmt.params import Axis, Frame +from pygmt.params import Axis, Frame, Perspective from pygmt.params.frame import _Axes @@ -120,7 +120,7 @@ def ternary( # noqa: PLR0913 verbose: Literal["quiet", "error", "warning", "timing", "info", "compat", "debug"] | bool = False, panel: int | Sequence[int] | bool = False, - perspective: float | Sequence[float] | str | bool = False, + perspective: Perspective | float | Sequence[float] | bool = False, transparency: float | None = None, **kwargs, ): diff --git a/pygmt/src/text.py b/pygmt/src/text.py index ca2bf13ef9e..6234a8f1dbb 100644 --- a/pygmt/src/text.py +++ b/pygmt/src/text.py @@ -6,7 +6,12 @@ from typing import Literal import numpy as np -from pygmt._typing import AnchorCode, PathLike, StringArrayTypes, TableLike +from pygmt._typing import ( + AnchorCode, + PathLike, + StringArrayTypes, + TableLike, +) from pygmt.alias import Alias, AliasSystem from pygmt.clib import Session from pygmt.exceptions import GMTParameterError, GMTTypeError @@ -19,6 +24,7 @@ non_ascii_to_octal, use_alias, ) +from pygmt.params import Perspective from pygmt.params import Axis, Frame @@ -52,7 +58,7 @@ def text( # noqa: PLR0912, PLR0913, PLR0915 verbose: Literal["quiet", "error", "warning", "timing", "info", "compat", "debug"] | bool = False, panel: int | Sequence[int] | bool = False, - perspective: float | Sequence[float] | str | bool = False, + perspective: Perspective | float | Sequence[float] | bool = False, transparency: float | Sequence[float] | bool | None = None, **kwargs, ): diff --git a/pygmt/src/tilemap.py b/pygmt/src/tilemap.py index 7a7c96c46d0..85dd23ebf30 100644 --- a/pygmt/src/tilemap.py +++ b/pygmt/src/tilemap.py @@ -10,7 +10,7 @@ from pygmt.datasets.tile_map import load_tile_map from pygmt.enums import GridType from pygmt.helpers import build_arg_list, fmt_docstring, use_alias -from pygmt.params import Axis, Frame +from pygmt.params import Axis, Frame, Perspective try: from xyzservices import TileProvider @@ -36,7 +36,7 @@ def tilemap( # noqa: PLR0913 verbose: Literal["quiet", "error", "warning", "timing", "info", "compat", "debug"] | bool = False, panel: int | Sequence[int] | bool = False, - perspective: float | Sequence[float] | str | bool = False, + perspective: Perspective | float | Sequence[float] | bool = False, transparency: float | None = None, **kwargs, ): diff --git a/pygmt/src/velo.py b/pygmt/src/velo.py index 957ce8cd58b..61473c3ad6c 100644 --- a/pygmt/src/velo.py +++ b/pygmt/src/velo.py @@ -12,7 +12,7 @@ from pygmt.clib import Session from pygmt.exceptions import GMTParameterError, GMTTypeError from pygmt.helpers import build_arg_list, deprecate_parameter, fmt_docstring, use_alias -from pygmt.params import Axis, Frame +from pygmt.params import Axis, Frame, Perspective @fmt_docstring @@ -47,7 +47,7 @@ def velo( # noqa : PLR0913 | bool = False, panel: int | Sequence[int] | bool = False, incols: int | str | Sequence[int | str] | None = None, - perspective: float | Sequence[float] | str | bool = False, + perspective: Perspective | float | Sequence[float] | bool = False, transparency: float | None = None, **kwargs, ): diff --git a/pygmt/src/vlines.py b/pygmt/src/vlines.py index 1e99de0b535..377064eb923 100644 --- a/pygmt/src/vlines.py +++ b/pygmt/src/vlines.py @@ -6,6 +6,7 @@ import numpy as np from pygmt.exceptions import GMTValueError +from pygmt.params import Perspective __doctest_skip__ = ["vlines"] @@ -18,7 +19,7 @@ def vlines( pen: str | None = None, label: str | None = None, no_clip: bool = False, - perspective: str | bool | None = None, + perspective: Perspective | float | Sequence[float] | bool | None = None, ): """ Plot one or multiple vertical line(s). diff --git a/pygmt/src/wiggle.py b/pygmt/src/wiggle.py index 290bd9bbed2..bda03c1ba7e 100644 --- a/pygmt/src/wiggle.py +++ b/pygmt/src/wiggle.py @@ -9,7 +9,7 @@ from pygmt.alias import Alias, AliasSystem from pygmt.clib import Session from pygmt.helpers import build_arg_list, deprecate_parameter, fmt_docstring, use_alias -from pygmt.params import Axis, Frame, Position +from pygmt.params import Axis, Frame, Perspective, Position from pygmt.src._common import _parse_position @@ -53,7 +53,7 @@ def wiggle( # noqa: PLR0913 panel: int | Sequence[int] | bool = False, incols: int | str | Sequence[int | str] | None = None, label: str | None = None, - perspective: float | Sequence[float] | str | bool = False, + perspective: Perspective | float | Sequence[float] | bool = False, transparency: float | None = None, **kwargs, ): From 637806e7e234298a04d456dc57611d1c31768663 Mon Sep 17 00:00:00 2001 From: Dongdong Tian Date: Fri, 26 Jun 2026 00:16:21 +0800 Subject: [PATCH 09/11] Revert unrelated changes in text --- pygmt/src/text.py | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/pygmt/src/text.py b/pygmt/src/text.py index 6234a8f1dbb..5a93eb7dffa 100644 --- a/pygmt/src/text.py +++ b/pygmt/src/text.py @@ -6,12 +6,7 @@ from typing import Literal import numpy as np -from pygmt._typing import ( - AnchorCode, - PathLike, - StringArrayTypes, - TableLike, -) +from pygmt._typing import AnchorCode, PathLike, StringArrayTypes, TableLike from pygmt.alias import Alias, AliasSystem from pygmt.clib import Session from pygmt.exceptions import GMTParameterError, GMTTypeError From adf1cc1af58ae852f0da0b5c3f70e6c54bfab633 Mon Sep 17 00:00:00 2001 From: Dongdong Tian Date: Fri, 26 Jun 2026 00:17:12 +0800 Subject: [PATCH 10/11] Fix styling --- pygmt/src/grdview.py | 3 +-- pygmt/src/meca.py | 3 +-- pygmt/src/text.py | 3 +-- 3 files changed, 3 insertions(+), 6 deletions(-) diff --git a/pygmt/src/grdview.py b/pygmt/src/grdview.py index 7f96b0854dc..6c21eb6b144 100644 --- a/pygmt/src/grdview.py +++ b/pygmt/src/grdview.py @@ -18,8 +18,7 @@ is_given, use_alias, ) -from pygmt.params import Perspective -from pygmt.params import Axis, Frame +from pygmt.params import Axis, Frame, Perspective from pygmt.src.grdinfo import grdinfo __doctest_skip__ = ["grdview"] diff --git a/pygmt/src/meca.py b/pygmt/src/meca.py index b5edfee6ba1..6aeb134fc22 100644 --- a/pygmt/src/meca.py +++ b/pygmt/src/meca.py @@ -18,8 +18,7 @@ fmt_docstring, use_alias, ) -from pygmt.params import Perspective -from pygmt.params import Axis, Frame +from pygmt.params import Axis, Frame, Perspective from pygmt.src._common import _FocalMechanismConvention diff --git a/pygmt/src/text.py b/pygmt/src/text.py index 5a93eb7dffa..88c962b231b 100644 --- a/pygmt/src/text.py +++ b/pygmt/src/text.py @@ -19,8 +19,7 @@ non_ascii_to_octal, use_alias, ) -from pygmt.params import Perspective -from pygmt.params import Axis, Frame +from pygmt.params import Axis, Frame, Perspective @fmt_docstring From edfd30d4dac6be106d30d9e6739b7bd2da6d7fba Mon Sep 17 00:00:00 2001 From: Dongdong Tian Date: Fri, 26 Jun 2026 00:20:10 +0800 Subject: [PATCH 11/11] Improve the docstrings for the perspective parameter --- pygmt/helpers/decorators.py | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/pygmt/helpers/decorators.py b/pygmt/helpers/decorators.py index c8f74a1380f..ef77d151508 100644 --- a/pygmt/helpers/decorators.py +++ b/pygmt/helpers/decorators.py @@ -277,9 +277,9 @@ perspective Select perspective view and set the azimuth and elevation of the viewpoint. - Accepts a :class:`pygmt.params.Perspective` object, a single value, or a - sequence of two or three values: *azimuth*, (*azimuth*, *elevation*), or - (*azimuth*, *elevation*, *level*). + Accepts a :class:`pygmt.params.Perspective` object, a single value + *azimuth*, a sequence of two values (*azimuth*, *elevation*), a sequence of + three values (*azimuth*, *elevation*, *level*). - *azimuth*: Azimuth angle of the viewpoint in degrees [Default is 180, i.e., looking from south to north]. @@ -288,14 +288,11 @@ - *level*: Z-level at which 2-D elements (e.g., the plot frame) are drawn. Only applied when used together with ``zsize`` or ``zscale``. [Default is at the bottom of the z-axis]. - - :class:`pygmt.params.Perspective`: A class-style way to specify the same - perspective parameters. + - :class:`pygmt.params.Perspective`: A class-style way for more control over + the perspective parameters. Alternatively, set ``perspective=True`` to reuse the perspective setting - from the previous plotting method, or pass a string following the full - GMT syntax for finer control (e.g., adding ``+w`` or ``+v`` modifiers to - select an axis location other than the plot origin). See - :gmt-docs:`gmt.html#perspective-full` for details.""", + from the previous plotting method.""", "projection": r""" projection *projcode*\[*projparams*/]\ *width*\|\ *scale*.