简介
在绘制诸如金融时间序列等每日数据时,人们通常希望忽略没有数据的日子,比如周末。这样可以使数据以固定的时间间隔绘制,而不会为没有数据的日子留出额外的空白。在本实验中,我们将学习如何使用“索引格式化器”来实现所需的绘图。
虚拟机使用提示
虚拟机启动完成后,点击左上角切换到“笔记本”标签页,以访问 Jupyter Notebook 进行练习。
有时,你可能需要等待几秒钟让 Jupyter Notebook 完成加载。由于 Jupyter Notebook 的限制,操作验证无法自动化。
如果你在学习过程中遇到问题,随时向 Labby 提问。课程结束后提供反馈,我们会及时为你解决问题。
导入所需的库和数据
我们首先需要导入所需的库,即 matplotlib、numpy 和 matplotlib.cbook。我们还需要从 mpl-data/sample_data 目录中加载一个来自雅虎 CSV 数据的 numpy 记录数组,其字段包括日期、开盘价、最高价、最低价、收盘价、成交量、调整收盘价。记录数组在日期列中将日期存储为具有日单位('D')的 np.datetime64。我们将使用这些数据来绘制金融时间序列图。
import matplotlib.pyplot as plt
import numpy as np
import matplotlib.cbook as cbook
## 从 sample_data 目录加载数据
r = cbook.get_sample_data('goog.npz')['price_data'].view(np.recarray)
r = r[:9] ## 获取前 9 天的数据
在周末使用默认间隔绘制数据
我们将首先使用 matplotlib 中的plot函数,以周末的默认间隔来绘制数据。我们还将使用白色虚线突出显示每日数据中的间隔。
## 在周末以间隔绘制数据
fig, ax1 = plt.subplots(figsize=(6, 3))
ax1.plot(r.date, r.adj_close, 'o-')
## 突出显示每日数据中的间隔
gaps = np.flatnonzero(np.diff(r.date) > np.timedelta64(1, 'D'))
for gap in r[['date', 'adj_close']][np.stack((gaps, gaps + 1)).T]:
ax1.plot(gap.date, gap.adj_close, 'w--', lw=2)
ax1.legend(handles=[ml.Line2D([], [], ls='--', label='Gaps in daily data')])
ax1.set_title("Plotting Data with Default Gaps on Weekends")
ax1.xaxis.set_major_locator(DayLocator())
ax1.xaxis.set_major_formatter(DateFormatter('%a'))
创建自定义索引格式化器
为了根据从 0、1、...、数据长度的索引来绘制数据,我们将创建一个自定义索引格式化器。这个格式化器会将刻度标记格式化为时间,而不是整数。
## 创建自定义索引格式化器
fig, ax2 = plt.subplots(figsize=(6, 3))
ax2.plot(r.adj_close, 'o-')
## 将 x 轴格式化为时间
def format_date(x, _):
try:
## 将 datetime64 转换为 datetime,并使用 datetime 的 strftime:
return r.date[round(x)].item().strftime('%a')
except IndexError:
pass
ax2.set_title("Creating Custom Index Formatter")
ax2.xaxis.set_major_formatter(format_date) ## 内部创建 FuncFormatter
使用可调用对象作为格式化器
除了将函数传递给.Axis.set_major_formatter,我们还可以使用任何其他可调用对象,例如实现了__call__的类的实例。在这一步中,我们将创建一个MyFormatter类,它将刻度标记格式化为时间。
## 使用可调用对象作为格式化器
class MyFormatter(Formatter):
def __init__(self, dates, fmt='%a'):
self.dates = dates
self.fmt = fmt
def __call__(self, x, pos=0):
"""返回位置 pos 处时间 x 的标签。"""
try:
return self.dates[round(x)].item().strftime(self.fmt)
except IndexError:
pass
ax2.xaxis.set_major_formatter(MyFormatter(r.date, '%a'))
显示图表
我们现在将使用 matplotlib 中的show函数来显示图表。
plt.show()
总结
在本实验中,我们学习了如何使用自定义索引格式化器来绘制周末无间隔的金融时间序列。我们还学习了如何使用可调用对象而非函数作为格式化器。通过使用这些技术,我们可以创建更具视觉吸引力的每日数据图表。