Matplotlib图表区域事件驱动型背景着色教程

Matplotlib图表区域事件驱动型背景着色教程

本教程详细介绍了如何在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

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2025年12月14日 15:06:08
下一篇 2025年12月14日 15:06:17

相关推荐

  • 解决 Tkinter sv_ttk 主题切换错误:多窗口应用中的主题管理

    本文旨在解决在 Tkinter 多窗口应用中使用 sv_ttk 库进行主题切换时遇到的 _tkinter.TclError: can’t invoke “winfo” command: application has been destroyed 错误。我们将深入…

    2025年12月14日
    000
  • Pyrogram Telegram 机器人会话管理与登录指南

    本文旨在提供使用 Pyrogram 构建 Telegram API 机器人时,关于会话管理和账户登录的专业指导。我们将详细阐述如何正确初始化客户端、请求并输入登录验证码以建立持久会话,并深入探讨机器人直接接收用户发送的验证码进行自身登录的限制,提供相应的解决方案和最佳实践。 Pyrogram 认证流…

    2025年12月14日
    000
  • Python Socket数据传输:深度解析recv的陷阱与完整数据接收策略

    本文探讨了Python Socket编程中,通过网络传输MP4文件时接收不完整的问题。核心原因是socket.recv()函数并非总能一次性返回请求的所有字节。教程将详细解释recv的工作机制,并提供一个健壮的解决方案,确保在循环接收数据时,准确累计已接收字节数并妥善处理连接中断,从而实现完整文件传…

    2025年12月14日
    000
  • 深入理解Python非静态方法:为何及何时使用它们?

    Python中的非静态方法是面向对象编程的核心,它们允许方法访问和操作类的实例状态(通过self参数)。虽然静态方法因其易于调用而受欢迎,但非静态方法在处理实例数据、实现多态、定义特殊行为(如运算符重载)以及构建清晰、可维护的面向对象代码结构方面不可或缺。理解它们的适用场景对于编写健壮和符合Pyth…

    2025年12月14日
    000
  • Python文档查询指南:深入理解pydoc与help()及seek方法查找

    本文旨在解决Python初学者在使用pydoc命令查询file.seek时遇到的困惑。文章详细阐述了pydoc和help()的工作原理,解释了为何file.seek无法直接被这些工具识别,并提供了查询模块、函数以及文件对象seek方法的正确途径和示例,帮助读者高效利用Python内置的文档系统。 1…

    2025年12月14日
    000
  • AsyncElasticsearch 异步批量操作指南

    本教程将指导您如何在 Python 中使用 AsyncElasticsearch 客户端执行异步批量操作。针对 elasticsearch.helpers.bulk 不支持异步客户端的问题,我们将重点介绍如何利用 elasticsearch.helpers.async_bulk 模块实现高效的数据索…

    2025年12月14日
    000
  • Python 包管理与虚拟环境的正确使用

    本文旨在帮助开发者理解并正确使用 Python 虚拟环境,避免直接在系统环境中安装 Python 包可能带来的风险。文章将详细介绍虚拟环境的概念、创建与激活,以及在不同场景下的使用方法,并推荐了几种常用的虚拟环境管理工具,助力开发者构建更健康、更稳定的 Python 开发环境。 为什么需要虚拟环境?…

    2025年12月14日
    000
  • Python pathlib跨平台路径兼容性:处理Windows风格反斜杠路径

    pathlib在处理跨平台路径时,直接使用Path()构造函数初始化包含反斜杠的Windows风格字符串可能导致在Linux上出现FileNotFoundError。本文详细阐述了pathlib的默认行为,并提供了一个健壮的跨平台解决方案:通过Path(PureWindowsPath(raw_str…

    2025年12月14日
    000
  • Python中处理嵌套JSON字符串:生成正确转义的单斜杠GeoJSON数据

    本教程详细阐述了在Python中如何将嵌套的JSON对象正确地序列化为字符串,并确保内部双引号被单个反斜杠转义。这对于将GeoJSON数据等复杂结构作为字符串存储在数据库字段(如BigQuery GIS的GEOGRAPHY类型)中至关重要,避免了常见的双反斜杠转义问题。 在数据处理和存储中,尤其是在…

    2025年12月14日
    000
  • ESP32 MicroPython:解决ADC与Wi-Fi并发使用冲突的策略

    本教程旨在解决ESP32在使用MicroPython时,ADC(模拟数字转换器)与Wi-Fi模块并发操作可能遇到的冲突问题。核心在于ESP32的ADC2被Wi-Fi驱动占用,导致两者无法同时工作。文章将详细阐述这一硬件限制,并提供两种主要解决方案:优先选用ADC1引脚,或在特定场景下管理Wi-Fi状…

    2025年12月14日
    000
  • Selenium 模态框自动化交互:应对点击防抖与动态元素定位挑战

    本文深入探讨了在 Selenium 自动化测试中与模态框(Modal)内元素进行交互的策略。文章重点解决点击事件的防抖逻辑、元素动态加载以及使用脆弱定位器导致 NoSuchElementException 的问题。通过引入显式等待、点击重试机制和健壮的 CSS 选择器,本教程旨在提供一套可靠且高效的…

    2025年12月14日
    000
  • Python中使用正则表达式解析特定格式数据并提取关键信息

    本文详细介绍了如何利用Python的re模块和正则表达式,从包含特定模式(如55=id|1007=symbol)的复杂字符串中高效提取所需的键值对。教程通过具体示例,演示了如何构建精确的正则表达式,并使用re.findall()函数解析数据,最终将不规则的字符串数据转换为结构化的信息,便于后续处理和…

    2025年12月14日
    000
  • Selenium 模态框元素交互:有效点击、智能等待与稳定定位策略

    在使用 Selenium 进行自动化测试时,处理模态框(Modal)内部元素常常遇到 NoSuchElementException。本文将深入探讨如何有效点击触发模态框的按钮(尤其当存在防抖逻辑时),并使用智能等待机制确保模态框及其内部元素加载完成。同时,强调采用稳定、可维护的定位策略,避免绝对 X…

    2025年12月14日
    000
  • Selenium Web元素数据提取指南:从列表到具体信息

    本教程详细阐述了如何利用Selenium从网页元素列表中高效提取所需信息。通过迭代WebElement对象并运用.text方法获取文本内容,以及.get_attribute()方法获取元素属性值,读者将学会精确地从复杂的网页结构中抓取数据,为自动化测试和数据抓取任务奠定坚实基础。 理解Seleniu…

    2025年12月14日
    000
  • 使用正则表达式解析并转换数据:从字符串中提取键值对

    本文旨在提供一种使用 Python 正则表达式从特定格式的字符串中提取数据,并将其转换为所需格式的方法。我们将解析包含 “55=id|1007=symbol” 模式的字符串,最终生成 “symbol = id” 格式的输出,以便后续用于创建订单等操作。…

    2025年12月14日
    000
  • python Protobuf定义消息类型

    编写 .proto 文件定义消息结构,如 search.proto 中声明 proto3 语法并用 message 定义字段;2. 使用 protoc 编译器执行 protoc –python_out=. search.proto 生成 search_pb2.py;3. 在 Python…

    2025年12月14日
    000
  • pathlib 进阶:优雅处理跨平台Windows风格路径

    本教程探讨了Python pathlib 模块在处理跨平台路径时遇到的常见问题,特别是如何将Windows风格的路径字符串(使用反斜杠)在非Windows系统(如Linux)上正确转换为本地路径格式。文章详细解释了 Path() 对象在默认情况下不自动转换路径分隔符的原因,并提供了一种健壮的解决方案…

    2025年12月14日
    000
  • PyPDF2:从PDF文件中高效提取文本内容的实用指南

    本教程详细介绍了如何使用Python的PyPDF2库从PDF文档中提取文本内容。针对初学者常见的误区,即直接打印PdfReader对象而非其内容,文章提供了正确的文本提取方法,通过遍历PDF的每一页并调用extract_text()方法,从而获取并显示PDF中的实际文本信息,帮助用户有效利用PyPD…

    2025年12月14日
    000
  • 解决Flask应用启动时SQLAlchemy无法连接MySQL服务器的问题

    本文旨在解决Flask应用在启动或重启后,SQLAlchemy无法立即与MySQL服务器建立连接的问题。通过分析常见的错误信息和提供相应的解决方案,帮助开发者避免因数据库连接问题导致的应用启动异常,确保应用的稳定运行。主要介绍使用Engine.dispose()和uwsgidecorators.po…

    2025年12月14日
    000
  • python默认参数如何使用

    默认参数在函数定义时用=设置,调用时不传参则使用默认值,如greet(name, message=”你好”);适用于配置、可选行为等场景,但需注意默认值只计算一次,避免使用可变对象作为默认值,且带默认值的参数必须位于无默认值参数之后。 Python 默认参数是在定义函数时为参…

    2025年12月14日
    000

发表回复

登录后才能评论
关注微信