Skip to content

Commit dc1d227

Browse files
noorbuchicklima616seismannathandloriamichaelgrund
authored
Add a tutorial for datetime data (#1193)
Co-authored-by: Claire Klima <[email protected]> Co-authored-by: Dongdong Tian <[email protected]> Co-authored-by: Nathan Loria <[email protected]> Co-authored-by: Michael Grund <[email protected]> Co-authored-by: Claire <[email protected]> Co-authored-by: Yao Jiayuan <[email protected]> Co-authored-by: Wei Ji <[email protected]>
1 parent bd52c10 commit dc1d227

File tree

2 files changed

+355
-0
lines changed

2 files changed

+355
-0
lines changed

doc/index.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
tutorials/plot.rst
4343
tutorials/lines.rst
4444
tutorials/vectors.rst
45+
tutorials/date_time_charts.rst
4546
tutorials/text.rst
4647
tutorials/contour_map.rst
4748
tutorials/earth_relief.rst
Lines changed: 354 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,354 @@
1+
"""
2+
Plotting datetime charts
3+
========================
4+
5+
PyGMT accepts a variety of datetime objects to plot data and create charts.
6+
Aside from the built-in Python ``datetime`` object, PyGMT supports input using
7+
ISO formatted strings, ``pandas``, ``xarray``, as well as ``numpy``.
8+
These data types can be used to plot specific points as well as get
9+
passed into the ``region`` parameter to create a range of the data on an axis.
10+
11+
The following examples will demonstrate how to create plots
12+
using the different datetime objects.
13+
"""
14+
# sphinx_gallery_thumbnail_number = 0
15+
16+
import datetime
17+
18+
import numpy as np
19+
import pandas as pd
20+
import pygmt
21+
import xarray as xr
22+
23+
###############################################################################
24+
# Using Python's ``datetime``
25+
# ---------------------------
26+
#
27+
# In this example, Python's built-in ``datetime`` module is used
28+
# to create data points stored in list ``x``. Additionally,
29+
# dates are passed into the ``region`` parameter in the format
30+
# ``(x_start, x_end, y_start, y_end)``,
31+
# where the date range is plotted on the x-axis.
32+
# An additional notable parameter is ``style``, where it's specified
33+
# that data points are to be plotted in an **X** shape with a size
34+
# of 0.3 centimeters.
35+
#
36+
37+
x = [
38+
datetime.date(2010, 6, 1),
39+
datetime.date(2011, 6, 1),
40+
datetime.date(2012, 6, 1),
41+
datetime.date(2013, 6, 1),
42+
]
43+
y = [1, 2, 3, 5]
44+
45+
fig = pygmt.Figure()
46+
fig.plot(
47+
projection="X10c/5c",
48+
region=[datetime.date(2010, 1, 1), datetime.date(2014, 12, 1), 0, 6],
49+
frame=["WSen", "afg"],
50+
x=x,
51+
y=y,
52+
style="x0.3c",
53+
pen="1p",
54+
)
55+
fig.show()
56+
57+
###############################################################################
58+
# In addition to specifying the date, ``datetime`` supports
59+
# the exact time at which the data points were recorded. Using :meth:`datetime.datetime`
60+
# the ``region`` parameter as well as data points can be created
61+
# with both date and time information.
62+
#
63+
# Some notable differences to the previous example include
64+
#
65+
# - Modifying ``frame`` to only include West (left) and South (bottom) borders, and removing grid lines
66+
# - Using circles to plot data points defined through ``c`` in ``style`` parameter
67+
68+
x = [
69+
datetime.datetime(2021, 1, 1, 3, 45, 1),
70+
datetime.datetime(2021, 1, 1, 6, 15, 1),
71+
datetime.datetime(2021, 1, 1, 13, 30, 1),
72+
datetime.datetime(2021, 1, 1, 20, 30, 1),
73+
]
74+
y = [5, 3, 1, 2]
75+
76+
fig = pygmt.Figure()
77+
fig.plot(
78+
projection="X10c/5c",
79+
region=[
80+
datetime.datetime(2021, 1, 1, 0, 0, 0),
81+
datetime.datetime(2021, 1, 2, 0, 0, 0),
82+
0,
83+
6,
84+
],
85+
frame=["WS", "af"],
86+
x=x,
87+
y=y,
88+
style="c0.4c",
89+
pen="1p",
90+
color="blue",
91+
)
92+
fig.show()
93+
94+
########################################################################################
95+
# Using ISO Format
96+
# ----------------
97+
#
98+
# In addition to Python's ``datetime`` library, PyGMT also supports passing times
99+
# in ISO format. Basic ISO strings are formatted as ``YYYY-MM-DD``
100+
# with each ``-`` delineated section marking the four digit year value, two digit
101+
# month value, and two digit day value respectively.
102+
#
103+
# When including time of day into ISO strings, the ``T`` character is used, as
104+
# can be seen in the following example. This character is immediately followed
105+
# by a string formatted as ``hh:mm:ss`` where each ``:`` delineated section marking
106+
# the two digit hour value, two digit minute value, and two digit second value
107+
# respectively. The figure in the following example is plotted over a horizontal
108+
# range of one year from 1/1/2016 to 1/1/2017.
109+
110+
x = ["2016-02-01", "2016-06-04T14", "2016-10-04T00:00:15", "2016-12-01T05:00:15"]
111+
y = [1, 3, 5, 2]
112+
fig = pygmt.Figure()
113+
fig.plot(
114+
projection="X10c/5c",
115+
region=["2016-01-01", "2017-01-1", 0, 6],
116+
frame=["WSen", "afg"],
117+
x=x,
118+
y=y,
119+
style="a0.45c",
120+
pen="1p",
121+
color="dodgerblue",
122+
)
123+
fig.show()
124+
125+
###############################################################################
126+
# Mixing and matching Python ``datetime`` and ISO dates
127+
# -----------------------------------------------------
128+
#
129+
# The following example provides context on how both ``datetime`` and ISO
130+
# date data can be plotted using PyGMT. This can be helpful when dates and times
131+
# are coming from different sources, meaning conversions do not need to take place
132+
# between ISO and datetime in order to create valid plots.
133+
134+
x = ["2020-02-01", "2020-06-04", "2020-10-04", datetime.datetime(2021, 1, 15)]
135+
y = [1.3, 2.2, 4.1, 3]
136+
fig = pygmt.Figure()
137+
fig.plot(
138+
projection="X10c/5c",
139+
region=[datetime.datetime(2020, 1, 1), datetime.datetime(2021, 3, 1), 0, 6],
140+
frame=["WSen", "afg"],
141+
x=x,
142+
y=y,
143+
style="i0.4c",
144+
pen="1p",
145+
color="yellow",
146+
)
147+
fig.show()
148+
149+
########################################################################################
150+
# Using :meth:`pandas.date_range`
151+
# -------------------------------
152+
#
153+
# In the following example, :func:`pandas.date_range` produces a list of
154+
# :class:`pandas.DatetimeIndex` objects, which gets is used to pass date
155+
# data to the PyGMT figure.
156+
# Specifically ``x`` contains 7 different :class:`pandas.DatetimeIndex` objects, with the
157+
# number being manipulated by the ``periods`` parameter. Each period begins at the start
158+
# of a business quarter as denoted by BQS when passed to the ``periods`` parameter. The inital
159+
# date is the first argument that is passed to :func:`pandas.date_range` and it marks the first
160+
# data point in the list ``x`` that will be plotted.
161+
162+
x = pd.date_range("2018-03-01", periods=7, freq="BQS")
163+
y = [4, 5, 6, 8, 6, 3, 5]
164+
165+
fig = pygmt.Figure()
166+
fig.plot(
167+
projection="X10c/10c",
168+
region=[datetime.datetime(2017, 12, 31), datetime.datetime(2019, 12, 31), 0, 10],
169+
frame=["WSen", "ag"],
170+
x=x,
171+
y=y,
172+
style="i0.4c",
173+
pen="1p",
174+
color="purple",
175+
)
176+
fig.show()
177+
178+
########################################################################################
179+
# Using :class:`xarray.DataArray`
180+
# ------------------------------
181+
#
182+
# In this example, instead of using a :func:`pandas.date_range`, ``x`` is initialized
183+
# as a list of :class:`xarray.DataArray` objects. This object provides a wrapper around
184+
# regular PyData formats. It also allows the data to have labeled dimensions
185+
# while supporting operations that use various pieces of metadata.The following
186+
# code uses :func:`pandas.date_range` object to fill the DataArray with data,
187+
# but this is not essential for the creation of a valid DataArray.
188+
189+
x = xr.DataArray(data=pd.date_range(start="2020-01-01", periods=4, freq="Q"))
190+
y = [4, 7, 5, 6]
191+
192+
fig = pygmt.Figure()
193+
fig.plot(
194+
projection="X10c/10c",
195+
region=[datetime.datetime(2020, 1, 1), datetime.datetime(2021, 4, 1), 0, 10],
196+
frame=["WSen", "ag"],
197+
x=x,
198+
y=y,
199+
style="n0.4c",
200+
pen="1p",
201+
color="red",
202+
)
203+
fig.show()
204+
205+
###############################################################################
206+
# Using :class:`numpy.datetime64`
207+
# ------------------------------
208+
# In this example, instead of using a :func:`pd.date_range`, ``x`` is initialized
209+
# as an ``np.array`` object. Similar to :class:`xarray.DataArray` this wraps the
210+
# dataset before passing it as a paramater. However, ``np.array`` objects use less
211+
# memory and allow developers to specify datatypes.
212+
213+
x = np.array(["2010-06-01", "2011-06-01T12", "2012-01-01T12:34:56"], dtype="datetime64")
214+
y = [2, 7, 5]
215+
216+
fig = pygmt.Figure()
217+
fig.plot(
218+
projection="X10c/10c",
219+
region=[datetime.datetime(2010, 1, 1), datetime.datetime(2012, 6, 1), 0, 10],
220+
frame=["WS", "ag"],
221+
x=x,
222+
y=y,
223+
style="s0.5c",
224+
pen="1p",
225+
color="blue",
226+
)
227+
fig.show()
228+
229+
########################################################################################
230+
# Generating an automatic region
231+
# ------------------------------
232+
#
233+
# Another way of creating charts involving datetime data can be done
234+
# by automatically generating the region of the plot. This can be done
235+
# by passing the dataframe to :meth:`pygmt.info`, which will find
236+
# maximum and minimum values for each column and create a list
237+
# that could be passed as region. Additionally, the ``spacing`` argument
238+
# can be passed to increase the range past the maximum and minimum
239+
# data points.
240+
241+
data = [
242+
["20200712", 1000],
243+
["20200714", 1235],
244+
["20200716", 1336],
245+
["20200719", 1176],
246+
["20200721", 1573],
247+
["20200724", 1893],
248+
["20200729", 1634],
249+
]
250+
df = pd.DataFrame(data, columns=["Date", "Score"])
251+
df.Date = pd.to_datetime(df["Date"], format="%Y%m%d")
252+
253+
fig = pygmt.Figure()
254+
region = pygmt.info(
255+
table=df[["Date", "Score"]], per_column=True, spacing=(700, 700), coltypes="T"
256+
)
257+
258+
fig.plot(
259+
region=region,
260+
projection="X15c/10c",
261+
frame=["WSen", "afg"],
262+
x=df.Date,
263+
y=df.Score,
264+
style="c0.4c",
265+
pen="1p",
266+
color="green3",
267+
)
268+
269+
fig.show()
270+
271+
########################################################################################
272+
# Setting Primary and Secondary Time Axes
273+
# ---------------------------------------
274+
#
275+
# This example focuses on labeling the axes and setting intervals
276+
# at which the labels are expected to appear. All of these modifications
277+
# are added to the ``frame`` parameter and each item in that list modifies
278+
# a specific section of the plot.
279+
#
280+
# Starting off with ``WS``, adding this string means that only
281+
# Western/Left (**W**) and Southern/Bottom (**S**) borders of
282+
# the plot will be shown. For more information on this, please
283+
# refer to :doc:`frame instructions </tutorials/frames>`.
284+
#
285+
# The other important item in the ``frame`` list is
286+
# ``"sxa1Of1D"``. This string modifies the secondary
287+
# labeling (**s**) of the x-axis (**x**). Specifically,
288+
# it sets the main annotation and major tick spacing interval
289+
# to one month (**a1O**) (capital letter o, not zero). Additionally,
290+
# it sets the minor tick spacing interval to 1 day (**f1D**).
291+
# The labeling of this axis can be modified by setting
292+
# :gmt-term:`FORMAT_DATE_MAP` to 'o' to use the month's
293+
# name instead of its number. More information about configuring
294+
# date formats can be found on the
295+
# :gmt-term:`official GMT documentation page <FORMAT_DATE_MAP>`.
296+
297+
x = pd.date_range("2013-05-02", periods=10, freq="2D")
298+
y = [4, 5, 6, 8, 9, 5, 8, 9, 4, 2]
299+
300+
fig = pygmt.Figure()
301+
with pygmt.config(FORMAT_DATE_MAP="o"):
302+
fig.plot(
303+
projection="X15c/10c",
304+
region=[datetime.datetime(2013, 5, 1), datetime.datetime(2013, 5, 25), 0, 10],
305+
frame=["WS", "sxa1Of1D", "pxa5d", "sy+lLength", "pya1+ucm"],
306+
x=x,
307+
y=y,
308+
style="c0.4c",
309+
pen="1p",
310+
color="green3",
311+
)
312+
313+
fig.show()
314+
315+
########################################################################################
316+
# The same concept shown above can be applied to smaller
317+
# as well as larger intervals. In this example,
318+
# data is plotted for different times throughout two days.
319+
# Primary x-axis labels are modified to repeat every 6 hours
320+
# and secondary x-axis label repeats every day and shows
321+
# the day of the week.
322+
#
323+
# Another notable mention in this example is
324+
# setting :gmt-term:`FORMAT_CLOCK_MAP` to "-hhAM"
325+
# which specifies the format used for time.
326+
# In this case, leading zeros are removed
327+
# using (**-**), and only hours are displayed.
328+
# Additionally, an AM/PM system is being used
329+
# instead of a 24-hour system. More information about configuring
330+
# time formats can be found on the
331+
# :gmt-term:`official GMT documentation page <FORMAT_CLOCK_MAP>`.
332+
333+
334+
x = pd.date_range("2021-04-15", periods=8, freq="6H")
335+
y = [2, 5, 3, 1, 5, 7, 9, 6]
336+
337+
fig = pygmt.Figure()
338+
with pygmt.config(FORMAT_CLOCK_MAP="-hhAM"):
339+
fig.plot(
340+
projection="X15c/10c",
341+
region=[
342+
datetime.datetime(2021, 4, 14, 23, 0, 0),
343+
datetime.datetime(2021, 4, 17),
344+
0,
345+
10,
346+
],
347+
frame=["WS", "sxa1K", "pxa6H", "sy+lSpeed", "pya1+ukm/h"],
348+
x=x,
349+
y=y,
350+
style="n0.4c",
351+
pen="1p",
352+
color="lightseagreen",
353+
)
354+
fig.show()

0 commit comments

Comments
 (0)