Create a boxchart with half-boxes

5 次查看(过去 30 天)
Hi,
i am trying to generate a boxchart with halfboxes to compare 2 datasets. Unfortunately there is no attribute to create a half-box in the boxchart function. so my idea was to plot 2 times the same dataset and shift them that they overlap and then make one boxplot completly white. You can see the results in the pictures. Now i want to fuse these two plots but i am facing the problem that when i generate a plot that consists both figures the white boxes are in foreground. does anyone have an idea how to do this? i am also open to other solutions.
thanks in advance
Joel

采纳的回答

Voss
Voss 2024-2-25
编辑:Voss 2024-2-25
As you may have realized already, there's no ordering of overlapping red, blue, and two white boxcharts that will give you the look you want. You'd need white #1 on top of red, blue on top of white #1, white #2 on top of blue, but red on top of white #2, which is a contradiction.
One thing you can do is to reproduce the built-in boxchart appearance using primitive lines and patches. Of course this requires calculating the statistics like boxchart does, but that's not too hard because boxchart is well-documented.
Something like this:
data1 = randn(100,5);
data2 = randn(100,5);
figure
grid on
box_width = 0.5;
% calculate the median and the box and whisker upper and lower limits for data1
box_med1 = median(data1,1);
q = quantile(data1,[0.25, 0.5, 0.75],1);
box_min1 = q(1,:);
box_max1 = q(3,:);
IQR = box_max1-box_min1;
is_outlier1 = data1 > q(3,:)+1.5*IQR | data1 < q(1,:)-1.5*IQR;
data1_temp = data1;
data1_temp(is_outlier1) = NaN;
whisker_min1 = min(data1_temp,[],1);
whisker_max1 = max(data1_temp,[],1);
% calculate the median and the box and whisker upper and lower limits for data2
box_med2 = median(data2,1);
q = quantile(data2,[0.25, 0.5, 0.75],1);
box_min2 = q(1,:);
box_max2 = q(3,:);
IQR = box_max2-box_min2;
is_outlier2 = data2 > q(3,:)+1.5*IQR | data2 < q(1,:)-1.5*IQR;
data1_temp = data2;
data1_temp(is_outlier2) = NaN;
whisker_min2 = min(data1_temp,[],1);
whisker_max2 = max(data1_temp,[],1);
% create the whiskers and box outlines for data1
N1 = size(data1,2);
xd = (1:N1)-box_width*[0.5;0;0;1;1;0;0;0.5;NaN]/2;
yd = [whisker_min1;whisker_min1;box_min1;box_min1;box_max1;box_max1;whisker_max1;whisker_max1;NaN(1,N1)];
line(xd(:),yd(:),'Color','r')
% create the whiskers and box outlines for data2
N2 = size(data2,2);
xd = (1:N2)+box_width*[0.5;0;0;1;1;0;0;0.5;NaN]/2;
yd = [whisker_min2;whisker_min2;box_min2;box_min2;box_max2;box_max2;whisker_max2;whisker_max2;NaN(1,N2)];
line(xd(:),yd(:),'Color','b')
% create the box interior for data1
xd = (1:N1)-box_width*[0;0;1;1;0]/2;
yd = [box_min1;box_max1;box_max1;box_min1;box_min1];
patch('XData',xd,'YData',yd,'FaceColor','r','FaceAlpha',0.2,'EdgeColor','none')
% create the box interior for data2
xd = (1:N2)+box_width*[0;0;1;1;0]/2;
yd = [box_min2;box_max2;box_max2;box_min2;box_min2];
patch('XData',xd,'YData',yd,'FaceColor','b','FaceAlpha',0.2,'EdgeColor','none')
% create the median line for data1
xd = (1:N1)-box_width*[0;1;NaN]/2;
yd = [box_med1;box_med1;NaN(1,N1)];
line(xd(:),yd(:),'Color','r')
% create the median line for data2
xd = (1:N2)+box_width*[0;1;NaN]/2;
yd = [box_med2;box_med2;NaN(1,N2)];
line(xd(:),yd(:),'Color','b')
% create the outliers line for data1
xd = 1:N1;
[~,idx] = find(is_outlier1);
xd = xd(idx)-box_width*0.25;
yd = data1(is_outlier1);
line(xd(:),yd(:),'Color','none','Marker','o','MarkerEdgeColor','r')
% create the outliers line for data2
xd = 1:N2;
[~,idx] = find(is_outlier2);
xd = xd(idx)+box_width*0.25;
yd = data2(is_outlier2);
line(xd(:),yd(:),'Color','none','Marker','o','MarkerEdgeColor','b')
For comparison, built-in overlapping boxcharts:
figure
hold on
grid on
b1 = boxchart(data1,'BoxFaceColor','r','BoxEdgeColor','r','WhiskerLineColor','r','MarkerColor','r');
b2 = boxchart(data2,'BoxFaceColor','b','BoxEdgeColor','b','WhiskerLineColor','b','MarkerColor','b');

更多回答(1 个)

Austin M. Weber
Austin M. Weber 2024-2-25
编辑:Austin M. Weber 2024-2-25
Since there is not already a built-in function for making "half" box plots, it might be beneficial to to write your own function (in case you want to make more of these plots in the future).
I have made a relatively simple function for you to use/modify to your needs (see attached). Just note that the approach I took was not to make regular boxchart objects, but rather I have written the function to plot all of the features of the boxplots using the rectangle function. Below is an example of how it works:
% Create two data arrays with the same number of columns
rng(1) % <-- for reproducibility
data1 = normalize(randn(30,10),'Range',[0.05 0.95]);
rng(2) % <-- change RNG seed so that the second data array is different from the first
data2 = normalize(randn(30,10),'Range',[0.05 0.95]);
% Plot the data
h = halfboxplot(data1,data2);
I also added documentation to the function, which you can view by typing the following into your command window:
doc halfboxplot
Feel free to modify the function to fit your needs. I might try to improve this function later on and add it to the File Exchange. If I do I will let you know.

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!

Translated by