How to draw a group by boxplot in matlab - matlab

I have a three groups such as
Group 1={x1,x2}
x1=[1,2,2,3,5,3]
x2=[2,5,4,5,8,6]
Group 2={x3,x4}
x3=[2,8,9,2,1,6]
x4=[5,4,3,22,11,6]
Group 2={x5,x6}
x5=[10,12,22,4]
x6=[12,15,4,25]
I want to draw them into char by boxplot function by group. I found the way to resolve it. But it cannot draw. Could you help me please?
x1=[1,2,2,3,5,3];
x2=[2,5,4,5,8,6];
g1={x1,x2};
%group2
x3=[2,8,9,2,1,6];
x4=[5,4,3,22,11,6];
g2={x3,x4};
%group3
x5=[10,12,22,4];
x6=[12,15,4,25];
g3={x5,x6};
G=cat(1,g1,g2,g3);
class={1,2,3}
positions = [1 1.25 2 2.25 3 3.25];
boxplot(G,class, 'positions', positions);
set(gca,'xtick',[mean(positions(1:2)) mean(positions(3:4)) mean(positions(5:6)) ])
set(gca,'xticklabel',{'Group1','Group2','Group3'})
color = ['c', 'y', 'c', 'y'];
h = findobj(gca,'Tag','Box');
for j=1:length(h)
patch(get(h(j),'XData'),get(h(j),'YData'),color(j),'FaceAlpha',.5);
end
c = get(gca, 'Children');
hleg1 = legend(c(1:2), 'Feature1', 'Feature2' );

Your problem is that the grouping variables were constructed in the wrong way. Use this sample:
x1=[1,2,2,3,5,3];
x2=[2,5,4,5,8,6];
g1=[x1,x2];
v1=[repmat('A',1,numel(x1)),repmat('B',1,numel(x2))];
%group2
x3=[2,8,9,2,1,6];
x4=[5,4,3,22,11,6];
g2=[x3,x4];
v2=[repmat('A',1,numel(x3)),repmat('B',1,numel(x4))];
%group3
x5=[10,12,22,4];
x6=[12,15,4,25];
g3=[x5,x6];
v3=[repmat('A',1,numel(x5)),repmat('B',1,numel(x6))];
%%
G=[g1,g2,g3]
vg1 = [repmat('1',1,numel(v1)),repmat('2',1,numel(v2)),repmat('3',1,numel(v3))];
vg2=[v1,v2,v3] ;
%%
clc
boxplot(G', {vg1';vg2'}, 'factorseparator',1 , 'factorgap',30,...
'colorgroup',vg2','labelverbosity','majorminor');

Related

How to minimize the white space from boxchart in MATLAB?

I would like to minimize the whitespace of the figure (boxchart). I have tried to get a transparent background using built-in function exportgraphics():
https://it.mathworks.com/help/matlab/creating_plots/save-figure-with-minimal-white-space.html
But it doesn't work. Instead, it gives the following error:
Warning: Background transparency is not supported; using white instead.
I wonder if someone help me to remove the white space from the figure?
Thank you in advance.
clc; clear; close;
% data
D1= [0.944790802 0.557698361 0.373906779 2.046704837 2.301581619 1.527444403 1.209060357 0.255009648 0.006522648 1.391635043 0.020485623 3.06E-05 2.219570211 0.031292703 1.4617617 0.709825512 0.140968679 0.39152202 0.118959281 0.604265713 0.108340057 1.254792134 0.187867762 0.391214936 0.527749647 0.284452271 0.137486525 1.50698204 0.398872235 1.09E-05 6.030073741 0.343347524 2.66E-05 0.244522229 1.828567513 0.384888011 0.150066426 0.458832813 0.039189943 1.356957639 0.162054596 0.547751882 3.835735492 0.038394762 0.661566595 0.13553248 0.270139424 1.451613168 0.044339379 0.413170264 1.795609121 0.109564539 0.201333355 1.207746569 0.812164457 0.003902586 3.508953738 0.024859534 1.193314027 ]';
D2= [0.523944609 1.423099939 1.869691969 0.920446948 1.977619794 0.781737256 0.95977679 1.100075857 0.017899515 4.533151907 0.03790224 2.80E-05 3.432894823 0.120809324 2.359138901 1.530822669 0.24903375 3.017043435 0.357091919 1.775763839 0.067044341 2.383827733 0.496209584 1.016302313 2.17366118 0.718760335 0.316183758 1.662342228 0.658886019 1.57E-05 1.798207987 2.194711665 3.12E-05 0.777365181 1.31022147 1.803898883 0.142538755 1.633823624 0.095730818 1.917168272 1.066430117 1.570445025 0.67080804 0.028328869 0.265164055 1.313050736 0.988211581 1.355540089 0.180799139 1.559261863 2.765900536 0.275343017 0.828076679 1.749404233 1.276678701 0.003919396 4.740058349 0.059366823 1.978131529 ]';
D3 = [7.503974554 2.43552972 8.907981809 10.82563814 11.09197623 18.18846472 6.084768631 5.464296776 4.067161596 14.26678079 2.792424541 0.572435047 2.733751731 3.559015982 2.505767574 5.449188972 2.786168085 12.06056623 9.470572167 3.116171421 0.458594772 0.434307287 3.447147643 5.200432201 6.18563517 19.19753749 3.656691267 4.967834173 10.29317107 2.121656326 1.394653476 2.790630109 3.152455521 2.082149563 5.232312376 1.259368399 6.269558563 3.251263155 3.898594351 10.54554845 10.20258999 6.661139665 4.464739104 1.665067753 8.608715167 8.084037724 2.402608378 7.60967001 7.554079841 6.05757598 3.768961429 3.502224334 1.027846476 1.537041705 17.67476646 1.538015623 15.93866248 6.015687282 6.338130064 ]';
data = [D1 D2 D3];
% Requires R2019b or later
t = tiledlayout(2,2, 'Padding', 'none', 'TileSpacing', 'compact');
%box chart
b=boxchart(data);
b.BoxFaceColor = [0 0.4470 0.7410];
b.WhiskerLineColor = [0.17 0.17 0.17];
b.MarkerColor = [0 0.4470 0.7410];%black
b.JitterOutliers = 'on';
b.MarkerStyle = '.';
xlabel('x')
ylabel('y ')
title('Transparent background')
% Requires R2020a or later
exportgraphics(t,'boxPlot.jpg','BackgroundColor','none')
If you wish to maximize chart space, you may manipulate the axis location, as seen in the following code. If exporting transparency is also required, use the PDF format.
figure()
b=boxchart(data);
b.BoxFaceColor = [0 0.4470 0.7410];
b.WhiskerLineColor = [0.17 0.17 0.17];
b.MarkerColor = [0 0.4470 0.7410];%black
b.JitterOutliers = 'on';
b.MarkerStyle = '.';
xlabel('x')
ylabel('y ')
ax.Position=[0.07,0.1,0.92,0.9];

How to set the custom marker in MATLAB figure legend

I have an image as follows.
In this images you can see 3 lines, these are actually 6 lines, one line in invisible just for showing markers and other line is smoothened version of original data points. Now the issue is that how do I get the markers in legend. In this case, you can see the figure legend consists of just line, not the markers. My code is as follows.
clc; clear all ;
colour_green = [12 195 82] ./ 255;
colour_lightgreen = [94 250 81] ./ 255;
colour_lightblue = [8 180 238] ./ 255;
colour_darkblue = [1 17 181] ./ 255;
colour_peach = [251 111 66] ./ 255;
figure('DefaultAxesFontSize',30);
set(0,'DefaultAxesFontName',' Times ');
hold on
time_window = xlsread('pattern_data.xlsx', 'effect_of_count', 'A2:A12');
count1plus = xlsread('pattern_data.xlsx', 'effect_of_count', 'B2:B12');
count10plus = xlsread('pattern_data.xlsx', 'effect_of_count', 'C2:C12');
count1to5 = xlsread('pattern_data.xlsx', 'effect_of_count', 'D2:D12');
x1 = 50:1:99;
% x1 = .01:.01:.5;
x2 = interp1(time_window,count1plus,x1, 'pchip') ;
x3 = interp1(time_window,count10plus,x1, 'pchip') ;
x4 = interp1(time_window,count1to5,x1, 'pchip') ;
% count 1+
plot(x1,x2,'b--','DisplayName', 'Count_{A} = 1: and Count_{B} = 1:','LineWidth',3)
plot(time_window,count1plus,'bs', 'HandleVisibility','off','LineWidth',5)
% count 1:5
plot(x1,x4,'-','DisplayName', 'Count_{A} = 1: and Count_{B} = 5:','LineWidth',3 , 'Color', colour_green)
plot(time_window,count1to5,'^', 'HandleVisibility','off','LineWidth',5 , 'Color', colour_green)
% count 10+
plot(x1,x3,'r--','DisplayName', 'Count_{A} = 1: and Count_{B} = 10:','LineWidth',3)
plot(time_window,count10plus,'ro', 'HandleVisibility','off','LineWidth',5)
hold off
xlabel('Th_{B} ')
ylabel('L (milliseconds)')
legend('Location','north')
legend show
set(gcf, 'PaperUnits', 'normalized');
set(gcf, 'PaperPosition', [0 0 1 1]);
set(gcf,'PaperOrientation','l');
print -dpng graphs/p1_effect_of_count_and_selB;
Please help. What I want is to have a marker(circle, square etc.) in the respective legend.
Edit# 1
The solution provided here did not solve my problem as it did not illustrates how to add a marker. An animation shows how to customize the position of a marker, but here I want to add a new marker not re-position the original existing one.
As explained in this answer to a very similar question, since R2014b onward the legend object is kind of opaque and cannot be easily changed. However, that answer also shows that there is a syntax to the legend function with four output arguments, which creates the legend in a different way such that it can be modified. The answer also shows how to modify the legend. We'll follow their lead.
The documentation says about this syntax:
This syntax is not recommended. It creates a legend that does not support some functionality, such as adding a legend title. Also, the legend does not automatically update when you add or remove data series from the axes.
But in this case these issues don't bother us, so we'll continue along.
In the case of the graph in the question, we'll replace
legend('Location','north')
with
[lgd,icons,plots,txt] = legend('Location','north');
Now, icons contains handles to the objects that form the legend:
>> icons
icons =
9×1 graphics array:
Text (Count_{A} = 1: and Count_{B} = 1:)
Text (Count_{A} = 1: and Count_{B} = 5:)
Text (Count_{A} = 1: and Count_{B} = 10:)
Line (Count_{A} = 1: and Count_{B} = 1:)
Line (Count_{A} = 1: and Count_{B} = 1:)
Line (Count_{A} = 1: and Count_{B} = 5:)
Line (Count_{A} = 1: and Count_{B} = 5:)
Line (Count_{A} = 1: and Count_{B} = 10:)
Line (Count_{A} = 1: and Count_{B} = 10:)
The display even helpfully shows which elements belong to which item. The first three are text objects, the last 6 are line objects. These line objects are what we need to modify.
Why are there two line objects for each of the items shown in the legend? That is because there is one line object (the first one) that is the rendered line (it has two data points):
>> icons(4)
ans =
Line (Count_{A} = 1: and Count_{B} = 1:) with properties:
Color: [0 0 1]
LineStyle: '--'
LineWidth: 3
Marker: 'none'
MarkerSize: 6
MarkerFaceColor: 'none'
XData: [0.0108 0.0919]
YData: [0.8246 0.8246]
ZData: [1×0 double]
and the other that is the marker (currently not visible, it has one data point):
>> icons(5)
ans =
Line (Count_{A} = 1: and Count_{B} = 1:) with properties:
Color: [0 0 1]
LineStyle: 'none'
LineWidth: 3
Marker: 'o'
MarkerSize: 6
MarkerFaceColor: 'none'
XData: 0.0514
YData: 0.8246
ZData: [1×0 double]
So, what we need to do is set these marker objects:
icons(5).Marker = 's';
icons(7).Marker = '^';
icons(9).Marker = 'o';
Now the plot looks like you wanted.
I hope that the description above is clear enough that you can now change the legend in other ways too.

PCA with colorbar

I have this data of which I want to make a principal component analysis.
In particular for each data point I want to associate a color.
This is my code:
for ii=1:size(SBF_ens,1)
SBF(ii) = SBF_ens(ii, max(find(SBF_ens(ii,:)~=0)) ); %value at the moment of the measurement
end
%matrix of data
toPCA =[
wind_trend_72h_ens-nanmean(wind_trend_72h_ens);
wind_trend_24h_ens-nanmean(wind_trend_24h_ens);
wind_trend_12to18h_ens-nanmean(wind_trend_12to18h_ens);
wind_trend_0to12h_ens-nanmean(wind_trend_0to12h_ens);
wind_trend_last6h_ens-nanmean(wind_trend_last6h_ens);
Mwind12h_ens-nanmean(Mwind12h_ens);
Mwind24h_ens-nanmean(Mwind24h_ens);
SBF-nanmean(SBF)]';
variables = { 'wt72h','wt24h','wt12to18h','wt0to12h','wtLast6h','Mw12h', 'Mw24h', 'SBF'}; %labels
%PCA algorithm
C = corr(toPCA,toPCA);
w = 1./var(toPCA);
[wcoeff,score,latent,tsquared,explained] = pca(toPCA,'VariableWeights',w);
coefforth = diag(sqrt(w))*wcoeff;
metric=decstd_ens; %metric for colorbar
hbi=biplot(coefforth(:,1:2),'scores',score(:,1:2),'varlabels',...
variables,'ObsLabels', num2str([1:length(toPCA)]'),...
'markersize', 15);
%plotting
cm = autumn;
colormap(cm);
for ii = length(hbi)-length(toPCA):length(hbi)
userdata = get(hbi(ii), 'UserData');
if ~isempty(userdata)
indCol = ceil( size(cm,1) * abs(metric(userdata))/max(abs(metric)) );%maps decstd between 0 and 1 and find the colormap index
if indCol==0 %just avoid 0
indCol=1;
end
col = cm(indCol,:); %color corresponding to the index
set(hbi(ii), 'Color', col); %modify the dot's color
end
end
for ii = 1:length(hbi)-length(toPCA)-1 %dots corresponding to the original dimensions are in black
set(hbi(ii), 'Color', 'k');
end
c=colorbar;
ylabel(c,'decstd') %is this true?
xlabel(['1^{st} PCA component ', num2str(explained(1)), ' of variance explained'])
ylabel(['2^{nd} PCA component ', num2str(explained(2)), ' of variance explained'])
The resulting figure is the following:
Everything is fine except for the colorbar range. In fact decstd has values between 0 and 2. Actually I do not understand at all what the values on the colorbar are.
Does anyone understand it?
Is it possible to rethrive the data in the colorbar? So to understand what they are?
size(autumn)
shows you that the default length of the autumn colourmap (actually of all the colourmaps) is 64. When you call colorbar, by default it will use tick labels from 1 to n where n is the length of your colourmap, in this case 64.
If you want the mapping of the colourbar ticklabels to match the mapping that you used to get your data to fit between 1 and 64 (i.e. this line of yours indCol = ceil( size(cm,1) * abs(metric(userdata))/max(abs(metric)) );), then you will need to set that yourself like this
numTicks = 6;
cAxisTicks = linspace(min(metric), max(metric), numTicks); % or whatever the correct limits are for your data
caxis([min(metric), max(metric)]);
set(c,'YTick', cAxisTicks );

Add legend to graph created iteratively

I am creating a graph iteratively from various data sets, and I try to add legend to it, but it fails.
colors = {'g','b','m','k','c'};
subplot(2,3,iii);
hold all;
for jjj=1:length(aggregation_methods),
aggregate = all_aggregate{jjj};
std_agg = all_std_agg{jjj};
plot(coverages, aggregate, colors{jjj});
h1 = errorbar(coverages,aggregate,std_agg,colors{jjj});
set(h1,'linestyle','none')
end
plot(coverages, regular, 'r');
h1 = errorbar(coverages,regular,std_reg,'r');
set(h1,'linestyle','none')
title(datasets{iii});
xlabel('coverage');
ylabel('MSE');
legend('enhanced with clustering(k=4)','enhanced random split', 'regular we');
The graph seems to be generated just fine, it's just the legend that is failing.
I expect the colors of the legend to be (top-down): green, blue, red.
P.S. I also tried (and it didn't work):
legend({'enhanced with clustering(k=4)','enhanced random split', 'regular we'});
EDIT:
Inspired by this thread, I changed the code to use the 'DisplayName' property for each plot:
colors = {'g','b','m','k','c'};
names = {'enhanced with clustering(k=4)','enhanced random split', 'regular we'};
subplot(2,3,iii);
hold all;
for jjj=1:length(aggregation_methods),
aggregate = all_aggregate{jjj};
std_agg = all_std_agg{jjj};
plot(coverages, aggregate, colors{jjj}, 'DisplayName', names{jjj});
h1 = errorbar(coverages,aggregate,std_agg,colors{jjj});
set(h1,'linestyle','none')
end
%plot(coverages,aggregate,'g',coverages ,regular,'r');
%h1 = errorbar(coverages,aggregate,std_agg,'g');
%set(h1,'linestyle','none')
plot(coverages, regular, 'r', 'DisplayName', names{length(aggregation_methods) + 1});
h1 = errorbar(coverages,regular,std_reg,'r');
set(h1,'linestyle','none')
%axis([0 1 0 max(mean(rc{iii}))]);
title(datasets{iii});
xlabel('coverage');
ylabel('MSE');
legend('show');
However, it yields the following legend, but I'd like to get rid of these 'dataX' strings.
a=[
1 2 3
4 5 6
7 8 9
];
clist={'g','b','m'};
for i=1:3
pt(i)=plot(a(i,:),'Color',clist{i});
hold on;
end
b=[5 6 7];
pt(4)=plot(b,'Color','r');
legend([pt(1:2) pt(4)],{'line1','line2','line4'});

Most efficient way of drawing grouped boxplot matlab

I have 3 vectors: Y=rand(1000,1), X=Y-rand(1000,1) and ACTid=randi(6,1000,1).
I'd like to create boxplots by groups of Y and X corresponding to their group value 1:6 (from ACTid).
This is rather ad-hoc and looks nasty
for ii=
dummyY(ii)={Y(ACTid==ii)};
dummyX(ii)={X(ACTid==ii)}
end
Now I have the data in a cell but can't work out how to group it in a boxplot. Any thoughts?
I've found aboxplot function that looks like this but I don't want that, I'd like the builtin boxplot function because i'm converting it to matlab2tikz and this one doesn't do it well.
EDIT
Thanks to Oleg: we now have a grouped boxplot... but the labels are all skew-whiff.
xylabel = repmat({'Bleh','Blah'},1000,1); % need a legend instead, but doesn't appear possible
boxplot([Y(:,end); cfu], {repmat(ACTid,2,1), xylabel(:)} ,'factorgap',10,'color','rk')
set(gca,'xtick',1.5:3.2:50)
set(gca,'xticklabel',{'Direct care','Housekeeping','Mealtimes','Medication','Miscellaneous','Personal care'})
>> ylabel('Raw CFU counts (Y)')
How to add a legend?
I had the same problem with grouping data in a box plot. A further constraint of mine was that different groups have different amounts of data points. Based on a tutorial I found, this seems to be a nice solution I wanted to share with you:
x = [1,2,3,4,5,1,2,3,4,6];
group = [1,1,2,2,2,3,3,3,4,4];
positions = [1 1.25 2 2.25];
boxplot(x,group, 'positions', positions);
set(gca,'xtick',[mean(positions(1:2)) mean(positions(3:4)) ])
set(gca,'xticklabel',{'Direct care','Housekeeping'})
color = ['c', 'y', 'c', 'y'];
h = findobj(gca,'Tag','Box');
for j=1:length(h)
patch(get(h(j),'XData'),get(h(j),'YData'),color(j),'FaceAlpha',.5);
end
c = get(gca, 'Children');
hleg1 = legend(c(1:2), 'Feature1', 'Feature2' );
Here is a link to the tutorial.
A two-line approach (although if you want to retain two-line xlables and center those in the first line, it's gonna be hackish):
Y = rand(1000,1);
X = Y-rand(1000,1);
ACTid = randi(6,1000,1);
xylabel = repmat('xy',1000,1);
boxplot([X; Y], {repmat(ACTid,2,1), xylabel(:)} ,'factorgap',10)
The result:
EDIT
To center labels...
% Retrieve handles to text labels
h = allchild(findall(gca,'type','hggroup'));
% Delete x, y labels
throw = findobj(h,'string','x','-or','string','y');
h = setdiff(h,throw);
delete(throw);
% Center labels
mylbl = {'this','is','a','pain','in...','guess!'};
hlbl = findall(h,'type','text');
pos = cell2mat(get(hlbl,'pos'));
% New centered position for first intra-group label
newPos = num2cell([mean(reshape(pos(:,1),2,[]))' pos(1:2:end,2:end)],2);
set(hlbl(1:2:end),{'pos'},newPos,{'string'},mylbl')
% delete second intra-group label
delete(hlbl(2:2:end))
Exporting as .png will cause problems...