You are now following this question
- You will see updates in your followed content feed.
- You may receive emails, depending on your communication preferences.
How can I estimate the average for each one of the intervals in an x axis?
7 views (last 30 days)
Show older comments
Hi
I need a method to split my x axis into intervals and estimate the average for each one of the intervals. The plots are polynomial curves, if that helps.
Any suggestion?
Thank you
2 Comments
Jan
on 17 May 2019
The question is not clear yet: It does not make sense to "split the x axis". But if you have two vectors, one containing the x and the other the y values of a curve, you can calculate a blockwise average. So please post, what your inputs are.
Stelios Fanourakis
on 19 May 2019
Exactly as you stated. Two vectors of X,Y in a 2d plot. I want to define intervals for the X values and average each interval and all together.
Accepted Answer
Adam Danz
on 19 May 2019
Edited: Adam Danz
on 20 May 2019
This is relatively straight forward with histcounts() and splitapply().
% Create fake data
x = randi(1000,1,1000); %doesn't have to be sorted
y = rand(size(x));
% Define the edges of your x data
% There's lots of ways to do this - this is just 1 example.
binWidth = 100; %how wide is each bin?
edges = min(x) : binWidth : max(x);
% determine which bin each x element is in
[~, ~, hbin] = histcounts(x,[edges,inf]);
% Get mean of y within each bin
% Here I ignore NaN values, too.
binMean = splitapply(@(x)mean(x,'omitna'),y,hbin);
To interpret the results, binMean(n) is the mean for all y values where x is greater or equal to edges(n) and less than edges(n+1).
To plot the data, the bins, and display the average values per bin above the axis:
figure
plot(x,y,'b.')
hold on
plot([edges;edges],[0,1],'k')
text(edges+binWidth/2, ones(size(edges)), strsplit(num2str(binMean,.1)), ...
'VerticalAlignment', 'Bottom', 'HorizontalAlignment', 'Center')
% * binMean must be a row vector

13 Comments
Stelios Fanourakis
on 19 May 2019
Edited: Stelios Fanourakis
on 20 May 2019
Dear Adam
Thanks a lot for providing me a feedback. Your approach seems very promising and interesting but why am I receiving this graph (see attached image .png) and it doesn't look like the one you have posted with the intervals visible
Whereas when I put a small interval value such as 2 for instance, I get the error
Error using regexp
The 'STRING' input must be either a char row vector, a cell array of char row vectors, or a string array.
Error in strsplit (line 125)
[c, matches] = regexp(str, aDelim, 'split', 'match');
Error in sheet7 (line 116)
text(edges+binWidth/2, ones(size(edges)), strsplit(num2str(round(binMean*10)/10,.1)), ...
Adam Danz
on 20 May 2019
Hi Stelios, please take a few minutes to understand what I've done in my code, it's only 4-5 lines and then another 2-3 lines to understand the plot.
I generated fake data. Then I defined edges for each bin based on the range of x values. Using histcounts(), I determined which points were in which bins. Then using splitapply() I took the mean of y for each bin.
My plot just shows my fake data, the vertical lines show the bin edges, and the numbers on top show the means.
This approach should be generalizable to any set of (x,y) coordinates.
I don't know where your plot comes from or what it representes. Is that the (x,y) data you're binning? Have you tried to apply my code to your data?
I can help you more if you show me the relevant sections of your code where you applied my analysis.
Stelios Fanourakis
on 20 May 2019
Actually, the only things I changed was to apply x as my x axis data and y as my y data which is a polynomial function.
The rest of your code remained the same. My x axis data begins from 0 up until 37. That's why when I put a big number e.g. 100 it won't show anything, but when I put a small number e.g. 2 it will show me the vertical lines, like your plot but I also get the error
Error using regexp
The 'STRING' input must be either a char row vector, a cell array of char row vectors, or a string array.
Error in strsplit (line 125)
[c, matches] = regexp(str, aDelim, 'split', 'match');
Error in sheet7 (line 116)
text(edges+binWidth/2, ones(size(edges)), strsplit(num2str(round(binMean*10)/10,.1)), ...
Adam Danz
on 20 May 2019
I see your updated comment now. Your error is coming from this line
[c, matches] = regexp(str, aDelim, 'split', 'match');
I don't have that line in my code.
What is the value of str ?
If I don't reply tonight (8pm my time) I can tomorrow AM.
Stelios Fanourakis
on 20 May 2019
Edited: Stelios Fanourakis
on 20 May 2019
Actually no. The basis of the error comes from this line
text(edges+binWidth/2, ones(size(edges)), strsplit(num2str(round(binMean*10)/10,.1)), ...
Last line of your code, because of the strsplit function. I guess my input should be a char row vector, cell array or string array.
Is it referring to my X, Y data? My x data are numbers and my y data is a polynomial function. Do I need to convert both to string array?
Actually, as I understand, binMean comes as double and I need to convert it to either char vector, cell array or string array. Num2str after the strsplit doesn't seem to work.
ANy idea ?
Adam Danz
on 20 May 2019
Ah, I see the source of the error in your message now.
It would be easier if I had the input values you were using in that line of code for the text() function.
That line can actually be simplifed, I just realized.
text(edges+binWidth/2, ones(size(edges)), strsplit(num2str(binMean,.1)), ...
'VerticalAlignment', 'Bottom', 'HorizontalAlignment', 'Center')
"binMean" is a row vector with 'n' elements where n is one less than the number of edges (remember, there will always be +1 edges than bins). num2str() converts that vector to one long sting like this:
binMean =
0.47372 0.49419 0.52058 0.49538 0.49438 0.50074 0.50679 0.53782 0.4761 0.50468
num2str(binMean,.1)
ans =
'0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5'
Note that it's one long string.
strsplit then separates that string into single numbers.
strsplit(num2str(binMean,.1))
ans =
1×10 cell array
{'0.5'} {'0.5'} {'0.5'} {'0.5'} {'0.5'} {'0.5'} {'0.5'} {'0.5'} {'0.5'} {'0.5'}
If that doesn't help, please share the inputs you are using.
Stelios Fanourakis
on 20 May 2019
@Adam
Unfortunately, same error
Error using regexp
The 'STRING' input must be either a char row vector, a cell array of char row vectors, or a string array.
Error in strsplit (line 125)
[c, matches] = regexp(str, aDelim, 'split', 'match');
Error in sheet7 (line 120)
text(edges+binWidth/2, ones(size(edges)), strsplit(num2str(binMean,.1)), ...
I attach my inputs
Stelios Fanourakis
on 20 May 2019
I append samples of what you asked me
binMean
-0.121451211827104
-0.177183817955014
-0.00685535745892493
0.151211113432096
0.204176787674413
0.152122136758402
0.0418768402726248
-0.0669371848658577
edges
0.0430000000000000 2.04300000000000 4.04300000000000 6.04300000000000 8.04300000000000 10.0430000000000 12.0430000000000 14.
binWidth = 2
I hope that helps
Adam Danz
on 20 May 2019
Edited: Adam Danz
on 20 May 2019
I found the error. If you look at my comment above, I showed examples of what binMean should be. In my example, binMean is a row vector. In your data it's a column vector so it wasn't properly converted to strings. You just need to transpose the vector.
text(edges+binWidth/2, ones(size(edges)), strsplit(num2str(binMean.',.1)), ...
% ^^ transpose there
'VerticalAlignment', 'Bottom', 'HorizontalAlignment', 'Center')
Stelios Fanourakis
on 20 May 2019
Edited: Stelios Fanourakis
on 20 May 2019
Yes indeed. You are magnificent Adam. Very good precision resolving the issue. Well done and thank you very much.
Although the plot comes a bit awkward. How should I margin it to appear properly?
Maybe I should play with axis margins, so I can make it look more like yours
Thanks once again
Adam Danz
on 20 May 2019
Edited: Adam Danz
on 20 May 2019
Glad I could help.
The 2nd input to text() indicates where along the y axis your labels should go. In my example I simply used y=1 for all labels because my data didn't span beyond 1. You could just do this
ylim([-0.5, 2])
text(edges+binWidth/2, ones(size(edges))*max(ylim()), ......
also, see the "rotation" text property. It might look better to rotate the labels by 90 deg.
Also, to draw the lines across your entire axis,
plot([edges;edges],[min(ylim()), max(ylim())],'k')
Stelios Fanourakis
on 20 May 2019
Thanks once again for your additional help. Althought, I might keep labels horizontally as they appear 'cause it looks better to me, than rotating them 90 degrees and have a vertical appearance.
More Answers (0)
See Also
Categories
Find more on Preprocessing Data in Help Center and File Exchange
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!An Error Occurred
Unable to complete the action because of changes made to the page. Reload the page to see its updated state.
Select a Web Site
Choose a web site to get translated content where available and see local events and offers. Based on your location, we recommend that you select: .
You can also select a web site from the following list
How to Get Best Site Performance
Select the China site (in Chinese or English) for best site performance. Other MathWorks country sites are not optimized for visits from your location.
Americas
- América Latina (Español)
- Canada (English)
- United States (English)
Europe
- Belgium (English)
- Denmark (English)
- Deutschland (Deutsch)
- España (Español)
- Finland (English)
- France (Français)
- Ireland (English)
- Italia (Italiano)
- Luxembourg (English)
- Netherlands (English)
- Norway (English)
- Österreich (Deutsch)
- Portugal (English)
- Sweden (English)
- Switzerland
- United Kingdom (English)
Asia Pacific
- Australia (English)
- India (English)
- New Zealand (English)
- 中国
- 日本Japanese (日本語)
- 한국Korean (한국어)