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.
Related
I was trying to create "consulting" waterfall chart in matlab, and I am having a really difficult time in creating it. I was expecting actually that there would be a built in way of doing that.
Given this data:
x = [5, 2, -5, 8, 2, 12];
total = [1, 0, 0 ,0 ,0, 1];
I want to make a waterfall chart.
Basically, the vector x has the values for the chart and the vector total indicates whether the corresponding column is a total column or not.
So the first column, is a 5 and is a total column. The second column is a two and it is not (so it adds up). The third column is minus five so it subtracts, and so on and so forth until the last column which is a total again. Below how the figure would look like.
1) How to get this figure?
2) How to color increases, decreases and totals with different colors?
3) How to include the connecting lines?
Method 1
Here's one possible solution using MATLAB's bar function.
Assumptions:
The total columns are always the first and last columns.
The basic idea is to use the 'Baseline' property of a Bar object, which allows a particular bar to start from a specific value. For example, bar([1,3,5], 'BaseValue', 2) produces 3 bars that start from the value 2: the first going down by 1 unit, the second going up by 1 unit, and the last going up by 3 units.
From testing on R2019b, unfortunately it appears that all Bar objects on an Axes must share the same BaseValue. Thus, for each Bar object to have its own Baseline value, each of them must be on a separate Axes object. We can workaround this by overlaying a bunch of Axes (one for each Bar) on top of each other, making all but one of them transparent. This way all bars will be visible.
Anyways, here's the function. The inputs are
ax (optional): a handle to an existing Axes object. You may want to do this if you have other things plotted already, or if you want to manually set various properties of an Axes.
y: a vector of all the incremental values. Note: the final value is NOT required, i.e. to reproduce the plot in the question, use y=[5, 2, -5, 8, 2];
The function outputs the handles to each Bar object created. You may want this to further change the EdgeColor of the Bars.
function h = wfall(ax, y)
if nargin == 1
y = ax;
ax = gca;
end
if ~strcmp(ax.NextPlot, 'add')
fprintf('hold on not set for current axes. Overriding.\n');
hold(ax, 'on');
end
y = y(:); % column vector
n = length(y);
cumy = cumsum(y);
set(ax, 'XLim', [0, n+1]+0.5, 'YLim', [min(min(cumy), 0), max(max(cumy), 0)]);
% colors:
% decrease - red - code as -1
% total - black - code as 0
% increase - blue - code as 1
set(ax, 'CLim', [-1, 1], 'ColorMap', [1 0 0; 0 0 0; 0 0 1]);
% copy a bunch of axes
for i = 1:n
ax(i+1) = copyobj(ax(1), ax(1).Parent);
end
% Make all subsequent axes invisible
% Make sure all axes will always be the same size by linking properties
set(ax(2:end), 'Color', 'none', 'XColor', 'none', 'YColor', 'none');
linkprop(ax, {'XLim', 'YLim', 'Position', 'DataAspectRatio'});
% define from/to of each bar (except 1st and last)
from = cumy(1:n-1);
to = cumy(2:n);
% color of each bar (except 1st and last)
c = double(y>0) - double(y<0);
c(1) = [];
% first total bar
h = bar(ax(1), 1, from(1), 'CData', 0, 'BaseValue', 0);
% 2nd to 2nd last bars
for i = 1:n-1
h(end+1) = bar(ax(i+1), i+1, to(i), 'CData', c(i), 'BaseValue', from(i), 'ShowBaseLine', 'off');
end
% last total bar
h(end+1) = bar(ax(1), n+1, cumy(n), 'CData', 0);
% setting FaceColor flat makes the Bars use the CData property
set(h, 'FaceColor', 'flat')
Run the code as follows to produce the following plot.
close all;
ax = gca;
h = wfall(ax, y(1:end-1));
Method 2
Here's another solution if you prefer not to stack Axes objects on top of each other.
In this case, we make an additional assumption:
The cumulative value is never negative (this would apply, for example, the cash in my pocket)
Simply, each bar we draw can be considered as one colored bar (either blue/red) that is partially covered by a shorter white bar.
function h = wfall2(ax, y)
if nargin == 1
y = ax;
ax = gca;
end
if ~strcmp(ax.NextPlot, 'add')
fprintf('hold on not set for current axes. Overriding.\n');
hold(ax, 'on');
end
y = y(:); % column vector
n = length(y);
cumy = cumsum(y);
from = cumy(1:n-1);
to = cumy(2:n);
% color values:
% 1 - blue (increase)
% 0 - white
% -1 - red (decrease)
c = double(y>0) - double(y<0);
c(1) = [];
upper = max(cumy(1:n-1), cumy(2:n));
lower = min(cumy(1:n-1), cumy(2:n));
h(1) = bar(ax, 2:n, upper, 'FaceColor', 'flat', 'CData', c);
h(2) = bar(ax, 2:n, lower, 'FaceColor', 'w');
h(3) = bar(ax, 1, cumy(1), 'FaceColor', 'k');
h(4) = bar(ax, n+1, cumy(n), 'FaceColor', 'k');
set(h, 'EdgeColor', 'none')
set(ax, 'CLim', [-1, 1], 'ColorMap', [1 0 0; 0 0 0; 0 0 1]);
Run the function as follows:
close all;
ax = gca;
h = wfall2(ax, y(1:end-1));
The resulting plot:
The result, however, is a bit ugly by my personal standards, since the white bar will partially cover the x-axis. You can fix this, however, by setting the lower YLim to a negative value, i.e. set(ax, 'YLim', [-0.5 inf])
Here is the sample code that i used to compare two groups with random mean and standard deviation. However, i want to plot both groups in a single box in the box plot as shown in the attached figure where x-axis is group 1 and y-axis is group 2. I could not find any code doing this. Can some one please help me with this?
clc
clear
x=[rand(1,10) rand(1,10) rand(1,10) rand(1,10) rand(1,10) rand(1,10)];
n=10 ; xx=([1:6])'; % example
r=repmat(xx,1,n)';
g=r(:)';
positions = [1 2 3 4 5 6 ];
h=boxplot(x,g, 'positions', positions);
set(h,'linewidth',2)
set(gca,'xtick',[mean(positions(1:2)) mean(positions(3:4)) mean(positions(5:6)) ])
set(gca,'xticklabel',{'exp1','exp2','exp3'},'Fontsize',28)
color = ['c', 'y', '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
now i want yellow and blue for exp1 in one box as shown below.. similarly for exp2 and exp3 so on.. so 3 boxes in one boxplot..Ideally this should work for any number of experiments.
For a single two-sided boxplot, we can use the 'Orientation' property, and overlay 2 boxplots one above the other:
x = [1 2 3 4 5 6 7 1 2 3 4 5 6 7];
group = [1,1,1,1,1,1,1,2,2,2,2,2,2,2];
% we need the precntiles of the groups so the boxes will overlap.
% on each boxplot we set the width to the other boxplot hight:
p1 = prctile(x(group==1),[25 75]);
p2 = prctile(x(group==2),[25 75]);
ax = axes;
% first group is vertical:
boxplot(x(group==2),'Positions',mean(x(group==1)),...
'Orientation','vertical','Widths',p1(2)-p1(1),'Colors','r');
lims1 = axis;
hold on
% secound group is horizontal:
boxplot(x(group==1),'Positions',mean(x(group==2)),...
'Orientation','horizontal','Widths',p2(2)-p2(1),'Colors','k');
% the values of the axis are no longer relevant, since they have two
% different meanings, depend on the group. So we hide them.
ax.XAxis.Visible = 'off';
ax.YAxis.Visible = 'off';
hold off
lims2 = axis;
% because each axis represent to different things, we make sure we see
% everything:
axis([max(lims1(1),lims2(1)),...
min(lims1(2),lims2(2)),...
min(lims1(3),lims2(3)),...
max(lims1(4),lims2(4))])
To create multiple two-sided box-plots you need to use an axes for each experiment:
x = rand(10,6);
nsp = floor(size(x,2)/2); % the number of subplots
meanx = mean(x);
% we need the precntiles of the groups so the boxes will overlap.
% on each boxplot we set the width to the other boxplot hight:
width = range(prctile(x,[25; 75]));
main_ax = axes; % create a tmporary axes
% we get the measurements of the ploting area:
pos = main_ax.Position;
% and divide it to our data:
axwidth = pos(3)/nsp; % the width of each group
% the bottom left corner of each group:
corner = linspace(pos(1),pos(3)+pos(1),nsp+1);
clf % clear the area!
% now we plot each pair of boxplot on a different subplot:
for k = 1:2:size(x,2)
ax = axes('Position',[corner((k+1)/2) pos(2) axwidth pos(4)]);
hold on
% first group is vertical:
boxplot(x(:,k),'Positions',meanx(k+1),...
'Orientation','vertical','Widths',width(k+1),'Colors','r');
% secound group is horizontal:
boxplot(x(:,k+1),'Positions',meanx(k),...
'Orientation','horizontal','Widths',width(k),'Colors','k');
% the values of the y-axis are no longer relevant, since they have two
% different meanings, depend on the group. So we hide them.
ax.YAxis.Visible = 'off';
% we use the x-axis to label the pairs of boxplots:
ax.XAxis.TickLabels = ['Exp ' num2str((k+1)/2)];
% because each axis represent to different things, we make sure we see
% everything:
minx = min(min(x(:,k:k+1)))*0.1;
maxx = max(max(x(:,k:k+1)))*1.1;
axis ([minx maxx minx maxx])
hold off
box off
% set the locations to the exact same place:
bx = findobj(ax,'tag','Box'); % get the boxes
posXdif = bx(2).XData(1)-bx(1).XData(1); % get the horizontal difference
posYdif = bx(2).YData(1)-bx(1).YData(1); % get the vertical difference
bx2Xdata = get(ax.Children(2).Children,{'XData'}); % get all X-data of box 2
bx2Ydata = get(ax.Children(2).Children,{'YData'}); % get all Y-data of box 2
% substruct horizontal difference X-data:
set(ax.Children(2).Children,{'XData'},...
cellfun(#(x) x-posXdif,bx2Xdata,'UniformOutput',false))
% substruct vertical difference Y-data:
set(ax.Children(2).Children,{'YData'},...
cellfun(#(y) y-posYdif,bx2Ydata,'UniformOutput',false))
end
I have the following code, which plots a 'map' using imagesc, and provides a legend, see output attached.
I am trying to replace the lines in the legend with solid squares. My attamps to far leave the lines and ad hollow squares (including a random square in the top left corner of the figure)
figure(6)
imagesc(lut)
title('Ditribution of Land use Types')
ylabel('Longitude')
xlabel('Latitude')
caxis([0, 7])
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'})
set(L(:),'Marker','s')
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]
Use nan to create invisible data (thanks #matlatbgui), and set L with all needed properties for no line and filled square markers:
% some arbitrary data:
N = 30;
lut = diag(1:N)*ones(N)+(diag(1:N)*ones(N)).';
% coloring settings:
caxis([0, 7])
myColorMap = jet(6);
% plotting:
imagesc(lut, 'AlphaData', ~isnan(lut))
colormap(myColorMap);
% Setting the legend:
L = line(nan(6), nan(6),'LineStyle','none'); % 'nan' creates 'invisible' data
set(L, {'MarkerEdgeColor'}, num2cell(myColorMap, 2),...
{'MarkerFaceColor'},num2cell(myColorMap, 2),... % setting the markers to filled squares
'Marker','s');
legend(L, {'Forest','Shrubland','Savanna','Grassland','Agricultural','Barron'})
and you don't need your line:
set(L(:),'Marker','s')
The square on the upper-left corner is obviously due to set(L(:),'Marker','s') which draws a square at the start and end points of the lines, at [1, 1]. Instead of changing the 'Marker', if you increase the 'LineWidth', you get much better results with:
L = line(ones(6), ones(6));
legend(L, {'Forest','Shrubland','Savanna','Grassland','Agricultural','Barron'})
set(L(:), 'LineWidth', 10)
With this output:
So if you are not restricted to make squares, I believe wide rectangles are better flags for color.
I want to add an entry manually to a MATLAB legend. This legend can be pre-existent and contain other graphed elements' entries, but not necessarily.
I make a scatter plot, but instead of using e.g. scatter(x,y), I plot it using
for n = 1:numel(x)
text(x(n),y(n),num2str(n), ...
'HorizontalAlignment','center','color',[1 0 0])
end
This results in a scatter plot of numbers one through the number of elements in x (and y, because they are of the same size). I want to add a legend entry for these numbers.
I tried to add or edit the legend with
[h,icons,plots,s] = legend(___)
as described on the legend documentation page. I can't figure out how I can add a legend entry, without having to plot something (such as an actual scatter plot or regular plot). I want the usual line or marker symbol in the legend to be a number or character such as 'n', indicating the numbers in the graph. Is this possible and how would one achieve this?
EDIT by Erik
My answer goes below zelanix's answer, because mine is based on it.
Original answer
A fairly workable solution may be as follows:
x = rand(10, 1);
y = rand(10, 1);
figure;
text(x,y,num2str(transpose(1:numel(x))),'HorizontalAlignment','center')
% Create dummy legend entries, with white symbols.
hold on;
plot(0, 0, 'o', 'color', [1 1 1], 'visible', 'off');
plot(0, 0, 'o', 'color', [1 1 1], 'visible', 'off');
hold off;
% Create legend with placeholder entries.
[h_leg, icons] = legend('foo', 'bar');
% Create new (invisible) axes on top of the legend so that we can draw
% text on top.
ax2 = axes('position', get(h_leg, 'position'));
set(ax2, 'Color', 'none', 'Box', 'off')
set(ax2, 'xtick', [], 'ytick', []);
% Draw the numbers on the legend, positioned as per the original markers.
text(get(icons(4), 'XData'), get(icons(4), 'YData'), '1', 'HorizontalAlignment', 'center')
text(get(icons(6), 'XData'), get(icons(6), 'YData'), '2', 'HorizontalAlignment', 'center')
axes(ax1);
Output:
The trick to this is that the new axes are created in exactly the same place as the legend, and the coordinates of the elements of the icons are in normalised coordinates which can now be used inside the new axes directly. Of course you are now free to use whatever font size / colour / whatever you need.
The disadvantage is that this should only be called after your legend has been populated and positioned. Moving the legend, or adding entries will not update the custom markers.
Erik's answer
Based on zelanix's answer above. It is a work-in-progress answer, I am trying to make a quite flexible function of this. Currently, it's just a script that you'd need to adapt to your situation.
% plot some lines and some text numbers
f = figure;
plot([0 1],[0 1],[0 1],[1 0])
x = rand(25,1);
y = rand(25,1);
for n = 1:numel(x)
text(x(n),y(n),num2str(n), ...
'HorizontalAlignment','center','color',[1 0 0])
end
hold on
% scatter(x,y) % used to test the number positions
scatter(x,y,'Visible','off') % moves the legend location to best position
% create the dummy legend using some dummy plots
plot(0,0,'o','Visible','off')
[l,i] = legend('some line','some other line','some numbers','location','best');
l.Visible = 'off';
% create empty axes to mimick legend
oa = gca; % the original current axes handle
a = axes;
axis manual
a.Box = 'on';
a.XTick = [];
a.YTick = [];
% copy the legend's properties and contents to the new axes
a.Units = l.Units; % just in case
a.Position = l.Position;
i = copyobj(i,a);
% replace the marker with a red 'n'
s = findobj(i,'string','some numbers');
% m = findobj(i(i~=s),'-property','YData','marker','o');
m = findobj(i(i~=s),'-property','YData');
sy = s.Position(2);
if numel(m)>1
dy = abs(m(1).YData - sy);
for k = 2:numel(m)
h = m(k);
dy2 = abs(h.YData - sy);
if dy2<dy
kbest = k;
dy = dy2;
end
end
m = m(kbest);
end
m.Visible = 'off';
mx = m.XData;
text(mx,sy,'n','HorizontalAlignment','center','color',[1 0 0])
% reset current axes to main axes
f.CurrentAxes = oa;
The result:
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]);