
本教程详细介绍了如何在Matplotlib图表中根据特定事件数据为图表的不同区域进行背景着色。通过识别数据系列中的事件发生点,并利用axvspan函数,我们可以为事件发生前、发生中和发生后的区域应用不同的颜色,从而增强数据可视化效果,突出关键时间段。教程提供了详细的代码示例和注意事项,帮助用户实现精确的区域着色。
引言
在数据分析和可视化中,我们经常需要突出图表中的特定时间段或数据区域,以标记事件、异常值或重要阶段。matplotlib提供了强大的绘图功能,其中axvspan函数是实现垂直区域着色的关键工具。本教程将指导您如何根据一个独立的事件序列(例如,一个表示事件发生与否的二进制序列)来动态地为图表的不同部分着色,特别地,我们将实现事件发生前、发生中和发生后三个阶段的不同颜色标记。
核心概念:axvspan函数
matplotlib.axes.Axes.axvspan(xmin, xmax, ymin=0, ymax=1, **kwargs) 函数用于在坐标轴上绘制一个垂直的矩形区域。
xmin, xmax: 定义了矩形区域的水平范围。ymin, ymax: 定义了矩形区域的垂直范围,默认是0到1,表示覆盖整个y轴范围。facecolor: 矩形区域的填充颜色。alpha: 矩形区域的透明度,值介于0(完全透明)和1(完全不透明)之间。
通过多次调用axvspan并指定不同的xmin、xmax和facecolor,我们可以创建多个自定义着色区域。
准备数据
首先,我们需要模拟一些数据,包括主数据系列和用于触发着色事件的事件序列。事件序列通常是一个二进制值,例如0表示无事件,1表示事件发生。
import numpy as npimport matplotlib.pyplot as pltimport pandas as pd# 设置随机种子以便结果可复现np.random.seed(42)# 生成事件数据,初始为0data_length = 56event = 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_periodsevent_periods = find_event_periods(event['event_status'])print(f"识别到的事件周期: {event_periods}")
输出示例:识别到的事件周期: [(10, 14), (24, 36)]
实现区域着色逻辑
现在,我们将根据识别到的事件周期,为每个周期定义三个着色区域:
事件前区域 (Pre-event): 事件开始前一个索引到事件开始的区域。事件中区域 (During-event): 事件发生期间的区域。事件后区域 (Post-event): 事件结束后两个索引的区域。
我们将定义这些区域的颜色和透明度。
# 定义着色方案color_pre_event = 'skyblue' # 事件前区域颜色color_during_event = 'lightcoral' # 事件中区域颜色color_post_event = 'lightgreen' # 事件后区域颜色alpha_level = 0.2 # 透明度
完整代码示例
以下是整合了数据生成、事件识别和区域着色逻辑的完整Matplotlib绘图代码。它将使用原始问题中定义的双轴子图结构。
import numpy as npimport matplotlib.pyplot as pltimport pandas as pd# --- 1. 数据准备 ---np.random.seed(42) # 确保结果可复现data_length = 56event = pd.DataFrame(np.zeros(data_length, dtype=int), columns=['event_status'])event.iloc[10:14, 0] = 1 # 事件1event.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_periodsevent_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] = lineax1.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] = lineax3.legend(unique_labels.values(), unique_labels.keys(), loc='upper left', prop={'size': 10})plt.tight_layout() # 自动调整子图参数,使之填充整个图像区域plt.show()
代码解析与注意事项
数据生成与事件定义:event DataFrame用于存储事件状态,其中0表示无事件,1表示事件发生。iloc用于精确设置事件发生的区间。find_event_periods函数:此函数通过遍历event_series来识别连续的1值块。它返回一个元组列表,每个元组(start, end)表示一个事件周期的起始和结束索引(end是排他性的)。这种方法比简单地查找1的索引更健壮,因为它能正确处理连续的事件块。着色方案定义:color_pre_event, color_during_event, color_post_event定义了三个阶段的颜色。alpha_level控制着色区域的透明度,通常设置为0.1到0.3之间,以便背景色不遮盖主要数据线。axvspan调用:对于每个识别到的事件周期(start, end),我们计算并调用三次axvspan:事件前: xmin为max(0, start – 1),xmax为start。max(0, …)确保区域不会超出图表左边界。事件中: xmin为start,xmax为end。事件后: xmin为end,xmax为`min(data_length, end +
以上就是Matplotlib图表区域事件驱动型背景着色教程的详细内容,更多请关注创想鸟其它相关文章!
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 chuangxiangniao@163.com 举报,一经查实,本站将立刻删除。
发布者:程序猿,转转请注明出处:https://www.chuangxiangniao.com/p/1375536.html
微信扫一扫
支付宝扫一扫