From 66c4b97320ce92fab9b70fde2791ad5054f0c71e Mon Sep 17 00:00:00 2001
From: Dongdong Tian <seisman.info@gmail.com>
Date: Fri, 13 Oct 2023 22:08:43 +0800
Subject: [PATCH 01/19] Refactor the data_kind and the virtualfile_to_data
functions
---
pygmt/clib/session.py | 35 ++++----
pygmt/helpers/__init__.py | 1 +
pygmt/helpers/utils.py | 166 +++++++++++++++++++-------------------
pygmt/src/contour.py | 2 +-
4 files changed, 99 insertions(+), 105 deletions(-)
diff --git a/pygmt/clib/session.py b/pygmt/clib/session.py
index 8db686812c1..0988d87728d 100644
--- a/pygmt/clib/session.py
+++ b/pygmt/clib/session.py
@@ -32,6 +32,7 @@
fmt_docstring,
tempfile_from_geojson,
tempfile_from_image,
+ validate_data_input,
)
FAMILIES = [
@@ -1474,11 +1475,8 @@ def virtualfile_from_data(
self,
check_kind=None,
data=None,
- x=None,
- y=None,
- z=None,
- extra_arrays=None,
- required_z=False,
+ vectors=None,
+ ncols=2,
required_data=True,
):
"""
@@ -1497,13 +1495,11 @@ def virtualfile_from_data(
Any raster or vector data format. This could be a file name or
path, a raster grid, a vector matrix/arrays, or other supported
data input.
- x/y/z : 1-D arrays or None
- x, y, and z columns as numpy arrays.
- extra_arrays : list of 1-D arrays
- Optional. A list of numpy arrays in addition to x, y, and z.
- All of these arrays must be of the same size as the x/y/z arrays.
- required_z : bool
- State whether the 'z' column is required.
+ vectors : list of 1-D arrays or None
+ A list of 1-D arrays. Each array will be a column in the table.
+ All of these arrays must be of the same size.
+ ncols : int
+ The minimum number of columns required for the data.
required_data : bool
Set to True when 'data' is required, or False when dealing with
optional virtual files. [Default is True].
@@ -1537,8 +1533,13 @@ def virtualfile_from_data(
...
<vector memory>: N = 3 <7/9> <4/6> <1/3>
"""
- kind = data_kind(
- data, x, y, z, required_z=required_z, required_data=required_data
+ kind = data_kind(data, required=required_data)
+ validate_data_input(
+ data=data,
+ vectors=vectors,
+ ncols=ncols,
+ required_data=required_data,
+ kind=kind,
)
if check_kind:
@@ -1579,11 +1580,7 @@ def virtualfile_from_data(
warnings.warn(message=msg, category=RuntimeWarning, stacklevel=2)
_data = (data,) if not isinstance(data, pathlib.PurePath) else (str(data),)
elif kind == "vectors":
- _data = [np.atleast_1d(x), np.atleast_1d(y)]
- if z is not None:
- _data.append(np.atleast_1d(z))
- if extra_arrays:
- _data.extend(extra_arrays)
+ _data = [np.atleast_1d(v) for v in vectors]
elif kind == "matrix": # turn 2-D arrays into list of vectors
try:
# pandas.Series will be handled below like a 1-D numpy.ndarray
diff --git a/pygmt/helpers/__init__.py b/pygmt/helpers/__init__.py
index 5eb265e8002..71bc0582252 100644
--- a/pygmt/helpers/__init__.py
+++ b/pygmt/helpers/__init__.py
@@ -20,4 +20,5 @@
is_nonstr_iter,
launch_external_viewer,
non_ascii_to_octal,
+ validate_data_input,
)
diff --git a/pygmt/helpers/utils.py b/pygmt/helpers/utils.py
index 31629a6ea52..d6b7ab8ce5a 100644
--- a/pygmt/helpers/utils.py
+++ b/pygmt/helpers/utils.py
@@ -15,113 +15,125 @@
from pygmt.exceptions import GMTInvalidInput
-def _validate_data_input(
- data=None, x=None, y=None, z=None, required_z=False, required_data=True, kind=None
+def validate_data_input(
+ data=None, vectors=None, ncols=2, required_data=True, kind=None
):
"""
- Check if the combination of data/x/y/z is valid.
+ Check if the data input is valid.
Examples
--------
- >>> _validate_data_input(data="infile")
- >>> _validate_data_input(x=[1, 2, 3], y=[4, 5, 6])
- >>> _validate_data_input(x=[1, 2, 3], y=[4, 5, 6], z=[7, 8, 9])
- >>> _validate_data_input(data=None, required_data=False)
- >>> _validate_data_input()
+ >>> validate_data_input(data="infile")
+ >>> validate_data_input(vectors=[[1, 2, 3], [4, 5, 6]], ncols=2)
+ >>> validate_data_input(vectors=[[1, 2, 3], [4, 5, 6], [7, 8, 9]], ncols=3)
+ >>> validate_data_input(data=None, required_data=False)
+ >>> validate_data_input()
Traceback (most recent call last):
...
pygmt.exceptions.GMTInvalidInput: No input data provided.
- >>> _validate_data_input(x=[1, 2, 3])
+ >>> validate_data_input(vectors=[[1, 2, 3], None], ncols=2)
Traceback (most recent call last):
...
- pygmt.exceptions.GMTInvalidInput: Must provide both x and y.
- >>> _validate_data_input(y=[4, 5, 6])
+ pygmt.exceptions.GMTInvalidInput: The 'y' column can't be None.
+ >>> validate_data_input(vectors=[None, [4, 5, 6]], ncols=2)
Traceback (most recent call last):
...
- pygmt.exceptions.GMTInvalidInput: Must provide both x and y.
- >>> _validate_data_input(x=[1, 2, 3], y=[4, 5, 6], required_z=True)
+ pygmt.exceptions.GMTInvalidInput: The 'x' column can't be None.
+ >>> validate_data_input(vectors=[[1, 2, 3], [4, 5, 6], None], ncols=3)
Traceback (most recent call last):
...
- pygmt.exceptions.GMTInvalidInput: Must provide x, y, and z.
+ pygmt.exceptions.GMTInvalidInput: The 'z' column can't be None.
>>> import numpy as np
>>> import pandas as pd
>>> import xarray as xr
>>> data = np.arange(8).reshape((4, 2))
- >>> _validate_data_input(data=data, required_z=True, kind="matrix")
+ >>> validate_data_input(data=data, ncols=3, kind="matrix")
Traceback (most recent call last):
...
- pygmt.exceptions.GMTInvalidInput: data must provide x, y, and z columns.
- >>> _validate_data_input(
+ pygmt.exceptions.GMTInvalidInput: data must have at least 3 columns.
+ >>> validate_data_input(
... data=pd.DataFrame(data, columns=["x", "y"]),
- ... required_z=True,
+ ... ncols=3,
... kind="matrix",
... )
Traceback (most recent call last):
...
- pygmt.exceptions.GMTInvalidInput: data must provide x, y, and z columns.
- >>> _validate_data_input(
+ pygmt.exceptions.GMTInvalidInput: data must have at least 3 columns.
+ >>> validate_data_input(
... data=xr.Dataset(pd.DataFrame(data, columns=["x", "y"])),
- ... required_z=True,
+ ... ncols=3,
... kind="matrix",
... )
Traceback (most recent call last):
...
- pygmt.exceptions.GMTInvalidInput: data must provide x, y, and z columns.
- >>> _validate_data_input(data="infile", x=[1, 2, 3])
+ pygmt.exceptions.GMTInvalidInput: data must have at least 3 columns.
+ >>> validate_data_input(data="infile", vectors=[[1, 2, 3], None])
Traceback (most recent call last):
...
- pygmt.exceptions.GMTInvalidInput: Too much data. Use either data or x/y/z.
- >>> _validate_data_input(data="infile", y=[4, 5, 6])
+ pygmt.exceptions.GMTInvalidInput: Too much data. Pass in either 'data' or 1-D arrays. # noqa: W505
+ >>> validate_data_input(data="infile", vectors=[None, [4, 5, 6]])
Traceback (most recent call last):
...
- pygmt.exceptions.GMTInvalidInput: Too much data. Use either data or x/y/z.
- >>> _validate_data_input(data="infile", z=[7, 8, 9])
+ pygmt.exceptions.GMTInvalidInput: Too much data. Pass in either 'data' or 1-D arrays. # noqa: W505
+ >>> validate_data_input(data="infile", vectors=[None, None, [7, 8, 9]])
Traceback (most recent call last):
...
- pygmt.exceptions.GMTInvalidInput: Too much data. Use either data or x/y/z.
+ pygmt.exceptions.GMTInvalidInput: Too much data. Pass in either 'data' or 1-D arrays. # noqa: W505
Raises
------
GMTInvalidInput
If the data input is not valid.
"""
- if data is None: # data is None
- if x is None and y is None: # both x and y are None
- if required_data: # data is not optional
- raise GMTInvalidInput("No input data provided.")
- elif x is None or y is None: # either x or y is None
- raise GMTInvalidInput("Must provide both x and y.")
- if required_z and z is None: # both x and y are not None, now check z
- raise GMTInvalidInput("Must provide x, y, and z.")
- else: # data is not None
- if x is not None or y is not None or z is not None:
- raise GMTInvalidInput("Too much data. Use either data or x/y/z.")
- # For 'matrix' kind, check if data has the required z column
- if kind == "matrix" and required_z:
+ if kind is None:
+ kind = data_kind(data=data, required=required_data)
+
+ if kind == "vectors": # From data_kind, we know that data is None
+ if vectors is None:
+ raise GMTInvalidInput("No input data provided.")
+ if len(vectors) < ncols:
+ raise GMTInvalidInput(
+ f"Requires {ncols} 1-D arrays but got {len(vectors)}."
+ )
+ for i, v in enumerate(vectors[:ncols]):
+ if v is None:
+ if i < 3:
+ msg = f"The '{'xyz'[i]}' column can't be None."
+ else:
+ msg = "Column {i} can't be None."
+ raise GMTInvalidInput(msg)
+ else:
+ if vectors is not None and any(v is not None for v in vectors):
+ raise GMTInvalidInput("Too much data. Pass in either 'data' or 1-D arrays.")
+ if kind == "matrix": # check number of columns for matrix-like data
if hasattr(data, "shape"): # np.ndarray or pd.DataFrame
- if len(data.shape) == 1 and data.shape[0] < 3:
- raise GMTInvalidInput("data must provide x, y, and z columns.")
- if len(data.shape) > 1 and data.shape[1] < 3:
- raise GMTInvalidInput("data must provide x, y, and z columns.")
- if hasattr(data, "data_vars") and len(data.data_vars) < 3: # xr.Dataset
- raise GMTInvalidInput("data must provide x, y, and z columns.")
+ if len(data.shape) == 1 and data.shape[0] < ncols:
+ raise GMTInvalidInput(f"data must have at least {ncols} columns.")
+ if len(data.shape) > 1 and data.shape[1] < ncols:
+ raise GMTInvalidInput(f"data must have at least {ncols} columns.")
+ if hasattr(data, "data_vars") and len(data.data_vars) < ncols: # xr.Dataset
+ raise GMTInvalidInput(f"data must have at least {ncols} columns.")
-def data_kind(data=None, x=None, y=None, z=None, required_z=False, required_data=True):
+def data_kind(data=None, required=True):
"""
- Check what kind of data is provided to a module.
+ Determine the kind of data that will be passed to a module.
- Possible types:
+ It checks the type of the ``data`` argument and determines the kind of
+ data. Falls back to ``"vectors"`` if ``data`` is None but required.
- * a file name provided as 'data'
- * a pathlib.PurePath object provided as 'data'
- * an xarray.DataArray object provided as 'data'
- * a 2-D matrix provided as 'data'
- * 1-D arrays x and y (and z, optionally)
- * an optional argument (None, bool, int or float) provided as 'data'
+ Possible data kinds:
- Arguments should be ``None`` if not used. If doesn't fit any of these
- categories (or fits more than one), will raise an exception.
+ - ``'file'``: a file name or a pathlib.PurePath object providfed as 'data'
+ - ``'arg'``: an optional argument (None, bool, int or float) provided
+ as 'data'
+ - ``'grid'``: an xarray.DataArray with 2 dimensions provided as 'data'
+ - ``'image'``: an xarray.DataArray with 3 dimensions provided as 'data'
+ - ``'geojson'``: a geo-like Python object that implements
+ ``__geo_interface__`` (geopandas.GeoDataFrame or shapely.geometry)
+ provided as 'data'
+ - ``'matrix'``: a 2-D array provided as 'data'
+ - ``'vectors'``: a list of 1-D arrays provided as 'vectors'
Parameters
----------
@@ -129,13 +141,7 @@ def data_kind(data=None, x=None, y=None, z=None, required_z=False, required_data
Pass in either a file name or :class:`pathlib.Path` to an ASCII data
table, an :class:`xarray.DataArray`, a 1-D/2-D
{table-classes} or an option argument.
- x/y : 1-D arrays or None
- x and y columns as numpy arrays.
- z : 1-D array or None
- z column as numpy array. To be used optionally when x and y are given.
- required_z : bool
- State whether the 'z' column is required.
- required_data : bool
+ required : bool
Set to True when 'data' is required, or False when dealing with
optional virtual files. [Default is True].
@@ -151,29 +157,28 @@ def data_kind(data=None, x=None, y=None, z=None, required_z=False, required_data
>>> import numpy as np
>>> import xarray as xr
>>> import pathlib
- >>> data_kind(data=None, x=np.array([1, 2, 3]), y=np.array([4, 5, 6]))
+ >>> data_kind(data=None)
'vectors'
- >>> data_kind(data=np.arange(10).reshape((5, 2)), x=None, y=None)
+ >>> data_kind(data=np.arange(10).reshape((5, 2)))
'matrix'
- >>> data_kind(data="my-data-file.txt", x=None, y=None)
+ >>> data_kind(data="my-data-file.txt")
'file'
- >>> data_kind(data=pathlib.Path("my-data-file.txt"), x=None, y=None)
+ >>> data_kind(data=pathlib.Path("my-data-file.txt"))
'file'
- >>> data_kind(data=None, x=None, y=None, required_data=False)
+ >>> data_kind(data=None, required=False)
'arg'
- >>> data_kind(data=2.0, x=None, y=None, required_data=False)
+ >>> data_kind(data=2.0, required=False)
'arg'
- >>> data_kind(data=True, x=None, y=None, required_data=False)
+ >>> data_kind(data=True, required=False)
'arg'
>>> data_kind(data=xr.DataArray(np.random.rand(4, 3)))
'grid'
>>> data_kind(data=xr.DataArray(np.random.rand(3, 4, 5)))
'image'
"""
- # determine the data kind
if isinstance(data, (str, pathlib.PurePath)):
kind = "file"
- elif isinstance(data, (bool, int, float)) or (data is None and not required_data):
+ elif isinstance(data, (bool, int, float)) or (data is None and not required):
kind = "arg"
elif isinstance(data, xr.DataArray):
kind = "image" if len(data.dims) == 3 else "grid"
@@ -181,19 +186,10 @@ def data_kind(data=None, x=None, y=None, z=None, required_z=False, required_data
# geo-like Python object that implements ``__geo_interface__``
# (geopandas.GeoDataFrame or shapely.geometry)
kind = "geojson"
- elif data is not None:
+ elif data is not None: # anything but None is taken as a matrix
kind = "matrix"
- else:
+ else: # fallback to vectors if data is None but required
kind = "vectors"
- _validate_data_input(
- data=data,
- x=x,
- y=y,
- z=z,
- required_z=required_z,
- required_data=required_data,
- kind=kind,
- )
return kind
diff --git a/pygmt/src/contour.py b/pygmt/src/contour.py
index 6aaf22b7cd6..ac34dcb5d95 100644
--- a/pygmt/src/contour.py
+++ b/pygmt/src/contour.py
@@ -116,7 +116,7 @@ def contour(self, data=None, x=None, y=None, z=None, **kwargs):
with Session() as lib:
file_context = lib.virtualfile_from_data(
- check_kind="vector", data=data, x=x, y=y, z=z, required_z=True
+ check_kind="vector", data=data, vectors=[x, y, z], ncols=3
)
with file_context as fname:
lib.call_module(
From 78c28cdd52679b92dfb78e36e27a029bc30c56e7 Mon Sep 17 00:00:00 2001
From: Dongdong Tian <seisman.info@gmail.com>
Date: Sat, 14 Oct 2023 21:59:34 +0800
Subject: [PATCH 02/19] Update more functions
---
pygmt/src/blockm.py | 2 +-
pygmt/src/nearneighbor.py | 2 +-
pygmt/src/plot.py | 19 ++++++++++++-------
pygmt/src/plot3d.py | 25 ++++++++++++-------------
pygmt/src/project.py | 2 +-
pygmt/src/rose.py | 2 +-
pygmt/src/sphdistance.py | 2 +-
pygmt/src/surface.py | 2 +-
pygmt/src/text.py | 13 ++++++++-----
pygmt/src/triangulate.py | 2 +-
pygmt/src/wiggle.py | 2 +-
pygmt/src/xyz2grd.py | 2 +-
12 files changed, 41 insertions(+), 34 deletions(-)
diff --git a/pygmt/src/blockm.py b/pygmt/src/blockm.py
index bc896c853dc..d8462445ed6 100644
--- a/pygmt/src/blockm.py
+++ b/pygmt/src/blockm.py
@@ -44,7 +44,7 @@ def _blockm(block_method, data, x, y, z, outfile, **kwargs):
with GMTTempFile(suffix=".csv") as tmpfile:
with Session() as lib:
table_context = lib.virtualfile_from_data(
- check_kind="vector", data=data, x=x, y=y, z=z, required_z=True
+ check_kind="vector", data=data, vectors=[x, y, z], ncols=3
)
# Run blockm* on data table
with table_context as infile:
diff --git a/pygmt/src/nearneighbor.py b/pygmt/src/nearneighbor.py
index 53aa9057dde..b53b8ec4a9f 100644
--- a/pygmt/src/nearneighbor.py
+++ b/pygmt/src/nearneighbor.py
@@ -150,7 +150,7 @@ def nearneighbor(data=None, x=None, y=None, z=None, **kwargs):
with GMTTempFile(suffix=".nc") as tmpfile:
with Session() as lib:
table_context = lib.virtualfile_from_data(
- check_kind="vector", data=data, x=x, y=y, z=z, required_z=True
+ check_kind="vector", data=data, vectors=[x, y, z], ncols=3
)
with table_context as infile:
if (outgrid := kwargs.get("G")) is None:
diff --git a/pygmt/src/plot.py b/pygmt/src/plot.py
index 069ef5c7077..3e998122486 100644
--- a/pygmt/src/plot.py
+++ b/pygmt/src/plot.py
@@ -213,11 +213,13 @@ def plot(self, data=None, x=None, y=None, size=None, direction=None, **kwargs):
# pylint: disable=too-many-locals
kwargs = self._preprocess(**kwargs) # pylint: disable=protected-access
- kind = data_kind(data, x, y)
+ kind = data_kind(data)
+ vectors = [x, y]
+ ncols = 2
- extra_arrays = []
if kwargs.get("S") is not None and kwargs["S"][0] in "vV" and direction is not None:
- extra_arrays.extend(direction)
+ vectors.extend(direction)
+ ncols += 2
elif (
kwargs.get("S") is None
and kind == "geojson"
@@ -239,14 +241,16 @@ def plot(self, data=None, x=None, y=None, size=None, direction=None, **kwargs):
raise GMTInvalidInput(
"Can't use arrays for fill if data is matrix or file."
)
- extra_arrays.append(kwargs["G"])
+ vectors.append(kwargs["G"])
+ ncols += 1
del kwargs["G"]
if size is not None:
if kind != "vectors":
raise GMTInvalidInput(
"Can't use arrays for 'size' if data is a matrix or file."
)
- extra_arrays.append(size)
+ vectors.append(size)
+ ncols += 1
for flag in ["I", "t"]:
if kwargs.get(flag) is not None and is_nonstr_iter(kwargs[flag]):
@@ -254,12 +258,13 @@ def plot(self, data=None, x=None, y=None, size=None, direction=None, **kwargs):
raise GMTInvalidInput(
f"Can't use arrays for {plot.aliases[flag]} if data is matrix or file."
)
- extra_arrays.append(kwargs[flag])
+ vectors.append(kwargs[flag])
+ ncols += 1
kwargs[flag] = ""
with Session() as lib:
file_context = lib.virtualfile_from_data(
- check_kind="vector", data=data, x=x, y=y, extra_arrays=extra_arrays
+ check_kind="vector", data=data, vectors=vectors, ncols=ncols
)
with file_context as fname:
diff --git a/pygmt/src/plot3d.py b/pygmt/src/plot3d.py
index 8999933ff6f..215b659ac8f 100644
--- a/pygmt/src/plot3d.py
+++ b/pygmt/src/plot3d.py
@@ -183,11 +183,13 @@ def plot3d(
# pylint: disable=too-many-locals
kwargs = self._preprocess(**kwargs) # pylint: disable=protected-access
- kind = data_kind(data, x, y, z)
+ kind = data_kind(data)
+ vectors = [x, y, z]
+ ncols = 3
- extra_arrays = []
if kwargs.get("S") is not None and kwargs["S"][0] in "vV" and direction is not None:
- extra_arrays.extend(direction)
+ vectors.extend(direction)
+ ncols += 2
elif (
kwargs.get("S") is None
and kind == "geojson"
@@ -209,14 +211,16 @@ def plot3d(
raise GMTInvalidInput(
"Can't use arrays for fill if data is matrix or file."
)
- extra_arrays.append(kwargs["G"])
+ vectors.append(kwargs["G"])
+ ncols += 1
del kwargs["G"]
if size is not None:
if kind != "vectors":
raise GMTInvalidInput(
"Can't use arrays for 'size' if data is a matrix or a file."
)
- extra_arrays.append(size)
+ ncols += 1
+ vectors.append(size)
for flag in ["I", "t"]:
if kwargs.get(flag) is not None and is_nonstr_iter(kwargs[flag]):
@@ -224,18 +228,13 @@ def plot3d(
raise GMTInvalidInput(
f"Can't use arrays for {plot3d.aliases[flag]} if data is matrix or file."
)
- extra_arrays.append(kwargs[flag])
+ vectors.append(kwargs[flag])
+ ncols += 1
kwargs[flag] = ""
with Session() as lib:
file_context = lib.virtualfile_from_data(
- check_kind="vector",
- data=data,
- x=x,
- y=y,
- z=z,
- extra_arrays=extra_arrays,
- required_z=True,
+ check_kind="vector", data=data, vectors=vectors, ncols=ncols
)
with file_context as fname:
diff --git a/pygmt/src/project.py b/pygmt/src/project.py
index bdb2490c071..dd7f665fd4b 100644
--- a/pygmt/src/project.py
+++ b/pygmt/src/project.py
@@ -228,7 +228,7 @@ def project(data=None, x=None, y=None, z=None, outfile=None, **kwargs):
with Session() as lib:
if kwargs.get("G") is None:
table_context = lib.virtualfile_from_data(
- check_kind="vector", data=data, x=x, y=y, z=z, required_z=False
+ check_kind="vector", data=data, vectors=[x, y, z], ncols=3
)
# Run project on the temporary (csv) data table
diff --git a/pygmt/src/rose.py b/pygmt/src/rose.py
index c60ede7d61d..4a9b39d2cfd 100644
--- a/pygmt/src/rose.py
+++ b/pygmt/src/rose.py
@@ -203,7 +203,7 @@ def rose(self, data=None, length=None, azimuth=None, **kwargs):
with Session() as lib:
file_context = lib.virtualfile_from_data(
- check_kind="vector", data=data, x=length, y=azimuth
+ check_kind="vector", data=data, vectors=[length, azimuth], ncols=2
)
with file_context as fname:
diff --git a/pygmt/src/sphdistance.py b/pygmt/src/sphdistance.py
index f6242b1f43d..46f2ee2abc2 100644
--- a/pygmt/src/sphdistance.py
+++ b/pygmt/src/sphdistance.py
@@ -120,7 +120,7 @@ def sphdistance(data=None, x=None, y=None, **kwargs):
with GMTTempFile(suffix=".nc") as tmpfile:
with Session() as lib:
file_context = lib.virtualfile_from_data(
- check_kind="vector", data=data, x=x, y=y
+ check_kind="vector", data=data, vectors=[x, y], ncols=2
)
with file_context as infile:
if (outgrid := kwargs.get("G")) is None:
diff --git a/pygmt/src/surface.py b/pygmt/src/surface.py
index 80987f80de4..32b099c2af0 100644
--- a/pygmt/src/surface.py
+++ b/pygmt/src/surface.py
@@ -165,7 +165,7 @@ def surface(data=None, x=None, y=None, z=None, **kwargs):
with GMTTempFile(suffix=".nc") as tmpfile:
with Session() as lib:
file_context = lib.virtualfile_from_data(
- check_kind="vector", data=data, x=x, y=y, z=z, required_z=True
+ check_kind="vector", data=data, vectors=[x, y, z], ncols=3
)
with file_context as infile:
if (outgrid := kwargs.get("G")) is None:
diff --git a/pygmt/src/text.py b/pygmt/src/text.py
index cd7dabcc3d5..f4a368aa16f 100644
--- a/pygmt/src/text.py
+++ b/pygmt/src/text.py
@@ -179,7 +179,7 @@ def text_(
raise GMTInvalidInput(
"Provide either position only, or x/y pairs, or textfiles."
)
- kind = data_kind(textfiles, x, y, text)
+ kind = data_kind(textfiles)
if kind == "vectors" and text is None:
raise GMTInvalidInput("Must provide text with x/y pairs")
else:
@@ -221,22 +221,25 @@ def text_(
if isinstance(position, str):
kwargs["F"] += f"+c{position}+t{text}"
- extra_arrays = []
+ vectors = [x, y]
+ ncols = 2
# If an array of transparency is given, GMT will read it from
# the last numerical column per data record.
if kwargs.get("t") is not None and is_nonstr_iter(kwargs["t"]):
- extra_arrays.append(kwargs["t"])
+ vectors.append(kwargs["t"])
kwargs["t"] = ""
+ ncols += 1
# Append text at last column. Text must be passed in as str type.
if kind == "vectors":
- extra_arrays.append(
+ vectors.append(
np.vectorize(non_ascii_to_octal)(np.atleast_1d(text).astype(str))
)
+ ncols += 1
with Session() as lib:
file_context = lib.virtualfile_from_data(
- check_kind="vector", data=textfiles, x=x, y=y, extra_arrays=extra_arrays
+ check_kind="vector", data=textfiles, vectors=vectors, ncols=ncols
)
with file_context as fname:
lib.call_module(module="text", args=build_arg_string(kwargs, infile=fname))
diff --git a/pygmt/src/triangulate.py b/pygmt/src/triangulate.py
index de77394cc9b..3f47926e90b 100644
--- a/pygmt/src/triangulate.py
+++ b/pygmt/src/triangulate.py
@@ -127,7 +127,7 @@ def _triangulate(
"""
with Session() as lib:
table_context = lib.virtualfile_from_data(
- check_kind="vector", data=data, x=x, y=y, z=z, required_z=False
+ check_kind="vector", data=data, vectors=[x, y, z], ncols=3
)
with table_context as infile:
# table output if outgrid is unset, else output to outgrid
diff --git a/pygmt/src/wiggle.py b/pygmt/src/wiggle.py
index ff5dec107a1..2b2577a0b2c 100644
--- a/pygmt/src/wiggle.py
+++ b/pygmt/src/wiggle.py
@@ -122,7 +122,7 @@ def wiggle(
with Session() as lib:
file_context = lib.virtualfile_from_data(
- check_kind="vector", data=data, x=x, y=y, z=z, required_z=True
+ check_kind="vector", data=data, vectors=[x, y, z], ncols=3
)
with file_context as fname:
diff --git a/pygmt/src/xyz2grd.py b/pygmt/src/xyz2grd.py
index fe510cc3316..b0cf1f51ff2 100644
--- a/pygmt/src/xyz2grd.py
+++ b/pygmt/src/xyz2grd.py
@@ -154,7 +154,7 @@ def xyz2grd(data=None, x=None, y=None, z=None, **kwargs):
with GMTTempFile(suffix=".nc") as tmpfile:
with Session() as lib:
file_context = lib.virtualfile_from_data(
- check_kind="vector", data=data, x=x, y=y, z=z, required_z=True
+ check_kind="vector", data=data, vectors=[x, y, z], ncols=3
)
with file_context as infile:
if (outgrid := kwargs.get("G")) is None:
From f37413b2aa03c24de6c9ea1e94053d7607b4d9b2 Mon Sep 17 00:00:00 2001
From: Dongdong Tian <seisman.info@gmail.com>
Date: Sun, 15 Oct 2023 19:14:33 +0800
Subject: [PATCH 03/19] Change ncols to names
---
pygmt/clib/session.py | 9 +++---
pygmt/helpers/utils.py | 64 +++++++++++++++++++++++++--------------
pygmt/src/blockm.py | 2 +-
pygmt/src/contour.py | 2 +-
pygmt/src/nearneighbor.py | 2 +-
pygmt/src/plot.py | 12 ++++----
pygmt/src/plot3d.py | 12 ++++----
pygmt/src/project.py | 2 +-
pygmt/src/rose.py | 5 ++-
pygmt/src/sphdistance.py | 2 +-
pygmt/src/surface.py | 2 +-
pygmt/src/text.py | 8 ++---
pygmt/src/triangulate.py | 2 +-
pygmt/src/wiggle.py | 2 +-
pygmt/src/xyz2grd.py | 2 +-
15 files changed, 75 insertions(+), 53 deletions(-)
diff --git a/pygmt/clib/session.py b/pygmt/clib/session.py
index 0988d87728d..c2a0ba12427 100644
--- a/pygmt/clib/session.py
+++ b/pygmt/clib/session.py
@@ -1476,7 +1476,7 @@ def virtualfile_from_data(
check_kind=None,
data=None,
vectors=None,
- ncols=2,
+ names=["x", "y"],
required_data=True,
):
"""
@@ -1498,8 +1498,9 @@ def virtualfile_from_data(
vectors : list of 1-D arrays or None
A list of 1-D arrays. Each array will be a column in the table.
All of these arrays must be of the same size.
- ncols : int
- The minimum number of columns required for the data.
+ names : list of str
+ A list of names for each of the columns. Must be of the same size
+ as the number of vectors. Default is ``["x", "y"]``.
required_data : bool
Set to True when 'data' is required, or False when dealing with
optional virtual files. [Default is True].
@@ -1537,7 +1538,7 @@ def virtualfile_from_data(
validate_data_input(
data=data,
vectors=vectors,
- ncols=ncols,
+ names=names,
required_data=required_data,
kind=kind,
)
diff --git a/pygmt/helpers/utils.py b/pygmt/helpers/utils.py
index d6b7ab8ce5a..6926f1a1911 100644
--- a/pygmt/helpers/utils.py
+++ b/pygmt/helpers/utils.py
@@ -16,30 +16,49 @@
def validate_data_input(
- data=None, vectors=None, ncols=2, required_data=True, kind=None
+ data=None, vectors=None, names=["x", "y"], required_data=True, kind=None
):
"""
Check if the data input is valid.
+ Parameters
+ ----------
+ data : str, pathlib.PurePath, None, bool, xarray.DataArray or {table-like}
+ Pass in either a file name or :class:`pathlib.Path` to an ASCII data
+ table, an :class:`xarray.DataArray`, a 1-D/2-D
+ {table-classes} or an option argument.
+ vectors : list of 1-D arrays
+ A list of 1-D arrays with the data columns.
+ names : list of str
+ List of column names.
+ required_data : bool
+ Set to True when 'data' is required, or False when dealing with
+ optional virtual files. [Default is True].
+ kind : str or None
+ The kind of data that will be passed to a module. If not given, it
+ will be determined by calling :func:`data_kind`.
+
Examples
--------
>>> validate_data_input(data="infile")
- >>> validate_data_input(vectors=[[1, 2, 3], [4, 5, 6]], ncols=2)
- >>> validate_data_input(vectors=[[1, 2, 3], [4, 5, 6], [7, 8, 9]], ncols=3)
+ >>> validate_data_input(vectors=[[1, 2, 3], [4, 5, 6]], names="xy")
+ >>> validate_data_input(
+ ... vectors=[[1, 2, 3], [4, 5, 6], [7, 8, 9]], names="xyz"
+ ... )
>>> validate_data_input(data=None, required_data=False)
>>> validate_data_input()
Traceback (most recent call last):
...
pygmt.exceptions.GMTInvalidInput: No input data provided.
- >>> validate_data_input(vectors=[[1, 2, 3], None], ncols=2)
+ >>> validate_data_input(vectors=[[1, 2, 3], None], names="xy")
Traceback (most recent call last):
...
pygmt.exceptions.GMTInvalidInput: The 'y' column can't be None.
- >>> validate_data_input(vectors=[None, [4, 5, 6]], ncols=2)
+ >>> validate_data_input(vectors=[None, [4, 5, 6]], names="xy")
Traceback (most recent call last):
...
pygmt.exceptions.GMTInvalidInput: The 'x' column can't be None.
- >>> validate_data_input(vectors=[[1, 2, 3], [4, 5, 6], None], ncols=3)
+ >>> validate_data_input(vectors=[[1, 2, 3], [4, 5, 6], None], names="xyz")
Traceback (most recent call last):
...
pygmt.exceptions.GMTInvalidInput: The 'z' column can't be None.
@@ -47,13 +66,13 @@ def validate_data_input(
>>> import pandas as pd
>>> import xarray as xr
>>> data = np.arange(8).reshape((4, 2))
- >>> validate_data_input(data=data, ncols=3, kind="matrix")
+ >>> validate_data_input(data=data, names="xyz", kind="matrix")
Traceback (most recent call last):
...
pygmt.exceptions.GMTInvalidInput: data must have at least 3 columns.
>>> validate_data_input(
... data=pd.DataFrame(data, columns=["x", "y"]),
- ... ncols=3,
+ ... names="xyz",
... kind="matrix",
... )
Traceback (most recent call last):
@@ -61,7 +80,7 @@ def validate_data_input(
pygmt.exceptions.GMTInvalidInput: data must have at least 3 columns.
>>> validate_data_input(
... data=xr.Dataset(pd.DataFrame(data, columns=["x", "y"])),
- ... ncols=3,
+ ... names="xyz",
... kind="matrix",
... )
Traceback (most recent call last):
@@ -91,28 +110,27 @@ def validate_data_input(
if kind == "vectors": # From data_kind, we know that data is None
if vectors is None:
raise GMTInvalidInput("No input data provided.")
- if len(vectors) < ncols:
+ if len(vectors) < len(names):
raise GMTInvalidInput(
- f"Requires {ncols} 1-D arrays but got {len(vectors)}."
+ f"Requires {len(names)} 1-D arrays but got {len(vectors)}."
)
- for i, v in enumerate(vectors[:ncols]):
+ for i, v in enumerate(vectors[: len(names)]):
if v is None:
- if i < 3:
- msg = f"The '{'xyz'[i]}' column can't be None."
- else:
- msg = "Column {i} can't be None."
- raise GMTInvalidInput(msg)
+ raise GMTInvalidInput(f"Column {i} ('{names[i]}') can't be None.")
else:
if vectors is not None and any(v is not None for v in vectors):
raise GMTInvalidInput("Too much data. Pass in either 'data' or 1-D arrays.")
if kind == "matrix": # check number of columns for matrix-like data
+ msg = f"data must have at least {len(names)} columns.\n" + " ".join(names)
if hasattr(data, "shape"): # np.ndarray or pd.DataFrame
- if len(data.shape) == 1 and data.shape[0] < ncols:
- raise GMTInvalidInput(f"data must have at least {ncols} columns.")
- if len(data.shape) > 1 and data.shape[1] < ncols:
- raise GMTInvalidInput(f"data must have at least {ncols} columns.")
- if hasattr(data, "data_vars") and len(data.data_vars) < ncols: # xr.Dataset
- raise GMTInvalidInput(f"data must have at least {ncols} columns.")
+ if len(data.shape) == 1 and data.shape[0] < len(names):
+ raise GMTInvalidInput(msg)
+ if len(data.shape) > 1 and data.shape[1] < len(names):
+ raise GMTInvalidInput(msg)
+ if hasattr(data, "data_vars") and len(data.data_vars) < len(
+ names
+ ): # xr.Dataset
+ raise GMTInvalidInput(msg)
def data_kind(data=None, required=True):
diff --git a/pygmt/src/blockm.py b/pygmt/src/blockm.py
index d8462445ed6..bfe1be138dd 100644
--- a/pygmt/src/blockm.py
+++ b/pygmt/src/blockm.py
@@ -44,7 +44,7 @@ def _blockm(block_method, data, x, y, z, outfile, **kwargs):
with GMTTempFile(suffix=".csv") as tmpfile:
with Session() as lib:
table_context = lib.virtualfile_from_data(
- check_kind="vector", data=data, vectors=[x, y, z], ncols=3
+ check_kind="vector", data=data, vectors=[x, y, z], names="xyz"
)
# Run blockm* on data table
with table_context as infile:
diff --git a/pygmt/src/contour.py b/pygmt/src/contour.py
index ac34dcb5d95..3e88c45aec5 100644
--- a/pygmt/src/contour.py
+++ b/pygmt/src/contour.py
@@ -116,7 +116,7 @@ def contour(self, data=None, x=None, y=None, z=None, **kwargs):
with Session() as lib:
file_context = lib.virtualfile_from_data(
- check_kind="vector", data=data, vectors=[x, y, z], ncols=3
+ check_kind="vector", data=data, vectors=[x, y, z], names="xyz"
)
with file_context as fname:
lib.call_module(
diff --git a/pygmt/src/nearneighbor.py b/pygmt/src/nearneighbor.py
index b53b8ec4a9f..d266cce075c 100644
--- a/pygmt/src/nearneighbor.py
+++ b/pygmt/src/nearneighbor.py
@@ -150,7 +150,7 @@ def nearneighbor(data=None, x=None, y=None, z=None, **kwargs):
with GMTTempFile(suffix=".nc") as tmpfile:
with Session() as lib:
table_context = lib.virtualfile_from_data(
- check_kind="vector", data=data, vectors=[x, y, z], ncols=3
+ check_kind="vector", data=data, vectors=[x, y, z], names="xyz"
)
with table_context as infile:
if (outgrid := kwargs.get("G")) is None:
diff --git a/pygmt/src/plot.py b/pygmt/src/plot.py
index 3e998122486..5c7bfb20351 100644
--- a/pygmt/src/plot.py
+++ b/pygmt/src/plot.py
@@ -215,11 +215,11 @@ def plot(self, data=None, x=None, y=None, size=None, direction=None, **kwargs):
kind = data_kind(data)
vectors = [x, y]
- ncols = 2
+ names = ["x", "y"]
if kwargs.get("S") is not None and kwargs["S"][0] in "vV" and direction is not None:
vectors.extend(direction)
- ncols += 2
+ names.extend(["x2", "y2"])
elif (
kwargs.get("S") is None
and kind == "geojson"
@@ -242,7 +242,7 @@ def plot(self, data=None, x=None, y=None, size=None, direction=None, **kwargs):
"Can't use arrays for fill if data is matrix or file."
)
vectors.append(kwargs["G"])
- ncols += 1
+ names.append("fill")
del kwargs["G"]
if size is not None:
if kind != "vectors":
@@ -250,7 +250,7 @@ def plot(self, data=None, x=None, y=None, size=None, direction=None, **kwargs):
"Can't use arrays for 'size' if data is a matrix or file."
)
vectors.append(size)
- ncols += 1
+ names.append("size")
for flag in ["I", "t"]:
if kwargs.get(flag) is not None and is_nonstr_iter(kwargs[flag]):
@@ -259,12 +259,12 @@ def plot(self, data=None, x=None, y=None, size=None, direction=None, **kwargs):
f"Can't use arrays for {plot.aliases[flag]} if data is matrix or file."
)
vectors.append(kwargs[flag])
- ncols += 1
+ names.append(plot.aliases[flag])
kwargs[flag] = ""
with Session() as lib:
file_context = lib.virtualfile_from_data(
- check_kind="vector", data=data, vectors=vectors, ncols=ncols
+ check_kind="vector", data=data, vectors=vectors, names=names
)
with file_context as fname:
diff --git a/pygmt/src/plot3d.py b/pygmt/src/plot3d.py
index 215b659ac8f..1cbce57bc6e 100644
--- a/pygmt/src/plot3d.py
+++ b/pygmt/src/plot3d.py
@@ -185,11 +185,11 @@ def plot3d(
kind = data_kind(data)
vectors = [x, y, z]
- ncols = 3
+ names = ["x", "y", "z"]
if kwargs.get("S") is not None and kwargs["S"][0] in "vV" and direction is not None:
vectors.extend(direction)
- ncols += 2
+ names.extend(["x2", "y2"])
elif (
kwargs.get("S") is None
and kind == "geojson"
@@ -212,15 +212,15 @@ def plot3d(
"Can't use arrays for fill if data is matrix or file."
)
vectors.append(kwargs["G"])
- ncols += 1
+ names.append("fill")
del kwargs["G"]
if size is not None:
if kind != "vectors":
raise GMTInvalidInput(
"Can't use arrays for 'size' if data is a matrix or a file."
)
- ncols += 1
vectors.append(size)
+ names.append("size")
for flag in ["I", "t"]:
if kwargs.get(flag) is not None and is_nonstr_iter(kwargs[flag]):
@@ -229,12 +229,12 @@ def plot3d(
f"Can't use arrays for {plot3d.aliases[flag]} if data is matrix or file."
)
vectors.append(kwargs[flag])
- ncols += 1
+ names.append(plot3d.aliases[flag])
kwargs[flag] = ""
with Session() as lib:
file_context = lib.virtualfile_from_data(
- check_kind="vector", data=data, vectors=vectors, ncols=ncols
+ check_kind="vector", data=data, vectors=vectors, names=names
)
with file_context as fname:
diff --git a/pygmt/src/project.py b/pygmt/src/project.py
index dd7f665fd4b..c5ecd8cb83a 100644
--- a/pygmt/src/project.py
+++ b/pygmt/src/project.py
@@ -228,7 +228,7 @@ def project(data=None, x=None, y=None, z=None, outfile=None, **kwargs):
with Session() as lib:
if kwargs.get("G") is None:
table_context = lib.virtualfile_from_data(
- check_kind="vector", data=data, vectors=[x, y, z], ncols=3
+ check_kind="vector", data=data, vectors=[x, y, z], names="xyz"
)
# Run project on the temporary (csv) data table
diff --git a/pygmt/src/rose.py b/pygmt/src/rose.py
index 4a9b39d2cfd..01862152543 100644
--- a/pygmt/src/rose.py
+++ b/pygmt/src/rose.py
@@ -203,7 +203,10 @@ def rose(self, data=None, length=None, azimuth=None, **kwargs):
with Session() as lib:
file_context = lib.virtualfile_from_data(
- check_kind="vector", data=data, vectors=[length, azimuth], ncols=2
+ check_kind="vector",
+ data=data,
+ vectors=[length, azimuth],
+ names=["length", "azimuth"],
)
with file_context as fname:
diff --git a/pygmt/src/sphdistance.py b/pygmt/src/sphdistance.py
index 46f2ee2abc2..a7179496531 100644
--- a/pygmt/src/sphdistance.py
+++ b/pygmt/src/sphdistance.py
@@ -120,7 +120,7 @@ def sphdistance(data=None, x=None, y=None, **kwargs):
with GMTTempFile(suffix=".nc") as tmpfile:
with Session() as lib:
file_context = lib.virtualfile_from_data(
- check_kind="vector", data=data, vectors=[x, y], ncols=2
+ check_kind="vector", data=data, vectors=[x, y], names="xy"
)
with file_context as infile:
if (outgrid := kwargs.get("G")) is None:
diff --git a/pygmt/src/surface.py b/pygmt/src/surface.py
index 32b099c2af0..62341a52b95 100644
--- a/pygmt/src/surface.py
+++ b/pygmt/src/surface.py
@@ -165,7 +165,7 @@ def surface(data=None, x=None, y=None, z=None, **kwargs):
with GMTTempFile(suffix=".nc") as tmpfile:
with Session() as lib:
file_context = lib.virtualfile_from_data(
- check_kind="vector", data=data, vectors=[x, y, z], ncols=3
+ check_kind="vector", data=data, vectors=[x, y, z], names="xyz"
)
with file_context as infile:
if (outgrid := kwargs.get("G")) is None:
diff --git a/pygmt/src/text.py b/pygmt/src/text.py
index f4a368aa16f..21e652bb8e4 100644
--- a/pygmt/src/text.py
+++ b/pygmt/src/text.py
@@ -222,24 +222,24 @@ def text_(
kwargs["F"] += f"+c{position}+t{text}"
vectors = [x, y]
- ncols = 2
+ names = ["x", "y"]
# If an array of transparency is given, GMT will read it from
# the last numerical column per data record.
if kwargs.get("t") is not None and is_nonstr_iter(kwargs["t"]):
vectors.append(kwargs["t"])
kwargs["t"] = ""
- ncols += 1
+ names.append("transparency")
# Append text at last column. Text must be passed in as str type.
if kind == "vectors":
vectors.append(
np.vectorize(non_ascii_to_octal)(np.atleast_1d(text).astype(str))
)
- ncols += 1
+ names.append("text")
with Session() as lib:
file_context = lib.virtualfile_from_data(
- check_kind="vector", data=textfiles, vectors=vectors, ncols=ncols
+ check_kind="vector", data=textfiles, vectors=vectors, names=names
)
with file_context as fname:
lib.call_module(module="text", args=build_arg_string(kwargs, infile=fname))
diff --git a/pygmt/src/triangulate.py b/pygmt/src/triangulate.py
index 3f47926e90b..da980730638 100644
--- a/pygmt/src/triangulate.py
+++ b/pygmt/src/triangulate.py
@@ -127,7 +127,7 @@ def _triangulate(
"""
with Session() as lib:
table_context = lib.virtualfile_from_data(
- check_kind="vector", data=data, vectors=[x, y, z], ncols=3
+ check_kind="vector", data=data, vectors=[x, y, z], names="xyz"
)
with table_context as infile:
# table output if outgrid is unset, else output to outgrid
diff --git a/pygmt/src/wiggle.py b/pygmt/src/wiggle.py
index 2b2577a0b2c..74cd5c34223 100644
--- a/pygmt/src/wiggle.py
+++ b/pygmt/src/wiggle.py
@@ -122,7 +122,7 @@ def wiggle(
with Session() as lib:
file_context = lib.virtualfile_from_data(
- check_kind="vector", data=data, vectors=[x, y, z], ncols=3
+ check_kind="vector", data=data, vectors=[x, y, z], names="xyz"
)
with file_context as fname:
diff --git a/pygmt/src/xyz2grd.py b/pygmt/src/xyz2grd.py
index b0cf1f51ff2..e0b0d041353 100644
--- a/pygmt/src/xyz2grd.py
+++ b/pygmt/src/xyz2grd.py
@@ -154,7 +154,7 @@ def xyz2grd(data=None, x=None, y=None, z=None, **kwargs):
with GMTTempFile(suffix=".nc") as tmpfile:
with Session() as lib:
file_context = lib.virtualfile_from_data(
- check_kind="vector", data=data, vectors=[x, y, z], ncols=3
+ check_kind="vector", data=data, vectors=[x, y, z], names="xyz"
)
with file_context as infile:
if (outgrid := kwargs.get("G")) is None:
From 3de76667a175493dda96be524cff3bc063515b89 Mon Sep 17 00:00:00 2001
From: Dongdong Tian <seisman.info@gmail.com>
Date: Sun, 15 Oct 2023 20:28:07 +0800
Subject: [PATCH 04/19] Fix more tests
---
pygmt/tests/test_clib.py | 22 +++++-----------------
1 file changed, 5 insertions(+), 17 deletions(-)
diff --git a/pygmt/tests/test_clib.py b/pygmt/tests/test_clib.py
index 9f2c73857cd..a537cd7306c 100644
--- a/pygmt/tests/test_clib.py
+++ b/pygmt/tests/test_clib.py
@@ -440,7 +440,7 @@ def test_virtualfile_from_data_required_z_matrix(array_func, kind):
data = array_func(dataframe)
with clib.Session() as lib:
with lib.virtualfile_from_data(
- data=data, required_z=True, check_kind="vector"
+ data=data, names="xyz", check_kind="vector"
) as vfile:
with GMTTempFile() as outfile:
lib.call_module("info", f"{vfile} ->{outfile.name}")
@@ -463,9 +463,7 @@ def test_virtualfile_from_data_required_z_matrix_missing():
data = np.ones((5, 2))
with clib.Session() as lib:
with pytest.raises(GMTInvalidInput):
- with lib.virtualfile_from_data(
- data=data, required_z=True, check_kind="vector"
- ):
+ with lib.virtualfile_from_data(data=data, names="xyz", check_kind="vector"):
pass
@@ -481,10 +479,7 @@ def test_virtualfile_from_data_fail_non_valid_data(data):
continue
with clib.Session() as lib:
with pytest.raises(GMTInvalidInput):
- lib.virtualfile_from_data(
- x=variable[0],
- y=variable[1],
- )
+ lib.virtualfile_from_data(vectors=variable[:2])
# Test all combinations where at least one data variable
# is not given in the x, y, z case:
@@ -494,19 +489,12 @@ def test_virtualfile_from_data_fail_non_valid_data(data):
continue
with clib.Session() as lib:
with pytest.raises(GMTInvalidInput):
- lib.virtualfile_from_data(
- x=variable[0], y=variable[1], z=variable[2], required_z=True
- )
+ lib.virtualfile_from_data(vectors=variable[:3], names="xyz")
# Should also fail if given too much data
with clib.Session() as lib:
with pytest.raises(GMTInvalidInput):
- lib.virtualfile_from_data(
- x=data[:, 0],
- y=data[:, 1],
- z=data[:, 2],
- data=data,
- )
+ lib.virtualfile_from_data(vectors=data[:, :3], data=data, names="xyz")
def test_virtualfile_from_vectors(dtypes):
From 93b91d041a9a925e1dccc233e0f4e727dcd88045 Mon Sep 17 00:00:00 2001
From: Dongdong Tian <seisman.info@gmail.com>
Date: Sun, 15 Oct 2023 23:43:30 +0800
Subject: [PATCH 05/19] Fix project
---
pygmt/src/project.py | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/pygmt/src/project.py b/pygmt/src/project.py
index c5ecd8cb83a..7eaf846accc 100644
--- a/pygmt/src/project.py
+++ b/pygmt/src/project.py
@@ -227,8 +227,9 @@ def project(data=None, x=None, y=None, z=None, outfile=None, **kwargs):
outfile = tmpfile.name
with Session() as lib:
if kwargs.get("G") is None:
+ # passed three vectors but only x/y are required
table_context = lib.virtualfile_from_data(
- check_kind="vector", data=data, vectors=[x, y, z], names="xyz"
+ check_kind="vector", data=data, vectors=[x, y, z], names="xy"
)
# Run project on the temporary (csv) data table
From 1d6e568227531fd1224196ae0e2d70cf94c33a8f Mon Sep 17 00:00:00 2001
From: Dongdong Tian <seisman.info@gmail.com>
Date: Mon, 16 Oct 2023 13:26:05 +0800
Subject: [PATCH 06/19] Fix more tests
---
pygmt/helpers/utils.py | 6 +++---
pygmt/tests/test_helpers.py | 21 ---------------------
2 files changed, 3 insertions(+), 24 deletions(-)
diff --git a/pygmt/helpers/utils.py b/pygmt/helpers/utils.py
index 6926f1a1911..f45d1d51375 100644
--- a/pygmt/helpers/utils.py
+++ b/pygmt/helpers/utils.py
@@ -53,15 +53,15 @@ def validate_data_input(
>>> validate_data_input(vectors=[[1, 2, 3], None], names="xy")
Traceback (most recent call last):
...
- pygmt.exceptions.GMTInvalidInput: The 'y' column can't be None.
+ pygmt.exceptions.GMTInvalidInput: Column 1 ('y') can't be None.
>>> validate_data_input(vectors=[None, [4, 5, 6]], names="xy")
Traceback (most recent call last):
...
- pygmt.exceptions.GMTInvalidInput: The 'x' column can't be None.
+ pygmt.exceptions.GMTInvalidInput: Column 0 ('x') can't be None.
>>> validate_data_input(vectors=[[1, 2, 3], [4, 5, 6], None], names="xyz")
Traceback (most recent call last):
...
- pygmt.exceptions.GMTInvalidInput: The 'z' column can't be None.
+ pygmt.exceptions.GMTInvalidInput: Column 2 ('z') can't be None.
>>> import numpy as np
>>> import pandas as pd
>>> import xarray as xr
diff --git a/pygmt/tests/test_helpers.py b/pygmt/tests/test_helpers.py
index b726897e12e..02871d62c84 100644
--- a/pygmt/tests/test_helpers.py
+++ b/pygmt/tests/test_helpers.py
@@ -3,7 +3,6 @@
"""
import os
-import numpy as np
import pytest
import xarray as xr
from pygmt import Figure
@@ -11,7 +10,6 @@
from pygmt.helpers import (
GMTTempFile,
args_in_kwargs,
- data_kind,
kwargs_to_strings,
unique_name,
)
@@ -31,25 +29,6 @@ def test_load_static_earth_relief():
assert isinstance(data, xr.DataArray)
-@pytest.mark.parametrize(
- "data,x,y",
- [
- (None, None, None),
- ("data.txt", np.array([1, 2]), np.array([4, 5])),
- ("data.txt", np.array([1, 2]), None),
- ("data.txt", None, np.array([4, 5])),
- (None, np.array([1, 2]), None),
- (None, None, np.array([4, 5])),
- ],
-)
-def test_data_kind_fails(data, x, y):
- """
- Make sure data_kind raises exceptions when it should.
- """
- with pytest.raises(GMTInvalidInput):
- data_kind(data=data, x=x, y=y)
-
-
def test_unique_name():
"""
Make sure the names are really unique.
From 6f9fc195107d8981ae20c368ae97c55f254557e2 Mon Sep 17 00:00:00 2001
From: Dongdong Tian <seisman.info@gmail.com>
Date: Mon, 16 Oct 2023 15:02:44 +0800
Subject: [PATCH 07/19] Fixes
---
pygmt/src/project.py | 8 ++++++--
pygmt/src/triangulate.py | 6 +++++-
2 files changed, 11 insertions(+), 3 deletions(-)
diff --git a/pygmt/src/project.py b/pygmt/src/project.py
index 7eaf846accc..b85c783004e 100644
--- a/pygmt/src/project.py
+++ b/pygmt/src/project.py
@@ -222,14 +222,18 @@ def project(data=None, x=None, y=None, z=None, outfile=None, **kwargs):
"The `convention` parameter is not allowed with `generate`."
)
+ # z is optional
+ vectors, names = [x, y], "xy"
+ if z is not None:
+ vectors.append(z)
+
with GMTTempFile(suffix=".csv") as tmpfile:
if outfile is None: # Output to tmpfile if outfile is not set
outfile = tmpfile.name
with Session() as lib:
if kwargs.get("G") is None:
- # passed three vectors but only x/y are required
table_context = lib.virtualfile_from_data(
- check_kind="vector", data=data, vectors=[x, y, z], names="xy"
+ check_kind="vector", data=data, vectors=vectors, names=names
)
# Run project on the temporary (csv) data table
diff --git a/pygmt/src/triangulate.py b/pygmt/src/triangulate.py
index da980730638..759b567a4c4 100644
--- a/pygmt/src/triangulate.py
+++ b/pygmt/src/triangulate.py
@@ -125,9 +125,13 @@ def _triangulate(
- None if ``output_type`` is "file" (output is stored in
``outgrid`` or ``outfile``)
"""
+ vectors, names = [x, y], "xy"
+ if z is not None:
+ vectors.append(z)
+
with Session() as lib:
table_context = lib.virtualfile_from_data(
- check_kind="vector", data=data, vectors=[x, y, z], names="xyz"
+ check_kind="vector", data=data, vectors=[x, y, z], names="xy"
)
with table_context as infile:
# table output if outgrid is unset, else output to outgrid
From 0db21bca0293140db92428788442830e7647d6c2 Mon Sep 17 00:00:00 2001
From: Dongdong Tian <seisman.info@gmail.com>
Date: Tue, 17 Oct 2023 17:05:08 +0800
Subject: [PATCH 08/19] Fix triangulate
---
pygmt/src/triangulate.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/pygmt/src/triangulate.py b/pygmt/src/triangulate.py
index edf8b010ac0..f89904e1b3f 100644
--- a/pygmt/src/triangulate.py
+++ b/pygmt/src/triangulate.py
@@ -131,7 +131,7 @@ def _triangulate(
with Session() as lib:
table_context = lib.virtualfile_from_data(
- check_kind="vector", data=data, vectors=[x, y, z], names="xy"
+ check_kind="vector", data=data, vectors=vectors, names=names
)
with table_context as infile:
# table output if outgrid is unset, else output to outgrid
From 7cf52903a362fa0ac9c87e3115df1c47ba92acd0 Mon Sep 17 00:00:00 2001
From: Dongdong Tian <seisman.info@gmail.com>
Date: Tue, 17 Oct 2023 17:06:58 +0800
Subject: [PATCH 09/19] Fix text
---
pygmt/src/text.py | 17 +++++++++++------
1 file changed, 11 insertions(+), 6 deletions(-)
diff --git a/pygmt/src/text.py b/pygmt/src/text.py
index f23b166ddd9..91b60b7187a 100644
--- a/pygmt/src/text.py
+++ b/pygmt/src/text.py
@@ -198,24 +198,29 @@ def text_(
):
kwargs.update({"F": ""})
- extra_arrays = []
- for arg, flag in [(angle, "+a"), (font, "+f"), (justify, "+j")]:
+ vectors = [x, y]
+ names = ["x", "y"]
+ for arg, flag, name in [
+ (angle, "+a", "angle"),
+ (font, "+f", "font"),
+ (justify, "+j", "justify"),
+ ]:
if arg is True:
kwargs["F"] += flag
elif is_nonstr_iter(arg):
kwargs["F"] += flag
if flag == "+a": # angle is numeric type
- extra_arrays.append(np.atleast_1d(arg))
+ vectors.append(np.atleast_1d(arg))
+ names.append(name)
else: # font or justify is str type
- extra_arrays.append(np.atleast_1d(arg).astype(str))
+ vectors.append(np.atleast_1d(arg).astype(str))
+ names.append(name)
elif isinstance(arg, (int, float, str)):
kwargs["F"] += f"{flag}{arg}"
if isinstance(position, str):
kwargs["F"] += f"+c{position}+t{text}"
- vectors = [x, y]
- names = ["x", "y"]
# If an array of transparency is given, GMT will read it from
# the last numerical column per data record.
if kwargs.get("t") is not None and is_nonstr_iter(kwargs["t"]):
From b0b6d2a3efd5c80f9bae0e6d59dc21b72ce4fc4a Mon Sep 17 00:00:00 2001
From: Dongdong Tian <seisman.info@gmail.com>
Date: Tue, 17 Oct 2023 17:18:23 +0800
Subject: [PATCH 10/19] Fix more failing tests
---
pygmt/helpers/utils.py | 3 +++
1 file changed, 3 insertions(+)
diff --git a/pygmt/helpers/utils.py b/pygmt/helpers/utils.py
index f45d1d51375..aa3796800f8 100644
--- a/pygmt/helpers/utils.py
+++ b/pygmt/helpers/utils.py
@@ -70,6 +70,7 @@ def validate_data_input(
Traceback (most recent call last):
...
pygmt.exceptions.GMTInvalidInput: data must have at least 3 columns.
+ x y z
>>> validate_data_input(
... data=pd.DataFrame(data, columns=["x", "y"]),
... names="xyz",
@@ -78,6 +79,7 @@ def validate_data_input(
Traceback (most recent call last):
...
pygmt.exceptions.GMTInvalidInput: data must have at least 3 columns.
+ x y z
>>> validate_data_input(
... data=xr.Dataset(pd.DataFrame(data, columns=["x", "y"])),
... names="xyz",
@@ -86,6 +88,7 @@ def validate_data_input(
Traceback (most recent call last):
...
pygmt.exceptions.GMTInvalidInput: data must have at least 3 columns.
+ x y z
>>> validate_data_input(data="infile", vectors=[[1, 2, 3], None])
Traceback (most recent call last):
...
From fa875efff861d512501b81f4f9c3e9c7a9e712f4 Mon Sep 17 00:00:00 2001
From: Dongdong Tian <seisman.info@gmail.com>
Date: Tue, 17 Oct 2023 17:33:47 +0800
Subject: [PATCH 11/19] More fixes
---
pygmt/helpers/utils.py | 6 +++---
pygmt/src/text.py | 2 ++
2 files changed, 5 insertions(+), 3 deletions(-)
diff --git a/pygmt/helpers/utils.py b/pygmt/helpers/utils.py
index aa3796800f8..ddc4c66ca40 100644
--- a/pygmt/helpers/utils.py
+++ b/pygmt/helpers/utils.py
@@ -92,15 +92,15 @@ def validate_data_input(
>>> validate_data_input(data="infile", vectors=[[1, 2, 3], None])
Traceback (most recent call last):
...
- pygmt.exceptions.GMTInvalidInput: Too much data. Pass in either 'data' or 1-D arrays. # noqa: W505
+ pygmt.exceptions.GMTInvalidInput: Too much data. Pass in either 'data' or 1-D arrays.
>>> validate_data_input(data="infile", vectors=[None, [4, 5, 6]])
Traceback (most recent call last):
...
- pygmt.exceptions.GMTInvalidInput: Too much data. Pass in either 'data' or 1-D arrays. # noqa: W505
+ pygmt.exceptions.GMTInvalidInput: Too much data. Pass in either 'data' or 1-D arrays.
>>> validate_data_input(data="infile", vectors=[None, None, [7, 8, 9]])
Traceback (most recent call last):
...
- pygmt.exceptions.GMTInvalidInput: Too much data. Pass in either 'data' or 1-D arrays. # noqa: W505
+ pygmt.exceptions.GMTInvalidInput: Too much data. Pass in either 'data' or 1-D arrays.
Raises
------
diff --git a/pygmt/src/text.py b/pygmt/src/text.py
index 91b60b7187a..87ecce5eb66 100644
--- a/pygmt/src/text.py
+++ b/pygmt/src/text.py
@@ -179,6 +179,8 @@ def text_(
kind = data_kind(textfiles)
if kind == "vectors" and text is None:
raise GMTInvalidInput("Must provide text with x/y pairs")
+ if kind != "vectors" and text is not None:
+ raise GMTInvalidInput("Must provide text with x/y pairs")
else:
if x is not None or y is not None or textfiles is not None:
raise GMTInvalidInput(
From 2ee0df27d06297b7313cb13e15ccb5a2b4ede505 Mon Sep 17 00:00:00 2001
From: Dongdong Tian <seisman.info@gmail.com>
Date: Tue, 17 Oct 2023 18:12:06 +0800
Subject: [PATCH 12/19] Fix linting issues
---
pygmt/helpers/utils.py | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/pygmt/helpers/utils.py b/pygmt/helpers/utils.py
index ddc4c66ca40..8f8099184f8 100644
--- a/pygmt/helpers/utils.py
+++ b/pygmt/helpers/utils.py
@@ -92,15 +92,15 @@ def validate_data_input(
>>> validate_data_input(data="infile", vectors=[[1, 2, 3], None])
Traceback (most recent call last):
...
- pygmt.exceptions.GMTInvalidInput: Too much data. Pass in either 'data' or 1-D arrays.
+ ...GMTInvalidInput: Too much data. Pass in either 'data' or 1-D arrays.
>>> validate_data_input(data="infile", vectors=[None, [4, 5, 6]])
Traceback (most recent call last):
...
- pygmt.exceptions.GMTInvalidInput: Too much data. Pass in either 'data' or 1-D arrays.
+ ...GMTInvalidInput: Too much data. Pass in either 'data' or 1-D arrays.
>>> validate_data_input(data="infile", vectors=[None, None, [7, 8, 9]])
Traceback (most recent call last):
...
- pygmt.exceptions.GMTInvalidInput: Too much data. Pass in either 'data' or 1-D arrays.
+ ...GMTInvalidInput: Too much data. Pass in either 'data' or 1-D arrays.
Raises
------
From d5c83408bdb59ae899566cf803bdf1535c2edaad Mon Sep 17 00:00:00 2001
From: Dongdong Tian <seisman.info@gmail.com>
Date: Tue, 17 Oct 2023 19:12:43 +0800
Subject: [PATCH 13/19] Fix linting issues
---
pygmt/helpers/utils.py | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/pygmt/helpers/utils.py b/pygmt/helpers/utils.py
index 8f8099184f8..9a243b7fb28 100644
--- a/pygmt/helpers/utils.py
+++ b/pygmt/helpers/utils.py
@@ -92,15 +92,15 @@ def validate_data_input(
>>> validate_data_input(data="infile", vectors=[[1, 2, 3], None])
Traceback (most recent call last):
...
- ...GMTInvalidInput: Too much data. Pass in either 'data' or 1-D arrays.
+ pygmt...GMTInvalidInput: Too much data. Use either 'data' or 1-D arrays.
>>> validate_data_input(data="infile", vectors=[None, [4, 5, 6]])
Traceback (most recent call last):
...
- ...GMTInvalidInput: Too much data. Pass in either 'data' or 1-D arrays.
+ pygmt...GMTInvalidInput: Too much data. Use either 'data' or 1-D arrays.
>>> validate_data_input(data="infile", vectors=[None, None, [7, 8, 9]])
Traceback (most recent call last):
...
- ...GMTInvalidInput: Too much data. Pass in either 'data' or 1-D arrays.
+ pygmt...GMTInvalidInput: Too much data. Use either 'data' or 1-D arrays.
Raises
------
@@ -122,7 +122,7 @@ def validate_data_input(
raise GMTInvalidInput(f"Column {i} ('{names[i]}') can't be None.")
else:
if vectors is not None and any(v is not None for v in vectors):
- raise GMTInvalidInput("Too much data. Pass in either 'data' or 1-D arrays.")
+ raise GMTInvalidInput("Too much data. Use either 'data' or 1-D arrays.")
if kind == "matrix": # check number of columns for matrix-like data
msg = f"data must have at least {len(names)} columns.\n" + " ".join(names)
if hasattr(data, "shape"): # np.ndarray or pd.DataFrame
From 30bacb13bd10e8c13e2faf617826e1b20861b1d6 Mon Sep 17 00:00:00 2001
From: Dongdong Tian <seisman.info@gmail.com>
Date: Wed, 18 Oct 2023 10:10:56 +0800
Subject: [PATCH 14/19] Fix linting issues
---
pygmt/clib/session.py | 2 +-
pygmt/helpers/utils.py | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/pygmt/clib/session.py b/pygmt/clib/session.py
index 82321f83b6a..052ae04ca0d 100644
--- a/pygmt/clib/session.py
+++ b/pygmt/clib/session.py
@@ -1474,7 +1474,7 @@ def virtualfile_from_data(
check_kind=None,
data=None,
vectors=None,
- names=["x", "y"],
+ names="xy",
required_data=True,
):
"""
diff --git a/pygmt/helpers/utils.py b/pygmt/helpers/utils.py
index 9a243b7fb28..0c25aaf251a 100644
--- a/pygmt/helpers/utils.py
+++ b/pygmt/helpers/utils.py
@@ -16,7 +16,7 @@
def validate_data_input(
- data=None, vectors=None, names=["x", "y"], required_data=True, kind=None
+ data=None, vectors=None, names="xy", required_data=True, kind=None
):
"""
Check if the data input is valid.
From 593f252178b9a5958dc8d82b90da78f6f59a509f Mon Sep 17 00:00:00 2001
From: Dongdong Tian <seisman.info@gmail.com>
Date: Fri, 20 Oct 2023 15:59:42 +0800
Subject: [PATCH 15/19] Update pygmt/clib/session.py
---
pygmt/clib/session.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/pygmt/clib/session.py b/pygmt/clib/session.py
index 052ae04ca0d..25260fb9581 100644
--- a/pygmt/clib/session.py
+++ b/pygmt/clib/session.py
@@ -1496,9 +1496,9 @@ def virtualfile_from_data(
vectors : list of 1-D arrays or None
A list of 1-D arrays. Each array will be a column in the table.
All of these arrays must be of the same size.
- names : list of str
+ names : str or list of str
A list of names for each of the columns. Must be of the same size
- as the number of vectors. Default is ``["x", "y"]``.
+ as the number of vectors. Default is ``"xy"``.
required_data : bool
Set to True when 'data' is required, or False when dealing with
optional virtual files. [Default is True].
From 409337f7572fb3ed865c35596ae59ae41608d07d Mon Sep 17 00:00:00 2001
From: Dongdong Tian <seisman.info@gmail.com>
Date: Wed, 25 Oct 2023 08:52:28 +0800
Subject: [PATCH 16/19] Apply suggestions from code review
Co-authored-by: Michael Grund <23025878+michaelgrund@users.noreply.github.com>
---
pygmt/helpers/utils.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/pygmt/helpers/utils.py b/pygmt/helpers/utils.py
index ff7ecb589b0..413993c6b1b 100644
--- a/pygmt/helpers/utils.py
+++ b/pygmt/helpers/utils.py
@@ -33,7 +33,7 @@ def validate_data_input(
List of column names.
required_data : bool
Set to True when 'data' is required, or False when dealing with
- optional virtual files. [Default is True].
+ optional virtual files [Default is True].
kind : str or None
The kind of data that will be passed to a module. If not given, it
will be determined by calling :func:`data_kind`.
@@ -145,7 +145,7 @@ def data_kind(data=None, required=True):
Possible data kinds:
- - ``'file'``: a file name or a pathlib.PurePath object providfed as 'data'
+ - ``'file'``: a file name or a pathlib.PurePath object provided as 'data'
- ``'arg'``: an optional argument (None, bool, int or float) provided
as 'data'
- ``'grid'``: an xarray.DataArray with 2 dimensions provided as 'data'
From 5c10fc47482687158aac5292c7f6adf6aab984b7 Mon Sep 17 00:00:00 2001
From: Dongdong Tian <seisman.info@gmail.com>
Date: Thu, 11 Jul 2024 18:05:37 +0800
Subject: [PATCH 17/19] Fix plot and plot3d
---
pygmt/src/plot.py | 81 +++++++++++++++++++--------------------------
pygmt/src/plot3d.py | 81 +++++++++++++++++++--------------------------
2 files changed, 68 insertions(+), 94 deletions(-)
diff --git a/pygmt/src/plot.py b/pygmt/src/plot.py
index ecf817d2b74..4d62db7ca4b 100644
--- a/pygmt/src/plot.py
+++ b/pygmt/src/plot.py
@@ -2,8 +2,6 @@
plot - Plot in two dimensions.
"""
-from pathlib import Path
-
from pygmt.clib import Session
from pygmt.exceptions import GMTInvalidInput
from pygmt.helpers import (
@@ -14,7 +12,6 @@
kwargs_to_strings,
use_alias,
)
-from pygmt.src.which import which
@fmt_docstring
@@ -210,50 +207,40 @@ def plot(self, data=None, x=None, y=None, size=None, direction=None, **kwargs):
vectors = [x, y]
names = ["x", "y"]
- if kwargs.get("S") is not None and kwargs["S"][0] in "vV" and direction is not None:
- vectors.extend(direction)
- names.extend(["x2", "y2"])
- elif (
- kwargs.get("S") is None
- and kind == "geojson"
- and data.geom_type.isin(["Point", "MultiPoint"]).all()
- ): # checking if the geometry of a geoDataFrame is Point or MultiPoint
- kwargs["S"] = "s0.2c"
- elif kwargs.get("S") is None and kind == "file" and str(data).endswith(".gmt"):
- # checking that the data is a file path to set default style
- try:
- with Path.open(which(data), encoding="utf8") as file:
- line = file.readline()
- if "@GMULTIPOINT" in line or "@GPOINT" in line:
- # if the file is gmt style and geometry is set to Point
- kwargs["S"] = "s0.2c"
- except FileNotFoundError:
- pass
- if is_nonstr_iter(kwargs.get("G")):
- if kind != "vectors":
- raise GMTInvalidInput(
- "Can't use arrays for fill if data is matrix or file."
- )
- vectors.append(kwargs["G"])
- names.append("fill")
- del kwargs["G"]
- if size is not None:
- if kind != "vectors":
- raise GMTInvalidInput(
- "Can't use arrays for 'size' if data is a matrix or file."
- )
- vectors.append(size)
- names.append("size")
-
- for flag in ["I", "t"]:
- if is_nonstr_iter(kwargs.get(flag)):
- if kind != "vectors":
- raise GMTInvalidInput(
- f"Can't use arrays for {plot.aliases[flag]} if data is matrix or file."
- )
- vectors.append(kwargs[flag])
- names.append(plot.aliases[flag])
- kwargs[flag] = ""
+ if kind == "vectors": # Add more columns for vectors input
+ # Parameters for vector styles
+ if (
+ kwargs.get("S") is not None
+ and kwargs["S"][0] in "vV"
+ and is_nonstr_iter(direction)
+ ):
+ vectors.extend(direction)
+ names.extend(["x2", "y2"])
+ # Fill
+ if is_nonstr_iter(kwargs.get("G")):
+ vectors.append(kwargs["G"])
+ names.append("fill")
+ del kwargs["G"]
+ # Size
+ if is_nonstr_iter(size):
+ vectors.append(size)
+ names.append("size")
+ # Intensity and transparency
+ for flag in ["I", "t"]:
+ if is_nonstr_iter(kwargs.get(flag)):
+ vectors.append(kwargs[flag])
+ names.append(plot.aliases[flag])
+ kwargs[flag] = ""
+ else:
+ for name, value in [
+ ("direction", direction),
+ ("fill", kwargs.get("G")),
+ ("size", size),
+ ("intensity", kwargs.get("I")),
+ ("transparency", kwargs.get("t")),
+ ]:
+ if is_nonstr_iter(value):
+ raise GMTInvalidInput(f"'{name}' can't be 1-D array if 'data' is used.")
with Session() as lib:
file_context = lib.virtualfile_in(
diff --git a/pygmt/src/plot3d.py b/pygmt/src/plot3d.py
index f85f8defccd..9b2e8da3610 100644
--- a/pygmt/src/plot3d.py
+++ b/pygmt/src/plot3d.py
@@ -2,8 +2,6 @@
plot3d - Plot in three dimensions.
"""
-from pathlib import Path
-
from pygmt.clib import Session
from pygmt.exceptions import GMTInvalidInput
from pygmt.helpers import (
@@ -14,7 +12,6 @@
kwargs_to_strings,
use_alias,
)
-from pygmt.src.which import which
@fmt_docstring
@@ -187,50 +184,40 @@ def plot3d(
vectors = [x, y, z]
names = ["x", "y", "z"]
- if kwargs.get("S") is not None and kwargs["S"][0] in "vV" and direction is not None:
- vectors.extend(direction)
- names.extend(["x2", "y2"])
- elif (
- kwargs.get("S") is None
- and kind == "geojson"
- and data.geom_type.isin(["Point", "MultiPoint"]).all()
- ): # checking if the geometry of a geoDataFrame is Point or MultiPoint
- kwargs["S"] = "u0.2c"
- elif kwargs.get("S") is None and kind == "file" and str(data).endswith(".gmt"):
- # checking that the data is a file path to set default style
- try:
- with Path.open(which(data), encoding="utf8") as file:
- line = file.readline()
- if "@GMULTIPOINT" in line or "@GPOINT" in line:
- # if the file is gmt style and geometry is set to Point
- kwargs["S"] = "u0.2c"
- except FileNotFoundError:
- pass
- if is_nonstr_iter(kwargs.get("G")):
- if kind != "vectors":
- raise GMTInvalidInput(
- "Can't use arrays for fill if data is matrix or file."
- )
- vectors.append(kwargs["G"])
- names.append("fill")
- del kwargs["G"]
- if size is not None:
- if kind != "vectors":
- raise GMTInvalidInput(
- "Can't use arrays for 'size' if data is a matrix or a file."
- )
- vectors.append(size)
- names.append("size")
-
- for flag in ["I", "t"]:
- if is_nonstr_iter(kwargs.get(flag)):
- if kind != "vectors":
- raise GMTInvalidInput(
- f"Can't use arrays for {plot3d.aliases[flag]} if data is matrix or file."
- )
- vectors.append(kwargs[flag])
- names.append(plot3d.aliases[flag])
- kwargs[flag] = ""
+ if kind == "vectors": # Add more columns for vectors input
+ # Parameters for vector styles
+ if (
+ kwargs.get("S") is not None
+ and kwargs["S"][0] in "vV"
+ and is_nonstr_iter(direction)
+ ):
+ vectors.extend(direction)
+ names.extend(["x2", "y2", "z2"])
+ # Fill
+ if is_nonstr_iter(kwargs.get("G")):
+ vectors.append(kwargs["G"])
+ names.append("fill")
+ del kwargs["G"]
+ # Size
+ if is_nonstr_iter(size):
+ vectors.append(size)
+ names.append("size")
+ # Intensity and transparency
+ for flag in ["I", "t"]:
+ if is_nonstr_iter(kwargs.get(flag)):
+ vectors.append(kwargs[flag])
+ names.append(plot3d.aliases[flag])
+ kwargs[flag] = ""
+ else:
+ for name, value in [
+ ("direction", direction),
+ ("fill", kwargs.get("G")),
+ ("size", size),
+ ("intensity", kwargs.get("I")),
+ ("transparency", kwargs.get("t")),
+ ]:
+ if is_nonstr_iter(value):
+ raise GMTInvalidInput(f"'{name}' can't be 1-D array if 'data' is used.")
with Session() as lib:
file_context = lib.virtualfile_in(
From 525a35339d37752efe3300c6ac9a28d3568bcecc Mon Sep 17 00:00:00 2001
From: Dongdong Tian <seisman.info@gmail.com>
Date: Thu, 11 Jul 2024 18:09:00 +0800
Subject: [PATCH 18/19] Fix errors in merging the main branch
---
pygmt/src/plot.py | 19 +++++++++++++++++--
pygmt/src/plot3d.py | 16 ++++++++++++++++
2 files changed, 33 insertions(+), 2 deletions(-)
diff --git a/pygmt/src/plot.py b/pygmt/src/plot.py
index 4d62db7ca4b..bc25f726d56 100644
--- a/pygmt/src/plot.py
+++ b/pygmt/src/plot.py
@@ -2,16 +2,19 @@
plot - Plot in two dimensions.
"""
+from pathlib import Path
+
from pygmt.clib import Session
from pygmt.exceptions import GMTInvalidInput
from pygmt.helpers import (
- build_arg_string,
+ build_arg_list,
data_kind,
fmt_docstring,
is_nonstr_iter,
kwargs_to_strings,
use_alias,
)
+from pygmt.src import which
@fmt_docstring
@@ -241,6 +244,18 @@ def plot(self, data=None, x=None, y=None, size=None, direction=None, **kwargs):
]:
if is_nonstr_iter(value):
raise GMTInvalidInput(f"'{name}' can't be 1-D array if 'data' is used.")
+ # Set the default style if data has a geometry of Point or MultiPoint
+ if kwargs.get("S") is None:
+ if kind == "geojson" and data.geom_type.isin(["Point", "MultiPoint"]).all():
+ kwargs["S"] = "s0.2c"
+ elif kind == "file" and str(data).endswith(".gmt"): # OGR_GMT file
+ try:
+ with Path(which(data)).open(encoding="utf-8") as file:
+ line = file.readline()
+ if "@GMULTIPOINT" in line or "@GPOINT" in line:
+ kwargs["S"] = "s0.2c"
+ except FileNotFoundError:
+ pass
with Session() as lib:
file_context = lib.virtualfile_in(
@@ -248,4 +263,4 @@ def plot(self, data=None, x=None, y=None, size=None, direction=None, **kwargs):
)
with file_context as fname:
- lib.call_module(module="plot", args=build_arg_string(kwargs, infile=fname))
+ lib.call_module(module="plot", args=build_arg_list(kwargs, infile=fname))
diff --git a/pygmt/src/plot3d.py b/pygmt/src/plot3d.py
index 9b2e8da3610..d7fd54ba140 100644
--- a/pygmt/src/plot3d.py
+++ b/pygmt/src/plot3d.py
@@ -2,6 +2,8 @@
plot3d - Plot in three dimensions.
"""
+from pathlib import Path
+
from pygmt.clib import Session
from pygmt.exceptions import GMTInvalidInput
from pygmt.helpers import (
@@ -12,6 +14,7 @@
kwargs_to_strings,
use_alias,
)
+from pygmt.src import which
@fmt_docstring
@@ -219,6 +222,19 @@ def plot3d(
if is_nonstr_iter(value):
raise GMTInvalidInput(f"'{name}' can't be 1-D array if 'data' is used.")
+ # Set the default style if data has a geometry of Point or MultiPoint
+ if kwargs.get("S") is None:
+ if kind == "geojson" and data.geom_type.isin(["Point", "MultiPoint"]).all():
+ kwargs["S"] = "u0.2c"
+ elif kind == "file" and str(data).endswith(".gmt"): # OGR_GMT file
+ try:
+ with Path(which(data)).open(encoding="utf-8") as file:
+ line = file.readline()
+ if "@GMULTIPOINT" in line or "@GPOINT" in line:
+ kwargs["S"] = "u0.2c"
+ except FileNotFoundError:
+ pass
+
with Session() as lib:
file_context = lib.virtualfile_in(
check_kind="vector", data=data, vectors=vectors, names=names
From b55a9ad384e258ce0a00715081d26e255fa31fb6 Mon Sep 17 00:00:00 2001
From: Dongdong Tian <seisman.info@gmail.com>
Date: Sat, 20 Jul 2024 14:09:11 +0800
Subject: [PATCH 19/19] Fix merging issue
---
pygmt/clib/session.py | 4 ++--
pygmt/helpers/__init__.py | 1 -
2 files changed, 2 insertions(+), 3 deletions(-)
diff --git a/pygmt/clib/session.py b/pygmt/clib/session.py
index 24ea1583f8f..dcab42d43b7 100644
--- a/pygmt/clib/session.py
+++ b/pygmt/clib/session.py
@@ -34,10 +34,10 @@
GMTVersionError,
)
from pygmt.helpers import (
+ _validate_data_input,
data_kind,
tempfile_from_geojson,
tempfile_from_image,
- validate_data_input,
)
FAMILIES = [
@@ -1682,7 +1682,7 @@ def virtualfile_in(
<vector memory>: N = 3 <7/9> <4/6> <1/3>
"""
kind = data_kind(data, required=required_data)
- validate_data_input(
+ _validate_data_input(
data=data,
vectors=vectors,
names=names,
diff --git a/pygmt/helpers/__init__.py b/pygmt/helpers/__init__.py
index 337ac1df530..862abbbdd64 100644
--- a/pygmt/helpers/__init__.py
+++ b/pygmt/helpers/__init__.py
@@ -23,6 +23,5 @@
is_nonstr_iter,
launch_external_viewer,
non_ascii_to_octal,
- validate_data_input,
)
from pygmt.helpers.validators import validate_output_table_type