Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

plot no longer accepts date/time data in pygmt 0.14 #3757

Closed
Tracked by #3759
eelcodoornbos opened this issue Jan 8, 2025 · 4 comments · Fixed by #3760
Closed
Tracked by #3759

plot no longer accepts date/time data in pygmt 0.14 #3757

eelcodoornbos opened this issue Jan 8, 2025 · 4 comments · Fixed by #3760
Labels
bug Something isn't working
Milestone

Comments

@eelcodoornbos
Copy link

The following script works in 0.13 (and before), but fails to plot anything in 0.14 with the message pygmt-session [WARNING]: Unable to parse 5 longitude strings:

import pygmt
import pandas as pd
xdata = [pd.to_datetime("2024-12-01"),
         pd.to_datetime("2024-12-15"),
         pd.to_datetime("2024-12-31"),
         pd.to_datetime("2025-01-15"),
         pd.to_datetime("2025-02-01")]
ydata = [0.1, 0.2, 0.5, 0.7, 0.4]
fig = pygmt.Figure()
fig.basemap(projection='X10cT/5c', region=["2024-12-01T", "2025-02-01T", 0, 1], frame=True)
fig.plot(x=xdata, y=ydata)
fig.show()
@weiji14 weiji14 added the bug Something isn't working label Jan 8, 2025
@weiji14
Copy link
Member

weiji14 commented Jan 8, 2025

Hmm yes, I can reproduce this on PyGMT v0.14.0. We'll need to check what changes caused this regression. In the meantime, could you put your list of pandas.Timestamp objects into a pandas.DatetimeIndex (following https://www.pygmt.org/v0.14.0/tutorials/advanced/date_time_charts.html#using-pandas-date-range) like so:

xdata = pd.DatetimeIndex(
    data=[
        pd.to_datetime("2024-12-01"),
        pd.to_datetime("2024-12-15"),
        pd.to_datetime("2024-12-31"),
        pd.to_datetime("2025-01-15"),
        pd.to_datetime("2025-02-01"),
    ]
)
ydata = [0.1, 0.2, 0.5, 0.7, 0.4]

fig = pygmt.Figure()
fig.basemap(
    projection="X10cT/5c", region=["2024-12-01T", "2025-02-01T", 0, 1], frame=True
)
fig.plot(x=xdata, y=ydata, verbose=True)
fig.show()

produces

Image

@yvonnefroehlich
Copy link
Member

yvonnefroehlich commented Jan 8, 2025

@eelcodoornbos Thanks for reporting this!
Just checked our Tutorial Plotting datetime charts. There we also have this warning when using datetime.datetime (not for datetime.date) in v0.14.0 (please see https://www.pygmt.org/v0.14.0/tutorials/advanced/date_time_charts.html#using-python-s-datetime the second example).

I do not remember I saw this warning, when making two minor changes to this tutorial (https://github.com/GenericMappingTools/pygmt/pull/3664/files, December 2).

@weiji14
Copy link
Member

weiji14 commented Jan 8, 2025

So the xdata array get converted into a numpy array of type np.str_ instead of an np.datetime64 dtype, and is parsed incorrectly as GMT_TEXT instead of GMT_DATETIME here:

pygmt/pygmt/clib/session.py

Lines 942 to 947 in 2a84b5e

# 1-D arrays can be numeric or text, 2-D arrays can only be numeric.
valid_dtypes = DTYPES if ndim == 1 else DTYPES_NUMERIC
if (dtype := array.dtype.type) not in valid_dtypes:
msg = f"Unsupported numpy data type '{dtype}'."
raise GMTInvalidInput(msg)
return self[DTYPES[dtype]]

These lines were most recently changed in #3563, but I don't think the bug was caused by that PR, probably somewhere else when we were doing the refactoring. Using the pandas.DatetimeIndex workaround above would correctly turn the array into a np.datetime64 type. The warning about Unable to parse 5 longitude strings is indicating that strings like '2024-12-01 00:00:00', '2024-12-15 00:00:00', ... (note the space in between the date and time) are being passed into pygmt's clib functions.

@seisman, should we revise the logic in that pygmt.clib.Session._check_dtype_and_dim method, or do you think it should be done elsewhere?

@seisman
Copy link
Member

seisman commented Jan 9, 2025

xdata is a list of Timestamp objects, and it can't be converted to the numpy.datetime64 dtype by the np.ascontiguousarray function:

>>> np.ascontiguousarray(xdata)
array([Timestamp('2024-12-01 00:00:00'), Timestamp('2024-12-15 00:00:00'),
       Timestamp('2024-12-31 00:00:00'), Timestamp('2025-01-15 00:00:00'),
       Timestamp('2025-02-01 00:00:00')], dtype=object)

Then, it's converted to np.str_ by the following lines:

# Check if a np.object_ array can be converted to np.str_.
if array.dtype == np.object_:
with contextlib.suppress(TypeError, ValueError):
return np.ascontiguousarray(array, dtype=np.str_)

The fix should be easy and should be done in the _to_numpy function.

Actually, I already had a branch to_numpy/datetime(commit 949b124) which can fix the "bug" (didn't realize the existence of the bug when I created the branch).

I can submit a PR for this branch, but I feel it would be better to have PRs #3670, #3687 merged first to ensure that the to_numpy/datetime branch has no side-effects.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants