From 6a75bb3fa234d571dacb89958ca3d1d21cdff9c9 Mon Sep 17 00:00:00 2001 From: Dongdong Tian Date: Wed, 27 May 2020 00:59:21 -0400 Subject: [PATCH 1/9] Support various datetime types as input Currently supported datetime types: - [numpy.datetime64](https://numpy.org/doc/stable/reference/arrays.datetime.html) - [pandas.DateTimeIndex](https://pandas.pydata.org/docs/user_guide/timeseries.html) --- pygmt/clib/conversion.py | 1 - pygmt/clib/session.py | 25 ++++++++++++-------- pygmt/tests/baseline/test_plot_datetime.png | Bin 0 -> 16890 bytes pygmt/tests/test_plot.py | 21 ++++++++++++++++ 4 files changed, 36 insertions(+), 11 deletions(-) create mode 100644 pygmt/tests/baseline/test_plot_datetime.png diff --git a/pygmt/clib/conversion.py b/pygmt/clib/conversion.py index 2e0c35d210b..723e56da8f9 100644 --- a/pygmt/clib/conversion.py +++ b/pygmt/clib/conversion.py @@ -2,7 +2,6 @@ Functions to convert data types into ctypes friendly formats. """ import numpy as np -import pandas from ..exceptions import GMTInvalidInput diff --git a/pygmt/clib/session.py b/pygmt/clib/session.py index 961965102a4..eda0f3999ff 100644 --- a/pygmt/clib/session.py +++ b/pygmt/clib/session.py @@ -48,12 +48,13 @@ REGISTRATIONS = ["GMT_GRID_PIXEL_REG", "GMT_GRID_NODE_REG"] DTYPES = { - "float64": "GMT_DOUBLE", - "float32": "GMT_FLOAT", - "int64": "GMT_LONG", - "int32": "GMT_INT", - "uint64": "GMT_ULONG", - "uint32": "GMT_UINT", + np.float64: "GMT_DOUBLE", + np.float32: "GMT_FLOAT", + np.int64: "GMT_LONG", + np.int32: "GMT_INT", + np.uint64: "GMT_ULONG", + np.uint32: "GMT_UINT", + np.datetime64: "GMT_DATETIME", } @@ -708,15 +709,15 @@ def _check_dtype_and_dim(self, array, ndim): True """ - if array.dtype.name not in DTYPES: + if array.dtype.type not in DTYPES: raise GMTInvalidInput( - "Unsupported numpy data type '{}'.".format(array.dtype.name) + "Unsupported numpy data type '{}'.".format(array.dtype.type) ) if array.ndim != ndim: raise GMTInvalidInput( "Expected a numpy 1d array, got {}d.".format(array.ndim) ) - return self[DTYPES[array.dtype.name]] + return self[DTYPES[array.dtype.type]] def put_vector(self, dataset, column, vector): """ @@ -762,7 +763,11 @@ def put_vector(self, dataset, column, vector): ) gmt_type = self._check_dtype_and_dim(vector, ndim=1) - vector_pointer = vector.ctypes.data_as(ctp.c_void_p) + if gmt_type == self["GMT_DATETIME"]: + vector_pointer = (ctp.c_char_p * len(vector))() + vector_pointer[:] = np.char.encode(np.datetime_as_string(vector)) + else: + vector_pointer = vector.ctypes.data_as(ctp.c_void_p) status = c_put_vector( self.session_pointer, dataset, column, gmt_type, vector_pointer ) diff --git a/pygmt/tests/baseline/test_plot_datetime.png b/pygmt/tests/baseline/test_plot_datetime.png new file mode 100644 index 0000000000000000000000000000000000000000..49c67c6909e19c3064df1feb4b7a060707d11533 GIT binary patch literal 16890 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 YKk3viuq}v6hN Date: Fri, 29 May 2020 23:16:24 -0400 Subject: [PATCH 2/9] Support raw strings and the Python built-in datetime and date --- pygmt/clib/session.py | 17 ++++++++++++----- pygmt/tests/test_plot.py | 15 +++++++++++++-- 2 files changed, 25 insertions(+), 7 deletions(-) diff --git a/pygmt/clib/session.py b/pygmt/clib/session.py index eda0f3999ff..f415ba15daa 100644 --- a/pygmt/clib/session.py +++ b/pygmt/clib/session.py @@ -709,14 +709,19 @@ def _check_dtype_and_dim(self, array, ndim): True """ - if array.dtype.type not in DTYPES: - raise GMTInvalidInput( - "Unsupported numpy data type '{}'.".format(array.dtype.type) - ) if array.ndim != ndim: raise GMTInvalidInput( "Expected a numpy 1d array, got {}d.".format(array.ndim) ) + + if array.dtype.type not in DTYPES: + # Try to convert the unknown numpy data type to np.datetime64 + try: + array = np.asarray(array, dtype=np.datetime64) + except ValueError: + raise GMTInvalidInput( + "Unsupported numpy data type '{}'.".format(array.dtype.type) + ) return self[DTYPES[array.dtype.type]] def put_vector(self, dataset, column, vector): @@ -765,7 +770,9 @@ def put_vector(self, dataset, column, vector): gmt_type = self._check_dtype_and_dim(vector, ndim=1) if gmt_type == self["GMT_DATETIME"]: vector_pointer = (ctp.c_char_p * len(vector))() - vector_pointer[:] = np.char.encode(np.datetime_as_string(vector)) + vector_pointer[:] = np.char.encode( + np.datetime_as_string(vector.astype(np.datetime64)) + ) else: vector_pointer = vector.ctypes.data_as(ctp.c_void_p) status = c_put_vector( diff --git a/pygmt/tests/test_plot.py b/pygmt/tests/test_plot.py index d61d1321dbd..78e175c8294 100644 --- a/pygmt/tests/test_plot.py +++ b/pygmt/tests/test_plot.py @@ -6,6 +6,7 @@ import numpy as np import pandas as pd +import datetime import pytest from .. import Figure @@ -284,7 +285,17 @@ def test_plot_datetime(): fig.plot(x, y, style="c0.2c", pen="1p") # pandas.DatetimeIndex - x = pd.date_range("2014", freq="YS", periods=3) - y = [5, 6, 7] + x = pd.date_range("2013", freq="YS", periods=3) + y = [4, 5, 6] fig.plot(x, y, style="t0.2c", pen="1p") + + # raw datetime strings + x = ["2016-02-01", "2017-03-04T00:00"] + y = [7, 8] + fig.plot(x, y, style="a0.2c", pen="1p") + + # the Python built-in datetime and date + x = [datetime.date(2018, 1, 1), datetime.datetime(2019, 1, 1)] + y = [8.5, 9.5] + fig.plot(x, y, style="i0.2c", pen="1p") return fig From 261f93cf3fae5f7cfc9f532024c316bdb1837230 Mon Sep 17 00:00:00 2001 From: Dongdong Tian Date: Fri, 29 May 2020 23:28:48 -0400 Subject: [PATCH 3/9] Add more comments --- pygmt/clib/session.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/pygmt/clib/session.py b/pygmt/clib/session.py index f415ba15daa..c9f81d0e424 100644 --- a/pygmt/clib/session.py +++ b/pygmt/clib/session.py @@ -709,14 +709,16 @@ def _check_dtype_and_dim(self, array, ndim): True """ + # check the array has the given dimension if array.ndim != ndim: raise GMTInvalidInput( "Expected a numpy 1d array, got {}d.".format(array.ndim) ) + # check the array has a valid/known data type if array.dtype.type not in DTYPES: - # Try to convert the unknown numpy data type to np.datetime64 try: + # Try to convert any unknown numpy data types to np.datetime64 array = np.asarray(array, dtype=np.datetime64) except ValueError: raise GMTInvalidInput( From fa6ab93c953001aef03f74004d0e543e05028f63 Mon Sep 17 00:00:00 2001 From: Dongdong Tian Date: Thu, 4 Jun 2020 01:41:10 -0400 Subject: [PATCH 4/9] Add a function array_to_datetime to convert any legal array/list to pandas.DateTimeIndex and numpy.datetime64 types --- pygmt/clib/conversion.py | 64 ++++++++++++++++++++++++++++++++++++++++ pygmt/clib/session.py | 3 +- 2 files changed, 66 insertions(+), 1 deletion(-) diff --git a/pygmt/clib/conversion.py b/pygmt/clib/conversion.py index 723e56da8f9..f3fb1063416 100644 --- a/pygmt/clib/conversion.py +++ b/pygmt/clib/conversion.py @@ -2,6 +2,7 @@ Functions to convert data types into ctypes friendly formats. """ import numpy as np +import pandas as pd from ..exceptions import GMTInvalidInput @@ -237,3 +238,66 @@ def kwargs_to_ctypes_array(argument, kwargs, dtype): if argument in kwargs: return dtype(*kwargs[argument]) return None + + +def array_to_datetime(array): + """ + Convert an 1D datetime array from various types into pandas.DatetimeIndex + (i.e., numpy.datetime64). + + If the input array is not in legal datetime formats, raise a "ParseError" + exception. + + Parameters + ---------- + array : list or 1d array + The input datetime array in various formats. + + Supported types: + + - str + - numpy.datetime64 + - pandas.DateTimeIndex + - datetime.datetime and datetime.date + + Returns + ------- + array : 1D datetime array in pandas.DatetimeIndex (i.e., numpy.datetime64) + + Examples + -------- + >>> import datetime + >>> # numpy.datetime64 array + >>> x = np.array(["2010-06-01", "2011-06-01T12", "2012-01-01T12:34:56"], + ... dtype="datetime64") + >>> array_to_datetime(x) + DatetimeIndex(['2010-06-01 00:00:00', '2011-06-01 12:00:00', + '2012-01-01 12:34:56'], + dtype='datetime64[ns]', freq=None) + >>> # pandas.DateTimeIndex array + >>> x = pd.date_range("2013", freq="YS", periods=3) + >>> array_to_datetime(x) + DatetimeIndex(['2013-01-01', '2014-01-01', '2015-01-01'], + dtype='datetime64[ns]', freq='AS-JAN') + >>> # Python's built-in date and datetime + >>> x = [datetime.date(2018, 1, 1), datetime.datetime(2019, 1, 1)] + >>> array_to_datetime(x) + DatetimeIndex(['2018-01-01', '2019-01-01'], dtype='datetime64[ns]', + freq=None) + >>> # Raw datetime strings in various format + >>> x = ['2018', "2018-02", "2018-03-01", "2018-04-01T01:02:03", + ... "5/1/2018", "Jun 05, 2018", "2018/07/02"] + >>> array_to_datetime(x) + DatetimeIndex(['2018-01-01 00:00:00', '2018-02-01 00:00:00', + '2018-03-01 00:00:00', '2018-04-01 01:02:03', + '2018-05-01 00:00:00', '2018-06-05 00:00:00', + '2018-07-02 00:00:00'], + dtype='datetime64[ns]', freq=None) + >>> # Mixed datetime types + >>> x = ['2018-01-01', np.datetime64('2018-01-01'), + ... datetime.datetime(2018, 1, 1)] + >>> array_to_datetime(x) + DatetimeIndex(['2018-01-01', '2018-01-01', '2018-01-01'], + dtype='datetime64[ns]', freq=None) + """ + return pd.to_datetime(array) diff --git a/pygmt/clib/session.py b/pygmt/clib/session.py index c9f81d0e424..434640179fc 100644 --- a/pygmt/clib/session.py +++ b/pygmt/clib/session.py @@ -22,6 +22,7 @@ vectors_to_arrays, dataarray_to_matrix, as_c_contiguous, + array_to_datetime, ) FAMILIES = [ @@ -773,7 +774,7 @@ def put_vector(self, dataset, column, vector): if gmt_type == self["GMT_DATETIME"]: vector_pointer = (ctp.c_char_p * len(vector))() vector_pointer[:] = np.char.encode( - np.datetime_as_string(vector.astype(np.datetime64)) + np.datetime_as_string(array_to_datetime(vector)) ) else: vector_pointer = vector.ctypes.data_as(ctp.c_void_p) From e21c1ae4ed9f50a26baa600c6cd71eb99d3e7d59 Mon Sep 17 00:00:00 2001 From: Dongdong Tian Date: Thu, 4 Jun 2020 02:02:55 -0400 Subject: [PATCH 5/9] Fix 1D to 1d in docstrings --- pygmt/clib/conversion.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pygmt/clib/conversion.py b/pygmt/clib/conversion.py index f3fb1063416..dd98e511abc 100644 --- a/pygmt/clib/conversion.py +++ b/pygmt/clib/conversion.py @@ -242,7 +242,7 @@ def kwargs_to_ctypes_array(argument, kwargs, dtype): def array_to_datetime(array): """ - Convert an 1D datetime array from various types into pandas.DatetimeIndex + Convert an 1d datetime array from various types into pandas.DatetimeIndex (i.e., numpy.datetime64). If the input array is not in legal datetime formats, raise a "ParseError" @@ -262,7 +262,7 @@ def array_to_datetime(array): Returns ------- - array : 1D datetime array in pandas.DatetimeIndex (i.e., numpy.datetime64) + array : 1d datetime array in pandas.DatetimeIndex (i.e., numpy.datetime64) Examples -------- From a3cc4b738d7a338e6a0dbb80787149fadec92aa5 Mon Sep 17 00:00:00 2001 From: Wei Ji Date: Fri, 5 Jun 2020 09:28:29 +1200 Subject: [PATCH 6/9] Test that xarray.DataArray datetimes can be plotted --- pygmt/tests/baseline/test_plot_datetime.png | Bin 16890 -> 18222 bytes pygmt/tests/test_plot.py | 9 ++++++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/pygmt/tests/baseline/test_plot_datetime.png b/pygmt/tests/baseline/test_plot_datetime.png index 49c67c6909e19c3064df1feb4b7a060707d11533..37640d5982a306c86a21a520b245a06f9b0268c9 100644 GIT binary patch literal 18222 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 YKk3viuq}v6hN Date: Mon, 13 Jul 2020 15:45:38 +1200 Subject: [PATCH 7/9] Normalize whitespace to fix doctest in array_to_datetime --- pygmt/clib/conversion.py | 54 ++++++++++++++++++++++++++-------------- 1 file changed, 35 insertions(+), 19 deletions(-) diff --git a/pygmt/clib/conversion.py b/pygmt/clib/conversion.py index 33710dbf34d..4334eb14daa 100644 --- a/pygmt/clib/conversion.py +++ b/pygmt/clib/conversion.py @@ -268,36 +268,52 @@ def array_to_datetime(array): -------- >>> import datetime >>> # numpy.datetime64 array - >>> x = np.array(["2010-06-01", "2011-06-01T12", "2012-01-01T12:34:56"], - ... dtype="datetime64") + >>> x = np.array( + ... ["2010-06-01", "2011-06-01T12", "2012-01-01T12:34:56"], + ... dtype="datetime64", + ... ) >>> array_to_datetime(x) DatetimeIndex(['2010-06-01 00:00:00', '2011-06-01 12:00:00', - '2012-01-01 12:34:56'], - dtype='datetime64[ns]', freq=None) + '2012-01-01 12:34:56'], + dtype='datetime64[ns]', freq=None) + >>> # pandas.DateTimeIndex array >>> x = pd.date_range("2013", freq="YS", periods=3) - >>> array_to_datetime(x) + >>> array_to_datetime(x) # doctest: +NORMALIZE_WHITESPACE DatetimeIndex(['2013-01-01', '2014-01-01', '2015-01-01'], - dtype='datetime64[ns]', freq='AS-JAN') + dtype='datetime64[ns]', freq='AS-JAN') + >>> # Python's built-in date and datetime >>> x = [datetime.date(2018, 1, 1), datetime.datetime(2019, 1, 1)] - >>> array_to_datetime(x) - DatetimeIndex(['2018-01-01', '2019-01-01'], dtype='datetime64[ns]', - freq=None) + >>> array_to_datetime(x) # doctest: +NORMALIZE_WHITESPACE + DatetimeIndex(['2018-01-01', '2019-01-01'], + dtype='datetime64[ns]', freq=None) + >>> # Raw datetime strings in various format - >>> x = ['2018', "2018-02", "2018-03-01", "2018-04-01T01:02:03", - ... "5/1/2018", "Jun 05, 2018", "2018/07/02"] + >>> x = [ + ... "2018", + ... "2018-02", + ... "2018-03-01", + ... "2018-04-01T01:02:03", + ... "5/1/2018", + ... "Jun 05, 2018", + ... "2018/07/02", + ... ] >>> array_to_datetime(x) DatetimeIndex(['2018-01-01 00:00:00', '2018-02-01 00:00:00', - '2018-03-01 00:00:00', '2018-04-01 01:02:03', - '2018-05-01 00:00:00', '2018-06-05 00:00:00', - '2018-07-02 00:00:00'], - dtype='datetime64[ns]', freq=None) + '2018-03-01 00:00:00', '2018-04-01 01:02:03', + '2018-05-01 00:00:00', '2018-06-05 00:00:00', + '2018-07-02 00:00:00'], + dtype='datetime64[ns]', freq=None) + >>> # Mixed datetime types - >>> x = ['2018-01-01', np.datetime64('2018-01-01'), - ... datetime.datetime(2018, 1, 1)] - >>> array_to_datetime(x) + >>> x = [ + ... "2018-01-01", + ... np.datetime64("2018-01-01"), + ... datetime.datetime(2018, 1, 1), + ... ] + >>> array_to_datetime(x) # doctest: +NORMALIZE_WHITESPACE DatetimeIndex(['2018-01-01', '2018-01-01', '2018-01-01'], - dtype='datetime64[ns]', freq=None) + dtype='datetime64[ns]', freq=None) """ return pd.to_datetime(array) From f4f401595bbe8c00cf55eeb3904a246db55034cc Mon Sep 17 00:00:00 2001 From: Wei Ji Date: Mon, 13 Jul 2020 16:10:40 +1200 Subject: [PATCH 8/9] Convert to np.datetime64 directly instead of using np.asarray --- pygmt/clib/session.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pygmt/clib/session.py b/pygmt/clib/session.py index d6ba299090c..03fac9ea7a2 100644 --- a/pygmt/clib/session.py +++ b/pygmt/clib/session.py @@ -720,7 +720,7 @@ def _check_dtype_and_dim(self, array, ndim): if array.dtype.type not in DTYPES: try: # Try to convert any unknown numpy data types to np.datetime64 - array = np.asarray(array, dtype=np.datetime64) + array = np.datetime64(array) except ValueError: raise GMTInvalidInput( "Unsupported numpy data type '{}'.".format(array.dtype.type) From a2258a5c252bb13407297d92c0a28f01eb2f43ba Mon Sep 17 00:00:00 2001 From: Wei Ji Date: Tue, 14 Jul 2020 10:43:57 +1200 Subject: [PATCH 9/9] Switch back to using np.asarray, but use dtype 'object' in test --- pygmt/clib/session.py | 2 +- pygmt/tests/test_clib.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pygmt/clib/session.py b/pygmt/clib/session.py index 03fac9ea7a2..d6ba299090c 100644 --- a/pygmt/clib/session.py +++ b/pygmt/clib/session.py @@ -720,7 +720,7 @@ def _check_dtype_and_dim(self, array, ndim): if array.dtype.type not in DTYPES: try: # Try to convert any unknown numpy data types to np.datetime64 - array = np.datetime64(array) + array = np.asarray(array, dtype=np.datetime64) except ValueError: raise GMTInvalidInput( "Unsupported numpy data type '{}'.".format(array.dtype.type) diff --git a/pygmt/tests/test_clib.py b/pygmt/tests/test_clib.py index 5fa8a1ae88d..a90be7c338e 100644 --- a/pygmt/tests/test_clib.py +++ b/pygmt/tests/test_clib.py @@ -349,7 +349,7 @@ def test_put_vector_invalid_dtype(): mode="GMT_CONTAINER_ONLY", dim=[2, 3, 1, 0], # columns, rows, layers, dtype ) - data = np.array([37, 12, 556], dtype="complex128") + data = np.array([37, 12, 556], dtype="object") with pytest.raises(GMTInvalidInput): lib.put_vector(dataset, column=1, vector=data)