#Matlab# 调用 eeglab 包实现 批量 绘制 脑电 拓扑图

使用topoplot函数可以轻松实现在matlab的figure中绘制脑电拓扑图,但对于大量数据,如果每次都手动调用topoplot绘制单张拓扑图片,将会消耗大量时间和精力,这里手写了一个matlab脚本读取存放在excel文件中的批量数据并实现批量绘图

1.数据源的存储结构

数据源为excel文件,excel文件内的数据截图如下:
在这里插入图片描述

数据基本分为三个部分:特征列,数据列和电极点列,其中:

  1. 特征列:代表数据的一个特征,
  2. 电极点列:表示测量数据所在的电极点位置
  3. 数据列:存储脑电强度数据

2.输入参数

算法前几行为输入参数:

参数名称 参数说明
featurecol 所选特征列在excel文件中的列标(数组)
datacol 数据列的列标(数组)
loccol 电极点数据在excel文件中的列标(int)
boundlimitcol 根据此列数据进行分组并计算每组的最大值和最小值,绘图时为同组的数据分配相同的上小限(int)

3.输出结构

算法会根据输入的excel文件名,在源文件目录下创建一个同名文件夹(这里称之为一级目录);在此文件夹下,算法会根据数据列数组的名称,继续创建和数据列数量相同的同名文件夹,(这里称之为二级目录);最后,算法会在多个二级目录下,生成对应的脑电拓扑图,同时算法用“-”将每条数据的特征连接起来作为每个图片的文件名。输出文件的树形结构如下:

|--data.xlsx(源文件)
|--data(一级目录)
	|--------数据列1(二级目录)
		|---------------------文件1.png
		|---------------------文件1.png
		|---------------------文件1.png
		|...
		|---------------------文件n.png
	|--------数据列2(二级目录)
	...
...	

算法生成的图片截图如下:

在这里插入图片描述

4.代码

运行此代码需要用到topoplot、chanlocsseek两个函数以及chanlocsposi.mat等文件,文件下载链接在开头,算法已更新V3.0版本请在文章开头下载!

clear all
clc
% filepath = uigetdir('*.*','请选择文件夹');%fliepath为文件夹路径</span>
featurecol=[1,3,4,5,6];     %特征列
datacol=7;          %数据列
loccol=2;            %电极点列
boundlimitcol=1;        %限制画图上下限的列标

%调用GUI界面选择文件
% [filename1,filepath1]=uigetfile('*.xlsx','打开文件');
% filepath=strcat(filepath1,filename1); 

filepath='源数据.xlsx';
[num,txt,raw]=xlsread(filepath);%读取xlsx文件
% size(raw)

%如果每列存在合并单元格的情况,则对空值进行填充
for i = 1:max([featurecol,loccol,datacol])
    temp=raw{2,i};
    for j = 2:size(raw,1)
        if isnan(raw{j,i})
            raw{j,i}=temp;
        else
            temp=raw{j,i};
        end
    end
end

%统计每个特征列值可能出现的值(读取每列数据并去重) ->colall
for i = 1:length(featurecol) 
    ii=featurecol(i);
    colall{i,1}=unique(raw(2:size(raw,1),ii));  
end

%根据boundlimitcol提供的列标,将所有数据中boundlimitcol列值相同的行划分为一组,
%计算每组的最大值和最小值,在后期绘图时相同组的数据使用相同的上小限。
alldatanum=ones(length(colall{boundlimitcol,1})*length(datacol),1);
for k1 = 2:size(raw,1)
    k1;
    for k2 =1:length(colall{boundlimitcol,1})
        k2;
        if(strcmp(raw{k1,boundlimitcol}(1,:),colall{boundlimitcol,1}(k2,:)))
           for ii =1:length(datacol)
               alldata(alldatanum(k2)+ii-1,k2) = raw{k1,datacol(ii)}(1,1);
               alldatanum(k2)=alldatanum(k2)+1;
           end
        end
    end
end
boundlow=min(alldata);
boundup=max(alldata);

%计算每列每个特征重复的次数
for i =1:length(colall)
    featurelen(i)=1;
    if i<length(colall)
        for ii =i+1:length(colall)
            featurelen(i)=featurelen(i)*length(colall{ii,1});
        end
    end
end

%遍历整个数据矩阵,穷举所有特征列可能出现的组合 ->dicttemp
for i =1:length(colall)
    if i==1
        circulatecount=1;
    else
        circulatecount=1;
        for t=1:i-1
            circulatecount=circulatecount*length(colall{t,1});
        end
    end
    for ii =1:length(colall{i,1})
        for iii=1:circulatecount
            startnum=1+(ii-1)*featurelen(i)+(iii-1)*length(colall{i,1})*featurelen(i);
            endunm=ii*featurelen(i)+(iii-1)*length(colall{i,1})*featurelen(i);
            dicttemp(startnum:endunm,i)=colall{i,1}(ii);
        end
    end
end

%生成每张图片保存所用的文件名,每张图片用到的数据,每张图片设定的上下线信息
loccolnum=length(unique(raw(2:size(raw,1),loccol)));  %电极点数目
for i =1:length(dicttemp) % dicttemp 条目
    i
    name='';
    for ii = 1:size(dicttemp,2)
        ii;
        name=[name,'-',dicttemp{i,ii}];
    end
    dict{i,1}=name;
    datavaluenum=1;
    datavalue=cell(loccolnum,1+length(datacol));
    for k1 = 2:size(raw,1)  % raw数据
        ismatch=1;
        for ii =1:length(featurecol)        % 所选特征数
            if ~(strcmp(raw{k1,featurecol(ii)}(1,:),dicttemp{i,ii}))
                ismatch=0;
                break;
            end    
        end
        if ismatch==1  %若raw的k1列特征和dicttemp当前列的特征相同,则将数据列的数据放入datavalue
            datavalue{datavaluenum,1}=raw{k1,loccol}(1,:);
            for iii =1:length(datacol)
                datavalue{datavaluenum,1+iii}=raw{k1,datacol(iii)}(1,:);
            end
            datavaluenum = datavaluenum+1;
        end
    end
    dict{i,2}=datavalue; %将所有符合dicttemp i列的数据返回给添加到dict矩阵中
    boundlimitcolpro=find(featurecol==boundlimitcol);%边界限制列内部下标
    boundindex=find(strcmp(colall{boundlimitcolpro,1},dicttemp(i,boundlimitcolpro)));%每条数据对应的上下限的索引
    for ii =1:length(datacol)%针对不同的数据列设置不同的上下限
       dict{i,3+(ii-1)*2}=boundlow(1,boundindex);
       dict{i,4+(ii-1)*2}=boundup(1,boundindex);
    end
end

filename=filepath(1:end-5);%删除文件名的后缀名

%创建一级目录
if exist(filename,'dir')==0
    mkdir(filename);
end

%创建二级目录
for i =1:length(datacol)
    if exist([filename,'/',raw{1,i}(1,:)],'dir')==0
        mkdir([filename,'/',raw{1,i}(1,:)]);
    end
end   

%调用topoplot画图
structloc=chanlocsseek(dict{1,2}(:,1));%将电极点位置数组转换成topoplot要求的矩阵结构
for i=1:length(dicttemp)
    for ii = 1:length(datacol)
        h_fig=figure('Visible', 'off');%
        %h_fig=figure('Visible', 'off');%显示每次绘制的图片
        axes = subplot(1,1,1);
        bound=[dict{i,3}(1,1),dict{i,4}(1,1)];
        topoplot(cell2mat(dict{i,2}(:,1+ii)),structloc,'maplimits',bound,'plotrad',0.6,'headrad',0.6,'gridscale',300)
        cbar(0,0,bound);%显示颜色bar
        saveas(h_fig, [filename,'/',raw{1,ii}(1,:),'/',(dict{i,1}),'-',raw{1,ii}(1,:),'.png']);%保存绘制的图片
        close(h_fig); %关闭图片资源
    end
end
发布了59 篇原创文章 · 获赞 2 · 访问量 4638

猜你喜欢

转载自blog.csdn.net/lch551218/article/details/103791448