使用 Matplotlib 创建时间线可视化

PythonPythonBeginner
立即练习

This tutorial is from open-source community. Access the source code

💡 本教程由 AI 辅助翻译自英文原版。如需查看原文,您可以 切换至英文原版

简介

在本实验中,你将学习如何使用 Matplotlib 的发布日期创建一个简单的时间线。时间线是按时间顺序排列的一系列事件的图形表示。时间线可以由一组日期和文本创建。在本示例中,我们将展示如何使用 Matplotlib 的最新发布日期创建一个简单的时间线。

虚拟机提示

虚拟机启动完成后,点击左上角切换到“笔记本”标签以访问 Jupyter Notebook 进行练习。

有时,你可能需要等待几秒钟让 Jupyter Notebook 完成加载。由于 Jupyter Notebook 的限制,操作验证无法自动化。

如果你在学习过程中遇到问题,请随时向 Labby 提问。课程结束后提供反馈,我们将立即为你解决问题。

获取数据

要创建时间线,我们需要获取诸如日期和名称之类的数据。在本示例中,我们将使用来自 GitHub 的 Matplotlib 版本发布信息及其日期。如果由于任何原因无法获取数据,我们将使用备用数据作为备份。以下是获取数据的代码:

from datetime import datetime

import matplotlib.pyplot as plt
import numpy as np

import matplotlib.dates as mdates

try:
    ## 尝试从 https://api.github.com/repos/matplotlib/matplotlib/releases 获取 Matplotlib 版本发布列表及其日期
    import json
    import urllib.request

    url = 'https://api.github.com/repos/matplotlib/matplotlib/releases'
    url += '?per_page=100'
    data = json.loads(urllib.request.urlopen(url, timeout=1).read().decode())

    dates = []
    names = []
    for item in data:
        if 'rc' not in item['tag_name'] and 'b' not in item['tag_name']:
            dates.append(item['published_at'].split("T")[0])
            names.append(item['tag_name'])
    ## 将日期字符串(例如 2014-10-18)转换为 datetime 对象
    dates = [datetime.strptime(d, "%Y-%m-%d") for d in dates]

except Exception:
    ## 如果上述操作失败,例如由于网络连接缺失
    ## 则使用以下列表作为备用数据。
    names = ['v2.2.4', 'v3.0.3', 'v3.0.2', 'v3.0.1', 'v3.0.0', 'v2.2.3',
             'v2.2.2', 'v2.2.1', 'v2.2.0', 'v2.1.2', 'v2.1.1', 'v2.1.0',
             'v2.0.2', 'v2.0.1', 'v2.0.0', 'v1.5.3', 'v1.5.2', 'v1.5.1',
             'v1.5.0', 'v1.4.3', 'v1.4.2', 'v1.4.1', 'v1.4.0']

    dates = ['2019-02-26', '2019-02-26', '2018-11-10', '2018-11-10',
             '2018-09-18', '2018-08-10', '2018-03-17', '2018-03-16',
             '2018-03-06', '2018-01-18', '2017-12-10', '2017-10-07',
             '2017-05-10', '2017-05-02', '2017-01-17', '2016-09-09',
             '2016-07-03', '2016-01-10', '2015-10-29', '2015-02-16',
             '2014-10-26', '2014-10-18', '2014-08-26']

    ## 将日期字符串(例如 2014-10-18)转换为 datetime 对象
    dates = [datetime.strptime(d, "%Y-%m-%d") for d in dates]

创建茎叶图

接下来,我们将创建一个茎叶图,通过设置不同的高度来区分相近的事件。我们在基线上添加标记,以突出时间线的一维特性。对于每个事件,我们通过 ~.Axes.annotate 添加一个文本标签,标签相对于事件线的顶端以点为单位进行偏移。以下是创建茎叶图的代码:

## 选择一些合适的高度
levels = np.tile([-5, 5, -3, 3, -1, 1],
                 int(np.ceil(len(dates)/6)))[:len(dates)]

## 创建图形并绘制带有日期的茎叶图
fig, ax = plt.subplots(figsize=(8.8, 4), layout="constrained")
ax.set(title="Matplotlib release dates")

ax.vlines(dates, 0, levels, color="tab:red")  ## 垂直的茎
ax.plot(dates, np.zeros_like(dates), "-o",
        color="k", markerfacecolor="w")  ## 基线及其上的标记

## 为线条添加注释
for d, l, r in zip(dates, levels, names):
    ax.annotate(r, xy=(d, l),
                xytext=(-3, np.sign(l)*3), textcoords="offset points",
                horizontalalignment="right",
                verticalalignment="bottom" if l > 0 else "top")

格式化图表

现在,我们将通过添加 x 轴和 y 轴标签、设置 x 轴主定位器和格式化器以及移除 y 轴和脊柱来格式化图表。以下是格式化图表的代码:

## 以 4 个月为间隔格式化 x 轴
ax.xaxis.set_major_locator(mdates.MonthLocator(interval = 4))
ax.xaxis.set_major_formatter(mdates.DateFormatter("%b %Y"))
plt.setp(ax.get_xticklabels(), rotation = 30, ha = "right")

## 移除 y 轴和脊柱
ax.yaxis.set_visible(False)
ax.spines[["left", "top", "right"]].set_visible(False)

ax.margins(y = 0.1)
plt.show()

整合所有内容

以下是使用 Matplotlib 发布日期创建简单时间线的最终代码:

from datetime import datetime

import matplotlib.pyplot as plt
import numpy as np

import matplotlib.dates as mdates

try:
    ## 尝试从 https://api.github.com/repos/matplotlib/matplotlib/releases 获取 Matplotlib 版本发布列表及其日期
    import json
    import urllib.request

    url = 'https://api.github.com/repos/matplotlib/matplotlib/releases'
    url += '?per_page=100'
    data = json.loads(urllib.request.urlopen(url, timeout=1).read().decode())

    dates = []
    names = []
    for item in data:
        if 'rc' not in item['tag_name'] and 'b' not in item['tag_name']:
            dates.append(item['published_at'].split("T")[0])
            names.append(item['tag_name'])
    ## 将日期字符串(例如 2014-10-18)转换为 datetime 对象
    dates = [datetime.strptime(d, "%Y-%m-%d") for d in dates]

except Exception:
    ## 如果上述操作失败,例如由于网络连接缺失
    ## 则使用以下列表作为备用数据。
    names = ['v2.2.4', 'v3.0.3', 'v3.0.2', 'v3.0.1', 'v3.0.0', 'v2.2.3',
             'v2.2.2', 'v2.2.1', 'v2.2.0', 'v2.1.2', 'v2.1.1', 'v2.1.0',
             'v2.0.2', 'v2.0.1', 'v2.0.0', 'v1.5.3', 'v1.5.2', 'v1.5.1',
             'v1.5.0', 'v1.4.3', 'v1.4.2', 'v1.4.1', 'v1.4.0']

    dates = ['2019-02-26', '2019-02-26', '2018-11-10', '2018-11-10',
             '2018-09-18', '2018-08-10', '2018-03-17', '2018-03-16',
             '2018-03-06', '2018-01-18', '2017-12-10', '2017-10-07',
             '2017-05-10', '2017-05-02', '2017-01-17', '2016-09-09',
             '2016-07-03', '2016-01-10', '2015-10-29', '2015-02-16',
             '2014-10-26', '2014-10-18', '2014-08-26']

    ## 将日期字符串(例如 2014-10-18)转换为 datetime 对象
    dates = [datetime.strptime(d, "%Y-%m-%d") for d in dates]

## 选择一些合适的高度
levels = np.tile([-5, 5, -3, 3, -1, 1],
                 int(np.ceil(len(dates)/6)))[:len(dates)]

## 创建图形并绘制带有日期的茎叶图
fig, ax = plt.subplots(figsize=(8.8, 4), layout="constrained")
ax.set(title="Matplotlib release dates")

ax.vlines(dates, 0, levels, color="tab:red")  ## 垂直的茎
ax.plot(dates, np.zeros_like(dates), "-o",
        color="k", markerfacecolor="w")  ## 基线及其上的标记

## 为线条添加注释
for d, l, r in zip(dates, levels, names):
    ax.annotate(r, xy=(d, l),
                xytext=(-3, np.sign(l)*3), textcoords="offset points",
                horizontalalignment="right",
                verticalalignment="bottom" if l > 0 else "top")

## 以 4 个月为间隔格式化 x 轴
ax.xaxis.set_major_locator(mdates.MonthLocator(interval = 4))
ax.xaxis.set_major_formatter(mdates.DateFormatter("%b %Y"))
plt.setp(ax.get_xticklabels(), rotation = 30, ha = "right")

## 移除 y 轴和脊柱
ax.yaxis.set_visible(False)
ax.spines[["left", "top", "right"]].set_visible(False)

ax.margins(y = 0.1)
plt.show()

总结

在本实验中,你已经学会了如何使用 Matplotlib 的发布日期创建一个简单的时间线。你已经学会了如何获取数据、创建茎叶图、格式化图表以及将所有内容整合在一起。时间线可用于按时间顺序可视化任何事件序列。