Repository: GenericMappingTools/pygmt

Issue:
Standardize parameter name for table data inputs
**Description of the desired feature**

_Originally posted by @meghanrjones in https://github.com/GenericMappingTools/pygmt/issues/1441#issuecomment-901303058_

> This is somewhat related - I am not sure if it's worth a deprecation but I think we should decide on whether the parameter for tabular input is `data` or `table` for all modules moving forward. Currently, this is the distribution:
> 
> `data` parameter: surface, wiggle, velo, rose, plot3d, plot, contour
> `table` parameter: blockmedian, blockmean, histogram
> other: grdtrack (`points`), text (`textfiles`)
> 
> It would also be worthwhile to set a consistent order for the positional arguments x, y, [z], data, [outfile]

<!-- Please be as detailed as you can in your description. If possible, include an example of how you would like to use this feature (even better if it's a code example). -->

**Are you willing to help implement and maintain this feature?** Discuss first

<!-- Every feature we add is code that we will have to maintain and keep updated. This takes a lot of effort. If you are willing to be involved in the project and help maintain your feature, it will make it easier for us to accept it. -->


Discussion:

Patch:
diff --git a/pygmt/clib/conversion.py b/pygmt/clib/conversion.py
index 57b2f92c..7c94b788 100644
--- a/pygmt/clib/conversion.py
+++ b/pygmt/clib/conversion.py
@@ -1,6 +1,8 @@
 """
 Functions to convert data types into ctypes friendly formats.
 """
+import warnings
+
 import numpy as np
 import pandas as pd
 from pygmt.exceptions import GMTInvalidInput
@@ -95,9 +97,14 @@ def dataarray_to_matrix(grid):
         coord_incs = coord[1:] - coord[0:-1]
         coord_inc = coord_incs[0]
         if not np.allclose(coord_incs, coord_inc):
-            raise GMTInvalidInput(
-                f"Grid appears to have irregular spacing in the '{dim}' dimension."
+            # calculate the increment if irregular spacing is found
+            coord_inc = (coord[-1] - coord[0]) / (coord.size - 1)
+            msg = (
+                f"Grid may have irregular spacing in the '{dim}' dimension, "
+                "but GMT only supports regular spacing. Calculated regular spacing "
+                f"{coord_inc} is assumed in the '{dim}' dimension."
             )
+            warnings.warn(msg, category=RuntimeWarning)
         if coord_inc == 0:
             raise GMTInvalidInput(
                 f"Grid has a zero increment in the '{dim}' dimension."
diff --git a/pygmt/src/blockm.py b/pygmt/src/blockm.py
index a7de8f77..05b69f04 100644
--- a/pygmt/src/blockm.py
+++ b/pygmt/src/blockm.py
@@ -6,13 +6,14 @@ from pygmt.clib import Session
 from pygmt.helpers import (
     GMTTempFile,
     build_arg_string,
+    check_data_input_order,
     fmt_docstring,
     kwargs_to_strings,
     use_alias,
 )
 
 
-def _blockm(block_method, table, outfile, x, y, z, **kwargs):
+def _blockm(block_method, data, x, y, z, outfile, **kwargs):
     r"""
     Block average (x,y,z) data tables by mean, median, or mode estimation.
 
@@ -38,12 +39,11 @@ def _blockm(block_method, table, outfile, x, y, z, **kwargs):
         - None if ``outfile`` is set (filtered output will be stored in file
           set by ``outfile``)
     """
-
     with GMTTempFile(suffix=".csv") as tmpfile:
         with Session() as lib:
             # Choose how data will be passed into the module
             table_context = lib.virtualfile_from_data(
-                check_kind="vector", data=table, x=x, y=y, z=z, required_z=True
+                check_kind="vector", data=data, x=x, y=y, z=z, required_z=True
             )
             # Run blockm* on data table
             with table_context as infile:
@@ -55,7 +55,7 @@ def _blockm(block_method, table, outfile, x, y, z, **kwargs):
         # Read temporary csv output to a pandas table
         if outfile == tmpfile.name:  # if user did not set outfile, return pd.DataFrame
             try:
-                column_names = table.columns.to_list()
+                column_names = data.columns.to_list()
                 result = pd.read_csv(tmpfile.name, sep="\t", names=column_names)
             except AttributeError:  # 'str' object has no attribute 'columns'
                 result = pd.read_csv(tmpfile.name, sep="\t", header=None, comment=">")
@@ -66,6 +66,7 @@ def _blockm(block_method, table, outfile, x, y, z, **kwargs):
 
 
 @fmt_docstring
+@check_data_input_order("v0.5.0", remove_version="v0.7.0")
 @use_alias(
     I="spacing",
     R="region",
@@ -82,7 +83,7 @@ def _blockm(block_method, table, outfile, x, y, z, **kwargs):
     w="wrap",
 )
 @kwargs_to_strings(R="sequence", i="sequence_comma", o="sequence_comma")
-def blockmean(table=None, outfile=None, *, x=None, y=None, z=None, **kwargs):
+def blockmean(data=None, x=None, y=None, z=None, outfile=None, **kwargs):
     r"""
     Block average (x,y,z) data tables by mean estimation.
 
@@ -93,7 +94,7 @@ def blockmean(table=None, outfile=None, *, x=None, y=None, z=None, **kwargs):
 
     Takes a matrix, xyz triplets, or a file name as input.
 
-    Must provide either ``table`` or ``x``, ``y``, and ``z``.
+    Must provide either ``data`` or ``x``, ``y``, and ``z``.
 
     Full option list at :gmt-docs:`blockmean.html`
 
@@ -101,7 +102,7 @@ def blockmean(table=None, outfile=None, *, x=None, y=None, z=None, **kwargs):
 
     Parameters
     ----------
-    table : str or {table-like}
+    data : str or {table-like}
         Pass in (x, y, z) or (longitude, latitude, elevation) values by
         providing a file name to an ASCII data table, a 2D
         {table-classes}.
@@ -138,11 +139,12 @@ def blockmean(table=None, outfile=None, *, x=None, y=None, z=None, **kwargs):
           set by ``outfile``).
     """
     return _blockm(
-        block_method="blockmean", table=table, outfile=outfile, x=x, y=y, z=z, **kwargs
+        block_method="blockmean", data=data, x=x, y=y, z=z, outfile=outfile, **kwargs
     )
 
 
 @fmt_docstring
+@check_data_input_order("v0.5.0", remove_version="v0.7.0")
 @use_alias(
     I="spacing",
     R="region",
@@ -159,7 +161,7 @@ def blockmean(table=None, outfile=None, *, x=None, y=None, z=None, **kwargs):
     w="wrap",
 )
 @kwargs_to_strings(R="sequence", i="sequence_comma", o="sequence_comma")
-def blockmedian(table=None, outfile=None, *, x=None, y=None, z=None, **kwargs):
+def blockmedian(data=None, x=None, y=None, z=None, outfile=None, **kwargs):
     r"""
     Block average (x,y,z) data tables by median estimation.
 
@@ -170,7 +172,7 @@ def blockmedian(table=None, outfile=None, *, x=None, y=None, z=None, **kwargs):
 
     Takes a matrix, xyz triplets, or a file name as input.
 
-    Must provide either ``table`` or ``x``, ``y``, and ``z``.
+    Must provide either ``data`` or ``x``, ``y``, and ``z``.
 
     Full option list at :gmt-docs:`blockmedian.html`
 
@@ -178,7 +180,7 @@ def blockmedian(table=None, outfile=None, *, x=None, y=None, z=None, **kwargs):
 
     Parameters
     ----------
-    table : str or {table-like}
+    data : str or {table-like}
         Pass in (x, y, z) or (longitude, latitude, elevation) values by
         providing a file name to an ASCII data table, a 2D
         {table-classes}.
@@ -215,17 +217,12 @@ def blockmedian(table=None, outfile=None, *, x=None, y=None, z=None, **kwargs):
           set by ``outfile``).
     """
     return _blockm(
-        block_method="blockmedian",
-        table=table,
-        outfile=outfile,
-        x=x,
-        y=y,
-        z=z,
-        **kwargs
+        block_method="blockmedian", data=data, x=x, y=y, z=z, outfile=outfile, **kwargs
     )
 
 
 @fmt_docstring
+@check_data_input_order("v0.5.0", remove_version="v0.7.0")
 @use_alias(
     I="spacing",
     R="region",
@@ -242,7 +239,7 @@ def blockmedian(table=None, outfile=None, *, x=None, y=None, z=None, **kwargs):
     w="wrap",
 )
 @kwargs_to_strings(R="sequence", i="sequence_comma", o="sequence_comma")
-def blockmode(table=None, outfile=None, *, x=None, y=None, z=None, **kwargs):
+def blockmode(data=None, x=None, y=None, z=None, outfile=None, **kwargs):
     r"""
     Block average (x,y,z) data tables by mode estimation.
 
@@ -253,7 +250,7 @@ def blockmode(table=None, outfile=None, *, x=None, y=None, z=None, **kwargs):
 
     Takes a matrix, xyz triplets, or a file name as input.
 
-    Must provide either ``table`` or ``x``, ``y``, and ``z``.
+    Must provide either ``data`` or ``x``, ``y``, and ``z``.
 
     Full option list at :gmt-docs:`blockmode.html`
 
@@ -261,7 +258,7 @@ def blockmode(table=None, outfile=None, *, x=None, y=None, z=None, **kwargs):
 
     Parameters
     ----------
-    table : str or {table-like}
+    data : str or {table-like}
         Pass in (x, y, z) or (longitude, latitude, elevation) values by
         providing a file name to an ASCII data table, a 2D
         {table-classes}.
@@ -298,5 +295,5 @@ def blockmode(table=None, outfile=None, *, x=None, y=None, z=None, **kwargs):
           set by ``outfile``).
     """
     return _blockm(
-        block_method="blockmode", table=table, outfile=outfile, x=x, y=y, z=z, **kwargs
+        block_method="blockmode", data=data, x=x, y=y, z=z, outfile=outfile, **kwargs
     )


Test patch:
diff --git a/pygmt/tests/test_blockm.py b/pygmt/tests/test_blockm.py
index d71b372b..112b672d 100644
--- a/pygmt/tests/test_blockm.py
+++ b/pygmt/tests/test_blockm.py
@@ -26,7 +26,7 @@ def test_blockmean_input_dataframe(dataframe):
     """
     Run blockmean by passing in a pandas.DataFrame as input.
     """
-    output = blockmean(table=dataframe, spacing="5m", region=[245, 255, 20, 30])
+    output = blockmean(data=dataframe, spacing="5m", region=[245, 255, 20, 30])
     assert isinstance(output, pd.DataFrame)
     assert all(dataframe.columns == output.columns)
     assert output.shape == (5849, 3)
@@ -40,7 +40,7 @@ def test_blockmean_input_table_matrix(array_func, dataframe):
     matrix.
     """
     table = array_func(dataframe)
-    output = blockmean(table=table, spacing="5m", region=[245, 255, 20, 30])
+    output = blockmean(data=table, spacing="5m", region=[245, 255, 20, 30])
     assert isinstance(output, pd.DataFrame)
     assert output.shape == (5849, 3)
     npt.assert_allclose(output.iloc[0], [245.888877, 29.978707, -384.0])
@@ -70,7 +70,7 @@ def test_blockmean_wrong_kind_of_input_table_grid(dataframe):
     invalid_table = dataframe.bathymetry.to_xarray()
     assert data_kind(invalid_table) == "grid"
     with pytest.raises(GMTInvalidInput):
-        blockmean(table=invalid_table, spacing="5m", region=[245, 255, 20, 30])
+        blockmean(data=invalid_table, spacing="5m", region=[245, 255, 20, 30])
 
 
 def test_blockmean_input_filename():
@@ -79,7 +79,7 @@ def test_blockmean_input_filename():
     """
     with GMTTempFile() as tmpfile:
         output = blockmean(
-            table="@tut_ship.xyz",
+            data="@tut_ship.xyz",
             spacing="5m",
             region=[245, 255, 20, 30],
             outfile=tmpfile.name,
@@ -95,7 +95,7 @@ def test_blockmean_without_outfile_setting():
     """
     Run blockmean by not passing in outfile parameter setting.
     """
-    output = blockmean(table="@tut_ship.xyz", spacing="5m", region=[245, 255, 20, 30])
+    output = blockmean(data="@tut_ship.xyz", spacing="5m", region=[245, 255, 20, 30])
     assert isinstance(output, pd.DataFrame)
     assert output.shape == (5849, 3)
     npt.assert_allclose(output.iloc[0], [245.888877, 29.978707, -384.0])
@@ -105,7 +105,7 @@ def test_blockmode_input_dataframe(dataframe):
     """
     Run blockmode by passing in a pandas.DataFrame as input.
     """
-    output = blockmode(table=dataframe, spacing="5m", region=[245, 255, 20, 30])
+    output = blockmode(data=dataframe, spacing="5m", region=[245, 255, 20, 30])
     assert isinstance(output, pd.DataFrame)
     assert all(dataframe.columns == output.columns)
     assert output.shape == (5849, 3)
diff --git a/pygmt/tests/test_blockmedian.py b/pygmt/tests/test_blockmedian.py
index 5a0ab604..99bb0869 100644
--- a/pygmt/tests/test_blockmedian.py
+++ b/pygmt/tests/test_blockmedian.py
@@ -24,7 +24,7 @@ def test_blockmedian_input_dataframe(dataframe):
     """
     Run blockmedian by passing in a pandas.DataFrame as input.
     """
-    output = blockmedian(table=dataframe, spacing="5m", region=[245, 255, 20, 30])
+    output = blockmedian(data=dataframe, spacing="5m", region=[245, 255, 20, 30])
     assert isinstance(output, pd.DataFrame)
     assert all(dataframe.columns == output.columns)
     assert output.shape == (5849, 3)
@@ -37,7 +37,7 @@ def test_blockmedian_input_table_matrix(dataframe):
     a matrix.
     """
     table = dataframe.values
-    output = blockmedian(table=table, spacing="5m", region=[245, 255, 20, 30])
+    output = blockmedian(data=table, spacing="5m", region=[245, 255, 20, 30])
     assert isinstance(output, pd.DataFrame)
     assert output.shape == (5849, 3)
     npt.assert_allclose(output.iloc[0], [245.88819, 29.97895, -385.0])
@@ -67,7 +67,7 @@ def test_blockmedian_wrong_kind_of_input_table_grid(dataframe):
     invalid_table = dataframe.bathymetry.to_xarray()
     assert data_kind(invalid_table) == "grid"
     with pytest.raises(GMTInvalidInput):
-        blockmedian(table=invalid_table, spacing="5m", region=[245, 255, 20, 30])
+        blockmedian(data=invalid_table, spacing="5m", region=[245, 255, 20, 30])
 
 
 def test_blockmedian_input_filename():
@@ -76,7 +76,7 @@ def test_blockmedian_input_filename():
     """
     with GMTTempFile() as tmpfile:
         output = blockmedian(
-            table="@tut_ship.xyz",
+            data="@tut_ship.xyz",
             spacing="5m",
             region=[245, 255, 20, 30],
             outfile=tmpfile.name,
@@ -92,7 +92,7 @@ def test_blockmedian_without_outfile_setting():
     """
     Run blockmedian by not passing in outfile parameter setting.
     """
-    output = blockmedian(table="@tut_ship.xyz", spacing="5m", region=[245, 255, 20, 30])
+    output = blockmedian(data="@tut_ship.xyz", spacing="5m", region=[245, 255, 20, 30])
     assert isinstance(output, pd.DataFrame)
     assert output.shape == (5849, 3)
     npt.assert_allclose(output.iloc[0], [245.88819, 29.97895, -385.0])
diff --git a/pygmt/tests/test_clib.py b/pygmt/tests/test_clib.py
index e88c04a8..b240015b 100644
--- a/pygmt/tests/test_clib.py
+++ b/pygmt/tests/test_clib.py
@@ -805,16 +805,18 @@ def test_dataarray_to_matrix_dims_fails():
         dataarray_to_matrix(grid)
 
 
-def test_dataarray_to_matrix_inc_fails():
+def test_dataarray_to_matrix_irregular_inc_warning():
     """
-    Check that it fails for variable increments.
+    Check that it warns for variable increments, see also
+    https://github.com/GenericMappingTools/pygmt/issues/1468.
     """
     data = np.ones((4, 5), dtype="float64")
     x = np.linspace(0, 1, 5)
     y = np.logspace(2, 3, 4)
     grid = xr.DataArray(data, coords=[("y", y), ("x", x)])
-    with pytest.raises(GMTInvalidInput):
+    with pytest.warns(expected_warning=RuntimeWarning) as record:
         dataarray_to_matrix(grid)
+        assert len(record) == 1
 
 
 def test_dataarray_to_matrix_zero_inc_fails():