MATLAB Multiple(parallel) box plots in single figure - matlab

I'm using the boxplot function in MATLAB. I need to plot boxplots for 6 different datasets for 6 'XTicks' i.e each tick in the x axis should contain 6 corresponding boxes, whiskers, median lines and set of outliers within it's domain. I tried manipulating the 'XTick' property by setting offsets for each variable, but it doesn't apply for boxplot() as it would for a normal plot(). I'm also not able to add legends.
A 3 variable equivalent of my problem would like the following:
Edit:
The following is the code snippet that needs to be modified
TreadmillData = randi([20,200],69,6);
Speeds = {'1.5mph' '2.5mph' '3.5mph' '4.5mph' '5.5mph' '6.5mph'};
DeviceColors = {'r' 'g' 'c' [0.5 0 0.5] 'b' [1 0.5 0]};
Pedometer1 = TreadmillData(1:7:end,:);
Pedometer2 = TreadmillData(2:7:end,:);
Pedometer3 = TreadmillData(3:7:end,:);
Pedometer4 = TreadmillData(4:7:end,:);
Pedometer5 = TreadmillData(5:7:end,:);
Pedometer6 = TreadmillData(6:7:end,:);
GroupedData = {Pedometer1 Pedometer2 Pedometer3 Pedometer4 Pedometer5 Pedometer6};
legendEntries = {'dev1' 'dev2' 'dev3' 'dev4' 'dev5' 'dev6'};
figure;
Xt = 20:20:120;
Xt_Offset = [-15,-10,-5,5,10,15];
for i=1:6
boxplot(GroupedData{i},'Color',DeviceColors{i});
set(gca,'XTick',Xt+Xt_Offset(i));
if i==3
set(gca,'XTickLabel',Speeds);
end
hold on;
end
xlabel('Speed');ylabel('Step Count'); grid on;
legend(legendEntries);
Any help would be appreciated!

I've made some modifications to your code. I've tested this in R2014b.
TreadmillData = randi([20,200],69,6);
Speeds = {'1.5mph' '2.5mph' '3.5mph' '4.5mph' '5.5mph' '6.5mph'};
DeviceColors = {'r' 'g' 'c' [0.5 0 0.5] 'b' [1 0.5 0]};
Pedometer1 = TreadmillData(1:7:end,:);
Pedometer2 = TreadmillData(2:7:end,:);
Pedometer3 = TreadmillData(3:7:end,:);
Pedometer4 = TreadmillData(4:7:end,:);
Pedometer5 = TreadmillData(5:7:end,:);
Pedometer6 = TreadmillData(6:7:end,:);
GroupedData = {Pedometer1 Pedometer2 Pedometer3 Pedometer4 Pedometer5 Pedometer6};
legendEntries = {'dev1' 'dev2' 'dev3' 'dev4' 'dev5' 'dev6'};
N = numel(GroupedData);
delta = linspace(-.3,.3,N); %// define offsets to distinguish plots
width = .2; %// small width to avoid overlap
cmap = hsv(N); %// colormap
legWidth = 1.8; %// make room for legend
figure;
hold on;
for ii=1:N %// better not to shadow i (imaginary unit)
%if ii~=ceil(N/2)
% labels = repmat({''},1,N); %// empty labels
%else
labels = Speeds; %// center plot: use real labels
%end
boxplot(GroupedData{ii},'Color', DeviceColors{ii}, 'boxstyle','filled', ...
'position',(1:numel(labels))+delta(ii), 'widths',width, 'labels',labels)
%// plot filled boxes with specified positions, widths, labels
plot(NaN,1,'color',DeviceColors{ii}); %// dummy plot for legend
end
xlabel('Speed'); ylabel('Step Count'); grid on;
xlim([1+2*delta(1) numel(labels)+legWidth+2*delta(N)]) %// adjust x limits, with room for legend
legend(legendEntries);

Here is a solution for plotting several boxplot. You have to group all the data in a single matrix, each group being separated by a column of Nan. After that, you can simply plot a single regular boxplot with ad-hoc options such as colors and labels.
The following example uses 2 groups of 3, so 7 columns. The 4 first lines of data:
0.6993 0.0207 -0.7485 NaN 0.5836 -0.1763 -1.8468
-0.0494 -1.5411 0.8022 NaN 2.7124 -0.0636 -2.3639
0.9134 0.7106 -0.1375 NaN -0.2200 -0.2528 -0.8350
-0.5655 1.3820 0.6038 NaN -0.7563 -0.9779 0.3789
And the code:
figure('Color', 'w');
c = colormap(lines(3));
A = randn(60,7); % some data
A(:,4) = NaN; % this is the trick for boxplot
C = [c; ones(1,3); c]; % this is the trick for coloring the boxes
% regular plot
boxplot(A, 'colors', C, 'plotstyle', 'compact', ...
'labels', {'','ASIA','','','','USA',''}); % label only two categories
hold on;
for ii = 1:3
plot(NaN,1,'color', c(ii,:), 'LineWidth', 4);
end
title('BOXPLOT');
ylabel('MPG');
xlabel('ORIGIN');
legend({'SUV', 'SEDAN', 'SPORT'});
set(gca, 'XLim', [0 8], 'YLim', [-5 5]);

Related

YTickLabel will be shown with some specified value (not show all) in Matlab

I have code and the result as below:
%% How to plot each matrix in a cell in 3d plot(1 matrix with 1 color) ?
% Generate Sample data cell A(1x10 cell array)
clear; clc;
A = cell(1,10); % cell A(1x10 cell array)
for kk = 1:numel(A)
z = 10*rand()+(0:pi/50:10*rand()*pi)';
x = 10*rand()*sin(z);
y = 10*rand()*cos(z);
A{kk} = [x,y,z];
end
A_6 = A(1:6); % generate a cell with the first 6 matrices in "A" cell array
% The numer "6" can be changed to be any number which you want to plot them by colormap
newA = vertcat(A_6{:}); %Concatenating all matrices inside A vertically
numcolors = numel(A_6); %Number of matrices equals number of colors
colourRGB = hsv(numcolors); %Generating colours to be used using hsv colormap
colourtimes = cellfun(#(x) size(x,1),A_6);%Determining num of times each colour will be used
colourind = zeros(size(newA,1),1); %Zero matrix with length equals num of points
colourind([1 cumsum(colourtimes(1:end-1))+1]) = 1;
colourind = cumsum(colourind); %Linear indices of colours for newA
scatter3(newA(:,1), newA(:,2), newA(:,3), [], colourRGB(colourind,:),'filled');
%if you want to specify the size of the circles, use the following line instead:
% scatter3(newA(:,1), newA(:,2), newA(:,3), colourind , colourRGB(colourind,:),'filled');
grid on;
view(3); %view in 3d plane
colormap(colourRGB); %using the custom colormap of the colors we used
%Adjusting the position of the colorbar ticks
caxis([1 numcolors]);
colorbar('YTick',[1+0.5*(numcolors-1)/numcolors:(numcolors-1)/numcolors:numcolors],'YTickLabel', num2str([1:numcolors]'), 'YLim', [1 numcolors]);
I have the image like this:
How can I shown "YTickLabel" with some specified value (not show all) as below figure?
Taking the code from your comment to the previous answer:
h = colorbar('YTick',[1:numcolors],'YTickLabel', num2str([1:numcolors]'), 'YLim', [1 numcolors]); set(h, 'Ticklabels', {1 [] 3 [] 5 6}); set(h, 'Ticks', {1 3 5 6});
You are now setting 6 tick labels for only 4 ticks. If set the ticks to the correct values, then the auto-generated tick labels will be what you want.
Try the following:
h = colorbar('YTick',[1:numcolors],'YTickLabel', num2str([1:numcolors]'), 'YLim', [1 numcolors]);
set(h, 'Ticks', {1 3 5 6});
To remove some ticks with their labels, just set the 'YTick' property of the colorbar accordingly. That is, replace your last line by something like:
colorbar('YTick', [1 3 5 6], 'YLim', [1 numcolors])

Adding a legend when using imagesc, including white for NaN

I have a 35x43 matrix of data with vales ranging from 1-6 and lots of NaNs.
I want to NaNs to be white, and the numbers to each be a different colour. I need a legend with the 6 different colour and labels on it.
I can achieve most of this with the following code, however the colours in the legend do not match the colours in the figure. See code below
figure(6)
subplot(1,2,1)
imagesc(lut)
title('Highest Weighted Predictor variable for each Pixel')
ylabel('Longitude')
xlabel('Latitude')
caxis([0, 7])
myColorMap = jet(7);
myColorMap(1,:) = 1;
colormap(myColorMap);
M = jet(7); % Notice the 3, here and below
hold on
L = line(ones(7),ones(7));
set(L,{'color'},mat2cell(M,ones(1,7),3))
[legh,objh,outh,outm] = legend('First','Second','Location','Southeast');
set(objh,'linewidth',200);
legend('Forest','Shrubland','Savanna','Grassland','Agricultural','Barron');
grid on
ax = gca
ax.GridAlpha = .2
ax.XTick = [5 10 15 20 25 30 35 40];
ax.YTick = [5 10 15 20 25 30];
ax.XTickLabel = {'118^{o}E','123^{o}E','128^{o}E', '133^{o}E', '138^{o}E', '143^{o}E','148^{o}E', '153^{o}E'};
ax.YTickLabel = {'13^{o}S','18^{o}S','23^{o}S','28^{o}S','33^{o}S','38^{o}S'};
ax.TickLength =[0.0 0.0]
To display the NaN values as white I would use something like this. Then for your colormap, just use jet(6). Then the colors will match up just fine.
lut = [1:6 NaN];
myColorMap = jet(6);
imagesc(lut, 'AlphaData', ~isnan(lut))
colormap(myColorMap);
L = line(ones(6), ones(6));
set(L, {'Color'}, num2cell(myColorMap, 2))
legend(L, {'Forest','Shrubland','Savanna','Grassland','Agricultural','Barron'})
I would suggest an alternative solution using a colorbar with individual ticks:
%// example data
lut = randi(6,35,43);
lut(1:23:end) = NaN;
%// parts of your your code
figure(6)
% subplot(1,2,1)
imagesc(lut)
title('Highest Weighted Predictor variable for each Pixel')
ylabel('Longitude')
xlabel('Latitude')
caxis([0, 7])
myColorMap = jet(7);
myColorMap(1,:) = 1;
colormap(myColorMap);
M = jet(7); % Notice the 3, here and below
hold on
%// colorbar
c = colorbar
c.Ticks = (1:6)+0.5
c.TickLabels = {'Forest','Shrubland','Savanna','Grassland','Agricultural','Barron'}

How to fix the legend of this boxplot in matlab?

The legend of this boxplot comes with the same color! How can I fix this? How can I move the x-axis lable a little bit lower ?Thanks for your help.
close all
clc;clear;
f=figure;
Temp_O=[-0.234115422389688;-0.153751688636750;3.03158128172032;-0.746185319551222;0.491616009046725;1.17490826218458;0.495331079652895;0.757394580248284;1.28467417069223;0.710444835069366;-0.979521722186138;-0.216850422633648;0.0596632891728577;-0.525362330358090;0.681608181821661;-0.995216710339821;-0.706416688978551;-0.147700048468633;-0.145946504735073;0.355209739265580;1.25860455564176;0.970569089382961;3.99404165520844;0.433235373567272;1.37023527554759;1.45032207715449;2.00968917969203;0.840884198707613;2.08558564237223;2.05435556980046;-15.5517060656394;3.18991806590028;1.28277879106186;2.15931490153483;3.19647581545030;2.97877640768595;0.0857405478541730;-1.59362648933500;-2.18109410889313;0.751077088333943;0.795072796032814;4.18896005388773;-0.591461781602054;-0.229818549439720];
position_O = 5:5:25;
position_O=position_O';
g = [ones(10,1); 2*ones(10,1); 3*ones(10,1) ;4*ones(10,1);5*ones(4,1)];
box_O = boxplot(Temp_O,g,'colors','b','positions',position_O,'width',0.8);
h=findobj(gca,'tag','Outliers');
delete(h)
set(gca,'XTickLabel',{' '})
hold on
Temp_S=[-0.234069549668875;-0.0803021151079149;0.166729084507040;-0.991371043478263;0.320651878289472;0.118699258741257;-0.190944834558825;0.540367970198674;1.02556298920863;0.112849364285713;-0.395341229166667;0.382362326388889;-1.40591456976744;0.247202120000001;-1.33262568333333;-1.27793610544218;0.0400995141843974;-1.32333150653595;-1.84221947163121;0.407607340136054;0.264276120300749;-0.337747273809525;1.03841878571429;-1.41048786507936;0.901727821428570;-1.03012908482143;2.69786876785714;-0.691010535714286;1.66913088345865;0.684260974489794;-10.3923539047619;1.04994314285714;2.13557031632653;3.87736348701299;7.38705700000000;0.0451628482142860;-3.69094742857143;-1.14071104081633;-3.15830153968254;-4.41399970408163;6.09908001655629;0.0267684861111112;-2.67854298170732;0.925146217948717;];
position_S = 6.8:5:26.8;
position_S=position_S';
box_S = boxplot(Temp_S,g,'colors','r','positions',position_S,'width',0.8);
h=findobj(gca,'tag','Outliers');
delete(h)
legend(findobj(gca,'Tag','Box'),'Group1','Group2')
set(gca,'XTickLabel',{' '}) ;
hold off
text('Position',[5,-11],'String','S')
text('Position',[10,-11],'String','M')
text('Position',[15,-11],'String','L')
text('Position',[20,-11],'String','V')
text('Position',[25,-11],'String','C')
xlabel('Types','FontSize',10);
% set(get(gca, 'XLabel'), 'Position', [0 .2 0]); %
ylim([-10.5 7.8]);
The issue is that you're only displaying the legend for the first two boxes (yours has a total of 10 boxes) and both of these are red. The first 5 boxes that are found are red and the last 5 are blue. Instead you could use the first and last box.
%// Create the box plot
box_S = boxplot(Temp_S, g, 'colors', 'r', 'positions', position_S, 'width', 0.8);
%// Get all of the box plot objects
boxes = findobj(gca, 'Tag', 'Box');
legend(boxes([end 1]), 'Group1', 'Group2')
You could do this more robustly though with the following:
boxes = findobj(gca, 'Tag', 'box');
%// Sort by xposition
[~, ind] = sort(cellfun(#mean, get(boxes, 'XData')));
%// Apply legends to one red and one blue one.
legend(boxes(ind(1:2)), 'Group1', 'Group2');
And to move the xlabel a little lower, you can simply adjust it's Position property.
yrange = diff(get(gca, 'YLim'));
XL = get(gca, 'XLabel');
original = get(XL, 'Position');
%// Add an extra 1% padding
set(XL, 'Position', original - [0 0.01*yrange 0])
Here is a small example (I only kept the necessary stuff):
x1 = randn(44,1);
x2 = randn(44,1);
pos1 = (5:5:25)';
pos2 = (6.8:5:26.8)';
g = repelem([1 2 3 4 5], [10 10 10 10 4]);
h1 = boxplot(x1, g, 'Colors','b', 'Positions',pos1, 'Width',0.8);
hold on
h2 = boxplot(x2, g, 'Colors','r', 'Positions',pos2, 'Width',0.8);
hold off
legend([h1(5,1),h2(5,1)], {'Group1','Group2'})
To quote help boxplot:
% H = BOXPLOT(...) returns the handle H to the lines in the box plot.
% H has one column per box, consisting of the handles for the various
% parts of the box. For the traditional plotstyle, the rows correspond
% to: upper whisker, lower whisker, upper adjacent value, lower adjacent
% value, box, median, and outliers. For the compact plotstyle, the rows
% correspond to: whiskers, box, median outer, median inner, and outliers.
% If median comparison intervals are indicated with markers, H will have
% two more rows for notch lo and notch hi. If medianstyle or boxstyle
% have been set explicitly, the meaning of the rows will adjust
% accordingly.

Change color of each point in scatter plot sequentially

I am new to Matlab, I was trying to you scatter plot to plot 4 points in an axes.
for example
x = [0;0;1;-1];
y = [1;-1;0;0];
scatter(x,y);
what I wanted to do was to change the color of one coordinate in the above plot continuously in clock wise direction
Like the above pic.
If not is there another way I can do so?
Thanks in advance.
You can add a 4th argument to scatter in order to set the color (the 3rd argument sets the size, you can leave it empty):
col = lines(4); % create 4 colors using the 'lines' colormap
scatter(x,y,[],col);
You can use some other colormaps (type doc colormap in Matlab for more details), or just enter some vector of numbers to use the current colormap.
Edit I've just realized you wanted to change the color of only one point; you can do it with (for example) col = [2 1 1 1].
You need to plot each point separately, get a handle to each, and then change their 'color' property sequentially in a loop:
%// Data
x = [-1;0;1;0]; %// define in desired (counterclockwise) order
y = [0;1;0;-1];
color1 = 'g';
color2 = 'r';
%// Initial plot
N = numel(x);
h = NaN(1,N);
hold on
for n = 1:N
h(n) = plot(x(n), y(n), 'o', 'color', color1);
end
axis([-1.2 1.2 -1.2 1.2]) %// set as desired
%// Change color of one point at a time, and restore the rest
k = 0;
while true
k = k+1;
pause(.5)
n = mod(k-1,N)+1;
set(h(n), 'color', color2);
set(h([1:n-1 n+1:end]), 'color', color1);
end

Combine the legends of shaded error and solid line mean

I am using this FEX entry to plot the horizontal shaded error bars for a variable plotted on the X-axis. This variable is plotted in different regions/zones and, therefore, there are 3 shaded error bars for 3 zones. I would like to combine the legends of the error bars (shaded region) as well as the mean (solid line) of any zone into a single legend represented by a solid line (or solid line inside a patch) of the same color as the zone.
THE WAY MY CODE WORKS FOR PLOTTING: A synthetic example of the way I am plotting is shown below
fh = figure();
axesh = axes('Parent', fh);
nZones = 4;
nPts = 10;
X = nan*ones(nPts, nZones);
Y = nan*ones(nPts, nZones);
XError = nan*ones(10, 4);
clr = {'r', 'b', 'g', 'm', 'y', 'c'};
for iZone = 1:nZones
X(:, iZone) = randi(10, nPts, 1);
Y(:, iZone) = randi(10, nPts, 1);
XError(:, iZone) = rand(nPts, 1);
% Append Legend Entries/Tags
if iZone == 1
TagAx = {['Zone # ', num2str(iZone)]};
else
TagAx = [TagAx, {['Zone # ', num2str(iZone)]}];
end
hold(axesh, 'on')
[hLine, hPatch] = boundedline(X(:, iZone), Y(:, iZone), XError(:, iZone),...
strcat('-', clr{iZone}), axesh, 'transparency', 0.15,...
'orientation', 'horiz');
legend(TagAx);
xlabel(axesh, 'X', 'Fontweight', 'Bold');
ylabel(axesh, 'Y', 'Fontweight', 'Bold');
title(axesh, 'Error bars in X', 'Fontweight', 'Bold');
end
THE WAY LEGENDS ARE SHOWING-UP CURRENTLY:
WHAT I HAVE TRIED:
As someone suggested in the comment section of that file's FEX page to add the following code after line 314 in boundedline code.
set(get(get(hp(iln),'Annotation'),'LegendInformation'),'IconDisplayStyle','off');
However, on doing that I get this error:
The name 'Annotation' is not an accessible property for an instance of
class 'root'.
EDIT: The first two answers suggested accessing the legend handles of the patch and line which are returned as output the by the function boundedline. I tried that but the problem is still not solved as the legend entries are still not consistent with the zones.
There is a direct general way to control legends. You can simply choose not to display line entries by fetching their 'Annotation' property and setting the 'IconDisplayStyle' to 'off'.
Also, in order to use chadsgilbert's solution, you need to collect each single patch handle from every loop iteration. I refactored your code a bit, such that it would work with both solutions.
% Refactoring you example (can be fully vectorized)
figure
axesh = axes('next','add'); % equivalent to hold on
nZones = 4;
nPts = 10;
clr = {'r', 'b', 'g', 'm', 'y', 'c'};
X = randi(10, nPts, nZones);
Y = randi(10, nPts, nZones);
XError = rand(nPts, nZones);
% Preallocate handles
hl = zeros(nZones,1);
hp = zeros(nZones,1);
% LOOP
for ii = 1:nZones
[hl(ii), hp(ii)] = boundedline(X(:, ii), Y(:, ii), XError(:, ii),...
['-', clr{ii}], 'transparency', 0.15, 'orientation', 'horiz');
end
The simplest method as shown by chadsgilbert:
% Create legend entries as a nZones x 8 char array of the format 'Zone #01',...
TagAx = reshape(sprintf('Zone #%02d',1:nZones),8,nZones)'
legend(hp,TagAx)
... or for general more complex manipulations, set the legend display properties of the graphic objects:
% Do not display lines in the legend
hAnn = cell2mat(get(hl,'Annotation'));
hLegEn = cell2mat(get(hAnn,'LegendInformation'));
set(hLegEn,'IconDisplayStyle','off')
% Add legend
legend(TagAx);
There is not an easy way to do this, You have to go into the legend and shift things up:
The following makes a sample plot where the mean lines are not superimposed on the bound patches.
N = 10;
x = 1:N;
y = sin(x);
b = ones([N,2,1]);
[hl, hp] = boundedline(x, y, b);
lh = legend('hi','');
We get a structure g associated with the legend handle lh. If you look at the types of the children, you'll see that g2 is the mean line and g4 is the patch. So I got the vertices of the patch and used it to shift the mean line up.
g = get(lh);
g2 = get(g.Children(2));
g4 = get(g.Children(4));
v = g4.Vertices;
vx = unique(v(:,1));
vy = diff(unique(v(:,2)))/2;
vy = [vy vy] + min(v(:,2));
set(g.Children(2), 'XData', vx);
set(g.Children(2), 'YData', vy);
Not a simple answer, and definitely requires you do a crazy amount of formatting for a plot with more than one mean line/patch pair, especially since it will leave gaps in your legend where the last zone's mean line was.
As per your comment, if you just want the shaded error bars to mark the legend then it's pretty easy:
x = 0:0.1:10;
N = length(x);
y1 = sin(x);
y2 = cos(x);
y3 = cos(2*x);
b1 = ones([N,2,1]);
b2 = 0.5*ones([N,2,1]);
b3 = 0.1*ones([N,2,1]);
hold on
[hl, hp] = boundedline(x, y1, b1, 'r', x, y2, b2, 'b', x, y3, b3,'c')
lh = legend('one','two','three');
That's a nice FEX entry. You can associate a specific set of handles with a legend. And luckily, boundedline already returns the handles to the lines separately from the handles to the patches.
>> [hl,hp] = boundedline([1 2 3],[4 5 6], [1 2 1],'b',[1 2 3],-[4 5 6],[2 1 1],'r');
>> %legend(hl,{'blue line' 'red line'}); % If you want narrow lines in the legend
>> legend(hp,{'blue patch' 'red patch'}); % If you want patches in the legend.