Matplotlib时间序列绘图全攻略:从基础到高级技巧
参考:How to Plot a Time Series in Matplotlib
时间序列数据在许多领域都扮演着重要角色,从金融市场分析到气象预报,再到社交媒体趋势追踪。能够有效地可视化这些数据对于理解趋势、识别模式和做出明智决策至关重要。Matplotlib作为Python中最流行的绘图库之一,为我们提供了强大而灵活的工具来创建各种时间序列图表。本文将深入探讨如何使用Matplotlib绘制时间序列图,从基础概念到高级技巧,全面覆盖您在实际应用中可能遇到的各种场景。
1. 时间序列数据的基本概念
在开始绘图之前,我们需要了解时间序列数据的基本概念。时间序列是按时间顺序排列的一系列数据点。在Python中,我们通常使用pandas库来处理时间序列数据,因为它提供了强大的日期时间处理功能。
让我们从一个简单的例子开始:
import pandas as pd
import matplotlib.pyplot as plt
# 创建一个简单的时间序列数据
dates = pd.date_range(start='2023-01-01', end='2023-12-31', freq='D')
values = range(len(dates))
df = pd.DataFrame({'date': dates, 'value': values})
# 绘制基本的时间序列图
plt.figure(figsize=(10, 6))
plt.plot(df['date'], df['value'])
plt.title('How to Plot a Time Series in Matplotlib - how2matplotlib.com')
plt.xlabel('Date')
plt.ylabel('Value')
plt.show()
Output:
在这个例子中,我们首先创建了一个包含整年日期的pandas DataFrame。然后,我们使用Matplotlib的plot
函数绘制了一个基本的时间序列图。figsize
参数用于设置图表的大小,title
、xlabel
和ylabel
用于添加标题和轴标签。
2. 自定义时间轴格式
默认情况下,Matplotlib会自动选择适当的时间轴格式。但有时我们可能需要自定义这个格式以更好地展示数据。以下是如何自定义时间轴格式的示例:
import matplotlib.dates as mdates
import pandas as pd
import matplotlib.pyplot as plt
# 创建一个简单的时间序列数据
dates = pd.date_range(start='2023-01-01', end='2023-12-31', freq='D')
values = range(len(dates))
df = pd.DataFrame({'date': dates, 'value': values})
plt.figure(figsize=(12, 6))
plt.plot(df['date'], df['value'])
plt.title('Custom Date Format - how2matplotlib.com')
plt.xlabel('Date')
plt.ylabel('Value')
# 自定义x轴日期格式
plt.gca().xaxis.set_major_formatter(mdates.DateFormatter('%Y-%m-%d'))
plt.gca().xaxis.set_major_locator(mdates.MonthLocator())
plt.gcf().autofmt_xdate() # 自动旋转日期标签
plt.show()
Output:
在这个例子中,我们使用matplotlib.dates
模块来自定义日期格式。DateFormatter
用于指定日期的显示格式,MonthLocator
用于设置刻度的位置(这里是每月一个刻度)。autofmt_xdate()
函数用于自动调整日期标签的角度,以防止它们重叠。
3. 绘制多个时间序列
在实际应用中,我们经常需要在同一图表上比较多个时间序列。Matplotlib使这变得非常简单:
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
# 创建一个简单的时间序列数据
dates = pd.date_range(start='2023-01-01', end='2023-12-31', freq='D')
values = range(len(dates))
df = pd.DataFrame({'date': dates, 'value': values})
# 创建多个时间序列
df['value2'] = df['value'] * np.random.randn(len(df)) + 500
plt.figure(figsize=(12, 6))
plt.plot(df['date'], df['value'], label='Series 1')
plt.plot(df['date'], df['value2'], label='Series 2')
plt.title('Multiple Time Series - how2matplotlib.com')
plt.xlabel('Date')
plt.ylabel('Value')
plt.legend()
plt.show()
Output:
这个例子展示了如何在同一图表上绘制两个不同的时间序列。我们使用label
参数为每个系列添加标签,然后调用plt.legend()
来显示图例。
4. 使用不同的图表类型
虽然线图是最常见的时间序列可视化方式,但Matplotlib还提供了其他类型的图表,可能更适合某些特定的数据或分析目的。
4.1 面积图
面积图可以很好地展示累积效应或比较不同类别的相对重要性:
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
# 创建一个简单的时间序列数据
dates = pd.date_range(start='2023-01-01', end='2023-12-31', freq='D')
values = range(len(dates))
df = pd.DataFrame({'date': dates, 'value': values})
plt.figure(figsize=(12, 6))
plt.fill_between(df['date'], df['value'], alpha=0.3)
plt.plot(df['date'], df['value'])
plt.title('Area Plot - how2matplotlib.com')
plt.xlabel('Date')
plt.ylabel('Value')
plt.show()
Output:
在这个例子中,fill_between
函数用于创建面积图。alpha
参数控制填充区域的透明度。
4.2 柱状图
对于离散的时间点数据,柱状图可能是一个更好的选择:
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
# 创建一个简单的时间序列数据
dates = pd.date_range(start='2023-01-01', end='2023-12-31', freq='D')
values = range(len(dates))
df = pd.DataFrame({'date': dates, 'value': values})
# 选择每月的数据点
monthly_data = df.resample('M', on='date').mean()
plt.figure(figsize=(12, 6))
plt.bar(monthly_data.index, monthly_data['value'], width=20)
plt.title('Bar Chart of Monthly Data - how2matplotlib.com')
plt.xlabel('Date')
plt.ylabel('Value')
plt.show()
Output:
这个例子首先使用pandas的resample
函数将数据聚合到月级别,然后使用bar
函数创建柱状图。width
参数控制柱子的宽度。
5. 处理缺失数据
实际的时间序列数据经常包含缺失值。Matplotlib提供了多种方法来处理这种情况:
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
# 创建一个简单的时间序列数据
dates = pd.date_range(start='2023-01-01', end='2023-12-31', freq='D')
values = range(len(dates))
df = pd.DataFrame({'date': dates, 'value': values})
# 创建包含缺失值的数据
df_missing = df.copy()
df_missing.loc[10:20, 'value'] = np.nan
plt.figure(figsize=(12, 6))
plt.plot(df_missing['date'], df_missing['value'], label='With gaps')
plt.plot(df_missing['date'], df_missing['value'].interpolate(), label='Interpolated')
plt.title('Handling Missing Data - how2matplotlib.com')
plt.xlabel('Date')
plt.ylabel('Value')
plt.legend()
plt.show()
Output:
这个例子展示了如何处理缺失数据。我们首先创建了一个包含缺失值的数据集,然后绘制了原始数据和使用interpolate
函数插值后的数据。
6. 添加注释和标记
为了突出显示时间序列中的重要点或事件,我们可以添加注释和标记:
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
# 创建一个简单的时间序列数据
dates = pd.date_range(start='2023-01-01', end='2023-12-31', freq='D')
values = range(len(dates))
df = pd.DataFrame({'date': dates, 'value': values})
plt.figure(figsize=(12, 6))
plt.plot(df['date'], df['value'])
plt.title('Annotations and Markers - how2matplotlib.com')
plt.xlabel('Date')
plt.ylabel('Value')
# 添加注释
plt.annotate('Important Event', xy=(df['date'][100], df['value'][100]),
xytext=(df['date'][50], df['value'][100]+100),
arrowprops=dict(facecolor='black', shrink=0.05))
# 添加标记
plt.plot(df['date'][200], df['value'][200], 'ro', markersize=10)
plt.show()
Output:
在这个例子中,我们使用annotate
函数添加了一个带箭头的注释,并使用plot
函数的额外参数添加了一个红色的圆形标记。
7. 子图和多轴图表
当需要在同一图形中显示多个相关但独立的时间序列时,子图和多轴图表非常有用:
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
# 创建一个简单的时间序列数据
dates = pd.date_range(start='2023-01-01', end='2023-12-31', freq='D')
values = range(len(dates))
df = pd.DataFrame({'date': dates, 'value': values})
fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(12, 10), sharex=True)
ax1.plot(df['date'], df['value'])
ax1.set_title('Subplots - how2matplotlib.com')
ax1.set_ylabel('Value 1')
ax2.plot(df['date'], df['value2'], color='red')
ax2.set_xlabel('Date')
ax2.set_ylabel('Value 2')
plt.tight_layout()
plt.show()
这个例子创建了两个垂直排列的子图。sharex=True
参数确保两个子图共享相同的x轴。
8. 自定义样式和颜色
Matplotlib提供了丰富的样式和颜色选项,可以帮助我们创建更具吸引力和信息量的图表:
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
# 创建一个简单的时间序列数据
dates = pd.date_range(start='2023-01-01', end='2023-12-31', freq='D')
values = range(len(dates))
df = pd.DataFrame({'date': dates, 'value': values})
plt.style.use('seaborn')
plt.figure(figsize=(12, 6))
plt.plot(df['date'], df['value'], color='#FF9999', linestyle='--', linewidth=2)
plt.plot(df['date'], df['value2'], color='#66B2FF', linestyle='-.')
plt.title('Custom Styles and Colors - how2matplotlib.com')
plt.xlabel('Date')
plt.ylabel('Value')
plt.grid(True, linestyle=':')
plt.show()
在这个例子中,我们首先使用plt.style.use
设置了一个预定义的样式。然后,我们为每条线设置了自定义的颜色、线型和线宽。grid
函数用于添加网格线。
9. 交互式时间序列图
虽然Matplotlib主要用于创建静态图表,但它也可以与其他库结合使用来创建交互式图表。以下是一个使用Matplotlib和ipywidgets创建简单交互式时间序列图的例子:
from ipywidgets import interact
import ipywidgets as widgets
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
# 创建一个简单的时间序列数据
dates = pd.date_range(start='2023-01-01', end='2023-12-31', freq='D')
values = range(len(dates))
df = pd.DataFrame({'date': dates, 'value': values})
@interact(start=widgets.DatePicker(value=df['date'].min()),
end=widgets.DatePicker(value=df['date'].max()))
def plot_range(start, end):
mask = (df['date'] >= start) & (df['date'] <= end)
plt.figure(figsize=(12, 6))
plt.plot(df.loc[mask, 'date'], df.loc[mask, 'value'])
plt.title('Interactive Time Series Plot - how2matplotlib.com')
plt.xlabel('Date')
plt.ylabel('Value')
plt.show()
这个例子创建了一个交互式图表,允许用户选择开始和结束日期。注意,这个代码需要在Jupyter Notebook环境中运行才能看到交互效果。
10. 时间序列的统计分析
Matplotlib不仅可以用来绘制原始的时间序列数据,还可以用来可视化各种统计分析结果:
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
# 创建一个简单的时间序列数据
dates = pd.date_range(start='2023-01-01', end='2023-12-31', freq='D')
values = range(len(dates))
df = pd.DataFrame({'date': dates, 'value': values})
# 计算移动平均
df['MA7'] = df['value'].rolling(window=7).mean()
df['MA30'] = df['value'].rolling(window=30).mean()
plt.figure(figsize=(12, 6))
plt.plot(df['date'], df['value'], alpha=0.5, label='Raw data')
plt.plot(df['date'], df['MA7'], label='7-day MA')
plt.plot(df['date'], df['MA30'], label='30-day MA')
plt.title('Moving Averages - how2matplotlib.com')
plt.xlabel('Date')
plt.ylabel('Value')
plt.legend()
plt.show()
Output:
这个例子计算并绘制了7天和30天的移动平均线。移动平均线可以帮助我们识别数据的长期趋势。
11. 处理不同时间尺度
有时我们需要在同一图表中展示不同时间尺度的数据:
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
# 创建一个简单的时间序列数据
dates = pd.date_range(start='2023-01-01', end='2023-12-31', freq='D')
values = range(len(dates))
df = pd.DataFrame({'date': dates, 'value': values})
# 创建日数据和月数据
daily_data = df.set_index('date')['value']
monthly_data = daily_data.resample('M').mean()
fig, ax1 = plt.subplots(figsize=(12, 6))
ax1.plot(daily_data.index, daily_data, label='Daily', alpha=0.5)
ax1.set_xlabel('Date')
ax1.set_ylabel('Daily Value')
ax2 = ax1.twinx()
ax2.plot(monthly_data.index, monthly_data, color='red', label='Monthly')
ax2.set_ylabel('Monthly Value')
plt.title('Multiple Time Scales - how2matplotlib.com')
fig.legend(loc='upper right')
plt.show()
Output:
这个例子展示了如何在同一图表中绘制日数据和月数据。我们使用twinx()
函数创建一个共享x轴但有独立y轴的图表。
12. 季节性分解
对于许多时间序列数据,识别和可视化其季节性成分是很重要的:
from statsmodels.tsa.seasonal import seasonal_decompose
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
# 创建一个简单的时间序列数据
dates = pd.date_range(start='2023-01-01', end='2023-12-31', freq='D')
values = range(len(dates))
df = pd.DataFrame({'date': dates, 'value': values})
# 假设我们的数据有季节性
result = seasonal_decompose(df.set_index('date')['value'], model='additive', period=30)
fig, (ax1, ax2, ax3, ax4) = plt.subplots(4, 1, figsize=(12, 16))
result.observed.plot(ax=ax1)
ax1.set_title('Observed - how2matplotlib.com')
result.trend.plot(ax=ax2)
ax2.set_title('Trend')
result.seasonal.plot(ax=ax3)
ax3.set_title('Seasonal')
result.resid.plot(ax=ax4)
ax4.set_title('Residual')
plt.tight_layout()
plt.show()
Output:
这个例子使用statsmodels
库的seasonal_decompose
函数将时间序列分解为趋势、季节性和残差成分,然后使用Matplotlib绘制这些成分。
13. 处理时区
在处理跨时区的数据时,正确处理时区信息很重要:
import pytz
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
# 创建一个简单的时间序列数据
dates = pd.date_range(start='2023-01-01', end='2023-12-31', freq='D')
values = range(len(dates))
df = pd.DataFrame({'date': dates, 'value': values})
# 创建包含时区信息的时间序列
dates_with_tz = pd.date_range(start='2023-01-01', end='2023-12-31', freq='D', tz='UTC')
df_tz = pd.DataFrame({'date': dates_with_tz, 'value': range(len(dates_with_tz))})
# 转换到不同的时区
df_tz['date_ny'] = df_tz['date'].dt.tz_convert('America/New_York')
plt.figure(figsize=(12, 6))
plt.plot(df_tz['date'], df_tz['value'], label='UTC')
plt.plot(df_tz['date_ny'], df_tz['value'], label='New York')
plt.title('Time Zone Handling - how2matplotlib.com')
plt.xlabel('Date')
plt.ylabel('Value')
plt.legend()
plt.show()
Output:
这个例子展示了如何处理和绘制不同时区的时间序列数据。我们首先创建了一个UTC时区的时间序列,然后将其转换为纽约时区,并在同一图表中绘制这两个时间序列。
14. 绘制股票数据
金融数据是时间序列的一个常见应用领域。以下是一个绘制股票数据的示例:
import yfinance as yf
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
# 创建一个简单的时间序列数据
dates = pd.date_range(start='2023-01-01', end='2023-12-31', freq='D')
values = range(len(dates))
df = pd.DataFrame({'date': dates, 'value': values})
# 下载股票数据
stock_data = yf.download('AAPL', start='2022-01-01', end='2023-01-01')
plt.figure(figsize=(12, 6))
plt.plot(stock_data.index, stock_data['Close'])
plt.title('Apple Stock Price - how2matplotlib.com')
plt.xlabel('Date')
plt.ylabel('Closing Price')
plt.fill_between(stock_data.index, stock_data['Close'], alpha=0.3)
plt.show()
这个例子使用yfinance
库下载苹果公司的股票数据,然后使用Matplotlib绘制收盘价的时间序列图。我们还使用fill_between
函数添加了一个半透明的填充区域,以增强视觉效果。
15. 绘制蜡烛图
对于金融数据,蜡烛图是另一种常用的可视化方式:
from mpl_finance import candlestick_ohlc
import matplotlib.dates as mdates
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
# 创建一个简单的时间序列数据
dates = pd.date_range(start='2023-01-01', end='2023-12-31', freq='D')
values = range(len(dates))
df = pd.DataFrame({'date': dates, 'value': values})
# 准备数据
data = stock_data.reset_index()
data['Date'] = data['Date'].map(mdates.date2num)
ohlc = data[['Date', 'Open', 'High', 'Low', 'Close']].values
fig, ax = plt.subplots(figsize=(12, 6))
candlestick_ohlc(ax, ohlc, width=0.6, colorup='g', colordown='r')
ax.xaxis.set_major_formatter(mdates.DateFormatter('%Y-%m-%d'))
ax.set_title('Apple Stock Candlestick Chart - how2matplotlib.com')
ax.set_xlabel('Date')
ax.set_ylabel('Price')
plt.xticks(rotation=45)
plt.tight_layout()
plt.show()
这个例子展示了如何使用Matplotlib的mpl_finance
扩展绘制蜡烛图。蜡烛图可以同时显示开盘价、收盘价、最高价和最低价,提供了更多的价格信息。
16. 绘制热力图
热力图是另一种有效的时间序列可视化方法,特别适合展示多个变量随时间的变化:
import seaborn as sns
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
# 创建一个简单的时间序列数据
dates = pd.date_range(start='2023-01-01', end='2023-12-31', freq='D')
values = range(len(dates))
df = pd.DataFrame({'date': dates, 'value': values})
# 创建多个时间序列
df['value3'] = df['value'] * np.random.randn(len(df)) + 1000
df['value4'] = df['value'] * np.random.randn(len(df)) + 1500
# 将数据重塑为适合热力图的格式
heatmap_data = df.set_index('date')[['value', 'value2', 'value3', 'value4']]
plt.figure(figsize=(12, 8))
sns.heatmap(heatmap_data.T, cmap='YlOrRd')
plt.title('Time Series Heatmap - how2matplotlib.com')
plt.xlabel('Date')
plt.ylabel('Variable')
plt.show()
这个例子使用Seaborn库(基于Matplotlib)创建了一个热力图。热力图用颜色的深浅来表示数值的大小,非常适合展示多个变量随时间的变化模式。
17. 绘制极坐标图
对于某些类型的周期性时间序列数据,极坐标图可能是一个有趣的可视化选择:
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
# 创建一个简单的时间序列数据
dates = pd.date_range(start='2023-01-01', end='2023-12-31', freq='D')
values = range(len(dates))
df = pd.DataFrame({'date': dates, 'value': values})
# 创建一年的每日数据
dates = pd.date_range(start='2023-01-01', end='2023-12-31', freq='D')
values = np.sin(np.linspace(0, 4*np.pi, len(dates))) + np.random.randn(len(dates))*0.1
df = pd.DataFrame({'date': dates, 'value': values})
fig, ax = plt.subplots(figsize=(10, 10), subplot_kw=dict(projection='polar'))
theta = 2 * np.pi * df['date'].dt.dayofyear / 365
ax.plot(theta, df['value'])
ax.set_title('Polar Plot of Annual Data - how2matplotlib.com')
ax.set_xticks(np.linspace(0, 2*np.pi, 12, endpoint=False))
ax.set_xticklabels(['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',
'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'])
plt.show()
Output:
这个例子创建了一个极坐标图,其中角度表示一年中的时间,半径表示数值。这种图表特别适合展示具有年度周期性的数据。
18. 绘制阶梯图
对于某些离散变化的时间序列数据,阶梯图可能是一个更好的选择:
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
# 创建一个简单的时间序列数据
dates = pd.date_range(start='2023-01-01', end='2023-12-31', freq='D')
values = range(len(dates))
df = pd.DataFrame({'date': dates, 'value': values})
# 创建离散变化的数据
dates = pd.date_range(start='2023-01-01', end='2023-12-31', freq='W')
values = np.cumsum(np.random.randint(-10, 11, size=len(dates)))
plt.figure(figsize=(12, 6))
plt.step(dates, values, where='post')
plt.title('Step Plot - how2matplotlib.com')
plt.xlabel('Date')
plt.ylabel('Value')
plt.grid(True)
plt.show()
Output:
这个例子使用step
函数创建了一个阶梯图。where='post'
参数指定每个步骤应该在数据点之后发生变化。这种图表适合表示在特定时间点发生离散变化的数据。
19. 绘制误差带
在展示时间序列数据时,有时需要显示数据的不确定性或变异性:
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
# 创建一个简单的时间序列数据
dates = pd.date_range(start='2023-01-01', end='2023-12-31', freq='D')
values = range(len(dates))
df = pd.DataFrame({'date': dates, 'value': values})
# 创建带有误差的数据
dates = pd.date_range(start='2023-01-01', end='2023-12-31', freq='D')
values = np.cumsum(np.random.randn(len(dates)))
errors = np.random.rand(len(dates)) * 10
plt.figure(figsize=(12, 6))
plt.plot(dates, values)
plt.fill_between(dates, values-errors, values+errors, alpha=0.2)
plt.title('Time Series with Error Band - how2matplotlib.com')
plt.xlabel('Date')
plt.ylabel('Value')
plt.show()
Output:
这个例子展示了如何使用fill_between
函数添加误差带。误差带可以表示数据的置信区间、标准差或其他不确定性度量。
20. 绘制堆叠面积图
堆叠面积图是展示多个相关时间序列及其总和的有效方式:
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
# 创建一个简单的时间序列数据
dates = pd.date_range(start='2023-01-01', end='2023-12-31', freq='D')
values = range(len(dates))
df = pd.DataFrame({'date': dates, 'value': values})
# 创建多个相关的时间序列
df['value5'] = df['value'] * 0.5 + np.random.randn(len(df)) * 50
df['value6'] = df['value'] * 0.3 + np.random.randn(len(df)) * 30
plt.figure(figsize=(12, 6))
plt.stackplot(df['date'], df['value'], df['value5'], df['value6'],
labels=['Series 1', 'Series 2', 'Series 3'])
plt.title('Stacked Area Plot - how2matplotlib.com')
plt.xlabel('Date')
plt.ylabel('Value')
plt.legend(loc='upper left')
plt.show()
Output:
这个例子使用stackplot
函数创建了一个堆叠面积图。这种图表特别适合展示多个组成部分随时间的变化,以及它们的总和。
结语
通过本文,我们详细探讨了如何使用Matplotlib绘制各种类型的时间序列图表。从基本的线图到复杂的多轴图表,从处理缺失数据到自定义样式,我们涵盖了广泛的主题和技巧。这些技能将帮助您更有效地分析和展示时间序列数据,无论是在金融分析、科学研究还是其他领域。
记住,数据可视化是一门艺术,也是一门科学。选择正确的图表类型和样式不仅取决于数据的性质,还取决于您想要传达的信息。通过实践和经验,您将能够创建既美观又信息丰富的时间序列图表。
最后,Matplotlib的功能远不止于此。随着您对库的深入了解,您会发现更多高级功能和技巧。不断探索和实验,您将能够创建出更加复杂和定制化的可视化效果,以满足各种数据分析和展示需求。