五. 添加圖例
(源代碼legends.m)
在圖像包含較多圖形時,適當?shù)膱D例對快速、正確的理解圖像反映的信息是必不可少的。以下一個實例可以說明精心設計圖例的重要性。
我們在一幅圖像中,同時繪出10個不同均值和方差的正態(tài)分布曲線。數(shù)據(jù)可以由如下代碼生成,或直接加載10NormalDistributions.mat
- % stdVect and meanVect
- stdVect = [.49,.26,.93,.47,.25,.43,.7,.4,.18,.86];
- meanVect = [-.8,-.62,-.44,-.27,-.09,.09,.27,.44,.62,.8];
-
- % 正態(tài)分布數(shù)據(jù),每行一個
- t = -1:.02:1;
- dataVect = ones(10,length(t));
- for i=1:10
- dataVect(i,:) = (1/sqrt(2*pi)/stdVect(i))*...
- exp(-(t-meanVect(i)).^2/(2*stdVect(i)^2));
- end
-
- % 圖例說明
- legendMatrix = cell(1,10);
- for i = 1:10
- legendMatrix{i} = [sprintf( 'mean = %.2f, std = %.2f',...
- meanVect(i),stdVect(i) )];
- end
- legend(legendMatrix);
-
- save('10NormalDistribution.mat', 'stdVect','meanVect',...
- 'dataVect','legendMatrix');
-
- clear;
1、首先,我們不加額外處理的使用圖例。(圖1)顯然,這幅圖的可讀性非常差,我們很難將參數(shù)和圖形對應起來,有的曲線顏色甚至還相同!
- % 加載數(shù)據(jù) meanVect stdVect legendMatrix
- load 10NormalDistributions;
-
- % 繪圖
- plot(dataVect');
- xlim([0,100]);
-
- % 添加標注
- title({'10種不同的正態(tài)分布','圖例不缺乏清晰度','顏色區(qū)分也不明顯!'},'Color',[1 0 0]);
- xlabel('x');
- ylabel('x的概率密度函數(shù)');
圖1
2、我們通過改變曲線的顏色(color)、線型(line style)和標志(marker)的方式增加可讀性,并將圖例放置在圖像外邊。(圖2)
- % 為不同曲線生成不同的設置
- LineStyles = {'-','--',':'};
- MarkerSpecs = {'+','o'};
- ColorSpecs = {'r','g','b','k'};
- cnt = 1;
- for i = 1:length(LineStyles)
- for j = 1:length(MarkerSpecs)
- for k = 1:length(ColorSpecs)
- LineSpecs{cnt} = [LineStyles{i} MarkerSpecs{j} ...
- ColorSpecs{k}];
- cnt = cnt+1;
- end
- end
- end
-
- figure; hold on;
- for i = 1:10
- plot(dataVect(i,:), LineSpecs{i});
- end
- xlim([0 100]);
-
- title({'10種不同的正態(tài)分布','使用不同的顏色和線型','可讀性大大提高'});
- xlabel('x'); ylabel('x的概率密度函數(shù)');
- legend(legendMatrix,'Location','NorthEastOutside',...
- 'Fontsize',8);
- box on;
圖2
3、 有時候,我們可能會將圖形分組。由于每執(zhí)行一次繪圖任務,legend的計數(shù)就會增加1,因此,在這種情況下,我們可以通過如下方式來減少圖例數(shù)量。(圖3)
- % 合并圖例
- figure; hold;
- h1 = plot(dataVect(1:6,:)','rd-','Color',[1 0 0]);
- h2 = plot(dataVect(7:10,:)','k*--','Color',[0 0 0]);
- xlim([0 100]);
-
- h = legend([h1(1),h2(1)],['Color 1' char(10) 'first 6 curves'],...
- ['Color 2' char(10) 'remaining 4 curves'],...
- 'Location','Best');
-
- % 提高可讀性,將圖例字體顏色調整為與圖形顏色一致
- % 注意:每兩個為一組,分別代表直線、標號和文字的顏色的屬性,且順序與所表示的圖形順序相反,即第一個繪制的圖形的圖例出現(xiàn)在數(shù)組的最后3個
- c = get(h,'Children');
- set(c(1:3),'Color',[0,0,0]);
- set(c(4:6),'Color',[1,0,0]);
圖3
4、利用legendlex優(yōu)化圖例。(圖4)
legendfex為我們提供了更加靈活的調整圖例格式的功能。得用legendflex, 我們不但可以調整說明的布局(指定分幾行或幾列顯示),還可以單獨調整圖標和文字的大小,設定圖例相對于任何對象的位置(原始legend限于坐標軸)。利用 legendflex ,我們還可以為圖例添加小標題。legendflex可從之里下載。
- figure('units','normalized','position',...
- [ 0.4172 0.1769 0.3 0.5]);
- hold on;
- for i = 1:10
- h(i) = plot(dataVect(i,:), LineSpecs{i});
- end
- xlim([0 100]);
- legendflex(h,... %handle to plot lines
- legendMatrix,... %corresponding legend entries
- 'ref', gcf, ... %which figure
- 'anchor', {'nw','nw'}, ... %location of legend box
- 'buffer',[30 -5], ... %an offset wrt the location
- 'nrow',4, ... %number of rows
- 'fontsize',8,... %font size
- 'xscale',.5); %a scale factor for actual symbols
-
- title({'應用legendflex優(yōu)化圖像顯示','可以調整相對位置、布局,字體及圖標大小'});
- xlabel('x'); ylabel('x的概率密度函數(shù)');
圖4
六. 通過數(shù)據(jù)變換突出細節(jié)特征
(源代碼trans.m)
有些數(shù)據(jù)通過一定的變換后,更便于可視化,也更容易發(fā)現(xiàn)隱藏的信息。
1、繪制一幅雙Y軸圖(圖5)
- %% 生成數(shù)據(jù)
- x = 1:50;
- r = 5e5;
- E = [ones(1,30) linspace(1,0,15) zeros(1,5)];
- y1 = r * (1+E).^x;
-
- %% 繪制又Y軸圖形
- y2 = log(y1);
- axes('position',[0.1300 0.1100 0.7750 0.7805]);
-
- [AX,H1,H2] = plotyy(x,y1,x,y2,'plot');
- title({'利用對數(shù)變換增強數(shù)據(jù)','增長、穩(wěn)定、衰減的可視化效果'});
- set(get(AX(1),'Ylabel'),'String','data');
- set(get(AX(2),'Ylabel'),'String','log(data)');
- xlabel('x'); set(H1,'LineStyle','--'); set(H2,'LineStyle',':');
-
- %% 添加標注
- annotation('textarrow',[.26 .28],[.67,.37],'String',['指數(shù)增長' char(10) '(1到30周期)']);
- annotation('textarrow',[.7 .7],[.8,.64],'String',['非指數(shù)衰減' char(10) '(30到45周期)']);
- annotation('textarrow',[.809 .859],[.669,.192],'String',['穩(wěn)定' char(10) '(45到50周期)']);
- legend({'原始數(shù)據(jù)','對數(shù)變換后的數(shù)據(jù)'},'Location','Best');
- set(gcf,'Paperpositionmode','auto','Color',[1 1 1]);
圖5
2、在數(shù)字較大時,matlab會默認采用科學計數(shù)法,有時這可能不是我們想要的,我們可以通過如下方式處理。(圖6)
- %% 關閉科學記數(shù)法格式
- % 改變圖像大小
- set(gcf,'units','normalized','position',[0.0411 0.5157 0.7510 0.3889]);
- % AX(1) 存儲的是原始數(shù)據(jù)的句柄
- title({'利用對數(shù)變換增強數(shù)據(jù)','增長、穩(wěn)定、衰減的可視化效果','關閉科學計數(shù)法格式'});
- n=get(AX(1),'Ytick');
- set(AX(1),'yticklabel',sprintf('%d |',n'));
圖6
3、通過縮放坐標軸達到變換的目的
上邊實例中,我們通過對原始數(shù)據(jù)進行取對數(shù)操作達到變換的效果。由于對數(shù)操作的常用性,Matlab允許我們直接對X和Y軸進行對數(shù)縮放。semilogx、semilogy、loglog可以分別對X軸、Y軸和XY軸進行對數(shù)縮放。這也可以通過設置坐標軸的xscale和yscale屬性實現(xiàn)。
- %% 直接利用 semilogx, semilogy, loglog
- figure;
- subplot(2,1,1);
- semilogy(x,y1);
- xlabel('x');
- ylabel('取對數(shù)后數(shù)據(jù)');
- title({'MATLAB的semilogy函數(shù)',...
- '直接將Y軸對數(shù)縮放后顯示'});
- subplot(2,1,2);
- plot(x,y1);
- set(gca,'yscale','log');
- xlabel('x');
- ylabel('取對數(shù)后的數(shù)據(jù)');
- title({'使用常規(guī)的plot進行繪圖','然后通過理性屬性達到相同目的'});
圖7
七. 多圖的繪制
(源代碼subfig.m)
1、常規(guī)子圖的繪制
我們利用蘋果公司2011年度每日股票交易數(shù)據(jù)為例,繪制包括開盤價、最高價、最低價、收盤價、成交量和臨近收盤價在內的6個趨勢圖。
首先加載數(shù)據(jù)
- %% 加載數(shù)據(jù)并按時間先后順序排列
- [AAPL dateAAPL] = xlsread('AAPL_090784_012412.csv');
- dateAAPL = datenum({dateAAPL{2:end,1}});
- dateAAPL = dateAAPL(end:-1:1);
- AAPL = AAPL(end:-1:1,:);
- % 選擇時間窗口(2011年全年)
- rangeMIN = datenum('1/1/2011');
- rangeMAX = datenum('12/31/2011');
- idx = find(dateAAPL >= rangeMIN & dateAAPL <= rangeMAX);
然后,通過subplot命令繪圖(圖8)
- %% 使用subplot繪圖命令繪制常規(guī)子圖網格
- % 注意設置各個子圖的標題內容的title命令的位置
-
- figure('units','normalized','position',[ 0.0609 0.0593 0.5844 0.8463]);
- matNames = {'開盤價','最高價','最低價','收盤價','成交量','臨近收盤價'};
- for i = 1:6
- subplot(3,2,i);
- plot(idx,AAPL(idx,i));
- if i~=5
- title([matNames{i} ' $, subplot(3,2,' num2str(i) ')'],'Fontsize',12,'Color',[1 0 0 ]);
- ylabel('美元');
- else
- title([matNames{i} ' vol, subplot(3,2,' num2str(i) ')'],'Fontsize',12,'Color',[1 0 0 ]);
- ylabel('成交量');
- end
- set(gca,'xtick',linspace(idx(1),idx(end),12),'xticklabel',...
- datestr(linspace(dateAAPL(idx(1)),dateAAPL(idx(end)),12),...
- 'mm'),'Fontsize',10,'fontweight','bold');
- rotateXLabels(gca,40);
- box on; axis tight
- end
- % 添加總標題
- annotation('textbox',[ 0.37 0.96 0.48 0.03],'String','2011年度蘋果公司股價趨勢','Fontsize',14,'Linestyle','none');
圖8
2、進階篇
我們可以自定義子圖的布局,并且子圖可以是任何一種圖形。下面我們繪制包括3個垂直排列的子圖(由上而下編號1、2、3)的圖像(如圖9)。子圖1展示選定時間窗口內的股價走勢,子圖2展示相同時期內的成交量,子圖3則顯示全部時間內股價的變化情況。
圖9
子圖1是一個面積圖,可通過area命令繪制。
- %% 自定義子圖布局
- figure('units','normalized','Position',[ 0.0427 0.2102 0.6026 0.6944]);
-
- %% 子圖1顯示收盤價隨時間的變化趨勢
- % 設置坐標軸位置
- Panel1 = axes('Position',[ 0.0570 0.5520 0.8850 0.3730]);hold;
- % 繪制面積圖
- area(AAPL(idx,4),'FaceColor',[188 210 238]/255,'edgecolor',[54 100 139 ]/255);
- % 設置坐標軸相關參數(shù)
- xlim([1 length(idx)]);
- yminv = min(AAPL(idx,4))-.5*range(AAPL(idx,4));
- ymaxv = max(AAPL(idx,4))+.1*range(AAPL(idx,4));
- ylim([yminv ymaxv]);
- box on;
- % 繪制網格線
- set(gca,'Ticklength',[0 0],'YAxisLocation','right');
- line([linspace(1,length(idx),15);linspace(1,length(idx),15)],[yminv*ones(1,15); ymaxv*ones(1,15)],'Color',[.9 .9 .9]);
- line([ones(1,10); length(idx)*ones(1,10)],[linspace(yminv, ymaxv,10); linspace(yminv, ymaxv,10);],'Color',[.9 .9 .9]);
- % 設置注解
- set(gca,'xtick',linspace(1,length(idx),10),'xticklabel',datestr(linspace(dateAAPL(idx(1)),dateAAPL(idx(end)),10),'ddmmmyy'));
- title({'蘋果公司股票價格,','(選定時間窗口內細節(jié)展示)'},'Fontsize',12);
子圖2是一個條形圖,可通過bar命令繪制。
- %% 子圖2展示相同時間段內成交量的變化情況
- % 設置坐標軸位置
- Panel2 = axes('Position',[ 0.0570 0.2947 0.8850 0.1880]);
- % 用條形圖繪圖
- bar(1:length(idx), AAPL(idx,5),.25,...
- 'FaceColor',[54 100 139 ]/255);
- hold; xlim([1 length(idx)]);hold on;
- % 添加網格線
- yminv = 0;
- ymaxv = round(max(AAPL(idx,5)));
- line([linspace(1,length(idx),30);...
- linspace(1,length(idx),30)],...
- [yminv*ones(1,30); ymaxv*ones(1,30)],...
- 'Color',[.9 .9 .9]);
- line([ones(1,5); length(idx)*ones(1,5)],...
- [linspace(yminv, ymaxv,5); ...
- linspace(yminv, ymaxv,5);],'Color',[.9 .9 .9]);
- ylim([yminv ymaxv]);
- % 設置特殊的時間刻度
- set(gca, 'Ticklength',[0 0],...
- 'xtick',linspace(1,length(idx),10),'xticklabel',...
- datestr(linspace(dateAAPL(idx(1)),dateAAPL(idx(end)),10),...
- 'ddmmmyy'));
- tickpos = get(Panel2,'ytick')/1000000;
- for i = 1:numel(tickpos)
- C{i} = [num2str(tickpos(i)) 'M'];
- end
- set(Panel2,'yticklabel',C,'YAxisLocation','right');
- text(0,1.15*ymaxv,'成交量','VerticalAlignment','top',...
- 'Color',[54 100 139 ]/255,'Fontweight','bold');
子圖3是也一個面積圖,其中選定時間段被高亮,這是通過在大圖上疊加繪制一個與子圖1相同顏色的小得到。
- %% 子圖3展示全部時間段內股價變化情況,其中被選中的時間窗口高亮顯示
- Panel3 = axes('Position',[0.0570 0.1100 0.8850 0.1273]);
- area(dateAAPL, AAPL(:,4),'FaceColor',[234 234 234 ]/255,'edgecolor',[.8 .8 .8]); hold;
- line([min(idx) min(idx)],get(gca,'ylim'),'Color','k');
- line([max(idx) max(idx)],get(gca,'ylim'),'Color','k');
- set(gca,'Ticklength',[0 0]);
- % 相同顏色重新繪制時間窗口內的趨勢
- area(dateAAPL(idx),AAPL(idx,4),'FaceColor',[188 210 238]/255,'edgecolor',[54 100 139 ]/255);
- ylim([min(AAPL(:,4)) 1.1*max(AAPL(:,4))]);
- xlabel('長期股價走勢');
- line([min(get(gca,'xlim')) min(get(gca,'xlim'))],get(gca,'ylim'),'Color',[1 1 1]);
- line([max(get(gca,'xlim')) max(get(gca,'xlim'))],get(gca,'ylim'),'Color',[1 1 1]);
- line(get(gca,'xlim'),[max(get(gca,'ylim')) max(get(gca,'ylim'))],'Color',[1 1 1]);
- line(get(gca,'xlim'),[min(get(gca,'ylim')) min(get(gca,'ylim'))],'Color',[1 1 1]);
- set(gca,'xticklabel',datestr(get(gca,'xtick'),'yyyy'),'yticklabel',[]);
八. 可視化直觀地比較實驗結果
(源代碼comparison.m)
這涉及多種方法的對比實驗中,選擇適當?shù)姆绞竭M行可視化分析,有助于我們快速、直觀地對各種方法的優(yōu)劣進行評判。我們以五種聚類算法在5個測試集上的實驗結果為數(shù)據(jù),通過繪圖對其進行比較。
我們已經知道,matlab自帶有多種配色方案(colormap)可供選擇,我們還可以自定義配色方案。為了保證配色的友好性和易區(qū)分性,我們可以通過在線工具color brewer(http:///),對配色進行測試,輔助我們找到比較好的方案。
圖10
- %% 定義可視化方案
- % 設定圖像大小和位置
- figure('units','normalized','Position',[ 0.0880 0.1028 0.6000 0.6352]);
-
- % 繪制一個隱藏的坐標軸,其X軸刻度標簽列出進行比較的五種算法的名稱
- hh = axes('Position',[.1,.135,.8,.1]);
- set(gca,'Visible','Off','TickLength',[0.0 0.0],'TickDir','out','YTickLabel','','xlim',[0 nosOfMethods],'FontSize',11,'FontWeight','bold');
- set(gca,'XTick',.5:nosOfMethods-.5,'XTickLabel',{'K Means','Fuzzy C Means','Hierarchical','Maximize Expectation','Dendogram'});
- catgeoryLabels = {'Fresh Tissue','FFPE','Blood','DNA','Simulated'};
- rotateXLabels(gca,20);
- % 將Y軸長等分為五份,分別分配給5個測試集結果
- y = linspace(.142,.75,nosOfCategories);
-
- % Place an axes for creating each row dedicated to a sample
- % category. The height of the axes corresponds to the total
- % number of samples in that category.
- %
- for i = 1 :nosOfCategories
-
- if CategoryTotals(i); ylimup = CategoryTotals(i); else ylimup = 1; end
- dat = [MethodPerformanceNumbers(i,:)];
- h(i) = axes('Position',[.1,y(i),.8,y(2)-y(1)]);
- set(gca,'XTickLabel','','TickLength',[0.0 0.0],'TickDir','out','YTickLabel','','xlim',[.5 nosOfMethods+.5],'ylim',[0 ylimup]);
-
- % Use the line command to create bars representing the number of successes
- % in each category using colour scheme defined at the beginning of this recipe
- line([1:nosOfMethods; 1:nosOfMethods],[zeros(1,nosOfMethods); dat],'Color',Colors(i,:),'Linewidth',7);box on;
-
- % Place the actual number as a text next to the bar
- for j= 1:nosOfMethods
- if dat(j); text(j+.01,dat(j)-.3*dat(j),num2str(dat(j)),'Rotation',20,'FontSize',13); end
- end
-
- % Add the category label
- ylabel([catgeoryLabels{i} char(10) '#Samples' char(10) ' = ' num2str(ylimup) ],'Fontsize',11);
- end
- % Add annotations
- title('5種聚類算法成功的次數(shù)','Fontsize',14,'Fontweight','bold');
- axes(h(3));
- text(-0.02,-80,'聚類算法在不同數(shù)據(jù)集上的表現(xiàn)','rotation',90,'Fontsize',14,'Fontweight','bold');
|