Horizontal line for each category in a swarmchart with categorical x axis

20 次查看(过去 30 天)
Hi all,
I would like to add a horizontal line in a swarmchart using categorical x axis. I'm using MATLAB2023b.
I'm using swarmchart to plot my data and I get this plot:
I would like to display a horizontal line for the mean value in each bin for each color that only covered that bin on the a-axis.
Like this example from R:
Using yline like give a line across the whole figure.
With line or plot I can get a horizontal line, but that give lines between limits (see green line from N-0 to R-0.15):
x_line = unique(T.x_cat);
figure(ii);
s1 = swarmchart(T.x_cat(T.Pos == "T" & T.Mixing == 'U'), T.y(T.Pos == "T" & T.Mixing == 'U'), '^');
hold on
s2 = swarmchart(T.x_cat(T.Pos == "B" & T.Mixing == 'U'), T.y(T.Pos == "B" & T.Mixing == 'U'), 'v');
hold on
s3 = swarmchart(T.x_cat(T.Pos == "P" & T.Mixing == 'U'), T.y(T.Pos == "P" & T.Mixing == 'U'), '+');
grid minor
xaxis=get(gca,'XAxis');
xaxis.Categories={'N-0' 'R-0.15' 'R-1' 'R-4' 'F-4' 'F-12' 'F-24'};
mean_y1 = mean(T.y(T.Pos == 'T' & T.Mixing == 'U' & T.Storage == "N"));
line([x_line(4); x_line(5)], [mean_y1 ; mean_y1 ]); % Produce same as line below
plot([x_line(4); x_line(5)], [mean_y1 ; mean_y1 ], '--r');
See data here attached.
Thank you for your inputs!
Best,
Jesper
  4 个评论

请先登录,再进行评论。

采纳的回答

dpb
dpb 2023-10-11
编辑:dpb 2023-10-11
load T
T.x_cat=reordercats(T.x_cat,{'N-0','R-0.15','R-1','R-4','F-4','F-12','F-24'});
x_line = unique(T.x_cat);
s1 = swarmchart(double(T.x_cat(T.Pos == "T" & T.Mixing == 'U')), T.y(T.Pos == "T" & T.Mixing == 'U'), '^');
hold on
s2 = swarmchart(double(T.x_cat(T.Pos == "B" & T.Mixing == 'U')), T.y(T.Pos == "B" & T.Mixing == 'U'), 'v');
s3 = swarmchart(double(T.x_cat(T.Pos == "P" & T.Mixing == 'U')), T.y(T.Pos == "P" & T.Mixing == 'U'), '+');
grid, box on
xticks(1:numel(x_line))
xticklabels({'N-0' 'R-0.15' 'R-1' 'R-4' 'F-4' 'F-12' 'F-24'})
will let you plot on numeric x-axis so you can draw lines between categorical locaions, but still look as if were categorical.
The key "trick" is to reorder the x categories into the desired order as you gave for the categorical x axis--then the numeric values are in the order you wish from 1:NumberCategories. You could create them initially that way as well by using the second optional input to the categorical function, optionally also making it an ordinal variable.
I didn't poke around inside the swarmchart properties to see if could extract the range of the x values around each midpoint to adjust the length of the lines to match. As @Cris LaPierre's alternate solution shows, if you stick with only a categorical axis, the options are very limited as a single point is all there is for addressing (as you already knew).
The other alternative I see would be essentially the same thing as above excepting leave the initial axes as categorical, but then overlay a second one to do the lines on as numeric -- that approach has the same issue as your original in having to pick and choose which category is which in sequence that you did manually if you don't turn it into an ordinal array...all in all, it's probably easier as above.
Also, there are similar efficiencies that could be incorporated in the above similar to @Cris LaPierre showed as far as the grouping...one might even manage a one-liner with rowfun or splitapply if reall put one's mind to it! :)
ADDENDUM:
Turns out the X values are the unique values, but there's XJitterWidth property that controls the amount of jitter...so something like
hL1=plot(1+0.5*hSW.XJitterWidth*[-1 1], [mny(1) mny(1)],'r-');
Unable to resolve the name 'hSW.XJitterWidth'.
for each mean of y will do the trick -- you might want to make the multiplier just a little larger than 1/2 -- as above it goes to the center of the outside markers, not quite all the way to the edge of the blob..."salt to suit"!
  5 个评论
Cris LaPierre
Cris LaPierre 2023-10-12
编辑:Cris LaPierre 2023-10-12
Just a caution that, based on the data you shared, T_pH.Storage == "N" corresponds to data with x_cat of 'R-0.15' and 'N-0'. Therefore, your averages for m_TN, m_BN and m_PN, which should be for N-0 only, are including values for R-0.15 as well, which appears to be making the average higher than it should be.
It also means that the values for x_cat of 'R-0.15' are not being included in your averages for m_TR, m_BR and m_PR, which will impact those values as well.
Jesper Kamp Jensen
Jesper Kamp Jensen 2023-10-16
Thanks for your comment, Cris!
I'm aware of the issue you raise - I have simplified my data that are shared here, so I just wanted to show the concept and how it could be done both over one or more rows.

请先登录,再进行评论。

更多回答(1 个)

Cris LaPierre
Cris LaPierre 2023-10-11
编辑:Cris LaPierre 2023-10-11
Here's one approach. I tried to simplify it, If you ignore the bit about setting up the colors, you may agree.
load T.mat
% define colors (optional)
c1 = [0 0.4470 0.7410];
c2 = [0.8500 0.3250 0.0980];
c3 = [0.9290 0.6940 0.1250];
T.C(T.Pos=="B",:) = repmat(c1,sum(T.Pos=="B"),1);
T.C(T.Pos=="P",:) = repmat(c2,sum(T.Pos=="P"),1);
T.C(T.Pos=="T",:) = repmat(c3,sum(T.Pos=="T"),1);
% Create a new table with just the desired data
T_U = T(T.Mixing=="U",:);
T_U.x_cat = reordercats(T_U.x_cat,{'N-0' 'R-0.15' 'R-1' 'R-4' 'F-4' 'F-12' 'F-24'});
% Create swarmchart
swarmchart(T_U,"x_cat","y",'ColorVariable','C');
grid minor
% calculate means
x_cat_mean = groupsummary(T_U,["x_cat","Pos"],"mean",["y","C"])
x_cat_mean = 21×5 table
x_cat Pos GroupCount mean_y mean_C ______ ___ __________ ______ _______________________ N-0 B 18 7.1322 0 0.447 0.741 N-0 P 18 7.2767 0.85 0.325 0.098 N-0 T 18 7.1844 0.929 0.694 0.125 R-0.15 B 3 7.2 0 0.447 0.741 R-0.15 P 3 7.3133 0.85 0.325 0.098 R-0.15 T 3 7.4067 0.929 0.694 0.125 R-1 B 3 7.235 0 0.447 0.741 R-1 P 3 7.4 0.85 0.325 0.098 R-1 T 3 7.4133 0.929 0.694 0.125 R-4 B 3 7.2733 0 0.447 0.741 R-4 P 3 7.365 0.85 0.325 0.098 R-4 T 3 7.4267 0.929 0.694 0.125 F-4 B 3 7.75 0 0.447 0.741 F-4 P 3 7.8783 0.85 0.325 0.098 F-4 T 3 7.76 0.929 0.694 0.125 F-12 B 3 7.835 0 0.447 0.741
% Add horizontal line for each mean (can be hard to see)
hold on
scatter(x_cat_mean.x_cat,x_cat_mean.mean_y,[],x_cat_mean.mean_C,'_','LineWidth',2)
hold off
  1 个评论
Jesper Kamp Jensen
Jesper Kamp Jensen 2023-10-11
编辑:Jesper Kamp Jensen 2023-10-11
Thanks for you answer Cris!
Agree, this is a simple approach - with help from dpd I also ended up with a quite simple solution, but thanks for your time, I appreciate it!

请先登录,再进行评论。

类别

Help CenterFile Exchange 中查找有关 Graphics Objects 的更多信息

产品


版本

R2023b

Community Treasure Hunt

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

Start Hunting!

Translated by