3 views (last 30 days)

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

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

dpb
on 27 Aug 2020

Of course they could... :) I thought the yellow on black the effect you were going for! :

Oh. Well, when you group bars, the bars for each member of the groups are one bar object handle so here you could color the left and right bars separately, but don't think you can make the two for each group the same...

I've railed at TMW about how difficult it is to work with bar() for years -- they've made some things a little easier, but others are still difficult or take some kludgy workarounds.

The klunky way here would be the expedient of the NaN elements for one of the bars or each group one-at-a-time and as many bar plots as the maximum number of repeated elements. That's not too bad with only two or three but would get pretty messy with more like your first example.

I'll have to mull that one over some and see if anything simpler comes to mind.

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.

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))

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

Start Hunting!
## 2 Comments

## Direct link to this comment

https://fr.mathworks.com/matlabcentral/answers/585356-identifying-and-keeping-duplicates-but-with-a-suffix#comment_987713

⋮## Direct link to this comment

https://fr.mathworks.com/matlabcentral/answers/585356-identifying-and-keeping-duplicates-but-with-a-suffix#comment_987713

## Direct link to this comment

https://fr.mathworks.com/matlabcentral/answers/585356-identifying-and-keeping-duplicates-but-with-a-suffix#comment_987761

⋮## Direct link to this comment

https://fr.mathworks.com/matlabcentral/answers/585356-identifying-and-keeping-duplicates-but-with-a-suffix#comment_987761

Sign in to comment.