Identifying and keeping duplicates but with a suffix

4 views (last 30 days)
Jason
Jason on 27 Aug 2020
Edited: dpb on 28 Aug 2020
Hello, I have a column vector that I use for x values for a Bar Chart from data extracted from a UITable.
Y=cell2mat(data(:,4))
X=data(:,2);
Xdata = categorical(X);
X = reordercats(Xdata,X);
b1=bar(X,Y,'Parent',app.UIAxes2);
My x data (Column vector) is one of 3 numbers 405, 532 or 660.
The data can be any of these and with any number of repeats e.g
405
405
405
405
405
or
405
532
532
660
405
The problem is the bar chart cannot handle repeat values. I'd still like to plot and thought one way would be to identify repeats and place an _ with a number, but am not sure how to
e.g
405
405
405
405
405
becomes
405_1
405_2
405_3
405_4
405_5
and
405
532
532
660
405
becomes
405_1
532_1
532_2
660
405_2
Thanks for any help
  2 Comments
Jason
Jason on 27 Aug 2020
The data represents Integrated fluorescence spectra of samples with some repeats. The number of repeats could be different for each value (e.g. below its 3 for the 405 and 2 for the 532 x-values)
The ideal chart would just be with the wavelength numbers being as they are without any suffixing going on.
The bar chart isn't crowded at all (note to make it work I had to suffix the category values with a,b, etc.)

Sign in to comment.

Accepted Answer

dpb
dpb on 27 Aug 2020
OK, that helps...actually, that's not too hard and even easier than the grouped solution -- I don't quite follow what your data storage must be with the mixing of cell2mat for Y and not for X so I'll write as if both are simple double arrays -- you can adapt to whatever data actually is that we can't see--I would tend to avoid creating copies of the same data, but since this is apparently small samples, it won't be that expensive to do so here.
[X,ix]=sort(X); % order by wave number
Y=Y(ix); % arrange counts to correspond
hBar=bar(Y,'Parent',app.UIAxes2); % plot against the ordinal position to avoid the duplicates
xticklabels(categorical(X)) % use the categorical names as tick labels
Can fixup the appearance as wanted from here...
The alternative with the grouping solution would be
>> [x y] % some made up sample data
ans =
405 529
532 166
532 602
660 263
405 655
>>
% the engine
N=groupcounts(x); % count elements in each wave number
Y=nan(numel(N),max(N)); % build the grouping array for bar()
[X,~,ib]=unique(x); % get the unique wave numbers/groups and group identity
yy=accumarray(ib,y,[],@(v) {v}); % separate by group to cell array
for i=1:3, Y(i,1:N(i))=yy{i}; end % and put by row into the 2D double array
figure
hBar=bar(X,Y);
xticklabels(categorical(X))
set(hBar,'FaceColor','y')
hAx=gca;
hAx.Color='k';
hAx.GridColor='w';
hAx.GridAlpha=0.5;
title('Gropued by Wave Number')
grid on
The above produced
  3 Comments
dpb
dpb on 27 Aug 2020
ADDENDUM:
NB: In the above code for the grouped barplot, the for...end loop indices are hardcoded as 1:3. That works for the sample dataset; in general that should be
for i=1:numel(N), Y(i,1:N(i))=yy{i}; end % and put by row into the 2D double array
to iterate over however many wave numbers are actually in the dataset.

Sign in to comment.

More Answers (1)

dpb
dpb on 28 Aug 2020
Edited: dpb on 28 Aug 2020
OK, this isn't complete, but is probably the simplest way to build something to do what you'd like -- it would need to be refined and made into a function, but the general idea is pretty simple...using the same [x y] data had before in sorted order...
colors=reshape([hBar.FaceColor],3,[]).'; % save the default color map from previous for convenience
figure
hBar(1)=bar(1,Y(1)); % the first one at ordinal position 1
hold on % prepare to add on top existing bar
c=1; % initial color index value
j=1; % x position location for each bar
for i=2:size(X,1) % add rest to same plot
if X(i)~=X(i-1), j=j+0.5; end % if new wave number, put separation to simulate groups
c=c+1; % increment color for next group
j=j+1; % increment the ordinal number
hBar(i)=bar(j,Y(i),'FaceColor',colors(c,:)); % plot at adjusted ordinal position in group color
end
xticks([hBar.XEndPoints]) % put tick marks at middle each bar
xticklabels(categorical(X)) % label with the wave numbers
title('Simulated Grouped by Wave Number')
grid on
Now, one has a separate bar() object handle for each bar so can set color as desired...this just cycles through the (somewhat ugly) default sequence; you can define whatever color array you wish.
The biggest refinement I see missing here is not computing the midpoint of the groups for locating the tick marks so only have one label for the wave number group--I ran out of time altho don't think it's hard, one just needs a running sum of the XendPoints values for each group and compute the mean for that set when the group/wave number changes and save that value in array to use for xticks argument. Then you will use the unique categorical variable as labels instead of the full X array.
The above initial step gets to this point --
Well, OK, I lied... :) Couldn't stand it!!!
The modifications are --
N=groupcounts(x); % bring this back...
tk=zeros(size(N)); % accumlator for the tick position calculation
hBar(1)=bar(1,Y(1));
tk(1)=hBar(1).XEndPoints; % initial position (if choose to use something other than 1)
c=1;j=1;
for i=2:size(X,1)
if X(i)~=X(i-1)
j=j+0.5;
tk(c)=tk(c)/N(c); % calculate the group tick average for midpoint for last group
c=c+1;
end
j=j+1;h
Bar(i)=bar(j,Y(i),'FaceColor',colors(c,:));
tk(c)=tk(c)+hBar(i).XEndPoints; % accumulate running sum for working group
end
xticks(tk)
xticklabels(unique(X))

Community Treasure Hunt

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

Start Hunting!

Translated by