diff --git a/pygmt/datasets/earth_age.py b/pygmt/datasets/earth_age.py index 22be9524327..07070751c7e 100644 --- a/pygmt/datasets/earth_age.py +++ b/pygmt/datasets/earth_age.py @@ -76,12 +76,8 @@ def load_earth_age( Note ---- The registration and coordinate system type of the returned - :class:`xarray.DataArray` grid can be accessed via the GMT accessors (i.e., - ``grid.gmt.registration`` and ``grid.gmt.gtype`` respectively). However, these - properties may be lost after specific grid operations (such as slicing) and will - need to be manually set before passing the grid to any PyGMT data processing or - plotting functions. Refer to :class:`pygmt.GMTDataArrayAccessor` for detailed - explanations and workarounds. + :class:`xarray.DataArray` grid can be accessed via the *gmt* accessor. Refer to + :class:`pygmt.GMTDataArrayAccessor` for detailed explanations and limitations. Examples -------- diff --git a/pygmt/datasets/earth_day.py b/pygmt/datasets/earth_day.py index f78d4714ba2..81f23378821 100644 --- a/pygmt/datasets/earth_day.py +++ b/pygmt/datasets/earth_day.py @@ -72,12 +72,8 @@ def load_blue_marble( Note ---- The registration and coordinate system type of the returned - :class:`xarray.DataArray` image can be accessed via the GMT accessors (i.e., - ``image.gmt.registration`` and ``image.gmt.gtype`` respectively). However, these - properties may be lost after specific image operations (such as slicing) and will - need to be manually set before passing the image to any PyGMT data processing or - plotting functions. Refer to :class:`pygmt.GMTDataArrayAccessor` for detailed - explanations and workarounds. + :class:`xarray.DataArray` image can be accessed via the *gmt* accessor. Refer to + :class:`pygmt.GMTDataArrayAccessor` for detailed explanations and limitations. Examples -------- diff --git a/pygmt/datasets/earth_deflection.py b/pygmt/datasets/earth_deflection.py index 28372f94a35..b8b29ce8884 100644 --- a/pygmt/datasets/earth_deflection.py +++ b/pygmt/datasets/earth_deflection.py @@ -90,12 +90,8 @@ def load_earth_deflection( Note ---- The registration and coordinate system type of the returned - :class:`xarray.DataArray` grid can be accessed via the GMT accessors (i.e., - ``grid.gmt.registration`` and ``grid.gmt.gtype`` respectively). However, these - properties may be lost after specific grid operations (such as slicing) and will - need to be manually set before passing the grid to any PyGMT data processing or - plotting functions. Refer to :class:`pygmt.GMTDataArrayAccessor` for detailed - explanations and workarounds. + :class:`xarray.DataArray` grid can be accessed via the *gmt* accessor. Refer to + :class:`pygmt.GMTDataArrayAccessor` for detailed explanations and limitations. Examples -------- diff --git a/pygmt/datasets/earth_dist.py b/pygmt/datasets/earth_dist.py index 0349a38aa53..6484be50d0d 100644 --- a/pygmt/datasets/earth_dist.py +++ b/pygmt/datasets/earth_dist.py @@ -77,12 +77,8 @@ def load_earth_dist( Note ---- The registration and coordinate system type of the returned - :class:`xarray.DataArray` grid can be accessed via the GMT accessors (i.e., - ``grid.gmt.registration`` and ``grid.gmt.gtype`` respectively). However, these - properties may be lost after specific grid operations (such as slicing) and will - need to be manually set before passing the grid to any PyGMT data processing or - plotting functions. Refer to :class:`pygmt.GMTDataArrayAccessor` for detailed - explanations and workarounds. + :class:`xarray.DataArray` grid can be accessed via the *gmt* accessor. Refer to + :class:`pygmt.GMTDataArrayAccessor` for detailed explanations and limitations. Examples -------- diff --git a/pygmt/datasets/earth_free_air_anomaly.py b/pygmt/datasets/earth_free_air_anomaly.py index b0542adcb94..ce8ee2e2fef 100644 --- a/pygmt/datasets/earth_free_air_anomaly.py +++ b/pygmt/datasets/earth_free_air_anomaly.py @@ -90,12 +90,8 @@ def load_earth_free_air_anomaly( Note ---- The registration and coordinate system type of the returned - :class:`xarray.DataArray` grid can be accessed via the GMT accessors (i.e., - ``grid.gmt.registration`` and ``grid.gmt.gtype`` respectively). However, these - properties may be lost after specific grid operations (such as slicing) and will - need to be manually set before passing the grid to any PyGMT data processing or - plotting functions. Refer to :class:`pygmt.GMTDataArrayAccessor` for detailed - explanations and workarounds. + :class:`xarray.DataArray` grid can be accessed via the *gmt* accessor. Refer to + :class:`pygmt.GMTDataArrayAccessor` for detailed explanations and limitations. Examples -------- diff --git a/pygmt/datasets/earth_geoid.py b/pygmt/datasets/earth_geoid.py index c511066529f..50cce3fe629 100644 --- a/pygmt/datasets/earth_geoid.py +++ b/pygmt/datasets/earth_geoid.py @@ -70,13 +70,8 @@ def load_earth_geoid( Note ---- The registration and coordinate system type of the returned - :class:`xarray.DataArray` grid can be accessed via the GMT accessors - (i.e., ``grid.gmt.registration`` and ``grid.gmt.gtype`` respectively). - However, these properties may be lost after specific grid operations (such - as slicing) and will need to be manually set before passing the grid to any - PyGMT data processing or plotting functions. Refer to - :class:`pygmt.GMTDataArrayAccessor` for detailed explanations and - workarounds. + :class:`xarray.DataArray` grid can be accessed via the *gmt* accessor. Refer to + :class:`pygmt.GMTDataArrayAccessor` for detailed explanations and limitations. Examples -------- diff --git a/pygmt/datasets/earth_magnetic_anomaly.py b/pygmt/datasets/earth_magnetic_anomaly.py index 65928acaa9d..5a1e22de2bf 100644 --- a/pygmt/datasets/earth_magnetic_anomaly.py +++ b/pygmt/datasets/earth_magnetic_anomaly.py @@ -102,13 +102,8 @@ def load_earth_magnetic_anomaly( Note ---- The registration and coordinate system type of the returned - :class:`xarray.DataArray` grid can be accessed via the GMT accessors - (i.e., ``grid.gmt.registration`` and ``grid.gmt.gtype`` respectively). - However, these properties may be lost after specific grid operations (such - as slicing) and will need to be manually set before passing the grid to any - PyGMT data processing or plotting functions. Refer to - :class:`pygmt.GMTDataArrayAccessor` for detailed explanations and - workarounds. + :class:`xarray.DataArray` grid can be accessed via the *gmt* accessor. Refer to + :class:`pygmt.GMTDataArrayAccessor` for detailed explanations and limitations. Examples -------- diff --git a/pygmt/datasets/earth_mask.py b/pygmt/datasets/earth_mask.py index fd147a2326b..ca1986fc6ae 100644 --- a/pygmt/datasets/earth_mask.py +++ b/pygmt/datasets/earth_mask.py @@ -89,13 +89,8 @@ def load_earth_mask( Note ---- The registration and coordinate system type of the returned - :class:`xarray.DataArray` grid can be accessed via the GMT accessors - (i.e., ``grid.gmt.registration`` and ``grid.gmt.gtype`` respectively). - However, these properties may be lost after specific grid operations (such - as slicing) and will need to be manually set before passing the grid to any - PyGMT data processing or plotting functions. Refer to - :class:`pygmt.GMTDataArrayAccessor` for detailed explanations and - workarounds. + :class:`xarray.DataArray` grid can be accessed via the *gmt* accessor. Refer to + :class:`pygmt.GMTDataArrayAccessor` for detailed explanations and limitations. Examples -------- diff --git a/pygmt/datasets/earth_mean_dynamic_topography.py b/pygmt/datasets/earth_mean_dynamic_topography.py index 2add521d46a..63ac3cbcc8d 100644 --- a/pygmt/datasets/earth_mean_dynamic_topography.py +++ b/pygmt/datasets/earth_mean_dynamic_topography.py @@ -73,12 +73,8 @@ def load_earth_mean_dynamic_topography( Note ---- The registration and coordinate system type of the returned - :class:`xarray.DataArray` grid can be accessed via the GMT accessors (i.e., - ``grid.gmt.registration`` and ``grid.gmt.gtype`` respectively). However, these - properties may be lost after specific grid operations (such as slicing) and will - need to be manually set before passing the grid to any PyGMT data processing or - plotting functions. Refer to :class:`pygmt.GMTDataArrayAccessor` for detailed - explanations and workarounds. + :class:`xarray.DataArray` grid can be accessed via the *gmt* accessor. Refer to + :class:`pygmt.GMTDataArrayAccessor` for detailed explanations and limitations. Examples -------- diff --git a/pygmt/datasets/earth_mean_sea_surface.py b/pygmt/datasets/earth_mean_sea_surface.py index d4b64b157f1..e9a081f0949 100644 --- a/pygmt/datasets/earth_mean_sea_surface.py +++ b/pygmt/datasets/earth_mean_sea_surface.py @@ -76,12 +76,8 @@ def load_earth_mean_sea_surface( Note ---- The registration and coordinate system type of the returned - :class:`xarray.DataArray` grid can be accessed via the GMT accessors (i.e., - ``grid.gmt.registration`` and ``grid.gmt.gtype`` respectively). However, these - properties may be lost after specific grid operations (such as slicing) and will - need to be manually set before passing the grid to any PyGMT data processing or - plotting functions. Refer to :class:`pygmt.GMTDataArrayAccessor` for detailed - explanations and workarounds. + :class:`xarray.DataArray` grid can be accessed via the *gmt* accessor. Refer to + :class:`pygmt.GMTDataArrayAccessor` for detailed explanations and limitations. Examples -------- diff --git a/pygmt/datasets/earth_night.py b/pygmt/datasets/earth_night.py index 9512186413a..059a5467ff0 100644 --- a/pygmt/datasets/earth_night.py +++ b/pygmt/datasets/earth_night.py @@ -71,12 +71,8 @@ def load_black_marble( Note ---- The registration and coordinate system type of the returned - :class:`xarray.DataArray` image can be accessed via the GMT accessors (i.e., - ``image.gmt.registration`` and ``image.gmt.gtype`` respectively). However, these - properties may be lost after specific image operations (such as slicing) and will - need to be manually set before passing the image to any PyGMT data processing or - plotting functions. Refer to :class:`pygmt.GMTDataArrayAccessor` for detailed - explanations and workarounds. + :class:`xarray.DataArray` image can be accessed via the *gmt* accessor. Refer to + :class:`pygmt.GMTDataArrayAccessor` for detailed explanations and limitations. Examples -------- diff --git a/pygmt/datasets/earth_relief.py b/pygmt/datasets/earth_relief.py index a54a09a2f17..097f7c22974 100644 --- a/pygmt/datasets/earth_relief.py +++ b/pygmt/datasets/earth_relief.py @@ -118,13 +118,8 @@ def load_earth_relief( Note ---- The registration and coordinate system type of the returned - :class:`xarray.DataArray` grid can be accessed via the GMT accessors - (i.e., ``grid.gmt.registration`` and ``grid.gmt.gtype`` respectively). - However, these properties may be lost after specific grid operations (such - as slicing) and will need to be manually set before passing the grid to any - PyGMT data processing or plotting functions. Refer to - :class:`pygmt.GMTDataArrayAccessor` for detailed explanations and - workarounds. + :class:`xarray.DataArray` grid can be accessed via the *gmt* accessor. Refer to + :class:`pygmt.GMTDataArrayAccessor` for detailed explanations and limitations. Examples -------- diff --git a/pygmt/datasets/earth_vertical_gravity_gradient.py b/pygmt/datasets/earth_vertical_gravity_gradient.py index f070e61ba89..09d3a5df682 100644 --- a/pygmt/datasets/earth_vertical_gravity_gradient.py +++ b/pygmt/datasets/earth_vertical_gravity_gradient.py @@ -78,13 +78,8 @@ def load_earth_vertical_gravity_gradient( Note ---- The registration and coordinate system type of the returned - :class:`xarray.DataArray` grid can be accessed via the GMT accessors - (i.e., ``grid.gmt.registration`` and ``grid.gmt.gtype`` respectively). - However, these properties may be lost after specific grid operations (such - as slicing) and will need to be manually set before passing the grid to any - PyGMT data processing or plotting functions. Refer to - :class:`pygmt.GMTDataArrayAccessor` for detailed explanations and - workarounds. + :class:`xarray.DataArray` grid can be accessed via the *gmt* accessor. Refer to + :class:`pygmt.GMTDataArrayAccessor` for detailed explanations and limitations. Examples -------- diff --git a/pygmt/datasets/mars_relief.py b/pygmt/datasets/mars_relief.py index 442693ab8e0..f63bd3cb9fb 100644 --- a/pygmt/datasets/mars_relief.py +++ b/pygmt/datasets/mars_relief.py @@ -92,12 +92,8 @@ def load_mars_relief( Note ---- The registration and coordinate system type of the returned - :class:`xarray.DataArray` grid can be accessed via the GMT accessors (i.e., - ``grid.gmt.registration`` and ``grid.gmt.gtype`` respectively). However, these - properties may be lost after specific grid operations (such as slicing) and will - need to be manually set before passing the grid to any PyGMT data processing or - plotting functions. Refer to :class:`pygmt.GMTDataArrayAccessor` for detailed - explanations and workarounds. + :class:`xarray.DataArray` grid can be accessed via the *gmt* accessor. Refer to + :class:`pygmt.GMTDataArrayAccessor` for detailed explanations and limitations. Examples -------- diff --git a/pygmt/datasets/mercury_relief.py b/pygmt/datasets/mercury_relief.py index 8079c8ece9f..fb5ade05c3b 100644 --- a/pygmt/datasets/mercury_relief.py +++ b/pygmt/datasets/mercury_relief.py @@ -91,12 +91,8 @@ def load_mercury_relief( Note ---- The registration and coordinate system type of the returned - :class:`xarray.DataArray` grid can be accessed via the GMT accessors (i.e., - ``grid.gmt.registration`` and ``grid.gmt.gtype`` respectively). However, these - properties may be lost after specific grid operations (such as slicing) and will - need to be manually set before passing the grid to any PyGMT data processing or - plotting functions. Refer to :class:`pygmt.GMTDataArrayAccessor` for detailed - explanations and workarounds. + :class:`xarray.DataArray` grid can be accessed via the *gmt* accessor. Refer to + :class:`pygmt.GMTDataArrayAccessor` for detailed explanations and limitations. Examples -------- diff --git a/pygmt/datasets/moon_relief.py b/pygmt/datasets/moon_relief.py index 504cdb3cdd4..7784508da0e 100644 --- a/pygmt/datasets/moon_relief.py +++ b/pygmt/datasets/moon_relief.py @@ -92,12 +92,8 @@ def load_moon_relief( Note ---- The registration and coordinate system type of the returned - :class:`xarray.DataArray` grid can be accessed via the GMT accessors (i.e., - ``grid.gmt.registration`` and ``grid.gmt.gtype`` respectively). However, these - properties may be lost after specific grid operations (such as slicing) and will - need to be manually set before passing the grid to any PyGMT data processing or - plotting functions. Refer to :class:`pygmt.GMTDataArrayAccessor` for detailed - explanations and workarounds. + :class:`xarray.DataArray` grid can be accessed via the *gmt* accessor. Refer to + :class:`pygmt.GMTDataArrayAccessor` for detailed explanations and limitations. Examples -------- diff --git a/pygmt/datasets/pluto_relief.py b/pygmt/datasets/pluto_relief.py index 1d4e944b412..6f82f35462c 100644 --- a/pygmt/datasets/pluto_relief.py +++ b/pygmt/datasets/pluto_relief.py @@ -91,12 +91,8 @@ def load_pluto_relief( Note ---- The registration and coordinate system type of the returned - :class:`xarray.DataArray` grid can be accessed via the GMT accessors (i.e., - ``grid.gmt.registration`` and ``grid.gmt.gtype`` respectively). However, these - properties may be lost after specific grid operations (such as slicing) and will - need to be manually set before passing the grid to any PyGMT data processing or - plotting functions. Refer to :class:`pygmt.GMTDataArrayAccessor` for detailed - explanations and workarounds. + :class:`xarray.DataArray` grid can be accessed via the *gmt* accessor. Refer to + :class:`pygmt.GMTDataArrayAccessor` for detailed explanations and limitations. Examples -------- diff --git a/pygmt/datasets/venus_relief.py b/pygmt/datasets/venus_relief.py index c9ac5c58363..95c9eccd7a0 100644 --- a/pygmt/datasets/venus_relief.py +++ b/pygmt/datasets/venus_relief.py @@ -76,12 +76,8 @@ def load_venus_relief( Note ---- The registration and coordinate system type of the returned - :class:`xarray.DataArray` grid can be accessed via the GMT accessors (i.e., - ``grid.gmt.registration`` and ``grid.gmt.gtype`` respectively). However, these - properties may be lost after specific grid operations (such as slicing) and will - need to be manually set before passing the grid to any PyGMT data processing or - plotting functions. Refer to :class:`pygmt.GMTDataArrayAccessor` for detailed - explanations and workarounds. + :class:`xarray.DataArray` grid can be accessed via the *gmt* accessor. Refer to + :class:`pygmt.GMTDataArrayAccessor` for detailed explanations and limitations. Examples -------- diff --git a/pygmt/xarray/accessor.py b/pygmt/xarray/accessor.py index 68162151853..401f6bd7ac0 100644 --- a/pygmt/xarray/accessor.py +++ b/pygmt/xarray/accessor.py @@ -17,16 +17,33 @@ class GMTDataArrayAccessor: GMT accessor for :class:`xarray.DataArray`. The *gmt* accessor extends :class:`xarray.DataArray` to store GMT-specific - properties for grids, which are important for PyGMT to correctly process and plot - the grids. The *gmt* accessor contains the following properties: + properties for grids and images, which are important for PyGMT to correctly process + and plot them. The *gmt* accessor contains the following properties: - ``registration``: Grid registration type :class:`pygmt.enums.GridRegistration`. - ``gtype``: Grid coordinate system type :class:`pygmt.enums.GridType`. + Notes + ----- + When accessed the first time, the *gmt* accessor will first be initialized to the + default values (``GridRegistration.GRIDLINE`` and ``GridType.CARTESIAN``, i.e., a + gridline-registered, Cartesian grid), and then the properties will be updated with + the correct grid registration and type determined from the source encoding (i.e., + ``grid.encoding["source"]``), if it is available. + + Due to the limitations of xarray accessors, the *gmt* accessor is created once per + :class:`xarray.DataArray` instance. Thus, the *gmt* accessor will be re-initialized + in cases where the :class:`xarray.DataArray` is manipulated (e.g., arithmetic and + slice operations) or when accessing a :class:`xarray.DataArray` from a + :class:`xarray.Dataset`. In these cases, the GMT-specific properties will result in + incorrect values if the source encoding is not defined or is dropped due to + operations, and users need to manually set these properties again. + Examples -------- - For GMT's built-in remote datasets, these GMT-specific properties are automatically - determined and you can access them as follows: + For grids loaded from a file (e.g., via :func:`xarray.load_dataarray`) and GMT's + built-in remote datasets, the GMT-specific properties are automatically determined + and you can access them as follows: >>> from pygmt.datasets import load_earth_relief >>> # Use the global Earth relief grid with 1 degree spacing @@ -37,11 +54,54 @@ class GMTDataArrayAccessor: >>> # See if grid is in Cartesian or Geographic coordinate system >>> grid.gmt.gtype + >>> grid.encoding["source"] is not None + True + + Inplace assignment operators like ``*=`` don't create new instances, so the + properties are still kept: + + >>> grid *= 2.0 + >>> grid.gmt.registration + + >>> grid.gmt.gtype + + + Slice operation creates a new instance, but the source encoding is kept, so the + properties are still kept: + + >>> grid_slice = grid[0:30, 50:80] + >>> # grid source encoding is kept in slice operation + >>> grid_slice.encoding["source"] is not None + True + >>> # properties are still kept + >>> grid_slice.gmt.registration + + >>> grid_slice.gmt.gtype + - For :class:`xarray.DataArray` grids created by yourself, ``registration`` and - ``gtype`` default to ``GridRegistration.GRIDLINE`` and ``GridType.CARTESIAN`` (i.e., - a gridline-registered, Cartesian grid). You need to set the correct properties - before passing it to PyGMT functions: + Other grid operations (e.g., arithmetic operations) create new instances and drop + the source encoding, so the properties will be reset to the default values: + + >>> grid2 = grid * 2.0 + >>> # grid source encoding is dropped in arithmetic operation. + >>> "source" in grid2.encoding + False + >>> # properties are reset to the default values + >>> grid2.gmt.registration + + >>> grid2.gmt.gtype + + >>> # Need to set these properties before passing the grid to PyGMT + >>> grid2.gmt.registration = grid.gmt.registration + >>> grid2.gmt.gtype = grid.gmt.gtype + >>> grid2.gmt.registration + + >>> grid2.gmt.gtype + + + For :class:`xarray.DataArray` grids created from scratch, the source encoding is not + available, so the properties will be set to the default values, and you need to + manually set the correct properties before passing it to PyGMT functions: >>> import numpy as np >>> import xarray as xr @@ -67,44 +127,10 @@ class GMTDataArrayAccessor: >>> grid.gmt.gtype - Notes - ----- - Due to the limitations of xarray accessors, the GMT accessors are created once per - :class:`xarray.DataArray` instance. You may lose these GMT-specific properties when - manipulating grids (e.g., arithmetic and slice operations) or when accessing a - :class:`xarray.DataArray` from a :class:`xarray.Dataset`. In these cases, you need - to manually set these properties before passing the grid to PyGMT. - - Inplace assignment operators like ``*=`` don't create new instances, so the - properties are still kept: - - >>> grid *= 2.0 - >>> grid.gmt.registration - - >>> grid.gmt.gtype - - - Other grid operations (e.g., arithmetic or slice operations) create new instances, - so the properties will be lost: - - >>> # grid2 is a slice of the original grid - >>> grid2 = grid[0:30, 50:80] - >>> # Properties are reset to the default values for new instance - >>> grid2.gmt.registration - - >>> grid2.gmt.gtype - - >>> # Need to set these properties before passing the grid to PyGMT - >>> grid2.gmt.registration = grid.gmt.registration - >>> grid2.gmt.gtype = grid.gmt.gtype - >>> grid2.gmt.registration - - >>> grid2.gmt.gtype - - Accessing a :class:`xarray.DataArray` from a :class:`xarray.Dataset` always creates - new instances, so these properties are always lost. The workaround is to assign the - :class:`xarray.DataArray` into a variable: + new instances, so these properties are always lost if the source encoding is not + available. The workaround is to assign the :class:`xarray.DataArray` into a + variable: >>> ds = xr.Dataset({"zval": grid}) >>> ds.zval.gmt.registration