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

20 visualizzazioni (ultimi 30 giorni)
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 Commenti

Accedi per commentare.

Risposta accettata

dpb
dpb il 11 Ott 2023
Modificato: dpb il 11 Ott 2023
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 Commenti
Cris LaPierre
Cris LaPierre il 12 Ott 2023
Modificato: Cris LaPierre il 12 Ott 2023
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 il 16 Ott 2023
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.

Accedi per commentare.

Più risposte (1)

Cris LaPierre
Cris LaPierre il 11 Ott 2023
Modificato: Cris LaPierre il 11 Ott 2023
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 Commento
Jesper Kamp Jensen
Jesper Kamp Jensen il 11 Ott 2023
Modificato: Jesper Kamp Jensen il 11 Ott 2023
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!

Accedi per commentare.

Categorie

Scopri di più su Graphics Objects in Help Center e File Exchange

Prodotti


Release

R2023b

Community Treasure Hunt

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

Start Hunting!

Translated by