Create a boxchart with half-boxes

조회 수: 4 (최근 30일)
Joey
Joey 2024년 2월 25일
댓글: Voss 2024년 2월 26일
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');
  댓글 수: 2
Joey
Joey 2024년 2월 26일
Thanks a lot for your response, that was very helpful!
Voss
Voss 2024년 2월 26일
You're welcome!

댓글을 달려면 로그인하십시오.

추가 답변 (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.
  댓글 수: 1
Joey
Joey 2024년 2월 26일
Thank you, this is also a very nice approach!

댓글을 달려면 로그인하십시오.

Community Treasure Hunt

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

Start Hunting!

Translated by