分享

Matlab数据可视化(4):一维数据绘图 II

 lynchlynch12 2013-11-15

五. 结点连接图(node link plot)

(源代码:NodeLinks.m)

有时,我们需要绘制出不同结点之间的连通关系,即结点连接图。以下以绘制美国128座城市之间的连通关系为例,介绍两种结点连接图的画法。

1) 定义每座城市与距它最近的城市连通,与其余视为不连通,然后根据连通性,利用gplot命令,直观的绘出结点连接图。(图9)

  1. %% #1  
  2. %% 定义数据  
  3. [XYCoord] = xlsread('inter_city_distances.xlsx','Sheet3');  
  4. [intercitydist citynames] = xlsread('inter_city_distances.xlsx','Distances');  
  5.   
  6. % 避免将自身判定为最近的城市  
  7. howManyCities = 128;  
  8. for i =1:howManyCities;intercitydist(i,i)=Inf;end  
  9.   
  10. %% 定义临接矩阵  
  11. % n阶方阵,1表示相连,0表示不相连; 这是我们规定城市只与它最近的城市相连  
  12. adjacency = zeros(howManyCities,howManyCities);  
  13. for i = 1:howManyCities  
  14.     alls = find(intercitydist(i,:)==min(intercitydist(i,:)));      
  15.     for j = 1:length(alls)  
  16.         adjacency(i,alls(j)) = 1;  
  17.         adjacency(alls(j),i) = 1;  
  18.     end      
  19.     clear alls  
  20. end  
  21. figure('units','normalized','position',[ 0.2813    0.2676    0.3536    0.3889]);  
  22. plot(XYCoord(1:howManyCities,1),XYCoord(1:howManyCities,2),'ro');hold on;  
  23. title('距离最近的城市彼此相连');  
  24. gplot(adjacency,XYCoord);  
  25. xlabel('南北');  
  26. ylabel('东西');  
  27. set(gcf,'Color',[1 1 1],'paperpositionmode','auto');  



图 9

2) 定义距离小于100英里的城市为相连,以更紧致的方式绘出连接情况。(图10

  1. %% 定义临接关系(距离小于100英里的城市之间认为是相邻的)  
  2. % 重新排列数据,以使距离短的城市大致靠近  
  3. for i = 1:howManyCities;  intercitydist(i,i) = 0; end  
  4. [balh I] = sort(intercitydist(1,:));  
  5. citynames = citynames(I);  
  6. XYCoord = XYCoord(I,:);  
  7. %% 重新计算距离矩阵  
  8. for i = 1:howManyCities;    
  9.     for j = 1:howManyCities  
  10.         if i==j  
  11.             intercitydist(i,i) = Inf;   
  12.         else  
  13.             intercitydist(i,j) = sqrt((XYCoord(i,1)-XYCoord(j,1))^2 + (XYCoord(i,2)-XYCoord(j,2))^2);   
  14.         end  
  15.     end  
  16. end  
  17. %% 计算临接矩阵  
  18. adjacency = zeros(howManyCities,howManyCities);  
  19. for i = 1:howManyCities  
  20.     alls = find(intercitydist(i,:)<100);      
  21.     for j = 1:length(alls)  
  22.         adjacency(i,alls(j)) = 1;  
  23.         adjacency(alls(j),i) = 1;  
  24.     end      
  25.     clear alls  
  26. end  
  27.   
  28. %% 图像大小和位置  
  29. figure('units','normalized','position',[0.0844    0.2259    0.8839    0.4324]);  
  30. axes('Position',[0.0371    0.2893    0.9501    0.6296]);   
  31. xlim([1 howManyCities]);  
  32. ylim([0 100]);  
  33. hold on;  
  34. %% 在X轴上标注城市名称  
  35. set(gca,'xtick',1:howManyCities,'xticklabel',citynames,...  
  36.                                    'ticklength',[0.001 0]);  
  37. box on;   
  38. rotateXLabels(gca,90);  
  39. %% 为不同弧线分配不同的颜色(距离越近,颜色越深)  
  40. m = colormap(pink(howManyCities+1));  
  41. cmin = min(min(intercitydist));  
  42. cmax = 150;  
  43. %% 绘制弧线  
  44. for i = 1:howManyCities  
  45.     for j = 1:howManyCities  
  46.         if adjacency(i,j)==1  
  47.             x=[i (i+j)/2 j];   
  48.             y=[0 intercitydist(i,j) 0];  
  49.             pol_camp=polyval(polyfit(x,y,2),linspace(i,j,25));  
  50.             plot(linspace(i,j,25),pol_camp,'Color',m(fix((intercitydist(i,j)-cmin)/(cmax-cmin)*howManyCities)+1,:),'linewidth',100/intercitydist(i,j));          
  51.         end  
  52.     end  
  53. end  
  54. %% 标注  
  55. title('公路距离小于100英里的城市','fontsize',14);  
  56. ylabel('城市间距离');  
  57. set(gca,'Position',[0.0371    0.2893    0.9501    0.6296]);  
  58. %% 绘制水平网格以增加可读性  
  59. line(repmat(get(gca,'xlim'),9,1)',[linspace(10,90,9); linspace(10,90,9)],'Color',[.8 .8 .8]);  
  60. set(gcf,'Color',[1 1 1],'paperpositionmode','auto');  


图 10

六. 日历热图(Heat Map)

(源代码:CalendarHeatMap.m)

数据大小可以用颜色的深浅直观的表示,这可以通过imagesc或pcolor命令获得(二者参考点的位置不同)。以下即是用Imagesc命令,绘制Google公司10到11年的股价数据。(图11)

  1. %% Add path to utilities  
  2. addpath('.\utilities');  
  3.   
  4.   
  5. %% 数据预处理  
  6. [GOOG dateGOOG] = xlsread('GOOG_090784_012412.csv');  
  7. dateGOOG = datenum({dateGOOG{2:end,1}});  
  8. dateGOOG = dateGOOG(end:-1:1);  
  9. GOOG = GOOG(end:-1:1,:);  
  10. % 选择最后两年的数据  
  11. newData = [];  
  12. newDateData=[];  
  13. for i =1:numel(dateGOOG)-1  
  14.     if abs(dateGOOG(i+1)-dateGOOG(i))==1  
  15.         newData     =   [newData;   GOOG(i)];  
  16.         newDateData =   [newDateData dateGOOG(i)];  
  17.     else  
  18.         delta = abs(dateGOOG(i+1)-dateGOOG(i));  
  19.         for j = 1:delta  
  20.             newData     =   [newData;   NaN];  
  21.             newDateData =   [newDateData dateGOOG(i)+j-1];  
  22.         end  
  23.     end  
  24. end  
  25. newData     =   [newData;   GOOG(end)];  
  26. newDateData =   [newDateData dateGOOG(end)];  
  27. idx = find(newDateData<=datenum('12/31/2011')&newDateData>=datenum('1/1/2010'));  
  28. newData=newData(idx);  
  29. newDateData = newDateData(idx);  
  30.   
  31.   
  32. %% 日历布局  
  33. % 1行6个月,两年共4行  
  34. figure('units','normalized','Position',[ 0.3380    0.0889    0.6406    0.8157]);  
  35. colormap('summer');  
  36. xs = [0.03 .03+.005*1+1*.1525 0.03+.005*2+2*.1525 0.03+.005*3+3*.1525 0.03...  
  37.     +.005*4+4*.1525 0.03+.005*5+5*.1525];  
  38. ys = [0.14 .14+0.04*1+1*.165   .14+0.04*2+2*.165   .14+0.04*3+3*.165];  
  39.   
  40.   
  41. % 估计每月的天数  
  42. isthereALeapyear = find(~(mod(unique(str2num(datestr(newDateData,'yyyy'))),4)| ...  
  43.     mod(unique(str2num(datestr(newDateData,'yyyy'))),400)));  
  44. if isempty(isthereALeapyear)  
  45.     D = [31 28 31 30 31 30; 31 31 30 31 30 31;31 28 31 30 31 30; 31 31 30 31 30 31];  
  46. else  
  47.     if isthereALeapyear==1  
  48.         D = [31 29 31 30 31 30; 31 31 30 31 30 31;31 28 31 30 31 30; 31 31 30 31 30 31];  
  49.     else  
  50.         D = [31 28 31 30 31 30; 31 31 30 31 30 31;31 29 31 30 31 30; 31 31 30 31 30 31];  
  51.     end  
  52. end  
  53.    
  54. %% 开始绘图  
  55. Dcnt=0;  
  56. for i = 1:4  
  57.     for j = 1:6  
  58.         % 绘制月视图  
  59.         axes('Position',[xs(j) ys(i) .1525    0.165]);           
  60.         % 计算所在的月份  
  61.         idx = find(newDateData>=datenum([datestr(newDateData(1)+Dcnt,'mm') ...  
  62.             '/01/'  datestr(newDateData(1)+Dcnt,'yyyy')]) & ...  
  63.              newDateData<=datenum([datestr(newDateData(1)+Dcnt,'mm') '/31/' ...  
  64.              datestr(newDateData(1)+Dcnt,'yyyy')]));  
  65.         % 得到当月信息  
  66.         A = calendar(newDateData(1)+Dcnt);  
  67.         % 填入股价数据  
  68.         data = NaN(size(A));  
  69.         for k = 1:max(max(A))  
  70.             [xx yy] = find(A==k);  
  71.             data(xx,yy) = newData(idx(k));  
  72.         end  
  73.         % 上色  
  74.         imagesc(data); alpha(.4);hold on;set(gca,'fontweight','bold');  
  75.         xlim([.5 7.5]); ylim([0 6.5]);  
  76.         for m = 1:6  
  77.             for n= 1:7  
  78.                 if A(m,n)~=0  
  79.                     text(n,m,num2str(A(m,n)));  
  80.                 end  
  81.             end  
  82.         end       
  83.         % 添加日历头  
  84.         text(.75,.25,'S','fontweight','bold'); text(1.75,.25,'M','fontweight','bold');  
  85.         text(2.75,.25,'T','fontweight','bold');  
  86.         text(3.75,.25,'W','fontweight','bold');text(4.75,.25,'R','fontweight','bold');  
  87.         text(5.75,.25,'F','fontweight','bold');text(6.75,.25,'S','fontweight','bold');  
  88.           
  89.         title([datestr(newDateData(1)+Dcnt,'mmm')  datestr(newDateData(1)+Dcnt,'yy')]);  
  90.         set(gca,'xticklabel',[],'yticklabel',[],'ticklength',[0 0]);  
  91.         line([-.5:7.5; -.5:7.5], [zeros(1,9); 6.5*ones(1,9)],'Color',[.8 .8 .8]);  
  92.         line([zeros(1,9); 7.5*ones(1,9)],[-.5:7.5; -.5:7.5], 'Color',[.8 .8 .8]);  
  93.         box on;  
  94.         Dcnt=Dcnt+D(i,j);  
  95.     end  
  96. end  
  97.   
  98.   
  99. %%增加图标和标题  
  100. colorbar('Location','SouthOutside','Position',[ 0.1227    0.0613    0.7750    0.0263]);  
  101. alpha(.4);  
  102. annotation('textbox',[0.30 0.9354 0.8366 0.0571],...  
  103.     'String','2010年1月到2011年12月Google股价日记录',...  
  104.     'LineStyle','none','Fontsize',14);  
  105.   
  106.   
  107.  set(gcf,'Color',[1 1 1],'paperpositionmode','auto');  


图 11

七. 数据分布的可视化分析

(源代码:DistributionAnalysis.m)

1) 首先利用散点图和直方图对数据进行初步观察。(图 12)

  1. %% 加载数据  
  2. load distriAnalysisData;  
  3.   
  4. %% 观测数据分布  
  5. % 绘制直方图  
  6. figure('units','normalized','position',[0.2099    0.6269    0.4354    0.2778]);  
  7. subplot(1,2,1);plot(sort(B),'.');xlabel('序号');ylabel('观察值');title('一维散点图');  
  8. subplot(1,2,2);hist(B);xlabel('间隔');ylabel('观测频率');title('直方图');  
  9. set(gcf,'Color',[1 1 1],'paperpositionmode','auto');  

图 12
2) 进一步优化直方图,对数据进行更细致考查。(图13)
  1. %% 优化直方图   
  2. figure('units','normalized','position',[0.2099    0.6269    0.4354    0.2778]);  
  3. [N c] = hist(B,round(sqrt(length(B))));  
  4. bar(c,N);  
  5. title('间隔大小 = sqrt(n)');  
  6. xlabel('间隔');ylabel('观测频率');title('优化直方图间隔以发现隐藏的结构');  
  7. set(gcf,'Color',[1 1 1],'paperpositionmode','auto');  
图 13
3) 利用样条插值,为直方图添加包络线。(图14)
  1. %% 利用样条插值绘制直方图的包络  
  2. [N c] = hist(B,200);  
  3. % 用样条计算包络  
  4. env = interp1(c,N,c,'spline');   
  5. % 绘制归一化的包络  
  6. figure('units','normalized','position',[ 0.2099    0.6269    0.4354    0.2778]);  
  7. bar(c,N./max(N));hold;  
  8. plot(c,env./max(env),'r','Linewidth',3);  
  9. xlabel('间隔'); ylabel({'归一化后的包络','间隔数为200'});  
  10. title('直方图包络是数据经验分布建模的有力工具');  
  11. set(gcf,'Color',[1 1 1],'paperpositionmode','auto');  
图 14
4) 绘制QQ图,观察数据分布的正态性。(图15)
  1. %% MATLAB qqplot 命令  
  2. figure;qqplot(B);box on  
  3. title({get(get(gca,'title'),'String'),'数据点越接近曲线,数据分布的正态性越好'});  
  4. set(gcf,'Color',[1 1 1],'paperpositionmode','auto');  
图 15
5) 残差分析,评估模型对数据真实分布的近似程度。(图16)
  1. %% 分析残差  
  2. figure;  
  3. sigma_ampl = [79.267229 8.121365 5 6.254915 5.062882 11.117357 577.45966 ...  
  4.     531.38438 962.45674 1800 800 357.92132];  
  5. mu=[29 38 51 70 103 133];  
  6. % 高斯混合模型  
  7. f_sum=0;x=1:200;  
  8. for i=1:6  
  9.     f_sum=f_sum+sigma_ampl(i+6)./(sigma_ampl(i)).*exp(-(x-mu(i)).^2./(2*sigma_ampl(i).^2));  
  10. end  
  11. subplot(2,1,1);  
  12. clear h;  
  13. h(1)=plot(c,env,'Linewidth',1.5);hold on;  
  14. h(2)=plot(c,f_sum,'r','Linewidth',1.5); axis tight  
  15. legendflex(h,{'直方图轮廓','高斯混合模型'},'ref',gcf,'anchor',{'ne','ne'},'xscale',.5,'buffer',[-50 -50]);  
  16. title({'对数据分布建模后,通过残差分析评估','模型对数据描述的符合程度'});  
  17. subplot(2,1,2);  
  18. plot(c,env-f_sum,'.');axis tight;  
  19. title(['残差 = 观测值 - 拟合值, 均方误差 = ' num2str(sqrt(sum(abs(env-f_sum).^2)))]);  
  20. set(gcf,'Color',[1 1 1],'paperpositionmode','auto');  
图 16


八. 时间序列分析

(源代码:TimeSeriesAnalysis.m)
1) 绘制散点图。(图17)
  1. load timeseriesAnalysis;  
  2.   
  3. %% 数据散点图  
  4. figure;  
  5. subplot(2,1,1);plot(x,ydata1);title('样本1实时心率(采样间隔0.5秒)');xlabel('时间(秒)');ylabel('心率(心跳次数/分钟)');  
  6. subplot(2,1,2);plot(x,ydata2);title('样本2实时心率(采样间隔0.5秒)');xlabel('时间(秒)');ylabel('心率(心跳次数/分钟)');  
  7. set(gcf,'color',[1 1 1],'paperpositionmode','auto');  

图 17
2) 过滤信号中的线性成分(detrend)。(图18)
  1. %% 过滤数据的线性趋势(detrend)  
  2. figure;  
  3. y_detrended1 = detrend(ydata1);   
  4. y_detrended2 = detrend(ydata2);   
  5. subplot(2,1,1);plot(x, ydata1,'-',x, ydata1-y_detrended1,'r');title('去除线性成分后的信号1');  
  6. legend({'信号','线性成分'});  
  7. xlabel('时间 (秒)');ylabel('心率(心跳次数/分钟)');  
  8. subplot(2,1,2);plot(x, ydata2,'-',x, ydata2-y_detrended2,'r');title('去除线性成分后的信号2');  
  9. legend({'信号','线性成分'});  
  10. xlabel('时间(秒)');ylabel('心率(心跳次数/分钟)');  
  11. set(gcf,'color',[1 1 1],'paperpositionmode','auto');  



图 18
3) 计算自相关函数,绘制自相关图(correlogram)。(图19)
  1. %% 自相关函数  
  2. figure;  
  3. y_autoCorr1 = acf(subplot(2,1,1),ydata1,100);   
  4. set(get(gca,'title'),'String','心率数据自相关函数(样本1)');  
  5. set(get(gca,'xlabel'),'String','间期(秒)');  
  6. tt = get(gca,'xtick');  
  7. for i = 1:length(tt); ttc{i} = sprintf('%.2f ',0.5*tt(i)); end  
  8. set(gca,'xticklabel',ttc);  
  9. y_autoCorr2 = acf(subplot(2,1,2),ydata2, 100);  
  10. set(gca,'xticklabel',ttc);  
  11. set(get(gca,'title'),'String','心率数据自相关函数(样本2)');  
  12. set(get(gca,'xlabel'),'String','间期(秒)');  
  13. set(gcf,'color',[1 1 1],'paperpositionmode','auto');  
图 19

4) 利用傅里叶变换寻找周期成分。(图20)
  1. %% 利用傅里叶变换寻找周期成分  
  2. figure;  
  3.   
  4. nfft = 2^(nextpow2(length(x)));  
  5. % 快速傅里叶变换(信号长度小于nfft时补零)   
  6. ySpectrum1 = fft(y_detrended1,nfft);  
  7. ySpectrum2 = fft(y_detrended2,nfft);  
  8.   
  9. NumUniquePts = ceil((nfft+1)/2);  
  10. % FFT is symmetric, throw away second half and use the magnitude of the coeeicients only  
  11. powerSpectrum1 = abs(ySpectrum1(1:NumUniquePts));  
  12. powerSpectrum2 = abs(ySpectrum2(1:NumUniquePts));  
  13. % Scale the fft so that it is not a function of the length of x  
  14. powerSpectrum1 = powerSpectrum1./max(powerSpectrum1);  
  15. powerSpectrum2 = powerSpectrum2./max(powerSpectrum2);  
  16. powerSpectrum1 = powerSpectrum1.^2;  
  17. powerSpectrum2 = powerSpectrum2.^2;  
  18. % Since we dropped half the FFT, we multiply the coeffixients we have by 2 to keep the same energy.  
  19. % The DC component and Nyquist component, if it exists, are unique and should not be multiplied by 2.   
  20. if rem(nfft, 2) % odd nfft excludes Nyquist point   
  21.      powerSpectrum1(2:end) = powerSpectrum1(2:end)*2;  
  22.      powerSpectrum2(2:end) = powerSpectrum2(2:end)*2;  
  23. else  
  24.      powerSpectrum1(2:end -1) = powerSpectrum1(2:end -1)*2;  
  25.      powerSpectrum2(2:end -1) = powerSpectrum2(2:end -1)*2;  
  26. end  
  27. % This is an evenly spaced frequency vector with NumUniquePts points.  
  28. % Sampling frequency  
  29. Fs = 1/(x(2)-x(1));   
  30. f = (0:NumUniquePts-1)*Fs/nfft;  
  31. plot(f,powerSpectrum1,'-',f,powerSpectrum2,'r');  
  32. title('心率信号能量谱');  
  33. xlabel('频率(赫兹)'); ylabel('能量');  
  34. xlim([0 .25]);  
  35. annotation_pinned('textarrow',[.15,.085],[.25,.03],'String',{'0.1Hz处的尖峰很可能','是该样本呼吸的频率'});  
  36. annotation_pinned('textarrow',[.1,.02],[.75,.87],'String',{'0.02 Hz处的尖峰很可能','是该样本呼吸的频率'});  
  37. set(gcf,'color',[1 1 1],'paperpositionmode','auto');  



图 20

5) 对信号平滑处理,去掉频谱上系数较小的成分。(图21)
  1. %% 去除能量较小的频率成分  
  2. figure;  
  3. % 不使用0垫位  
  4. ySpectrum1 = fft(ydata1);  
  5. ySpectrum2 = fft(ydata2);  
  6. % 去掉很小的系数  
  7. freqInd1=find(abs(ySpectrum1)<400);   
  8. freqInd2=find(abs(ySpectrum2)<400);   
  9. ySpectrum1(freqInd1)=0;  
  10. ySpectrum2(freqInd2)=0;  
  11. % 重建信号  
  12. y_cyclic1=ifft(ySpectrum1);  
  13. y_cyclic2=ifft(ySpectrum2);  
  14. subplot(2,1,1);  
  15. h(1)= plot(x,ydata1,'b');hold on;h(2)=plot(x,y_cyclic1,'r','linewidth',1.5);  
  16. title('心率信号1');axis tight;  
  17. legendflex(h,...                %handle to plot lines  
  18.     {'原始信号','平滑后信号'},... %corresponding legend entries  
  19.     'ref', gcf, ...             %which figure  
  20.     'anchor', {'e','e'}, ...  %location of legend box  
  21.     'buffer',[-10 0], ...         % an offset wrt the location  
  22.     'fontsize',8,...            %font size  
  23.     'xscale',.5);               %a scale factor for actual symbols      
  24. xlabel('时间(秒)');ylabel('心率(心跳次数/分钟)');  
  25. subplot(2,1,2);  
  26. h(1) = plot(x,ydata2,'b');hold on;h(2)=plot(x,y_cyclic2,'r','linewidth',1.5);  
  27. title('心率信号2');axis tight;  
  28. xlabel('时间(秒)');ylabel('心率(心跳次数/分钟)');  
  29. set(gcf,'color',[1 1 1],'paperpositionmode','auto');  



图 21

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约