Note
Go to the end to download the full example code.
Plotting datetime charts
PyGMT accepts a variety of datetime objects to plot data and create charts. Aside from
the built-in Python datetime
module, PyGMT supports inputs containing ISO formatted
strings as well as objects generated with numpy
, pandas
, and xarray
. These
data types can be used to plot specific points as well as get passed into the region
parameter to create a range of the data on an axis.
The following examples will demonstrate how to create plots using these different datetime objects.
import datetime
import numpy as np
import pandas as pd
import pygmt
import xarray as xr
Using Python’s datetime
In this example, Python’s built-in datetime
module is used to create data points
stored in the list x
. Additionally, dates are passed into the region
parameter
in the format [x_start, x_end, y_start, y_end]
, where the date range is plotted on
the x-axis. An additional notable parameter is style
, where it’s specified that
data points are plotted as circles with a diameter of 0.3 centimeters.
x = [
datetime.date(2010, 6, 1),
datetime.date(2011, 6, 1),
datetime.date(2012, 6, 1),
datetime.date(2013, 6, 1),
]
y = [1, 2, 3, 5]
fig = pygmt.Figure()
fig.plot(
projection="X10c/5c",
region=[datetime.date(2010, 1, 1), datetime.date(2014, 12, 1), 0, 6],
frame=["WSen", "afg"],
x=x,
y=y,
style="c0.3c",
pen="1p",
)
fig.show()
In addition to specifying the date, datetime
supports the time at which the data
points were recorded. Using datetime.datetime
the region
parameter as well
as data points can be created with both date and time information.
Some notable differences to the previous example include:
Modifying
frame
to only include West (left) and South (bottom) borders, and removing grid linesUsing circles to plot data points defined by
c
in the argument passed through thestyle
parameter
x = [
datetime.datetime(2021, 1, 1, 3, 45, 1),
datetime.datetime(2021, 1, 1, 6, 15, 1),
datetime.datetime(2021, 1, 1, 13, 30, 1),
datetime.datetime(2021, 1, 1, 20, 30, 1),
]
y = [5, 3, 1, 2]
fig = pygmt.Figure()
fig.plot(
projection="X10c/5c",
region=[
datetime.datetime(2021, 1, 1, 0, 0, 0),
datetime.datetime(2021, 1, 2, 0, 0, 0),
0,
6,
],
frame=["WS", "af"],
x=x,
y=y,
style="c0.4c",
pen="1p",
fill="blue",
)
fig.show()
pygmt-session [WARNING]: Unable to parse 4 longitude strings
Using ISO Format
In addition to Python’s datetime
module, PyGMT also supports passing dates in ISO
format. Basic ISO strings are formatted as YYYY-MM-DD
with each -
delineated
section marking the four-digit year value, two-digit month value, and two-digit day
value, respectively.
For including the time into an ISO string, the T
character is used, as it can be
seen in the following example. This character is immediately followed by a string
formatted as hh:mm:ss
where each :
delineated section marking the two-digit
hour value, two-digit minute value, and two-digit second value, respectively. The
figure in the following example is plotted over a horizontal range of one year from
2016-01-01 to 2017-01-01.
Note
PyGMT doesn’t recognize non-ISO datetime strings like “Jun 05, 2018”. If your data
contain non-ISO datetime strings, you can convert them to a recognized format
using pandas.to_datetime
and then pass it to PyGMT.
Mixing and matching Python datetime
and ISO dates
The following example provides context on how both datetime
and ISO date data can
be plotted using PyGMT. This can be helpful when dates and times are coming from
different sources, meaning conversions do not need to take place between ISO and
datetime in order to create valid plots.
x = ["2020-02-01", "2020-06-04", "2020-10-04", datetime.datetime(2021, 1, 15)]
y = [1.3, 2.2, 4.1, 3]
fig = pygmt.Figure()
fig.plot(
projection="X10c/5c",
region=[datetime.datetime(2020, 1, 1), datetime.datetime(2021, 3, 1), 0, 6],
frame=["WSen", "afg"],
x=x,
y=y,
style="i0.4c",
pen="1p",
fill="yellow",
)
fig.show()
Using pandas.date_range
In the following example, pandas.date_range
produces a list of
pandas.DatetimeIndex
objects, which is used to pass date data to the PyGMT
figure. Specifically x
contains 7 different pandas.DatetimeIndex
objects,
with the number being manipulated by the periods
parameter. Each period begins at
the start of a business quarter as denoted by BQS when passed to the freq
parameter. The initial date is the first argument that is passed to
pandas.date_range
and it marks the first data point in the list x
that
will be plotted.
x = pd.date_range("2018-03-01", periods=7, freq="BQS")
y = [4, 5, 6, 8, 6, 3, 5]
fig = pygmt.Figure()
fig.plot(
projection="X10c/10c",
region=[datetime.datetime(2017, 12, 31), datetime.datetime(2019, 12, 31), 0, 10],
frame=["WSen", "ag"],
x=x,
y=y,
style="i0.4c",
pen="1p",
fill="purple",
)
fig.show()
Using xarray.DataArray
In this example, instead of using a list of pandas.DatetimeIndex
objects,
x
is initialized as an xarray.DataArray
object. This object provides a
wrapper around numpy ndarrays. It also allows the data to have labeled dimensions
while supporting operations that use various pieces of metadata. The following code
uses pandas.date_range
to fill the DataArray with data, but this is not
essential for the creation of a valid DataArray.
x = xr.DataArray(data=pd.date_range(start="2020-01-01", periods=4, freq="QE"))
y = [4, 7, 5, 6]
fig = pygmt.Figure()
fig.plot(
projection="X10c/10c",
region=[datetime.datetime(2020, 1, 1), datetime.datetime(2021, 4, 1), 0, 10],
frame=["WSen", "ag"],
x=x,
y=y,
style="n0.4c",
pen="1p",
fill="red",
)
fig.show()
Using numpy.datetime64
In this example, instead of using pd.date_range
, x
is initialized as an
np.array
object. Similar to xarray.DataArray
this wraps the dataset
before passing it as an argument. However, np.array
objects use less memory and
allow developers to specify data types.
x = np.array(
["2010-06-01", "2011-06-01T12", "2012-01-01T12:34:56"], dtype=np.datetime64
)
y = [2, 7, 5]
fig = pygmt.Figure()
fig.plot(
projection="X10c/10c",
region=[datetime.datetime(2010, 1, 1), datetime.datetime(2012, 6, 1), 0, 10],
frame=["WS", "ag"],
x=x,
y=y,
style="s0.5c",
pen="1p",
fill="blue",
)
fig.show()
Generating an automatic region
Another way of creating charts involving datetime data can be done by automatically
generating the region of the plot. This can be done by passing the DataFrame to
pygmt.info
, which will find the maximum and minimum values for each column and
create a list that could be passed as region. Additionally, the spacing
parameter
can be used to increase the range past the maximum and minimum data points.
data = [
["20200712", 1000],
["20200714", 1235],
["20200716", 1336],
["20200719", 1176],
["20200721", 1573],
["20200724", 1893],
["20200729", 1634],
]
df = pd.DataFrame(data, columns=["Date", "Score"])
df.Date = pd.to_datetime(df["Date"], format="%Y%m%d")
region = pygmt.info(
data=df[["Date", "Score"]], per_column=True, spacing=(700, 700), coltypes="T"
)
fig = pygmt.Figure()
fig.plot(
region=region,
projection="X15c/10c",
frame=["WSen", "afg"],
x=df.Date,
y=df.Score,
style="c0.4c",
pen="1p",
fill="green3",
)
fig.show()
Setting Primary and Secondary Time Axes
This example focuses on annotating the axes and setting the interval in which the
annotations should appear. All of these modifications are passed to the frame
parameter and each item in that list modifies a specific aspect of the frame.
Adding "WS"
means that only the Western/Left (W) and Southern/Bottom (S)
borders of the plot are annotated. For more information on this, please refer to the
Frames, ticks, titles, and labels tutorial.
Another important item in the list passed to frame
is "sxa1Of1D"
. This string
modifies the secondary annotation (s) of the x-axis (x). Specifically, it sets
the main annotation and major tick spacing interval to one month (a1O) (capital
letter O, not zero). Additionally, it sets the minor tick spacing interval to 1 day
(f1D). To use the month name instead of its number set FORMAT_DATE_MAP
to o. More information on configuring date formats can be found at
FORMAT_DATE_MAP, FORMAT_DATE_IN, and
FORMAT_DATE_OUT.
x = pd.date_range("2013-05-02", periods=10, freq="2D")
y = [4, 5, 6, 8, 9, 5, 8, 9, 4, 2]
fig = pygmt.Figure()
with pygmt.config(FORMAT_DATE_MAP="o"):
fig.plot(
projection="X15c/10c",
region=[datetime.datetime(2013, 5, 1), datetime.datetime(2013, 5, 25), 0, 10],
frame=["WS", "sxa1Of1D", "pxa5d", "sy+lLength", "pya1+ucm"],
x=x,
y=y,
style="c0.4c",
pen="1p",
fill="green3",
)
fig.show()
The same concept shown above can be applied to smaller as well as larger intervals. In this example, data are plotted for different times throughout two days. The primary x-axis annotations are modified to repeat every 6 hours, and the secondary x-axis annotations repeat every day and show the day of the week.
Another notable mention in this example is setting FORMAT_CLOCK_MAP to -hhAM which specifies the format used for time. In this case, leading zeros are removed using (-), and only hours are displayed. Additionally, an AM/PM system is used instead of a 24-hour system. More information on configuring time formats can be found at FORMAT_CLOCK_MAP, FORMAT_CLOCK_IN, and FORMAT_CLOCK_OUT.
x = pd.date_range("2021-04-15", periods=8, freq="6h")
y = [2, 5, 3, 1, 5, 7, 9, 6]
fig = pygmt.Figure()
with pygmt.config(FORMAT_CLOCK_MAP="-hhAM"):
fig.plot(
projection="X15c/10c",
region=[
datetime.datetime(2021, 4, 14, 23, 0, 0),
datetime.datetime(2021, 4, 17),
0,
10,
],
frame=["WS", "sxa1K", "pxa6H", "sy+lSpeed", "pya1+ukm/h"],
x=x,
y=y,
style="n0.4c",
pen="1p",
fill="lightseagreen",
)
fig.show()
Total running time of the script: (0 minutes 1.247 seconds)