Creating customized barplot for different lengths of arrays

I have data comes from three different sources. Each of [data1, data2, and data3] are column vectors with different lengths and it only contains integer values from 1-3. Like following:
data1 = randi([1 3], 20,1])
data2 = randi([1 3], 34,1])
data3 = randi([1 3], 56,1])
The code should calculate the percentage of each integers value and group them on the same bar plot for data1, data2, and data 3. See below hand sketched picture [approximate]. Any thoughts would be greatly appreciated!

1 Commento

BTW: As discussed in the other comment and the answer, that it takes such effort in HG1 and is, from what I've read at File Exchange, even more complicated if not actually impossible with HG2 is simply unacceptable in my opinion.
I would suggest submitting this topic as a bug report; it really is a worse omission than simply an enhancement request.
Just imo, $0.02, ymmv, etc., etc., with all the other associated caveats...

Accedi per commentare.

 Risposta accettata

dpb
dpb il 29 Dic 2016
Modificato: dpb il 30 Dic 2016
n=100*bsxfun(@rdivide,[histc(data1,1:3) histc(data2,1:3) histc(data3,1:3)], ...
[length(data1) length(data2) length(data3)]).';
hBarH=bar(n,'hist'); % force style to return array handle to patches
xpts=cell2mat(get(hBarH,'XData')); % return patch x position array
xpts=mean(reshape(xpts(1:2:end),2,[])) % then average by twos...
set(gca,'xtick',xpts,'xticklabel',[1:3]) % set new tick positions, label
ylim([0 50])
y=n.'; y=y(:); % order from left to right in column vector to label
hTxt=text(xpts,y(:),num2str(y(:),'%.1f%%'), ...
'horizontalalign','center', ...
'verticalalign','bottom', ...
'fontsize',8);
to get
NB: See the more extensive discussion in Comment about the logic behind the above positioning and caveats re: HG vis a vis HG2 about what you can/cannot possibly be able to do with the latter.
NB2: The default 'group' option, while I can't tell the result apart from 'hist' visually, results in bar returning an array of hggroup objects, the patch objects of which are children. This makes retrieving their 'XData' property another level of indirection; hence I force the 'hist' style to get the vector of patch objects directly instead.
ADDENDUM
I just noticed the trees for the forest--have always concentrated on how to retrieve the necessary data so didn't pick up on what looks to be a simple algorithm to compute the bar positions. It looks from this sample of one that the delta to the various bars from the center x position is (N-1)/(M*N) where N is number of bars/group and M is number of groups.
That would be readily computed without handle-diving if it holds in general--
>> dx=(size(n,1)-1)/numel(n);
>> xpts=[[1:3].'-dx [1:3].' [1:3].'+dx].'; xpts=xpts(:).'
xpts =
0.7778 1.0000 1.2222 1.7778 2.0000 2.2222 2.7778 3.0000 3.2222
>>
Those are the values we obtained from the averages of the patches x-axis locations above so looks like we've uncovered the magic Rosetta stone used by the internal logic. Try this out with HG2; if it works as I suspect it will, then the problem about opaque objects at least has a relatively simple workaround for this particular issue.
A NOTE: I tried some other sizes of groups and bars/group and while the above gets in the ballpark, the spacings aren't that simply derived for them so the above is true only for the case of the 3x3 arrangement it appears, unfortunately.

6 Commenti

Is it possible to have x-axis labeled as a sequence of (1,2, and3) per group as shown above?
"Possible?", yes. "Easy?", not so much, unfortunately.
The bar plot is a real bugger in Matlab HG or in some ways it appears even more so in HG2 to annotate or modify. In particular, the x-axis position of the bars' midpoints for grouped or histogram bar plots are not available directly and there's no documentation on the width calculation from which to compute what is used internally.
In HG "classic", the necessary information can be obtained by retrieving the 'XData' property and massaging it to compute the locations of the individual bar patches, but TMW didn't see fit to create a user-friendly interface to return the needed center values of the individual bars nor to label them (and thereby removing much, if not all of the need to actually have the positions themselves).
In HG2, bar returns a new bar object instead of an array of patch object handles and methods to set some properties of same but not, again, the needed geometric values nor ways to do the (what should be obviously) wanted/needed labeling. Plus, it appears that they've made handles to the lower-level objects needed to query to figure it out opaque so can't even get there from here. I don't have the later release so can't really poke around and see just what is/is not actually available, sorry.
There are some submittals at the File Exchange to address the issue; I've noted that the HG1 solutions are broken by HG2 and much frustration expressed there as well...
Example for HG1 with the above example of your data shows what the patch coordinates look like; perhaps you can adapt to HG2, presuming it is what you have; if not, the below works, albeit with some what seems to be unnecessary grief...
>> xpts=cell2mat(get(hBar','xdata')) % the face data for each group
xpts =
0.6667 1.6667 2.6667
0.6667 1.6667 2.6667
0.8889 1.8889 2.8889
0.8889 1.8889 2.8889
0.8889 1.8889 2.8889
0.8889 1.8889 2.8889
1.1111 2.1111 3.1111
1.1111 2.1111 3.1111
1.1111 2.1111 3.1111
1.1111 2.1111 3.1111
1.3333 2.3333 3.3333
1.3333 2.3333 3.3333
>>
Note that these don't include the integer 'xtick' locations; the bars aren't centered there, these are the edge locations of the bars; to get the centers we need for labeling must find means of each bar--
>> x=xpts(:); % first orient all as a single vector
>> xpts=mean(reshape(x(1:2:end),2,[])) % then average by twos...
xpts =
0.7778 1.0000 1.2222 1.7778 2.0000 2.2222 2.7778 3.0000 3.2222
>>
Those are the locations needed for either text or add 'xtick' values and use 'xticklabel'
>> set(gca,'xtick',xpts,'xticklabel',[1:3])
For a set of dummy data 3x3 as yours the above gives the following figure--
Can't be much grateful. That was great and detailed explanation. Thank you! I did a slight update to the bar plot and here is how the output looks like:
dpb
dpb il 31 Dic 2016
Modificato: dpb il 31 Dic 2016
Out of curiosity, which release are you using?
I'd kept putting it off but finally earlier today did an update to R2014b (about if not the last version that will run on this old hardware) and so could test the HG2 issues...
Indeed, even findall can't uncover the bowels of the bars from which to generically compute the midpoints of the bars as drawn for labeling. :(
The previous formula for (N-1)/(N*M) still holds for the 3x3 case as I surmised, but it doesn't translate to larger N,M directly. It would take some detailed spelunking to determine the actual spacing algorithm.
I still think this is a serious flaw TMW should've addressed years ago...
Mohammed
Mohammed il 1 Gen 2017
Modificato: Mohammed il 1 Gen 2017
I am using R2013a. I agree, finding midpoints was very thoughtful from you as I spent sometime to discover how to approach the concept before I raise the question. I looked into few codes online and I was wondering if there an easier/simpler way to find mid-points but I wasn't convinced to use them and when I saw your elaboration, I realized that's my only way. Thanks!
"...finding midpoints was very thoughtful from you..."
Well, I'd had occasion to do the labeling before so had managed previously to get there so I had a starting point... :) Hadn't previously got it down to quite as concise as the reasonably simple calculation above, but knew the general idea and so another iteration made some simplification easier. Anyway, thanks for the kind words and glad it helped.
With HG1 (prior to R2014b) this method should always work with the aforementioned caveat about hggroup vis a vis bar patch handles depending on the option chosen.
I believe I will submit a subset of the question (again) as a bug this time rather than an enhancement since now with HG2 they've broken any possible way other than having to reverse engineer the spacing algorithm that's buried in inaccessible code below the m-file level (I've already looked :<).

Accedi per commentare.

Più risposte (0)

Categorie

Richiesto:

il 29 Dic 2016

Modificato:

dpb
il 2 Gen 2017

Community Treasure Hunt

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

Start Hunting!

Translated by