Issue with reading data in text files and plotting a graph (Matlab) - matlab

I use the following code to collect data from two text files join them together and then plot them. For some reason, I appear to get two plots rather than 1, I am not sure why this is happening.
load MODES1.dat; % read data into the MODES1 matrix
x1 = MODES1(:,1); % copy first column of MODES1 into x1
y1 = MODES1(:,2); % and second column of MODES1 into y1
load MODES.dat; % read data into the MODES matrix
x = MODES(:,1); % copy first column of MODES into x
y = MODES(:,2); % and second column of MODES into y
% Joining the two sets of data
endx = [x1;x];
endy = [y1;y];
figure(1)
plot(endx,endy)
xlabel('Unique Threshold Strains','FontSize',12);
ylabel('Probabilities of occurrence','FontSize',12);
title('\it{Unique Values versus frequencies of occurrence}','FontSize',16);
Thanks

Your problem is quite a simple one. Matlab's plot command creates a point for each data point defined by the parameters and connects those points in the order they appeared in the first parameter. To get an idea of this behavior, try
x = [0;1;-1;2;-2;3;-3;4;-4;5];
plot(x,x.^2);
You won't get the quadratic function graph you might expect.
To fix this, you must sort you input arrays identically. Sorting one array is simple (sort(endx)), but you want to sort both in the same way. Matlab actually gives you a function to do this, but it only works on matrices, so you need to do some concatenating/seperating:
input = sortrows( [endx endy] );
endx = input(:,1);
endy = input(:,2);
This will sort the rows of the matrix built by putting endy right of endx with respect to the first column (endx). Now your inputs are correctly sorted and the resulting plot should only show one line. (More accurately, one line which does not at some point go back where it came from.)
Another way to achieve this, depending on you actual use case and data origin, would be to build the mean value of both parts of x, so instead of endx = [x1;x];, you'd build endx = mean([x1 x],2);.
Yet another way is to drop the line altogether and go with
plot(endx,endy,'.');
or
plot(endx,endy,'LineStyle','none');
But this is only useful if your data points are very close to each other.

Related

comparing generated data to measured data

we have measured data that we managed to determine the distribution type that it follows (Gamma) and its parameters (A,B)
And we generated n samples (10000) from the same distribution with the same parameters and in the same range (between 18.5 and 59) using for loop
for i=1:1:10000
tot=makedist('Gamma','A',11.8919,'B',2.9927);
tot= truncate(tot,18.5,59);
W(i,:) =random(tot,1,1);
end
Then we tried to fit the generated data using:
h1=histfit(W);
After this we tried to plot the Gamma curve to compare the two curves on the same figure uing:
hold on
h2=histfit(W,[],'Gamma');
h2(1).Visible='off';
The problem s the two curves are shifted as in the following figure "Figure 1 is the generated data from the previous code and Figure 2 is without truncating the generated data"
enter image description here
Any one knows why??
Thanks in advance
By default histfit fits a normal probability density function (PDF) on the histogram. I'm not sure what you were actually trying to do, but what you did is:
% fit a normal PDF
h1=histfit(W); % this is equal to h1 = histfit(W,[],'normal');
% fit a gamma PDF
h2=histfit(W,[],'Gamma');
Obviously that will result in different fits because a normal PDF != a gamma PDF. The only thing you see is that for the gamma PDF fits the curve better because you sampled the data from that distribution.
If you want to check whether the data follows a certain distribution you can also use a KS-test. In your case
% check if the data follows the distribution speccified in tot
[h p] = kstest(W,'CDF',tot)
If the data follows a gamma dist. then h = 0 and p > 0.05, else h = 1 and p < 0.05.
Now some general comments on your code:
Please look up preallocation of memory, it will speed up loops greatly. E.g.
W = zeros(10000,1);
for i=1:1:10000
tot=makedist('Gamma','A',11.8919,'B',2.9927);
tot= truncate(tot,18.5,59);
W(i,:) =random(tot,1,1);
end
Also,
tot=makedist('Gamma','A',11.8919,'B',2.9927);
tot= truncate(tot,18.5,59);
is not depending in the loop index and can therefore be moved in front of the loop to speed things up further. It is also good practice to avoid using i as loop variable.
But you can actually skip the whole loop because random() allows to return multiple samples at once:
tot=makedist('Gamma','A',11.8919,'B',2.9927);
tot= truncate(tot,18.5,59);
W =random(tot,10000,1);

Why is the resultant of my improfile function returning with a mirrored graph in MATLAB?

I am currently running improfile on MATLAB with a line going through the center of the picture below:
After doing so, I'm plotting the resultant using the code below:
xi = [1 size(d_Img,2) size(d_Img,2) 1];
yi = [ceil(size(d_Img,1)/2), ceil(size(d_Img,1)/2), ceil(size(d_Img,1)/2 ),ceil(size(d_Img,1)/2)];
c_d = improfile(d_Img,xi,yi);
c_c = improfile(c_Img,xi,yi);
c_d = c_d';
c_c = c_c';
size_c = size(c_d);
n = 1:size_c(2);
plot(n,c_d);
And here is the plot:
Why are the curves mirroring each other? I am asking to gain a better understanding of what exactly improfile seems to be achieving in MATLAB.
improfile computes something like a "path integral", it gives you the image intensity values around a user specified path. For example, if you use:
improfile(img,[1 1],[1 size(img,2)]);
It gives the same as img(:,1). This is because the path you are using in improfile is from (1,1) to (1,size(img,2)) , meaning the first row. However you could definitely add more complicated paths.
In your case you are going trow a path defined by 4 points. The points are, if I substitute your equation by the resultant numbers:
(1,79)->(134,79)->(134,79)->(1,79). Thus, looking at this, it is obvious that your result should be mirrored, because you are integrating over a line the way there, and back!
Sidenote:
you can do plot(c_d); and forget about that n

How tick labels on one of the plot's axis can be multiplied in MATLAB?

I am currently trying to make 'nice looking' axis on my plot in Matlab. The values are samples where each is taken every 20ms. So on X axis I'd like to have time in ms. My general code for plotting data is very simple:
plot(1:size( data.matrix,1), data.matrix(:,1),'b');
So far I've been able to correctly display sample numbers on this axis:
Code:
set(gca,'XTick',(1:size(data.matrix,1))*20);
Result (a):
In the given example the number of samples equals 184, that makes:
time = 184 * 20ms = 3680ms
Because changing the XTick value didn't do much of a change, I've tested XTickLabel property:
Code:
set(gca,'XTickLabel',ceil(linspace(0,size(data.matrix,1)*20,10)));
Result (b):
Code:
set(gca,'XTickLabel',0:ceil((size(data.matrix,1)*20)/10):size(data.matrix,1)*20);
Result (c):
As you may see, the results aren't the worst one. But this is not what I am trying to achieve. My goal is to have values like this:
So it simply first plot's (result a) X axis multiplied by 20.
Can someone please tell me how to achieve this?
when you use :
plot(1:size( data.matrix,1), data.matrix(:,1),'b');
The first parameter 1:size( data.matrix,1) create a vector of consecutive integers representing the indices of your data points. Two things are wrong with that:
1) You do not need to specify it. Matlab plot function called with only the Y data will create this vector automatically and use it to plot the data.
2) These indices represent the position of your data in an array, they have no physical meaning (like "time" for your case).
The solution is to create a proper 'time' vector and send it as the first parameter to the plot function. This way Matlab will take care of the tick management and you don't have to temper with the manual xtick settings.
Look at the two ways of doing it in the example below and everything will be clear:
%// build a simple index "X" vector (as you were doing)
x_index = 1:size(data.matrix,1) ;
%// build a properly scaled time vector
timeInterval = 20 ; % in milliseconds
x_time = ( 0:size(data.matrix,1)-1 ) * timeInterval ;
plot( x_index , data.matrix(:,1) ) %// this will do like in your example
plot( x_time , data.matrix(:,1) ) %// this will do what you want
Can you not just do?
set(gca,'XTickLabel',(1:size(data.matrix,1))*20*20);

Interactive curve fitting with MATLAB using custom GUI?

I find examples the best way to demonstrate my question. I generate some data, add some random noise, and fit it to get back my chosen "generator" value...
x = linspace(0.01,1,50);
value = 3.82;
y = exp(-value.*x);
y = awgn(y,30);
options = optimset('MaxFunEvals',1000,'MaxIter',1000,'TolFun',1e-10,'Display','off');
model = #(p,x) exp(-p(1).*x);
startingVals = [5];
lb = [1];
ub = [10];
[fittedValue] = lsqcurvefit(model,startingVals,x,y,lb,ub,options)
fittedGraph = exp(-fittedValue.*x);
plot(x,y,'o');
hold on
plot(x,fittedGraph,'r-');
In this new example, I have generated the same data but this time added much more noise to the first 15 points. Because it is random sometimes it works out okay, but after a few runs I get a good example that illustrates my problem. Same code, except for these lines added under value = 3.82
y = exp(-value.*x);
y(1:15) = awgn(y(1:15),5);
y(15:end) = awgn(y(15:end),30);
As you can see, it has clearly not given a good fit to where the data seems reliable, because it is fitting from points 1-50. What I want to do is say, okay MATLAB, I can see we have some noisy data but it seems decent over a range, only fit your exponential from points 15 to the end. I could go back to my code and update it to do this, but I will be batch fitting graphs like this where each one will have different ranges of 'good' data.
So what I am after is a GUI callback mechanisms that allows me to click on two circles from the data and have them change color or something, which indicates the lsqcurvefit will only fit over that range. Internally all it has to change is inside the lsqcurvefit call e.g.
x(16:end),y(16:end)
But the range should update depending on the starting and ending circles I have clicked.
I hope my question is clear. Thanks.
You could use ginput to select the two points for your min and max in the plot.
[x,y]=ginput(2);
%this returns you the x and y coordinates of two points clicked after each other
%the min point is assumed to be clicked first
min=[x(1) y(1)];
max=[x(2) y(2)];
then you could fit your curve with the coordinates for min and max I guess.
You could also switch between a rightclick for the min and a leftclick for the max etc.
Hope this helps you.

Matlab Plot Smoothing having no effect

I'm currently having some trouble with the 'smooth' command, namely that it seems to have no effect on the generated plot. I have already used the following script to generate a plot
for h=1:4
linespec = {'rx', 'gx', 'bx', 'yx'};
hold on
for b=1:365
y=mean(mean(A(b,6*(h-1)+1:6*h)));
p(h)=plot(b,y,linespec{h});
end
hold off
end
Going row by row in data set A and taking the average of the values in the first six columns, then column 7 through 12, 13 through 18 and 19 through 14; generating four plots in total.
The next step was to smooth the resultant plot by averaging the values over a span of 9. So, I tweaked the script to the following;
for h=1:4
linespec = {'rx', 'gx', 'bx', 'yx'};
hold on
for b=1:365
y=mean(mean(A(b,6*(h-1)+1:6*h)));
w = smooth(y,9,'moving');
p(h)=plot(b,w,linespec{h});
end
hold off
end
Essentially just adding the w variable and replacing y with w in the plot command. Yet this has no effect whatsoever on my plot. Matlab doesn't throw up any errors either, so there doesn't seem to be a problem with the input size. Does anyone have an idea as to what the issue might be?
In either version of the loop, you appear to be plotting individual values of y against individual values of b. I presume, then, that y is a single value. You can't smooth a point, so the smooth operation is having no effect.
From the start, you don't need to make a loop to calculate the various means; mean can take a 2D matrix and return a vector. Calculate y in one go, then smooth that vector (should have length 365, I presume - depends on the size of input A). e.g.:
b = 1:365;
y=mean(A(:,6*(h-1)+1:6*h),2);
w = smooth(y,9,'moving');
plot(b,y,'rx');
hold on
plot(b,w,'gx');