
在数据分析和可视化中,我们经常需要突出图表中的特定时间段或数据区域,以标记事件、异常值或重要阶段。matplotlib提供了强大的绘图功能,其中axvspan函数是实现垂直区域着色的关键工具。本教程将指导您如何根据一个独立的事件序列(例如,一个表示事件发生与否的二进制序列)来动态地为图表的不同部分着色,特别地,我们将实现事件发生前、发生中和发生后三个阶段的不同颜色标记。
matplotlib.axes.Axes.axvspan(xmin, xmax, ymin=0, ymax=1, **kwargs) 函数用于在坐标轴上绘制一个垂直的矩形区域。
通过多次调用axvspan并指定不同的xmin、xmax和facecolor,我们可以创建多个自定义着色区域。
首先,我们需要模拟一些数据,包括主数据系列和用于触发着色事件的事件序列。事件序列通常是一个二进制值,例如0表示无事件,1表示事件发生。
import numpy as np import matplotlib.pyplot as plt import pandas as pd # 设置随机种子以便结果可复现 np.random.seed(42) # 生成事件数据,初始为0 data_length = 56 event = pd.DataFrame(np.zeros(data_length, dtype=int), columns=['event_status']) # 模拟事件发生 # 事件1:从索引10到13(即[10:14]) event.iloc[10:14, 0] = 1 # 事件2:从索引24到35(即[24:36]) event.iloc[24:36, 0] = 1 # 生成主图表数据 data_series_1 = pd.DataFrame(np.random.randint(200, 300, size=(data_length, 1)), columns=['Series1']) data_series_2 = pd.DataFrame(np.random.randint(0, 3, size=(data_length, 1)), columns=['Series2']) data_series_3 = pd.DataFrame(np.random.randint(300, 400, size=(data_length, 1)), columns=['Series3']) data_series_4 = pd.DataFrame(np.random.randint(0, 5, size=(data_length, 1)), columns=['Series4'])
为了实现精确着色,我们需要从事件序列中识别出所有连续的事件发生周期(即event值为1的连续区间)。
def find_event_periods(event_series):
    """
    识别事件序列中值为1的连续周期。
    返回一个列表,每个元素是一个元组 (start_index, end_index),
    其中end_index是该周期的结束索引(不包含)。
    """
    event_periods = []
    in_event = False
    start_idx = -1
    for i in range(len(event_series)):
        if event_series.iloc[i] == 1 and not in_event:
            start_idx = i
            in_event = True
        elif event_series.iloc[i] == 0 and in_event:
            event_periods.append((start_idx, i))
            in_event = False
    # 处理事件持续到序列末尾的情况
    if in_event:
        event_periods.append((start_idx, len(event_series)))
    return event_periods
event_periods = find_event_periods(event['event_status'])
print(f"识别到的事件周期: {event_periods}")输出示例:识别到的事件周期: [(10, 14), (24, 36)]
现在,我们将根据识别到的事件周期,为每个周期定义三个着色区域:
我们将定义这些区域的颜色和透明度。
# 定义着色方案 color_pre_event = 'skyblue' # 事件前区域颜色 color_during_event = 'lightcoral' # 事件中区域颜色 color_post_event = 'lightgreen' # 事件后区域颜色 alpha_level = 0.2 # 透明度
以下是整合了数据生成、事件识别和区域着色逻辑的完整Matplotlib绘图代码。它将使用原始问题中定义的双轴子图结构。
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
# --- 1. 数据准备 ---
np.random.seed(42) # 确保结果可复现
data_length = 56
event = pd.DataFrame(np.zeros(data_length, dtype=int), columns=['event_status'])
event.iloc[10:14, 0] = 1 # 事件1
event.iloc[24:36, 0] = 1 # 事件2
# 主图表数据
data_series_1 = pd.DataFrame(np.random.randint(200, 300, size=(data_length, 1)), columns=['Series1'])
data_series_2 = pd.DataFrame(np.random.randint(0, 3, size=(data_length, 1)), columns=['Series2'])
data_series_3 = pd.DataFrame(np.random.randint(300, 400, size=(data_length, 1)), columns=['Series3'])
data_series_4 = pd.DataFrame(np.random.randint(0, 5, size=(data_length, 1)), columns=['Series4'])
# --- 2. 事件周期识别函数 ---
def find_event_periods(event_series):
    event_periods = []
    in_event = False
    start_idx = -1
    for i in range(len(event_series)):
        if event_series.iloc[i] == 1 and not in_event:
            start_idx = i
            in_event = True
        elif event_series.iloc[i] == 0 and in_event:
            event_periods.append((start_idx, i))
            in_event = False
    if in_event:
        event_periods.append((start_idx, len(event_series)))
    return event_periods
event_periods = find_event_periods(event['event_status'])
# --- 3. 定义着色方案 ---
color_pre_event = 'blue'      # 事件前区域颜色
color_during_event = 'red'    # 事件中区域颜色
color_post_event = 'green'    # 事件后区域颜色
alpha_level = 0.2             # 透明度
# --- 4. 绘图部分 ---
plt.figure(figsize=(18, 8)) # 调整图表大小以适应内容和布局
# 第一个子图 (2行2列的第1个)
ax1 = plt.subplot(1, 2, 1) # 调整为1行2列,便于展示
ax2 = ax1.twinx() # 创建第二个y轴
# 绘制主数据系列
ax1.plot(data_series_1, label='Series 1', color='g')
ax1.plot(data_series_2, label='Series 2', color='r')
ax2.plot(event, label='Event Status', color='k', linestyle='--', linewidth=1) # 事件状态曲线
# 应用区域着色
for start, end in event_periods:
    # 事件前区域: 从 max(0, start-1) 到 start
    pre_event_xmin = max(0, start - 1)
    pre_event_xmax = start
    if pre_event_xmin < pre_event_xmax: # 确保区域有效
        ax1.axvspan(pre_event_xmin, pre_event_xmax, facecolor=color_pre_event, alpha=alpha_level, label='Pre-Event' if start == event_periods[0][0] else "")
    # 事件中区域: 从 start 到 end
    ax1.axvspan(start, end, facecolor=color_during_event, alpha=alpha_level, label='During-Event' if start == event_periods[0][0] else "")
    # 事件后区域: 从 end 到 min(data_length, end+2)
    post_event_xmin = end
    post_event_xmax = min(data_length, end + 2)
    if post_event_xmin < post_event_xmax: # 确保区域有效
        ax1.axvspan(post_event_xmin, post_event_xmax, facecolor=color_post_event, alpha=alpha_level, label='Post-Event' if start == event_periods[0][0] else "")
# 设置标签和标题
ax1.set_ylabel('Value (m)', fontsize=12)
ax2.set_ylabel('Event Status (t)', color='k', fontsize=12)
ax1.set_title('图表 0: 事件驱动背景着色示例', fontsize=14)
ax1.tick_params(axis='y', labelsize=10)
ax1.tick_params(axis='x', labelsize=10)
ax2.tick_params(axis='y', labelsize=10)
# 合并图例,避免重复标签
lines, labels = ax1.get_legend_handles_labels()
lines2, labels2 = ax2.get_legend_handles_labels()
# 过滤掉axvspan的重复标签,只保留第一次出现的
unique_labels = {}
for line, label in zip(lines + lines2, labels + labels2):
    if label not in unique_labels:
        unique_labels[label] = line
ax1.legend(unique_labels.values(), unique_labels.keys(), loc='upper left', prop={'size': 10})
# 第二个子图 (2行2列的第2个) - 结构与第一个类似,但使用不同的数据
ax3 = plt.subplot(1, 2, 2)
ax4 = ax3.twinx()
ax3.plot(data_series_3, label='Series 3', color='purple')
ax3.plot(data_series_4, label='Series 4', color='orange')
ax4.plot(event, label='Event Status', color='k', linestyle='--', linewidth=1)
# 应用区域着色 (与第一个子图逻辑相同)
for start, end in event_periods:
    pre_event_xmin = max(0, start - 1)
    pre_event_xmax = start
    if pre_event_xmin < pre_event_xmax:
        ax3.axvspan(pre_event_xmin, pre_event_xmax, facecolor=color_pre_event, alpha=alpha_level)
    ax3.axvspan(start, end, facecolor=color_during_event, alpha=alpha_level)
    post_event_xmin = end
    post_event_xmax = min(data_length, end + 2)
    if post_event_xmin < post_event_xmax:
        ax3.axvspan(post_event_xmin, post_event_xmax, facecolor=color_post_event, alpha=alpha_level)
ax3.set_ylabel('Value (m)', fontsize=12)
ax4.set_ylabel('Event Status (t)', color='k', fontsize=12)
ax3.set_title('图表 1: 事件驱动背景着色示例', fontsize=14)
ax3.tick_params(axis='y', labelsize=10)
ax3.tick_params(axis='x', labelsize=10)
ax4.tick_params(axis='y', labelsize=10)
# 合并图例
lines, labels = ax3.get_legend_handles_labels()
lines2, labels2 = ax4.get_legend_handles_labels()
unique_labels = {}
for line, label in zip(lines + lines2, labels + labels2):
    if label not in unique_labels:
        unique_labels[label] = line
ax3.legend(unique_labels.values(), unique_labels.keys(), loc='upper left', prop={'size': 10})
plt.tight_layout() # 自动调整子图参数,使之填充整个图像区域
plt.show()以上就是Matplotlib图表区域事件驱动型背景着色教程的详细内容,更多请关注php中文网其它相关文章!
 
                 
                                
                                 收藏
收藏
                                                                             
                                
                                 收藏
收藏
                                                                             
                                
                                 收藏
收藏
                                                                            Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号