Not sure what this 'histogram code' is doing in MATLAB - matlab

I have following code that was given to me, but I am not sure at all as to what the logic here is. The idea, I believe, is that this will histogram/quantize my data. Here is the code:
The input:
x = 180.*rand(1,1000); %1000 points from 0 to 180 degrees.
binWidth = 20; %I want the binWidth to be 20 degrees.
The main function:
% -------------------------------------------------------------------------
% Compute the closest bin center x1 that is less than or equal to x
% -------------------------------------------------------------------------
function [x1, b1] = computeLowerHistBin(x, binWidth)
% Bin index
bin = floor(x./binWidth - 0.5);
% Bin center x1
x1 = binWidth * (bin + 0.5);
% add 2 to get to 1-based indexing
b1 = bin + 2;
end
Finally, the final 'quantized' data:
w = 1 - (x - x1)./binWidth
Here is what I do not get: I do not understand - at all - just why exactly x1 is computed the way it is, and also why/how w is computed the way it is. In fact, of all the things, w confuses me the most. I literally cannot understand the logic here, or what is really intended. Would appreciate a detailed elucidation of this logic. Thanks.

He is binning with lb <= x < up and splitting the interval [0,180] in [-10,10), [10, 30), [30,40) ..., [150,170), [170,190).
Suppose x = 180, then:
bin = floor(180/20-0.5) = floor(9-0.5) = floor(8.5) = 8;
while if x = 0:
bin = floor(`0/20-0.5) = floor(-0.5) = floor(-1) = -1;
which respectively translate into x1 = 20 * (8+0.5) = 170 and x1 = -10 which seems like what the function suggests lowerHistBin().
In the end, w simply measures how far the point x is from the corresponding lower bin x1. Notice that w is in (0,1], with w being 1 when x = x1 and approaching 0 when x -> x1+binWidth. So, if x say approaches 170, then w will approach 1 - (170-150)/20 = 0.

Related

find nearest point to a fitting line and the neighborhood of it in Matlab

Supposed I have two random double array, which means that one x coordinate might have multiple y value.
X = randi([-10 10],1,1000);
Y = randi([-10 10],1,1000);
Then I give a line equation: y=ax+b.
I want to find the nearest point to the nearest point to the line based on every x point. And when I find this point, I will find it's neighborhood points within specific range. Please forgive my poor English, maybe following picture can help more.
Because I have a lot of data points, I hope there is an efficient way to deal with this problem.
if your X's are discrete you can try something like:
xrng = [-10 10];
yrng = [-10 10];
a = rand;
b = rand;
f = #(x) a*x + b;
X = randi(xrng,1,1000);
Y = randi(yrng,1,1000);
ezplot(f,xrng);
hold on;
plot(X,Y,'.');
xx = xrng(1):xrng(2);
nbrSz = 2;
nx = diff(xrng);
nearestIdx = zeros(nx,1);
nbrIdxs = cell(nx,1);
for ii = 1:nx
x = xx(ii);
y = f(x);
idx = find(X == x);
[~,idxidx] = min(abs(y - Y(idx)));
nearestIdx(ii) = idx(idxidx);
nbrIdxIdxs = abs(Y(nearestIdx(ii)) - Y(idx)) <= nbrSz;
nbrIdxs{ii} = idx(nbrIdxIdxs);
plot(X(nearestIdx(ii)),Y(nearestIdx(ii)),'og');
plot(X(nearestIdx(ii)) + [0 0],Y(nearestIdx(ii)) + [-nbrSz nbrSz],'g')
plot(X(nbrIdxs{ii}),Y(nbrIdxs{ii}),'sy')
end

Matlab: Extract values that I plot but which has not been stored

I have a mathematical function E which I want to minimize. I get from solving this 16 possible solutions x1, x2, ..., x16, only two of which that actually minimize the function (located at a minimum). Using a for loop, I can then plug all of these 16 solutions into the original function, and select the solutions I need by applying some criteria via if statements (plotting E vs E(x) if x is real and positive, if first derivative of E is below a threshold, and if the second derivative of E is positive).
That way I only plot the solutions I'm interested in. However, I would now like to extract the relevant x that I plot. Here's a sample MATLAB code that plots the way I just described. I want to extract the thetas that I actually end up plotting. How to do that?
format long
theta_s = 0.77944100;
sigma = 0.50659500;
Delta = 0.52687700;
%% Defining the coefficients of the 4th degree polynomial
alpha = cos(2*theta_s);
beta = sin(2*theta_s);
gamma = 2*Delta^2/sigma^2;
a = -gamma^2 - beta^2*Delta^2 - alpha^2*Delta^2 + 2*alpha*Delta*gamma;
b = 2*alpha*gamma - 2*Delta*gamma - 2*alpha^2*Delta + 2*alpha*Delta^2 -...
2*beta^2*Delta;
c = 2*gamma^2 - 2*alpha*Delta*gamma - 2*gamma - alpha^2 + 4*alpha*Delta +...
beta^2*Delta^2 - beta^2 - Delta^2;
d = -2*alpha*gamma + 2*Delta*gamma + 2*alpha + 2*beta^2*Delta - 2*Delta;
e = beta^2 - gamma^2 + 2*gamma - 1;
%% Solve the polynomial numerically.
P = [a b c d e];
R = roots(P);
%% Solve r = cos(2x) for x: x = n*pi +- 1/2 * acos(r). Using n = 0 and 1.
theta = [1/2.*acos(R) -1/2.*acos(R) pi+1/2.*acos(R) pi-1/2.*acos(R)];
figure;
hold on;
x = 0:1/1000:2*pi;
y_1 = sigma*cos(x - theta_s) + sqrt(1 + Delta*cos(2*x));
y_2 = sigma*cos(x - theta_s) - sqrt(1 + Delta*cos(2*x));
plot(x,y_1,'black');
plot(x,y_2,'black');
grid on;
%% Plot theta if real, if positive, if 1st derivative is ~zero, and if 2nd derivative is positive
for j=1:numel(theta);
A = isreal(theta(j));
x_j = theta(j);
y_j = sigma*cos(x_j - theta_s) + sqrt(1 + Delta*cos(2*x_j));
FirstDer = sigma* sin(theta(j) - theta_s) + Delta*sin(2*theta(j))/...
sqrt(1 + Delta*cos(2*theta(j)));
SecDer = -sigma*cos(theta(j)-theta_s) - 2*Delta*cos(2*theta(j))/...
(1 + Delta*cos(2*theta(j)))^(1/2) - Delta^2 * (sin(2*theta(j)))^2/...
(1 + Delta*cos(2*theta(j)))^(3/2);
if A == 1 && x_j>=0 && FirstDer < 1E-7 && SecDer > 0
plot(x_j,y_j,['o','blue'])
end
end
After you finish all plotting, get the axes handle:
ax = gca;
then write:
X = get(ax.Children,{'XData'});
And X will be cell array of all the x-axis values from all lines in the graph. One cell for each line.
For the code above:
X =
[1.961054062875753]
[4.514533853417446]
[1x6284 double]
[1x6284 double]
(First, the code all worked. Thanks for the effort there.)
There are options here. A are couple below
Record the values as you generate them
Within the "success" if statement, simply record the values. See edits to your code below.
This would always be the preferred option for me, it just seems much more efficient.
xyResults = zeros(0,2); %%% INITIALIZE HERE
for j=1:numel(theta);
A = isreal(theta(j));
x_j = theta(j);
y_j = sigma*cos(x_j - theta_s) + sqrt(1 + Delta*cos(2*x_j));
FirstDer = sigma* sin(theta(j) - theta_s) + Delta*sin(2*theta(j))/...
sqrt(1 + Delta*cos(2*theta(j)));
SecDer = -sigma*cos(theta(j)-theta_s) - 2*Delta*cos(2*theta(j))/...
(1 + Delta*cos(2*theta(j)))^(1/2) - Delta^2 * (sin(2*theta(j)))^2/...
(1 + Delta*cos(2*theta(j)))^(3/2);
if A == 1 && x_j>=0 && FirstDer < 1E-7 && SecDer > 0
xyResults(end+1,:) = [x_j y_j]; %%%% RECORD HERE
plot(x_j,y_j,['o','blue'])
end
end
Get the result from the graphics objects
You can get the data you want from the actual graphics objects. This would be the option if there was just no way to capture the data as it was generated.
%First find the objects witht the data you want
% (Ideally you could record handles to the lines as you generated
% them above. But then you could also simply record the answer, so
% let's assume that direct record is not possible.)
% (BTW, 'findobj' is an underused, powerful function.)
h = findobj(0,'Marker','o','Color','b','type','line')
%Then get the `xdata` filed from each
capturedXdata = get(h,'XData');
capturedXdata =
2×1 cell array
[1.96105406287575]
[4.51453385341745]
%Then get the `ydata` filed from each
capturedYdata = get(h,'YData');
capturedYdata =
2×1 cell array
[1.96105406287575]
[4.51453385341745]

Construct ternary grid, evaluate a function on the grid and contour plot in Matlab

I need to evaluate a function (say)
Fxy = 2*x.^2 +3 *y.^2;
on a ternary grid x-range (0 - 1), y-range (0-1) and 1-x-y (0 - 1).
I am unable to construct the ternary grid on which I need to evaluate the above function. Also, once evaluated I need to plot the function in a ternary contour plot. Ideally, I need the axes to go counter clockwise in the sense (x -> y--> (1-x-y)).
I have tried the function
function tg = triangle_grid ( n, t )
ng = ( ( n + 1 ) * ( n + 2 ) ) / 2;
tg = zeros ( 2, ng );
p = 0;
for i = 0 : n
for j = 0 : n - i
k = n - i - j;
p = p + 1;
tg(1:2,p) = ( i * t(1:2,1) + j * t(1:2,2) + k * t(1:2,3) ) / n;
end
end
return
end
for the number of sub intervals between the triangle edge coordinates
n = 10 (say)
and for the edge coordinates of an equilateral triangle
t = tcoord = [0.0, 0.5, 1.0;
0.0, 1.0*sqrt(3)/2, 0.0];
This generated a triangular grid with the x-axis from 0-1 but the other two are not from 0-1.
I need something like this:
... with the axes range 0-1 (0-100 would also do).
In addition, I need to know the coordinate points for all intersections within the triangular grid. Once I have this I can proceed to evaluate the function in this grid.
My final aim is to get something like this. This is a better representation of what I need to achieve (as compared to the previous plot which I have now removed)
Note that the two ternary plots have iso-value contours which are different in in magnitude. In my case the difference is an order of magnitude, two very different Fxy's.
If I can plot the two ternary plots on top of each other then and evaluate the compositions at the intersection of two iso-value contours on the ternary plane. The compositions should be as read from the ternary plot and not the rectangular grid on which triangle is defined.
Currently there are issues (as highlighted in the comments section, will update this once the problem is closer to solution).
I am the author of ternplot. As you have correctly surmised, ternpcolor does not do what you want, as it is built to grid data automatically. In retrospect, this was not a particularly wise decision, I've made a note to change the design. In the mean time this code should do what you want:
EDIT: I've changed the code to find the intersection of two curves rather than just one.
N = 10;
x = linspace(0, 1, N);
y = x;
% The grid intersections on your diagram are actually rectangularly arranged,
% so meshgrid will build the intersections for us
[xx, yy] = meshgrid(x, y);
zz = 1 - (xx + yy);
% now that we've got the intersections, we can evaluate the function
f1 = #(x, y) 2*x.^2 + 3*y.^2 + 0.1;
Fxy1 = f1(xx, yy);
Fxy1(xx + yy > 1) = nan;
f2 = #(x, y) 3*x.^2 + 2*y.^2;
Fxy2 = f2(xx, yy);
Fxy2(xx + yy > 1) = nan;
f3 = #(x, y) (3*x.^2 + 2*y.^2) * 1000; % different order of magnitude
Fxy3 = f3(xx, yy);
Fxy3(xx + yy > 1) = nan;
subplot(1, 2, 1)
% This constructs the ternary axes
ternaxes(5);
% These are the coordinates of the compositions mapped to plot coordinates
[xg, yg] = terncoords(xx, yy);
% simpletri constructs the correct triangles
tri = simpletri(N);
hold on
% and now we can plot
trisurf(tri, xg, yg, Fxy1);
trisurf(tri, xg, yg, Fxy2);
hold off
view([137.5, 30]);
subplot(1, 2, 2);
ternaxes(5)
% Here we plot the line of intersection of the two functions
contour(xg, yg, Fxy1 - Fxy2, [0 0], 'r')
axis equal
EDIT 2: If you want to find the point of intersection between two contours, you are effectively solving two simultaneous equations. This bit of extra code will solve that for you (notice I've used some anonymous functions in the code above now, as well):
f1level = 1;
f3level = 1000;
intersection = fsolve(#(v) [f1(v(1), v(2)) - f1level; f3(v(1), v(2)) - f3level], [0.5, 0.4]);
% if you don't have the optimization toolbox, this command works almost as well
intersection = fminsearch(#(v) sum([f1(v(1), v(2)) - f1level; f3(v(1), v(2)) - f3level].^2), [0.5, 0.4]);
ternaxes(5)
hold on
contour(xg, yg, Fxy1, [f1level f1level]);
contour(xg, yg, Fxy3, [f3level f3level]);
ternplot(intersection(1), intersection(2), 1 - sum(intersection), 'r.');
hold off
I have played a bit with the file exchange submission https://www.mathworks.com/matlabcentral/fileexchange/2299-alchemyst-ternplot.
if you just do this:
[x,y]=meshgrid(0:0.1:1);
Fxy = 2*x.^2 +3 *y.^2;
ternpcolor(x(:),y(:),Fxy(:))
You get:
The thirds axis is created exactly as you say (1-x-y) inside the ternpcolor function. There are lots of things to "tune" here but I hope it is enough to get you started.
Here is a solution using R and my package ggtern. I have also included the points within proximity underneath, for the purpose of comparison.
library(ggtern)
Fxy = function(x,y){ 2*x^2 + 3*y^2 }
x = y = seq(0,1,length.out = 100)
df = expand.grid(x=x,y=y);
df$z = 1 - df$x - df$y
df = subset(df,z >= 0)
df$value = Fxy(df$x,df$y)
#The Intended Breaks
breaks = pretty(df$value,n=10)
#Create subset of the data, within close proximity to the breaks
df.sub = ldply(breaks,function(b,proximity = 0.02){
s = b - abs(proximity)/2; f = b + abs(proximity)/2
subset(df,value >= s & value <= f)
})
#Plot the ternary diagram
ggtern(df,aes(x,y,z)) +
theme_bw() +
geom_point(data=df.sub,alpha=0.5,color='red',shape=21) +
geom_interpolate_tern(aes(value = value,color=..level..), size = 1, n = 200,
breaks = c(breaks,max(df$value) - 0.01,min(df$value) + 0.01),
base = 'identity',
formula = value ~ poly(x,y,degree=2)) +
labs(title = "Contour Plot on Modelled Surface", x = "Left",y="Top",z="Right")
Which produces the following:

How to use integration limits correctly (Matlab)

I've made a script that calculates a given integral with the limits:
0 <= x <= 2 and 0 <= y <= 1
But now I want to change the limits to:
0 <= x <= 2 and 0 <= y <= sin((pi*x)/2)
Function:
function f = inte(x,y)
dz = 10;
f = exp(-dz*((x-1.25).^2+y.^2)).*cos(y.*(x-1.25));
end
This is my script for the earlier limits:
L = 100; M = L/2;
hx = (2)/L; hy = (1)/M;
x=[0:L]*hx;
y=[0:M]*hy;
Fx=[];
for i = 1:L+1
Fy=[];
for j = 1:M+1
f = inte(x(i),y(j));
Fy = [Fy f];
end
ycor = hy*(sum(Fy) - Fy(1)/2 - Fy(end)/2);
Fx = [Fx ycor];
end
ans = hx*(sum(Fx) - Fx(1)/2 - Fx(end)/2);
disp (ans)
I can't seem to get the right answer when I try to change the code. The correct answer should be 0.1560949...
L is amount of steps in x direction, M in y direction. hx and hy are step lengths.
This is really bugging me. And no I can only use the commands integral2 or traps as reference.
Thanks in advance!
In your present code, the lines
hy = (1)/M;
y=[0:M]*hy;
refer to the y-variable. When the limits for y depend on x, these lines cannot stay outside of the loop over x: they should be moved in and use the value x(i). Like this:
for i = 1:L+1 % as in your code
hy = (sin(pi*x(i)/2))/M;
y = [0:M]*hy;
Fy=[]; % this and the rest as in your code
I get output 0.1561, as you wanted.

Normalizing a histogram in matlab

I have a histogram
hist(A, 801)
that currently resembles a normal curve but with max value at y = 1500, and mean at x = 0.5. I want to normalize it, so I tried
h = hist(A, 801)
h = h ./ sum(h)
bar(h)
now I get a normal curve with max at y = .03, but a mean at x = 450.
how do I decrease the frequency so the sum is 1, while retaining the same x range?
A is derived from
A = walk(50000, 800, .05, 2, .25, 0)
where
function [X_new] = walk(N_sim, N, mu, T, sigma, X_init)
delt = T/N;
up = sigma*sqrt(delt);
down = -sigma*sqrt(delt);
p = 1./2.*(1.+mu/sigma*sqrt(delt));
X_new = zeros(N_sim,1);
X_new(1:N_sim,1) = X_init;
ptest = zeros(N_sim,1);
for i = 1:N
ptest(:,1) = rand(N_sim,1);
ptest(:,1) = (ptest(:,1) <= p);
X_new(:,1) = X_new(:,1) + ptest(:,1)*up + (1.-ptest(:,1))*down;
end
The sum is 1 with your code as it stands.
You may want integral equal to 1 (so that you can compare with the theoretical pdf). In that case:
[h, c] = hist(A, 801); %// c contains bin centers. They are equally spaced
h = h / sum(h) / (c(2)-c(1)); %// normalize to area 1
trapz(c,h) %// compute integral. Should be approximately 1