数据可视化解析-第五部分--在-Python-中可视化时间序列数据-Matplotlib-Plotly-和-Altair-

数据可视化解析(第五部分):在 Python 中可视化时间序列数据(Matplotlib、Plotly 和 Altair)

towardsdatascience.com/data-visualization-explained-part-5-visualizing-time-series-data-in-python-matplotlib-plotly-and-altair/

这是我的数据可视化系列中的第五篇文章。请参阅以下内容:

是时候开始构建你自己的数据可视化了。在这篇文章中,我将详细介绍在 Python 中可视化时间序列数据的过程。如果你还没有阅读我数据可视化系列中的前几篇文章,我强烈建议至少阅读前一篇关于 Python 的回顾

在 Python 中编码可视化过程中,我将重点关注三个 Python 包:Matplotlib、Plotly 和 Altair。学习这些包的一个方法可能是为每个包写 1-2 篇文章,每篇文章都详细探讨所选包。虽然这是一个有效的方法,但本系列的重点不是任何特定的库;它关注的是数据可视化过程本身。这些包仅仅是工具——达到目的的手段。

因此,我将围绕特定类型的可视化来构建这篇文章和后续的文章,并讨论如何在列出的每个包中实现这种可视化,以确保你有多样化的方法可供选择。

首先:时间序列数据的定义。

什么是时间序列数据?

正式来说,时间序列数据涉及一个随时间变化的变量。简单来说,这仅仅意味着一些随时间变化的数据。

例如,一家上市公司过去十年的股价就是时间序列数据。如果你更喜欢一个更科学的例子,考虑一下天气。展示你最喜欢的城市一年中每日温度的图表就是一个展示时间序列数据的图表。

时间序列数据是数据可视化一个很好的起点,原因有几个:

  • 它是一种极其常见且有用的数据类型。有许多信息依赖于时间,理解它可以为对感兴趣的主题提供有意义的见解。

  • 如您所看到的,有一些经过验证的方法可以有效地可视化时间序列数据。掌握这些方法,您就会做得很好。

  • 与其他类型的数据相比,时间序列的可视化对人类来说相当直观,并与我们对时间的感知相一致。这使得在开始时更容易专注于可视化设计的要素,而不是陷入试图理解非常复杂的数据。

让我们从概念层面开始,看看不同的可视化方法。

如何可视化时间序列数据?

时间序列可视化的标准是著名的折线图:

图片

图片来源 维基共享资源

此图表通常将时间放在 x 轴上,随时间变化的变量放在 y 轴上。这提供了一个看似“向前移动”的视图,符合人类对时间的线性感知。

虽然折线图是标准,但还有其他相关可能性。

多条折线图

这种方法是对单一折线图的直接扩展,并在同一图表上显示多个相关的时间序列,允许比较组或类别(例如,按地区划分的销售):

图片

图片来源 Our World in Data

面积图

从功能上讲,面积图几乎与折线图完全相同,但线下的区域被填充。它强调了变化的大小:

图片来源 维基共享资源

堆积面积图

技术上,堆积面积图是多条折线图的对应物,但阅读起来有点复杂。特别是,总数是累积的,每个堆积线的基线从下面的一个开始。例如,在下面的图表中 2023 年,“25-64 岁”代表约 40 亿人,因为我们从“15-24 岁”结束的地方开始计数。

图片

图片来源 Our World in Data

柱状图(垂直或水平)

最后,在某些情况下,柱状图也适用于时间序列可视化。如果您希望显示离散的时间间隔——例如某些指标的月度总和或年度平均值——而不是连续数据,这种方法很有用。但在此文章中,我将不会编写柱状图的代码。

图片

图片来源 Our World In Data

现在,让我们实际构建这些可视化。在下面的每个示例中,我将逐步讲解构建线图和面积图的特定可视化库中的代码。我已经在此链接了数据,并鼓励你跟随操作。为了内化这些技术,你必须亲自练习使用它们。

在 Matplotlib 中编码时间序列可视化

import pandas as pd
import matplotlib.pyplot as plt

# Load data
df = pd.read_csv('sales_data.csv')
df['Date'] = pd.to_datetime(df['Date'])

# Example 1: Simple Line Chart
fig1, ax1 = plt.subplots(figsize=(10, 6))
ax1.plot(df['Date'], df['Product A Sales'], linewidth=2)
ax1.set_xlabel('Date')
ax1.set_ylabel('Sales')
ax1.set_title('Product A Sales Over Time')
ax1.grid(True, alpha=0.3)
plt.tight_layout()
# Display with: fig1

# Example 2: Multiple Line Chart
fig2, ax2 = plt.subplots(figsize=(10, 6))
ax2.plot(df['Date'], df['Product A Sales'], label='Product A', linewidth=2)
ax2.plot(df['Date'], df['Product B Sales'], label='Product B', linewidth=2)
ax2.plot(df['Date'], df['Product C Sales'], label='Product C', linewidth=2)
ax2.set_xlabel('Date')
ax2.set_ylabel('Sales')
ax2.set_title('Sales Comparison - All Products')
ax2.legend()
ax2.grid(True, alpha=0.3)
plt.tight_layout()
# Display with: fig2

# Example 3: Area Chart
fig3, ax3 = plt.subplots(figsize=(10, 6))
ax3.fill_between(df['Date'], df['Product A Sales'], alpha=0.4)
ax3.plot(df['Date'], df['Product A Sales'], linewidth=2)
ax3.set_xlabel('Date')
ax3.set_ylabel('Sales')
ax3.set_title('Product A Sales - Area Chart')
ax3.grid(True, alpha=0.3)
plt.tight_layout()
# Display with: fig3

# Example 4: Stacked Area Chart
fig4, ax4 = plt.subplots(figsize=(10, 6))
ax4.stackplot(df['Date'], df['Product A Sales'], df['Product B Sales'], df['Product C Sales'],
              labels=['Product A', 'Product B', 'Product C'], alpha=0.7)
ax4.set_xlabel('Date')
ax4.set_ylabel('Sales')
ax4.set_title('Total Sales - Stacked Area Chart')
ax4.legend(loc='upper left')
ax4.grid(True, alpha=0.3)
plt.tight_layout()
# Display with: fig4

运行此代码会产生以下四个可视化:

图片 1图片 2图片 3图片 4

让我们一步步分解代码,以确保你理解正在发生的事情:

  1. 首先,我们将数据加载到 pandas 中作为 CSV 文件,并确保日期被正确地表示为 datetime 对象。

  2. Matplotlib 在 Figure 对象中构建图表,该对象代表整个画布。这可以通过 plt.figure 直接访问,但使用 plt.subplots 创建多个变量进行多个可视化更为直观。每次调用 plt.subplots 都定义了一个新的、独立的 Figure(画布)。

  3. 代码行 fig1, ax1 = plt.subplots(figsize=(10, 6)) 定义了第一个子图;fig1 代表画布,但 ax1 代表其中的实际绘图区域,并且是你在其中进行大多数更改的变量。

  4. Matplotlib 为不同的图表有不同的函数。plot 函数绘制二维点,然后将它们连接起来构成折线图。这就是我们在行 ax1.plot(df['Date'], df['Product A Sales'], linewidth=2) 中指定的。

  5. 剩余的行主要是审美函数,它们确实如它们的名称所暗示的那样:标记轴,添加网格线,并指定布局。

  6. 对于多线图,代码完全相同,只是我们调用 plot 三次:一次用于每对 x-y 点,以便显示所有产品。

  7. 面积图几乎与折线图相同,只是增加了 ax3.fill_between(df['Date'], df['Product A Sales'], alpha=0.4),这告诉 Matplotlib 在线下方着色区域。

  8. 与之相比,堆积面积图需要我们使用 stacked_plot 函数,该函数一次性接收我们想要绘制的所有三个数据数组。然而,剩余的审美代码是相同的。

尝试在你最喜欢的 IDE 或 Jupyter 笔记本中自己编程这些内容。你看到了什么模式?你最喜欢哪种图表?

此外,请记住,你不需要记住这个语法,特别是如果你是数据可视化或 Python 的新手。专注于尝试从概念层面理解正在发生的事情;你总是可以查找特定的语法,并在需要时将数据插入其中。

这对剩余的两个示例也适用。

在 Plotly 中编码时间序列可视化

下面是生成与上面相同的可视化,这次使用 Plotly 风格的代码:

import pandas as pd
import plotly.graph_objects as go

# Load data
df = pd.read_csv('sales_data.csv')
df['Date'] = pd.to_datetime(df['Date'])

# Example 1: Simple Line Chart
fig1 = go.Figure()
fig1.add_trace(go.Scatter(x=df['Date'], y=df['Product A Sales'], mode='lines', name='Product A'))
fig1.update_layout(
    title='Product A Sales Over Time',
    xaxis_title='Date',
    yaxis_title='Sales',
    template='plotly_white'
)
# Display with: fig1

# Example 2: Multiple Line Chart
fig2 = go.Figure()
fig2.add_trace(go.Scatter(x=df['Date'], y=df['Product A Sales'], mode='lines', name='Product A'))
fig2.add_trace(go.Scatter(x=df['Date'], y=df['Product B Sales'], mode='lines', name='Product B'))
fig2.add_trace(go.Scatter(x=df['Date'], y=df['Product C Sales'], mode='lines', name='Product C'))
fig2.update_layout(
    title='Sales Comparison - All Products',
    xaxis_title='Date',
    yaxis_title='Sales',
    template='plotly_white'
)
# Display with: fig2

# Example 3: Area Chart
fig3 = go.Figure()
fig3.add_trace(go.Scatter(
    x=df['Date'], y=df['Product A Sales'],
    mode='lines',
    name='Product A',
    fill='tozeroy'
))
fig3.update_layout(
    title='Product A Sales - Area Chart',
    xaxis_title='Date',
    yaxis_title='Sales',
    template='plotly_white'
)
# Display with: fig3

# Example 4: Stacked Area Chart
fig4 = go.Figure()
fig4.add_trace(go.Scatter(
    x=df['Date'], y=df['Product A Sales'],
    mode='lines',
    name='Product A',
    stackgroup='one'
))
fig4.add_trace(go.Scatter(
    x=df['Date'], y=df['Product B Sales'],
    mode='lines',
    name='Product B',
    stackgroup='one'
))
fig4.add_trace(go.Scatter(
    x=df['Date'], y=df['Product C Sales'],
    mode='lines',
    name='Product C',
    stackgroup='one'
))
fig4.update_layout(
    title='Total Sales - Stacked Area Chart',
    xaxis_title='Date',
    yaxis_title='Sales',
    template='plotly_white'
)
# Display with: fig4

我们得到了以下四个可视化:

图片 5图片 6图片 7图片 8

下面是代码的分解:

  • Plotly 完全独立于 Matplotlib。它使用类似命名的Figure对象,但没有任何ax对象。

  • 使用具有“lines”模式的Scatter函数来构建带有指定 x 轴和 y 轴数据的折线图。您可以将add_trace函数视为向现有的Figure添加新组件。因此,对于多线图,我们只需三次调用add_trace并传入适当的Scatter输入即可。

  • 对于 Plotly 中的标签和美学,请使用update_layout函数。

  • 面积图与折线图构建方式相同,只是增加了可选参数fill='tozeroy'

    • 初看,这可能看起来像一些晦涩的颜色,但实际上它是在说“到零 Y”,指定了 Plotly 应该填充的区域。

    • 如果您在可视化方面遇到困难,请尝试将参数更改为“tozerox”并查看结果。

  • 对于堆叠面积图,我们需要一个不同的可选参数:stackgroup='one'。将此参数添加到每个Scatter调用中,告诉 Plotly 它们都是作为同一堆栈的一部分构建的。

Plotly 的一个优点是默认情况下,所有 Plotly 图表都是交互式的,并带有缩放、悬停显示工具提示和切换图例的能力。(注意上面的图片已保存为 PNG 格式,因此您需要自己生成这些图表才能看到这些功能。)

在 Altair 中编码时间序列可视化

让我们通过在 Altair 中生成这四个可视化来完成。以下是代码:

import pandas as pd
import altair as alt

# Load data
df = pd.read_csv('sales_data.csv')
df['Date'] = pd.to_datetime(df['Date'])

# Example 1: Simple Line Chart
chart1 = alt.Chart(df).mark_line().encode(
    x='Date:T',
    y='Product A Sales:Q'
).properties(
    title='Product A Sales Over Time',
    width=700,
    height=400
)
# Display with: chart1

# Example 2: Multiple Line Chart
# Reshape data for Altair
df_melted = df.melt(id_vars='Date', var_name='product', value_name='sales')

chart2 = alt.Chart(df_melted).mark_line().encode(
    x='Date:T',
    y='sales:Q',
    color='product:N'
).properties(
    title='Sales Comparison - All Products',
    width=700,
    height=400
)
# Display with: chart2

# Example 3: Area Chart
chart3 = alt.Chart(df).mark_area(opacity=0.7).encode(
    x='Date:T',
    y='Product A Sales:Q'
).properties(
    title='Product A Sales - Area Chart',
    width=700,
    height=400
)
# Display with: chart3

# Example 4: Stacked Area Chart
chart4 = alt.Chart(df_melted).mark_area(opacity=0.7).encode(
    x='Date:T',
    y='sales:Q',
    color='product:N'
).properties(
    title='Total Sales - Stacked Area Chart',
    width=700,
    height=400
)
# Display with: chart4

我们得到了以下图表:

图片 1图片 2图片 3图片 4

让我们分解一下代码:

  • Altair 的结构与 Matplotlib 和 Plotly 略有不同。掌握它需要一些练习,但一旦理解了,它的直观性使得构建新的可视化变得简单。

  • 在 Altair 中,所有内容都围绕Chart对象展开,您将数据传递给它。然后,您使用mark_函数来指定您想要构建的图表类型,并使用encoding函数来指定哪些变量将对应于图表上的哪些视觉元素(例如,x 轴、y 轴、颜色、大小等)。

  • 对于折线图,我们使用mark_line函数,并指定 x 轴为日期,y 轴为销售额。

  • melt 函数不会改变数据本身,只是它的结构。它将所有产品放入一个单独的列中,这是一种“长格式”,更适合 Altair 的可视化模型。更多详情,请查看这篇有用的文章。

  • 一旦我们按照上述方式转换数据,我们就可以通过添加“颜色”编码来简单地构建我们的多线图,如代码所示。这是因为所有产品类型现在都在一个单独的列中,我们可以告诉 Altair 通过颜色来区分它们。

  • 生成面积图的代码展示了 Altair 结构的美丽。一切保持不变——你所需要做的就是更改正在使用的函数为 mark_area

当你探索其他类型的可视化(以及未来的文章!)时,Altair 构建可视化的模型将更容易实现(并且希望你会欣赏)。

接下来是什么?

在未来的文章中,我将介绍如何使用这些库来构建其他类型的可视化。随着你继续学习,请记住,这些文章的目的是不是掌握任何一种工具。这是关于全面学习数据可视化,我希望你通过这篇文章对时间序列数据可视化有了更深的理解。

关于代码,这种舒适感来自于时间和实践。目前,你可以自由地使用上面的例子,并根据需要调整它们以适应你自己的数据。

直到下次见面。

参考文献

posted @ 2026-03-28 10:00  布客飞龙III  阅读(58)  评论(0)    收藏  举报