You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用Matplotlib将超长EEG折线图保存为高分辨率单张图片

问题描述

我需要保存一份时长超100小时、每5分钟一个数据点的EEG折线图,要求生成约10×10000px分辨率的单张图,放大后仍能清晰可读。但遇到以下问题:

  • 设置figsize=(10000,10)时直接报错,提示图片尺寸过大
  • 用合理范围内的figsize生成的图片会被压缩,根本没法用来判读EEG
  • 用MNE库只能在交互窗口正常显示,保存后的全EEG图还是压缩状态

我想要的效果是能清晰放大查看的长图,局部放大后能看清每一个数据点的细节。

更新尝试

我试过提高dpi并保存为SVG格式,代码如下:

def visualize_eeg(mat_path):
    mat = scipy.io.loadmat(mat_path)
    fs = mat['fs'][0][0]
    ch_labels = [x[0].upper() for x in mat['ch_labels'][0]]
    eeg_data = list(list(x) for x in mat['eeg_data'])
    dict_data = dict(zip(ch_labels,eeg_data))
    df = pd.DataFrame(dict_data)
    df = df.T.sort_index().T
    fig = plt.figure(figsize=(50, 10)) 
    gs = gridspec.GridSpec(len(df.columns), 1,wspace=0.0, hspace=0.0)
    hours = get_hours(df,fs)
    # plot each column (channel) in a subplot
    for i in tqdm(range(len(df.columns))):
        ch = df.columns[i]
        ax = plt.subplot(gs[i])
        ax.spines['top'].set_visible(False)
        ax.spines['right'].set_visible(False)
        ax.set_yticks([0])
        ax.set_yticklabels([ch])
        if i == len(df.columns)-1:
            ax.tick_params(left = True, right = False , labelleft = True ,
                labelbottom = True, bottom = True)
            ax.set_xticks(hours.index,hours)
        else:
            ax.spines['bottom'].set_visible(False)
            ax.tick_params(left = True, right = False , labelleft = True ,
                    labelbottom = False, bottom = False)
        ax.plot(df[ch].apply(lambda x : x*1000), label=ch)
        
    fig.set_dpi(1000)
    fig.savefig('test.svg')

但生成的图片缩放效果还是很差,局部放大后细节模糊不清。

解决方案

1. 关闭SVG自动路径简化

SVG本身是矢量格式,但Matplotlib为了减小文件体积,会自动简化大量数据点的路径,导致放大后失真。你可以在保存时强制关闭这个优化:

# 绘图代码不变,修改savefig部分
fig.savefig('eeg_full.svg', bbox_inches='tight', pad_inches=0, dpi=300, rasterized=False)

同时可以指定SVG后端,避免不必要的优化:

import matplotlib
matplotlib.use('SVG')  # 放在绘图代码最开头

2. 用底层SVG后端直接输出

如果默认保存还是有压缩,直接调用Matplotlib的SVG后端底层接口,强制保留所有数据点:

from matplotlib.backends.backend_svg import FigureCanvasSVG

# 完成绘图后替换savefig
canvas = FigureCanvasSVG(fig)
canvas.print_svg('eeg_full.svg', dpi=300)

3. 分块生成后拼接(适合超大规模数据)

100小时的EEG数据点数量极大,直接生成单张图容易触发尺寸限制或自动压缩。可以按时间段分块生成子图,再用PIL拼接成完整长图:

from PIL import Image
import matplotlib.pyplot as plt
import gridspec
from tqdm import tqdm
import scipy.io
import pandas as pd

def visualize_eeg_chunk(chunk, ch_labels, chunk_idx, fs):
    df = pd.DataFrame(chunk)
    df = df.T.sort_index().T
    fig = plt.figure(figsize=(50, 10), dpi=100)
    gs = gridspec.GridSpec(len(df.columns), 1, wspace=0.0, hspace=0.0)
    hours = get_hours(df, fs)
    for i in tqdm(range(len(df.columns))):
        ch = df.columns[i]
        ax = plt.subplot(gs[i])
        ax.spines['top'].set_visible(False)
        ax.spines['right'].set_visible(False)
        ax.set_yticks([0])
        ax.set_yticklabels([ch])
        if i == len(df.columns)-1:
            ax.tick_params(left=True, right=False, labelleft=True,
                           labelbottom=True, bottom=True)
            ax.set_xticks(hours.index, hours)
        else:
            ax.spines['bottom'].set_visible(False)
            ax.tick_params(left=True, right=False, labelleft=True,
                           labelbottom=False, bottom=False)
        ax.plot(df[ch].apply(lambda x: x*1000), label=ch)
    fig.savefig(f'chunk_{chunk_idx}.png', bbox_inches='tight', pad_inches=0)
    plt.close(fig)
    return Image.open(f'chunk_{chunk_idx}.png')

# 加载原始数据
mat_path = "your_data.mat"
mat = scipy.io.loadmat(mat_path)
fs = mat['fs'][0][0]
ch_labels = [x[0].upper() for x in mat['ch_labels'][0]]
eeg_data = list(list(x) for x in mat['eeg_data'])
dict_data = dict(zip(ch_labels, eeg_data))
df = pd.DataFrame(dict_data)
df = df.T.sort_index().T

# 按每10小时分块(可根据需求调整)
chunk_duration_hours = 10
chunk_size = chunk_duration_hours * (60 // 5)  # 每5分钟1个点,1小时12个点
chunks = [df[i:i+chunk_size] for i in range(0, len(df), chunk_size)]

# 生成所有子图
subfigs = []
for idx, chunk in enumerate(chunks):
    subfig = visualize_eeg_chunk(chunk, ch_labels, idx, fs)
    subfigs.append(subfig)

# 拼接子图
width = subfigs[0].width
total_height = sum(img.height for img in subfigs)
final_img = Image.new('RGB', (width, total_height))

current_y = 0
for img in subfigs:
    final_img.paste(img, (0, current_y))
    current_y += img.height

final_img.save('eeg_full.png')

4. 禁用MNE的自动降采样

MNE在保存图片时默认会对数据降采样,你可以在绘图时指定完整时长,并关闭降采样:

import mne

# 加载你的EEG数据(根据实际格式调整)
raw = mne.io.read_raw_mat(mat_path, preload=True)
# 设置绘图时长为总时长(秒),禁用降采样
fig = raw.plot(duration=100*3600, scalings='auto', show=False, use_opengl=False)
fig.savefig('mne_eeg.svg', dpi=300, bbox_inches='tight', rasterized=False)

内容的提问来源于stack exchange,提问作者Fabio Magarelli

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.22 13:45:32