plt.figure、plt.subplot介绍以及绘制图中图(含代码)

matplotlib图形库:figure,subplot与subplots函数详解
本文介绍了matplotlib库中的figure函数,用于创建画布,并提供了实例展示如何绘制曲线。接着详细解释了subplot函数,用于创建多子图,并展示了2x2布局的子图绘制。还介绍了subplots函数,它能更方便地一次性创建多个子图。最后,文章演示了如何使用add_axes函数在已有图形内部添加新的子图,实现图中图的效果。

1.1 plt.figure()函数语法介绍

figure(num=None, figsize=None, dpi=None, facecolor=None, edgecolor=None, frameon=True)

1、num:图像编号或名称,数字为编号 ,字符串为名称
2、figsize:指定figure的宽和高,单位为英寸;
3、dpi参数指定绘图对象的分辨率,即每英寸多少个像素;
4、facecolor:背景颜色;
5、edgecolor:边框颜色;
6、frameon:是否显示边框。

figure函数就相当于画画所用的画布,在此简单描绘一个曲线来说明

1.2 figure实例

import matplotlib.pyplot as plt
import numpy as np
#np.linspace(start, stop, num)num是起点终点间隔总点数
x = np.linspace(0, 50, 1000)
y = np.cos(x)
fig = plt.figure()
plt.plot(x, y)
# plt.show()的作用就是将画布及其所画内容显示出来
plt.show()

结果显示:
在这里插入图片描述

关于linespace的语法说明:
np.linspace(start, stop, num, endpoint, retstep, dtype)
1、star和stop为起始和终止位置,均为标量
2、num为包括start和stop的间隔点总数,默认为50
3、endpoint为bool值,为False时将会去掉最后一个点计算间隔
4、restep为bool值,为True时会同时返回数据列表和间隔值
5、dtype默认为输入变量的类型,给定类型后将会把生成的数组类型转为目标类型
***通常是用前三个参数就可以了

2.1 subplot函数及其语法说明

subplot(a,b,c)

1、a是subplot的行数;
2、b是subplot的列数;
3、c是subplot中子图的序列号;

2.2 用subplot画多个子图

import numpy as np
# 依次输出函数f(x)=x、f(x)=x**2f(x)=sin(x)f(x)=tan(x)的图像
x = np.linspace(0, 10, 100)
x1 = x
x2 = x ** 2
x3 = np.sin(x)
x4 = np.tan(x)

fig = plt.figure()
# 此处的221指输出模式是两行两列,且输出对应的第一个子图
plt.subplot(221)
plt.plot(x, x1)
plt.subplot(222)
plt.plot(x, x2)
plt.subplot(223)
plt.plot(x, x3)
plt.subplot(224)
plt.plot(x, x4)
plt.show()

运行程序后输出的结果为:
在这里插入图片描述
根据上面程序可以看出,每一个subplot()只可以输出一个子图,要想输出多个子图,就需要使用对应的多个subplot()函数。

如果想用一个函数就直接输出多个子图,可以使用subplots()函数实现。

3.1 subplots函数介绍

在此用subplots()函数来实现同样的2*2类型的子图描绘,实现代码如下:

import numpy as np
import matplotlib.pyplot as plt

x = np.linspace(0, 10, 100)
# 划分2*2子图
fig, axes = plt.subplots(2, 2)
ax1 = axes[0, 0]
ax2 = axes[0, 1]
ax3 = axes[1, 0]
ax4 = axes[1, 1]

# 作图f(x)=x
ax1.plot(x, x)
# 作图f(x)=x**2
ax2.plot(x, x ** 2)
ax2.grid(color='r', linestyle='--', linewidth=1, alpha=0.3)
# 作图f(x)=sin(x)
ax3.plot(x, np.sin(x))
# 作图f(x)=tan(x)
ax4.plot(x, np.tan(x))
plt.show()

显示结果如下:
在这里插入图片描述
由此,我们可以看到subplots()函数同样实现了四个子图的描绘,在功能上和2.2节所用的subplot()函数达到了一样的效果。

4.1 使用add_axes函数绘制图中图

import numpy as np
import matplotlib.pyplot as plt

# 新建figure
fig = plt.figure()
# 定义数据
x = np.linspace(0, 10, 100)
y1=np.exp(x)
y2 = np.sin(x)
# 新建区域a
left, bottom, width, height = 0, 0, 1, 1
# 绘制图像y1
ax1 = fig.add_axes([left, bottom, width, height])
ax1.plot(x, y1, 'b')
ax1.set_title('y1=exp(x)')

# 设置新增区域b,嵌套在a图内
left, bottom, width, height = 0.3, 0.5, 0.4, 0.4
# 绘制图像y2
ax2 = fig.add_axes([left, bottom, width, height])
ax2.plot(x, y2, 'g')
ax2.set_title('y2=sin(x)')
plt.show()

得到的输出结果为:
在这里插入图片描述

# -*- coding: utf-8 -*- import scipy.io import numpy as np import matplotlib.pyplot as plt from scipy import signal import pandas as pd import seaborn as sns import os from scipy import stats # 图表中文配置 plt.rcParams['font.sans-serif'] = ['SimHei'] # 使用黑体显示中文 plt.rcParams['axes.unicode_minus'] = False # 解决负号 '-' 显示为方块的问题 def process_alpha_eeg_data(mat_file_path): """ 处理脑电数据 参数: mat_file_path: .mat文件路径 返回: fig_time_series: 时间序列图表对象 fig_comparison: 条件比较图表对象 fig_alpha_power: Alpha功率随时间变化图表对象 results_df: 包所有分析结果的DataFrame p_value: 统计显著性p值 """ # 1. 加载.mat文件数据 mat_data = scipy.io.loadmat(mat_file_path) # 2. 提取数据矩阵 if 'data' not in mat_data: # 改进的数据矩阵检测 valid_keys = [k for k in mat_data.keys() if not k.startswith('__') and isinstance(mat_data[k], np.ndarray) and mat_data[k].ndim == 2] if not valid_keys: raise ValueError("未找到有效的2D数据矩阵") # 选择最大的数据矩阵 data_matrix = mat_data[max(valid_keys, key=lambda k: mat_data[k].size)] print(f"使用自动检测的数据矩阵: {max(valid_keys, key=lambda k: mat_data[k].size)}") else: data_matrix = mat_data['data'] # 3. 解析数据矩阵结构 timestamps = data_matrix[:, 0] # 时间戳 # 检查数据列数 num_columns = data_matrix.shape[1] if num_columns < 19: raise ValueError(f"数据矩阵只有 {num_columns} 列,需要至少19列 (时间戳 + 16个EEG通道 + 2个触发器)") eeg_data = data_matrix[:, 1:17] # 16个EEG通道 trigger_eyes_closed = data_matrix[:, 17] # 闭眼触发器 trigger_eyes_open = data_matrix[:, 18] # 睁眼触发器 # 固定采样率512Hz sampling_rate = 512.0 # 4. 预处理 - 带通滤波和陷波滤波 def preprocess(data): """应用带通滤波和陷波滤波预处理EEG数据""" # 带通滤波提取Alpha波 (8-12Hz) nyquist = 0.5 * sampling_rate low = 8 / nyquist high = 12 / nyquist b, a = signal.butter(4, [low, high], btype='bandpass') alpha_data = signal.filtfilt(b, a, data) # 陷波滤波去除50/60Hz工频干扰 notch_freq = 50.0 # 根据实际工频干扰调整 notch_width = 2.0 freq = notch_freq / nyquist q = freq / (notch_width / nyquist) b, a = signal.iirnotch(freq, q) return signal.filtfilt(b, a, alpha_data) # 应用预处理到所有通道 eeg_data_filtered = np.apply_along_axis(preprocess, 0, eeg_data) # 5. 计算注意力指数 def calculate_attention(alpha_data): """计算基于Alpha波的注意力指数""" # 计算Alpha波能量 (RMS) alpha_energy = np.sqrt(np.mean(alpha_data**2)) # 计算注意力指数 (与Alpha能量负相关) attention_index = 1 / (1 + alpha_energy) # 归一化到0-100范围 attention_index = np.clip(attention_index * 100, 0, 100) return attention_index # 6. 识别所有会话块 def find_sessions(trigger): """识别所有会话的开始和结束""" # 找到所有上升沿(会话开始) trigger_diff = np.diff(trigger) session_starts = np.where(trigger_diff == 1)[0] + 1 # 找到所有下降沿(会话结束) session_ends = np.where(trigger_diff == -1)[0] + 1 # 确保每个开始都有对应的结束 sessions = [] for start in session_starts: # 找到下一个结束点 ends_after_start = session_ends[session_ends > start] if len(ends_after_start) > 0: end = ends_after_start[0] sessions.append((start, end)) return sessions # 获取所有会话块(闭眼和睁眼) closed_eye_sessions = find_sessions(trigger_eyes_closed) open_eye_sessions = find_sessions(trigger_eyes_open) # 7. 处理每个会话块 - 使用固定10秒时长 session_results = [] session_duration_sec = 10.0 # 每个会话固定10秒 # 为不同条件创建单独的计数器 closed_counter = 1 open_counter = 1 # 处理闭眼会话块 for session_idx, (start_idx, end_idx) in enumerate(closed_eye_sessions): # 提取会话数据 session_eeg = eeg_data_filtered[start_idx:end_idx, :] # 计算整个会话块的平均注意力指数 channel_attention = [] for ch in range(session_eeg.shape[1]): attention = calculate_attention(session_eeg[:, ch]) channel_attention.append(attention) session_avg_attention = np.mean(channel_attention) # 存储会话结果 session_results.append({ 'session_id': f"闭眼{closed_counter}", 'condition': '闭眼', 'start_time': timestamps[start_idx], 'duration': session_duration_sec, 'avg_attention': session_avg_attention, 'channel_attention': channel_attention }) # 更新闭眼会话计数器 closed_counter += 1 # 处理睁眼会话块 for session_idx, (start_idx, end_idx) in enumerate(open_eye_sessions): # 提取会话数据 session_eeg = eeg_data_filtered[start_idx:end_idx, :] # 计算整个会话块的平均注意力指数 channel_attention = [] for ch in range(session_eeg.shape[1]): attention = calculate_attention(session_eeg[:, ch]) channel_attention.append(attention) session_avg_attention = np.mean(channel_attention) # 存储会话结果 session_results.append({ 'session_id': f"睁眼{open_counter}", 'condition': '睁眼', 'start_time': timestamps[start_idx], 'duration': session_duration_sec, 'avg_attention': session_avg_attention, 'channel_attention': channel_attention }) # 更新睁眼会话计数器 open_counter += 1 # 创建结果DataFrame results_df = pd.DataFrame(session_results) # 8. 可视化结果 - 拆分为三张独立的图表 # 图表1: 随时间变化的注意力指数 fig_time_series = plt.figure(figsize=(14, 7)) ax1 = fig_time_series.add_subplot(111) # 为不同条件设置不同颜色 colors = {'闭眼': 'blue', '睁眼': 'orange'} # 为每个会话块创建三个子点 segment_results = [] # 处理所有会话块,为每个会话块创建三个子点 for i, row in results_df.iterrows(): # 计算三个子点的位置和值 for seg_idx in range(3): # 子点值 = 主点值 + 随机偏移(模拟变化) offset = np.random.uniform(-5, 5) # 小范围随机偏移 segment_value = max(0, min(100, row['avg_attention'] + offset)) segment_results.append({ 'session_id': row['session_id'], 'condition': row['condition'], 'session_idx': i, # 会话索引 'segment_idx': seg_idx, 'value': segment_value, 'x_position': i + seg_idx * 0.3 # 在x轴上均匀分布 }) segment_df = pd.DataFrame(segment_results) # 绘制每个会话块的三个子点 for session_id in segment_df['session_id'].unique(): session_data = segment_df[segment_df['session_id'] == session_id] condition = session_data['condition'].iloc[0] color = colors[condition] # 绘制折线连接三个子点(同一会话块内) ax1.plot(session_data['x_position'], session_data['value'], 'o-', markersize=8, color=color, alpha=0.7, linewidth=1.5) # 添加数值标签 - 增大字号到11 for _, seg_row in session_data.iterrows(): ax1.text(seg_row['x_position'], seg_row['value'] + 2, f"{seg_row['value']:.1f}", ha='center', va='bottom', fontsize=11) # 字号从9增大到11 # 连接同一条件下相邻会话块的首尾点 for condition in ['闭眼', '睁眼']: condition_data = segment_df[segment_df['condition'] == condition] # 按会话索引排序 condition_data = condition_data.sort_values('session_idx') # 获取所有会话索引 session_indices = condition_data['session_idx'].unique() session_indices.sort() # 连接相邻会话块 for i in range(len(session_indices) - 1): # 前一个会话的最后一个点(segment_idx=2) prev_session = condition_data[ (condition_data['session_idx'] == session_indices[i]) & (condition_data['segment_idx'] == 2) ] # 后一个会话的第一个点(segment_idx=0) next_session = condition_data[ (condition_data['session_idx'] == session_indices[i+1]) & (condition_data['segment_idx'] == 0) ] # 确保找到两个点 if len(prev_session) == 1 and len(next_session) == 1: prev_point = prev_session.iloc[0] next_point = next_session.iloc[0] # 绘制连接线(使用与子点相同的样式) ax1.plot( [prev_point['x_position'], next_point['x_position']], [prev_point['value'], next_point['value']], '-', color=colors[condition], alpha=0.7, linewidth=1.5 ) # 设置x轴刻度和标签 ax1.set_xticks(results_df.index) ax1.set_xticklabels(results_df['session_id'], rotation=45, ha='right', fontsize=10) # 调整x轴标签字号 # 设置y轴范围到10-60 ax1.set_ylim(10, 60) ax1.set_title('不同条件下注意力指数随时间变化', fontsize=16) ax1.set_xlabel('会话块ID', fontsize=14) ax1.set_ylabel('平均注意力指数 (%)', fontsize=14) # 添加图例 from matplotlib.lines import Line2D legend_elements = [ Line2D([0], [0], marker='o', color='w', markerfacecolor='blue', markersize=10, label='闭眼'), Line2D([0], [0], marker='o', color='w', markerfacecolor='orange', markersize=10, label='睁眼') ] ax1.legend(handles=legend_elements, loc='best', fontsize=12) ax1.grid(True, linestyle='--', alpha=0.3) # 添加分隔线区分不同会话块 for i in range(1, len(results_df)): ax1.axvline(i - 0.5, color='gray', linestyle='--', alpha=0.5) plt.tight_layout() # 图表2: 闭眼与睁眼条件下的注意力比较 fig_comparison = plt.figure(figsize=(10, 6)) ax2 = fig_comparison.add_subplot(111) # 箱线图展示条件间差异 sns.boxplot(x='condition', y='avg_attention', data=results_df, ax=ax2, palette='Set2', hue='condition', legend=False) # 添加散点图显示个体数据点 sns.stripplot(x='condition', y='avg_attention', data=results_df, ax=ax2, color='black', alpha=0.7, size=7, jitter=True) ax2.set_title('闭眼与睁眼条件下注意力比较', fontsize=16) ax2.set_xlabel('条件', fontsize=14) ax2.set_ylabel('平均注意力指数 (%)', fontsize=14) # 添加统计显著性标记(使用独立样本t检验) closed_data = results_df[results_df['condition'] == '闭眼']['avg_attention'] open_data = results_df[results_df['condition'] == '睁眼']['avg_attention'] t_stat, p_value = stats.ttest_ind(closed_data, open_data) # 添加显著性标记 y_max = max(results_df['avg_attention']) + 5 ax2.plot([0, 0, 1, 1], [y_max, y_max+2, y_max+2, y_max], lw=1.5, c='black') ax2.text(0.5, y_max+3, f"p = {p_value:.4f}", ha='center', va='bottom', fontsize=12) plt.tight_layout() # 图表3: Alpha功率随时间变化(使用固定10秒时长) fig_alpha_power = plt.figure(figsize=(15, 8)) ax3 = fig_alpha_power.add_subplot(111) # 计算每个时间点的Alpha功率(所有通道的平均RMS) # 使用滑动窗口平均平滑数据(窗口大小=1秒) window_size = int(sampling_rate) # 512个采样点(1秒) alpha_power = np.sqrt(np.mean(eeg_data_filtered**2, axis=1)) # 所有通道的RMS smoothed_alpha_power = np.convolve(alpha_power, np.ones(window_size)/window_size, mode='same') # 绘制整个实验期间的Alpha功率 ax3.plot(timestamps, smoothed_alpha_power, 'b-', linewidth=1.5, alpha=0.8, label='Alpha功率') # 增强背景标注 - 闭眼会话(使用固定10秒时长) for session_idx, (start_idx, end_idx) in enumerate(closed_eye_sessions): start_time = timestamps[start_idx] end_time = start_time + session_duration_sec # 固定10秒时长 # 增强背景色 ax3.axvspan(start_time, end_time, color='royalblue', alpha=0.3, label='闭眼' if session_idx == 0 else "") # 添加文字标注(居中) mid_time = start_time + session_duration_sec/2 y_min, y_max = ax3.get_ylim() label_y = y_min + 0.05 * (y_max - y_min) ax3.text(mid_time, label_y, '闭眼', ha='center', va='bottom', fontsize=12, fontweight='bold', bbox=dict(facecolor='white', alpha=0.7, edgecolor='royalblue', boxstyle='round,pad=0.2')) # 增强背景标注 - 睁眼会话(使用固定10秒时长) for session_idx, (start_idx, end_idx) in enumerate(open_eye_sessions): start_time = timestamps[start_idx] end_time = start_time + session_duration_sec # 固定10秒时长 # 增强背景色 ax3.axvspan(start_time, end_time, color='darkorange', alpha=0.3, label='睁眼' if session_idx == 0 else "") # 添加文字标注(居中) mid_time = start_time + session_duration_sec/2 y_min, y_max = ax3.get_ylim() label_y = y_min + 0.05 * (y_max - y_min) ax3.text(mid_time, label_y, '睁眼', ha='center', va='bottom', fontsize=12, fontweight='bold', bbox=dict(facecolor='white', alpha=0.7, edgecolor='darkorange', boxstyle='round,pad=0.2')) # 添加标记和标签 ax3.set_title('Alpha功率随时间变化(闭眼与睁眼期间)', fontsize=18, fontweight='bold') ax3.set_xlabel('时间 ()', fontsize=14) ax3.set_ylabel('Alpha功率 (RMS)', fontsize=14) ax3.grid(True, linestyle='--', alpha=0.3) # 添加图例(只显示曲线图例) ax3.legend(loc='upper right', fontsize=12) # 添加垂直参考线标记每个会话的开始(使用更明显的颜色) all_sessions = closed_eye_sessions + open_eye_sessions for start_idx, _ in all_sessions: ax3.axvline(x=timestamps[start_idx], color='darkred', linestyle='--', alpha=0.7, linewidth=1.2) # 添加时间轴刻度增强 ax3.xaxis.set_major_locator(plt.MaxNLocator(20)) # 增加刻度数量 # 添加背景色图例说明 from matplotlib.patches import Patch legend_elements = [ Patch(facecolor='royalblue', alpha=0.3, edgecolor='royalblue', label='闭眼期间'), Patch(facecolor='darkorange', alpha=0.3, edgecolor='darkorange', label='睁眼期间'), plt.Line2D([0], [0], color='darkred', linestyle='--', label='会话开始') ] ax3.legend(handles=legend_elements, loc='upper left', fontsize=10) # 添加会话时长信息 ax3.text(0.02,0.95, f"每个会话时长: {session_duration_sec}秒", transform=ax3.transAxes, fontsize=12, bbox=dict(facecolor='white', alpha=0.8)) plt.tight_layout() # 9. 保存结果 base_name = os.path.splitext(os.path.basename(mat_file_path))[0] # 保存图像 fig_time_series.savefig(f"{base_name}_time_series.png", dpi=300, bbox_inches='tight') fig_comparison.savefig(f"{base_name}_comparison.png", dpi=300, bbox_inches='tight') fig_alpha_power.savefig(f"{base_name}_alpha_power.png", dpi=300, bbox_inches='tight') # 保存结果到CSV results_df.to_csv(f"{base_name}_results.csv", index=False, encoding='utf-8-sig') return fig_time_series, fig_comparison, fig_alpha_power, results_df, p_value # 主程序入口 if __name__ == "__main__": # 输入文件路径 mat_file = "F:/Grade2/attention/2348892/subject_02.mat" try: # 处理数据并生成可视化 fig1, fig2, fig3, results_df, p_value = process_alpha_eeg_data(mat_file) # 显示图像 plt.show() # 打印会话结果和统计显著性 - 英文输出 print("EEG Analysis Results:") print(results_df[['session_id', 'condition', 'duration', 'avg_attention']]) print(f"\nStatistical Significance: p = {p_value:.4f}") # 根据p值输出不同结论 - 英文输出 if p_value < 0.05: print("There is a significant difference between eyes-closed and eyes-open conditions (p < 0.05)") else: print("No significant difference between eyes-closed and eyes-open conditions") except Exception as e: # 错误处理 - 保持英文错误信息 print(f"Error during processing: {str(e)}") import traceback traceback.print_exc() 将该代码修改为,提供一个文件夹的路径后,可以读取该文件内全部的mat文件,并且图1、图2和图3的输出为所有mat文件的结果的平均值
最新发布
06-28
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Dream_Bri

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值