在Matlab中使用barweb繪製帶方差的分組柱狀圖時的幾個注意事項

題目:在Matlab中使用barweb繪製帶方差的分組柱狀圖時的幾個注意事項

        注:本人電腦上安裝有Matlab r2009b, r2014a, r2017b三個Matlab版本,其中r2009b, r2014a對應文中提到的Matlab低版本,r2017b對應文中提到的Matlab高版本;程序在本人電腦上的測試通過,不同Matlab可能會出現新的問題。

        Matlab自帶的bar加上errorbar功能有限,不能繪製有分組情況下的帶方差的柱狀圖(bar本身可以繪製有分組的柱狀圖但不能帶方差,bar+errorbar聯合使用可繪製帶方差的柱狀圖但不能分組),此時一般使用barweb函數,這是一個由第三方個人編寫的函數,鏈接如下:

https://ww2.mathworks.cn/matlabcentral/fileexchange/10803-barweb-bargraph-with-error-bars

        編寫如下示例程序barweb_demo.m:

        (注:由於數據X和E均由rand隨機生成的,所以每次運行所得圖形是不同的):

%barweb使用舉例@2019-09-04
close all;clear;clc;
X = 5+rand(6,3);%隨機生成數據
E = rand(6,3);%隨機生成誤差

legends = {'Type-I','Type-II','Type-III'};
groupnames = cell(6,1);
groupnames{1} = 'Group1';groupnames{2} = 'Group2';groupnames{3} = 'Group3';
groupnames{4} = 'Group4';groupnames{5} = 'Group5';groupnames{6} = 'Group6';
Title = 'title of barweb example';
Xlabel = 'xlabel of barweb example';
Ylabel = 'ylabel of barweb exampe';

barweb(X,E,1,groupnames,Title,Xlabel,Ylabel,jet,'none',legends,2,'plot');

        若你的Matlab版本比較低,例如Matlab R2014,那麼應該可以正常運行:

注:如果不想顯示橫軸、縱軸、圖片標題,則將對應的參數用[]替代即可,例如:

barweb(X,E,1,groupnames,Title,[],Ylabel,jet,'none',legends,2,'plot');

則將不再顯示橫軸的“xlabel of barweb example”內容;

        但你的若Matlab版本比較高,例如Matlab R2017,運行時會出錯:

這時可能會看到barweb主頁上的評論:

即出錯位置在原程序的如下位置:

將以上兩行註釋掉,換成:

x = handles.bars(i).XData + handles.bars(i).XOffset;

這時再運行示例程序barweb_demo.m就不報錯了:

        你會發現那個legend顯示是有問題的,除了想要的Type-I、Type-II、Type-III之外,還有多餘的data1、data2、data3(另外legend顯示的位置也有問題,這個後面再說)。這個是因爲原先138~143行繪製legend的代碼有問題:

只要將這段代碼換個位置,剪切至%Plot erros部分的for循環之後就可以了,如下:

這時再次運行示例程序barweb_demo.m,一切就正常了:

 

        但是,倘若有一天你又在低版本Matlab上使用該修改過後的程序,發現又會報錯:

        其實,原作者的程序是沒錯的。之所以部分人直接運行時會報錯,主要是由於不同版本的Matlab軟件中函數bar的返回值不同。在Matlab的Command Window中輸入命令help bar,然後打開函數bar的幫助文檔:

        以下是Matlab r2009b中的幫助文檔部分截圖:

        以下是Matlab r2014a中的幫助文檔部分截圖:

        以下是Matlab r2017b中的幫助文檔部分截圖:

對比一下可以發現,R2009b和R2014a的返回值是a vector of handles,而R2017b的返回值是one or more Bar objects,原作者的程序只適用於返回值是a vector of handles的Matlab版本,而按barweb主頁上的評論修改後的程序只適用於返回值是one or more Bar objects的Matlab版本。所以具體使用哪個版本,要自己根據自己的Matlab版本中bar函數的返回值確定。爲了使修改後的barweb函數適應不同Matlab版本中bar函數這兩種不同的返回值,可將%Plot erros部分的for循環做如下修改:

也就是使用if…else…語句判斷bar函數返回值的類型,進而選擇執行相應的代碼。

 

        對於legend顯示的位置問題,只要針對性修改如下代碼即可:

可以發現,目前legend顯示位置’location’的參數值爲’best’,可以把這個參數值去掉,即將原代碼第139行改爲

handles.legend = legend(bw_legend, 'fontsize', 12);

此時legend會按’location’ 的默認參數設置,顯示在圖形的左上角:

另外還可以將接下來的legend boxoff;註釋掉,legend示例會有邊框:

當然還可以修改上面的’fontsize’參數,改變legend示例的字號大小;更多設置那就自己摸索吧。

 

        另外,還可能要修改圖形的標題、橫軸、縱軸的顯示格式,尤其是字號大小,可通過barweb函數的如下代碼修改:

	if ~isempty(bw_title)
		title(bw_title, 'fontsize',14);
	end
	if ~isempty(bw_xlabel)
		xlabel(bw_xlabel, 'fontsize',14);
	end
	if ~isempty(bw_ylabel)
		ylabel(bw_ylabel, 'fontsize',14);
	end

相信一般人都熟悉使用title, xlabel, ylabel三個函數分別設置figure的標題、橫軸、縱軸。

 

        若想修改group的內容,即本例中橫軸的Group1~Group6的格式,應該修改barweb原來的第180行:

set(gca, 'xticklabel', groupnames, 'box', 'off', 'ticklength', [0 0], 'fontsize', 12, 'xtick',1:numgroups, 'linewidth', 2,'xgrid','off','ygrid','off');

        更多修改設置可以大致瀏覽一下barweb函數源碼;實際上,barweb就是結合了bar和errorbar兩個函數,關鍵是errorbar不能適用於帶分組的情形,因此特別調整了一下而已。

 

        最後,說一個圖片存儲的技巧:平時可以使用“文件--->另存爲”(save as),選擇自己想要的格式保存即可,但如此存儲的圖片白色邊框會比較大。還可以運行如下語句保存圖片:

print('barweb_example','-depsc2','-r600');

其中,barweb_example是文件名,-depsc2是文件格式,-r600是圖片分辨率。可以help print,打開print函數的幫助文檔查看,例如對-depsc2參數的解釋:

即存儲爲EPS彩色圖片;

對-r600的解釋:

即此處的number=600。單獨運行以上語句時,若有多張圖片,最新單擊瀏覽了哪張圖片就會存儲哪張圖片。

 

        這裏的柱狀圖的填充顏色都是隨機的,如果黑白打印的話顯示效果就不好了,如果能用不同的條紋填充就最好了,這時可以使用另外一個第三方個人寫的函數:applyhatch,鏈接如下:

http://www.aos.wisc.edu/~dvimont/matlab/Graphics_Tools/applyhatch.html

或者applyhatch_plusC,鏈接如下:

https://ww2.mathworks.cn/matlabcentral/fileexchange/26797-applyhatch_plusc

但效果並不是特別好,這裏就不說了,需要的話可以自行探索使用方法。

 

附錄1:barweb修改後的代碼(兼容多版本Matlab,修改了原先138~143行繪製legend的代碼)

function handles = barweb(barvalues, errors, width, groupnames, bw_title, bw_xlabel, bw_ylabel, bw_colormap, gridstatus, bw_legend, error_sides, legend_type)
%
% Usage: handles = barweb(barvalues, errors, width, groupnames, bw_title, bw_xlabel, bw_ylabel, bw_colormap, gridstatus, bw_legend, error_sides, legend_type)
%
% Ex: handles = barweb(my_barvalues, my_errors, [], [], [], [], [], bone, [], bw_legend, 1, 'axis')
%
% barweb is the m-by-n matrix of barvalues to be plotted.
% barweb calls the MATLAB bar function and plots m groups of n bars using the width and bw_colormap parameters.
% If you want all the bars to be the same color, then set bw_colormap equal to the RBG matrix value ie. (bw_colormap = [1 0 0] for all red bars)
% barweb then calls the MATLAB errorbar function to draw barvalues with error bars of length error.
% groupnames is an m-length cellstr vector of groupnames (i.e. groupnames = {'group 1'; 'group 2'}).  For no groupnames, enter [] or {}
% The errors matrix is of the same form of the barvalues matrix, namely m group of n errors.
% Gridstatus is either 'x','xy', 'y', or 'none' for no grid.
% No legend will be shown if the legend paramter is not provided
% 'error_sides = 2' plots +/- std while 'error_sides = 1' plots just + std
% legend_type = 'axis' produces the legend along the x-axis while legend_type = 'plot' produces the standard legend.  See figure for more details
%
% The following default values are used if parameters are left out or skipped by using [].
% width = 1 (0 < width < 1; widths greater than 1 will produce overlapping bars)
% groupnames = '1', '2', ... number_of_groups
% bw_title, bw_xlabel, bw_ylabel = []
% bw_color_map = jet
% gridstatus = 'none'
% bw_legend = []
% error_sides = 2;
% legend_type = 'plot';
%
% A list of handles are returned so that the user can change the properties of the plot
% handles.ax: handle to current axis
% handles.bars: handle to bar plot
% handles.errors: a vector of handles to the error plots, with each handle corresponding to a column in the error matrix
% handles.legend: handle to legend
%
%
% See the MATLAB functions bar and errorbar for more information
%
% Author: Bolu Ajiboye
% Created: October 18, 2005 (ver 1.0)
% Updated: Dec 07, 2006 (ver 2.1)
% Updated: July 21, 2008 (ver 2.3)
% Get function arguments
if nargin < 2
	error('Must have at least the first two arguments:  barweb(barvalues, errors, width, groupnames, bw_title, bw_xlabel, bw_ylabel, bw_colormap, gridstatus, bw_legend, barwebtype)');
elseif nargin == 2
	width = 1;
	groupnames = 1:size(barvalues,1);
	bw_title = [];
	bw_xlabel = [];
	bw_ylabel = [];
	bw_colormap = jet;
	gridstatus = 'none';
	bw_legend = [];
	error_sides = 2;
	legend_type = 'plot';
elseif nargin == 3
	groupnames = 1:size(barvalues,1);
	bw_title = [];
	bw_xlabel = [];
	bw_ylabel = [];
	bw_colormap = jet;
	gridstatus = 'none';
	bw_legend = [];
	error_sides = 2;
	legend_type = 'plot';
elseif nargin == 4
	bw_title = [];
	bw_xlabel = [];
	bw_ylabel = [];
	bw_colormap = jet;
	gridstatus = 'none';
	bw_legend = [];
	error_sides = 2;
	legend_type = 'plot';
elseif nargin == 5
	bw_xlabel = [];
	bw_ylabel = [];
	bw_colormap = jet;
	gridstatus = 'none';
	bw_legend = [];
	error_sides = 2;
	legend_type = 'plot';
elseif nargin == 6
	bw_ylabel = [];
	bw_colormap = jet;
	gridstatus = 'none';
	bw_legend = [];
	error_sides = 2;
	legend_type = 'plot';
elseif nargin == 7
	bw_colormap = jet;
	gridstatus = 'none';
	bw_legend = [];
	error_sides = 2;
	legend_type = 'plot';
elseif nargin == 8
	gridstatus = 'none';
	bw_legend = [];
	error_sides = 2;
	legend_type = 'plot';
elseif nargin == 9
	bw_legend = [];
	error_sides = 2;
	legend_type = 'plot';
elseif nargin == 10
	error_sides = 2;
	legend_type = 'plot';
elseif nargin == 11
	legend_type = 'plot';
end
change_axis = 0;
ymax = 0;
if size(barvalues,1) ~= size(errors,1) || size(barvalues,2) ~= size(errors,2)
	error('barvalues and errors matrix must be of same dimension');
else
	if size(barvalues,2) == 1
		barvalues = barvalues';
		errors = errors';
	end
	if size(barvalues,1) == 1
		barvalues = [barvalues; zeros(1,length(barvalues))];
		errors = [errors; zeros(1,size(barvalues,2))];
		change_axis = 1;
	end
	numgroups = size(barvalues, 1); % number of groups
	numbars = size(barvalues, 2); % number of bars in a group
	if isempty(width)
		width = 1;
	end
	
	% Plot bars
	handles.bars = bar(barvalues, width, 'edgecolor','k', 'linewidth', 2);
	hold on
	if ~isempty(bw_colormap)
		colormap(bw_colormap);
	else
		colormap(jet);
	end
	
	% Plot erros
	for i = 1:numbars
        bar_versions = class(handles.bars(i));
        if strcmp(bar_versions,'double')
            x =get(get(handles.bars(i),'children'), 'xdata');
            x = mean(x([1 3],:));
        else
            x = handles.bars(i).XData + handles.bars(i).XOffset;
        end
		handles.errors(i) = errorbar(x, barvalues(:,i), errors(:,i), 'k', 'linestyle', 'none', 'linewidth', 2);
		ymax = max([ymax; barvalues(:,i)+errors(:,i)]);
    end
    
	if ~isempty(bw_legend) && ~strcmp(legend_type, 'axis')
		handles.legend = legend(bw_legend, 'fontsize',12);%'location', 'best',
% 		legend boxoff;
	else
		handles.legend = [];
	end
	
	if error_sides == 1
		set(gca,'children', flipud(get(gca,'children')));
	end
	
	ylim([0 ymax*1.1]);
	xlim([0.5 numgroups-change_axis+0.5]);
	
	if strcmp(legend_type, 'axis')
		for i = 1:numbars
			xdata = get(handles.errors(i),'xdata');
			for j = 1:length(xdata)
				text(xdata(j),  -0.03*ymax*1.1, bw_legend(i), 'Rotation', 60, 'fontsize', 12, 'HorizontalAlignment', 'right');
			end
		end
		set(gca,'xaxislocation','top');
	end
	
	if ~isempty(bw_title)
		title(bw_title, 'fontsize',14);
	end
	if ~isempty(bw_xlabel)
		xlabel(bw_xlabel, 'fontsize',14);
	end
	if ~isempty(bw_ylabel)
		ylabel(bw_ylabel, 'fontsize',14);
	end
	
	set(gca, 'xticklabel', groupnames, 'box', 'off', 'ticklength', [0 0], 'fontsize', 12, 'xtick',1:numgroups, 'linewidth', 2,'xgrid','off','ygrid','off');
	if ~isempty(gridstatus) && any(gridstatus == 'x')
		set(gca,'xgrid','on');
	end
	if ~isempty(gridstatus) && any(gridstatus ==  'y')
		set(gca,'ygrid','on');
	end
	
	handles.ax = gca;
	
	hold off
end

 

附錄2:barweb原來代碼(可以在開篇給出的鏈接中複製,放在此處僅作備份)

function handles = barweb(barvalues, errors, width, groupnames, bw_title, bw_xlabel, bw_ylabel, bw_colormap, gridstatus, bw_legend, error_sides, legend_type)
%
% Usage: handles = barweb(barvalues, errors, width, groupnames, bw_title, bw_xlabel, bw_ylabel, bw_colormap, gridstatus, bw_legend, error_sides, legend_type)
%
% Ex: handles = barweb(my_barvalues, my_errors, [], [], [], [], [], bone, [], bw_legend, 1, 'axis')
%
% barweb is the m-by-n matrix of barvalues to be plotted.
% barweb calls the MATLAB bar function and plots m groups of n bars using the width and bw_colormap parameters.
% If you want all the bars to be the same color, then set bw_colormap equal to the RBG matrix value ie. (bw_colormap = [1 0 0] for all red bars)
% barweb then calls the MATLAB errorbar function to draw barvalues with error bars of length error.
% groupnames is an m-length cellstr vector of groupnames (i.e. groupnames = {'group 1'; 'group 2'}).  For no groupnames, enter [] or {}
% The errors matrix is of the same form of the barvalues matrix, namely m group of n errors.
% Gridstatus is either 'x','xy', 'y', or 'none' for no grid.
% No legend will be shown if the legend paramter is not provided
% 'error_sides = 2' plots +/- std while 'error_sides = 1' plots just + std
% legend_type = 'axis' produces the legend along the x-axis while legend_type = 'plot' produces the standard legend.  See figure for more details
%
% The following default values are used if parameters are left out or skipped by using [].
% width = 1 (0 < width < 1; widths greater than 1 will produce overlapping bars)
% groupnames = '1', '2', ... number_of_groups
% bw_title, bw_xlabel, bw_ylabel = []
% bw_color_map = jet
% gridstatus = 'none'
% bw_legend = []
% error_sides = 2;
% legend_type = 'plot';
%
% A list of handles are returned so that the user can change the properties of the plot
% handles.ax: handle to current axis
% handles.bars: handle to bar plot
% handles.errors: a vector of handles to the error plots, with each handle corresponding to a column in the error matrix
% handles.legend: handle to legend
%
%
% See the MATLAB functions bar and errorbar for more information
%
% Author: Bolu Ajiboye
% Created: October 18, 2005 (ver 1.0)
% Updated: Dec 07, 2006 (ver 2.1)
% Updated: July 21, 2008 (ver 2.3)
% Get function arguments
if nargin < 2
	error('Must have at least the first two arguments:  barweb(barvalues, errors, width, groupnames, bw_title, bw_xlabel, bw_ylabel, bw_colormap, gridstatus, bw_legend, barwebtype)');
elseif nargin == 2
	width = 1;
	groupnames = 1:size(barvalues,1);
	bw_title = [];
	bw_xlabel = [];
	bw_ylabel = [];
	bw_colormap = jet;
	gridstatus = 'none';
	bw_legend = [];
	error_sides = 2;
	legend_type = 'plot';
elseif nargin == 3
	groupnames = 1:size(barvalues,1);
	bw_title = [];
	bw_xlabel = [];
	bw_ylabel = [];
	bw_colormap = jet;
	gridstatus = 'none';
	bw_legend = [];
	error_sides = 2;
	legend_type = 'plot';
elseif nargin == 4
	bw_title = [];
	bw_xlabel = [];
	bw_ylabel = [];
	bw_colormap = jet;
	gridstatus = 'none';
	bw_legend = [];
	error_sides = 2;
	legend_type = 'plot';
elseif nargin == 5
	bw_xlabel = [];
	bw_ylabel = [];
	bw_colormap = jet;
	gridstatus = 'none';
	bw_legend = [];
	error_sides = 2;
	legend_type = 'plot';
elseif nargin == 6
	bw_ylabel = [];
	bw_colormap = jet;
	gridstatus = 'none';
	bw_legend = [];
	error_sides = 2;
	legend_type = 'plot';
elseif nargin == 7
	bw_colormap = jet;
	gridstatus = 'none';
	bw_legend = [];
	error_sides = 2;
	legend_type = 'plot';
elseif nargin == 8
	gridstatus = 'none';
	bw_legend = [];
	error_sides = 2;
	legend_type = 'plot';
elseif nargin == 9
	bw_legend = [];
	error_sides = 2;
	legend_type = 'plot';
elseif nargin == 10
	error_sides = 2;
	legend_type = 'plot';
elseif nargin == 11
	legend_type = 'plot';
end
change_axis = 0;
ymax = 0;
if size(barvalues,1) ~= size(errors,1) || size(barvalues,2) ~= size(errors,2)
	error('barvalues and errors matrix must be of same dimension');
else
	if size(barvalues,2) == 1
		barvalues = barvalues';
		errors = errors';
	end
	if size(barvalues,1) == 1
		barvalues = [barvalues; zeros(1,length(barvalues))];
		errors = [errors; zeros(1,size(barvalues,2))];
		change_axis = 1;
	end
	numgroups = size(barvalues, 1); % number of groups
	numbars = size(barvalues, 2); % number of bars in a group
	if isempty(width)
		width = 1;
	end
	
	% Plot bars
	handles.bars = bar(barvalues, width,'edgecolor','k', 'linewidth', 2);
	hold on
	if ~isempty(bw_colormap)
		colormap(bw_colormap);
	else
		colormap(jet);
	end
	if ~isempty(bw_legend) && ~strcmp(legend_type, 'axis')
		handles.legend = legend(bw_legend, 'location', 'best', 'fontsize',12);
		legend boxoff;
	else
		handles.legend = [];
	end
	
	% Plot erros
	for i = 1:numbars
		x =get(get(handles.bars(i),'children'), 'xdata');
		x = mean(x([1 3],:));
		handles.errors(i) = errorbar(x, barvalues(:,i), errors(:,i), 'k', 'linestyle', 'none', 'linewidth', 2);
		ymax = max([ymax; barvalues(:,i)+errors(:,i)]);
	end
	
	if error_sides == 1
		set(gca,'children', flipud(get(gca,'children')));
	end
	
	ylim([0 ymax*1.1]);
	xlim([0.5 numgroups-change_axis+0.5]);
	
	if strcmp(legend_type, 'axis')
		for i = 1:numbars
			xdata = get(handles.errors(i),'xdata');
			for j = 1:length(xdata)
				text(xdata(j),  -0.03*ymax*1.1, bw_legend(i), 'Rotation', 60, 'fontsize', 12, 'HorizontalAlignment', 'right');
			end
		end
		set(gca,'xaxislocation','top');
	end
	
	if ~isempty(bw_title)
		title(bw_title, 'fontsize',14);
	end
	if ~isempty(bw_xlabel)
		xlabel(bw_xlabel, 'fontsize',14);
	end
	if ~isempty(bw_ylabel)
		ylabel(bw_ylabel, 'fontsize',14);
	end
	
	set(gca, 'xticklabel', groupnames, 'box', 'off', 'ticklength', [0 0], 'fontsize', 12, 'xtick',1:numgroups, 'linewidth', 2,'xgrid','off','ygrid','off');
	if ~isempty(gridstatus) && any(gridstatus == 'x')
		set(gca,'xgrid','on');
	end
	if ~isempty(gridstatus) && any(gridstatus ==  'y')
		set(gca,'ygrid','on');
	end
	
	handles.ax = gca;
	
	hold off
end

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章