Unordered X Y coordinate pairs + Concentration contourplot - matlab

I have 2 vectors, X and Y, corresponding to a list of unordered coordinates, and a corresponding concentration vector C for each point.
I'd like to plot this on a structured grid as a 2D contour plot.
scatter3(X,Y,C,[],C);
gives me what I want visually, but I'm looking for 2D contours, i.e. pcolor. Is there an easy solution like griddata or trigriddata?
EDIT: Ok, so `scatter3(X,Y,C,[],C); view([0 90])ยด is the correct visual.
TriScatteredInterp works nicely for a rectangle. But what about an irregular shape like a map? :=)
F = TriScatteredInterp(x,y,C);
ty=0:0.005:0.284;
tx=0:0.005:0.65;
[qx,qy] = meshgrid(tx,ty);
qC = F(qx,qy);
pcolor(qx,qy,qC);
EXAMPLE: (X=width coordinate , Y= height coordinate, C= concentration of pollutant)
X Y C
0.1 0.0 5
0.1 0.1 10
0.1 0.21 5
0.2 0.1 4
0.2 0.3 1
0.2 0.5 2
0.2 0.51 7
0.3 0.15 4
0.3 0.36 6
0.3 0.5 3
0.3 0.52 7
scatter3(X,Y,C,[],C,'filled'); %individual plotting of X,Y pairs and colors=C
view([0 90]) %see only XY and Z becomes flat
Imagine we had 10000 XY pairs so scatter3 produces almost an image but without interpolation.

If I understand your question correctly you can use contour(X,Y,Z)
EDIT: You can use imagesc with a matrix that you make yourself. So if your x and y values are in a reasonable range you can just start with:
I = zeros(max(x), max(y));
for d = 1: length(x),
I(x(d),y(d)) = z(d);
end
imagesc(I);

Related

Matlab find x of weighted average

How to find the weighted average x? From graphing x(y) it looks to be around x=0.45?
y = [0.1 0.1 0.2 0.5 0.4 0.2]
x = [0.1 0.2 0.3 0.4 0.5 0.6]
One way to perhaps compute it would to find x where the area under the curve y(x) is half of the area under the whole curve. But how to write that in matlab?
Assuming you intend y to be the weights, and you want to compute the weighted average of x, then the weighted average is simply
sum(x.*y) / sum(y)

Drawing star-like figure in Matlab

I had to plot this in matlab :
so I wrote the following code:
x=[0.9 1 0.9 -0.9 0.7 0.7 -0.9 0.9];
y=[-1 0 1 -0.5 -0.8 0.8 -0.4 -1];
plot(x,y);
but this gives me:
Is this method insufficient to draw the first figure....Is there some other short method for this...
You can do better positioning your data points
nPoints = 7;
th = linspace(-2*pi, 2*pi, 2*nPoints+1);%// extra point to close the curve
r = 1;
x = r*cos(th);
y = r*sin(th);
scatter( x, y, 'ro' );
hold on;
plot( x(1:2:end), y(1:2:end), 'b-' );
axis equal;
Resulting with:
BTW, this code works for any odd nPoints - just try ;)
It seems to me that you want to construct a star polygon, which has the property that all points are equidistant to its neighboring points, and all points lie on the same circle.
First, we generate the desired angles a (measured from the x-axis to a line that connects the origin with the desired point, see wikipedia). Based on the polygon, we rearrage the angles in such a way that a desired number of points is skipped (in the code below, this is done by using among others repmat - but many alternatives exist).
To convert the angles to actual points in the plane, we take sine and cosine values, and then we can plot the dots and lines. Putting this together results in the following code, which results in the dersired figure
n = 7;
a = linspace(0,2*pi,n+1);
skip = 1;
b = [repmat(a(1:end-1),1,skip+1) a(end)];
a = b(1:skip+1:end);
figure;
clf;
hold on;
plot(cos(a),sin(a),'b-');
plot(cos(a(1:end-1)),sin(a(1:end-1)),'ro');
axis([-1 1 -1 1])
axis equal
A little less involved would be to compute the vector a like this:
a = mod(linspace(0,(skip+1)*2*pi,n+1),(skip+1)*2*pi);
I tried manually:
x = [-0.4 0.6 1 0.6 -0.4 -0.8 -0.8];
y = [-0.9 -0.7 0 0.7 0.9 0.4 -0.4];
x_ = [x,x];
y_ = [y,y];
figure;
hold on;
for ii=1:numel(x),
scatter(x(ii),y(ii),'ro');
plot([x_(ii),x_(ii+1+1)],[y_(ii),y_(ii+1+1)],'b-');
end
axis([-1 1 -1 1]);
And I get his:

Custom Scaling on y-axis in matlab

I come across a strange scaling in y- axis in a IEEE journal paper.
From top to bottom
y_axis = [0.9999 0.9995 0.999 0.995 0.99 0.98 0.95 0.9 0.8 0.7 0.5 0.3 0.2 0.1 0.05 0.02 0.01 0.005 0.001 0.0005 0.0001].
The scaling is not logaritmic. The space between the ticks are not equal. Definitely, it is not linear. You can see the big numbers (0.9... 0.999) and very small numbers(0.0001... 0.1) in detail in only one y-axis. I don't know how to do in MATLAB. I googled it, but i could not find. Can anyone help me? Thanks in advance.
The figure is the following code:
clear all
close all
set(0,'defaulttextinterpreter','latex')
P_tb = 1e-2;
Ntrial = 1e7; % # of Monte Carlo trials
jey=sqrt(-1);
omega_db = -15; % sidelobe gain of main antenna
omega = db2pow(omega_db); % omega in linear scale
F_db = [-5 -2 0 2 5];
JNR_db = -5:20;
beta_db = 2;
F_lin = 10.^(0.1*F_db);
JNR = 10.^(0.1*JNR_db);
beta = 10.^(0.1*beta_db);
temp = cell (length(F_db),1);
P_b = zeros (length(JNR_db), length(F_db));
for ii = 1:length(F_db)
SNR = JNR;
x = sqrt(omega);
F = F_lin(ii);
P_b(:,ii) = 1 - 1./(F+1).*(1-marcumq(x.*sqrt(2.*SNR./(F+1)),sqrt(2.*SNR.*F./(F+1))))-F./(F+1).*marcumq(sqrt(2.*SNR.*F./(F+1)), x.*sqrt(2.*SNR./(F+1)));
temp (ii) = {['$F=$' num2str(F_db(ii)) ' dB']};
end
figure,
h = plot(JNR_db, (P_b));
set(gca,'YTick',fliplr([0.9999 0.9995 0.999 0.995 0.99 0.98 0.95 0.9 0.8 0.7 0.5 0.3 0.2 0.1 0.05 0.02 0.01 0.005 0.001 0.0005 0.0001]))
set(gca,'YTickLabel',num2cell(fliplr([0.9999 0.9995 0.999 0.995 0.99 0.98 0.95 0.9 0.8 0.7 0.5 0.3 0.2 0.1 0.05 0.02 0.01 0.005 0.001 0.0005 0.0001])));
grid on
In the figure posted by the OP, the tickmarks are not at all equally distributed. Also, the scale of the axis is rather the inverse of sigmoidal (see below). To really see what the authors of that paper did, we can skeletonize the figure
im = conv2(im, fspecial('gaussian', [5, 5], 2));
im = ~bwmorph(im < 2.5, 'skel', inf);
and obtain the exact positions y_px as in
y_px = flipud(find(im(:, 285) == 0));
y_px([1, 2, 3, 11, 15, 19, 28]) = [];
I am removing some of the detections which are from the trendlines or from the -10 tick mark label of the x-axis.
If you plot the y-tick labels y_val (flipping your y_axis into ascending order) as a function of those pixel positions y_px, you can confirm that the relationship is exactly sigmoidal as suggested by #chapjc. However, in order to produce similar plots, you may rather want to invert the formula and define a function
px_y = #(y) log(-y ./ (y - 1));
You can use this function then for plotting. The paper you refer to shows data in a range x = -10 : 0.1 : 4. Let's plot in this same range a sine function somewhere between 0.0001 and 0.9999. Note that we use our scaling function px_y, and then replace the y-tick positions and labels
plot(x, px_y(0.7 + sin(x) / 4));
set(gca(), 'ytick', px_y(y_val), 'yticklabel', num2cell(y_val));
resulting in something that should look like this
In summary, you can define a function y_px to transform your y-data, and then set the ytick and yticklabel properties of your axes. Whatever scale you choose for this approach, it is important to transform both the ytick values and all y-data with the same function.
Try this:
set(gca,'YTick',fliplr([0.9999 0.9995 0.999 0.995 0.99 0.98 0.95 0.9 0.8 0.7 0.5 0.3 0.2 0.1 0.05 0.02 0.01 0.005 0.001 0.0005 0.0001]));
set(gca,'YTickLabel',num2cell(fliplr([0.9999 0.9995 0.999 0.995 0.99 0.98 0.95 0.9 0.8 0.7 0.5 0.3 0.2 0.1 0.05 0.02 0.01 0.005 0.001 0.0005 0.0001])));
Matlab wants the numbers to be in increasing order, so instead of reordering your numbers, I just invoked fliplr instead.
To get an idea of this custom y-axis space, you can do plot(linspace(-5,5,numel(y_axis)),fliplr(y_axis),'r'). This looked a lot like a dose curve, so plot an equation I found with hold on; x=-5:0.01:5; plot(x,exp(x)./(1+exp(x))). Here's what it looks like:
The form looks right. There is probably a constant on one of the terms to tweak the shape. If you want to put your data in this space, apply this function (yscFun = #(x) exp(x)./(1+exp(x)) or yscFun = #(x) 1./(1+exp(-x))). Then set the tick labels to y_axis with set(gca,'YTickLabel',num2cell(fliplr(y_axis))); as suggested by nispio.
This is the final solution that I found. Thank you very much. I did not know the sigmoid function. Below are the MATLAB codes for this puporse.
close all
clear all
%your desired y_ticks
y_axis = [0.9999 0.9995 0.999 0.995 0.99 0.98 0.95 0.9 0.8 0.7 0.5 0.3 0.2 0.1 0.05 0.02 0.01 0.005 0.001 0.0005 0.0001];
%order in increasing way
y_val = fliplr (y_axis);
% the Sigmoid function and its inverse
py_x = #(x) 0.5*erf(x*sqrt(pi/8)) + 0.5;
px_y = #(x) sqrt (8/pi)*erfinv (2*x - 1);
beta = 10^(0.1*-15);
F = 10^(0.1*-5);
JNR_db = -5:20;
SNR = 10.^(0.1.*JNR_db);
% my original data
P_b = # (x) 1 - 1./(F+1).*(1-marcumq(x.*sqrt(2.*SNR./(F+1)),sqrt(2.*SNR.*F./(F+1))))-F./(F+1).*marcumq(sqrt(2.*SNR.*F./(F+1)), x.*sqrt(2.*SNR./(F+1)));
P_b1 = P_b(sqrt(beta));
% tranfrom it using inverse function
P_b2 = px_y(P_b1);
figure,
plot(JNR_db, P_b2);
grid on
ylim ([ px_y(0.0001) px_y(0.9999) ]);
% tranform the desired y_tick using inverse function
set(gca(), 'ytick', px_y (y_val));
set (gca (), 'yticklabel', num2cell(y_val));
% % Sigmoid function verification
x_temp = linspace(-5,5,numel(y_axis));
figure
plot(x_temp, fliplr(y_axis), 'r');
hold on
plot (x_temp, py_x (x_temp), 'b' )

Contour plot with 3 vector

I've a matrix M 10201x3 where the first 2 column are constant used to compute the response Z in column 3. Example:
.... ... .................
0.0031 0.02 0.792729854583740
0.0031 0.03 0.802729845046997
0.0031 0.04 0.812729895114899
0.0031 0.05 0.822729885578156
.... ... .................
0.0034 0.02 0.867461800575256
0.0034 0.03 0.877461791038513
0.0034 0.04 0.887461841106415
0.0034 0.05 0.897461831569672
0.0034 0.06 0.907461822032929
.... ... .................
I wanna make a contour plot where X = M(:,1), Y = M(:,2) and Z = M(:,3) with different colors for different hights. I need to do the same thing in both 2D and 3D.
I assume your data is regular, and you know how many repeating x-elements you have.
Let's call the number of repeating x = L - or you'll be able to find that out.
You need to reshape your vectors:
X = reshape(X,[],L);
Y = reshape(Y,[],L);
Z = reshape(Z,[],L);
You need Z how it is, but just the first row of X and the first column of Y.
X = X(:,1);
Y = Y(1,:);
and then you can use contour:
contour(X,Y,Z);
There is no need for interpolation!
contour(X,Y,Z), contour(X,Y,Z,n), and contour(X,Y,Z,v) draw contour
plots of Z using X and Y to determine the x- and y-axis limits.
If X and Y are vectors, then the length of X must equal the number of
columns in Z and the length of Y must equal the number of rows in Z.
If X and Y are matrices, then their sizes must equal the size of Z.
Therefore shorter:
X = X(1:L:end);
Y = Y(1:L);
Z = reshape(Z,[],L);
contour(X,Y,Z);
I would suggest to transform this array to three 2D arrays using interpolation with function griddata(). Interpolation could be useful for nonregular data. First, we create grid of coordinates:
xq=min(X):(max(X)-min(X))/200:max(X);
yq=min(Y):(max(Y)-min(Y))/200:max(Y);
[Xq, Yq] = meshgrid(xq,yq);
Than, we use interpolating:
Zq =griddata(X,Y,Z,Xq,Yq);
Than you can plot:
countour(Xq,Yq,Zq)

interpolating a data along y axis at points defined along x axis

Due to lack of explaining i am going to edit my question a bit.
I have a data set along y axis plotted against x axis with step of 0.01 along x axis. Of course along y axis the step can be any arbitrary value. For example i have 0.02 and 0.03 then 0.05. Which means value 0.04 is missing along y axis. I want to interpolate this and values like this.
Please help me out.
Data: (Its just part of data, Actuall data goes till 1 in both columns)
0 0.154994
0.01 0.161559
0.02 0.16794
0.03 0.168151
0.04 0.172584
0.05 0.177927
0.06 0.187229
0.07 0.194835
0.08 0.195799
0.09 0.200876
0.1 0.207076
0.11 0.213972
0.12 0.220275
0.13 0.227207
0.14 0.234465
0.15 0.238785
0.16 0.250232
0.17 0.257551
Following what #tmpearce said, the simplest use would be something like:
>> x = 0.0:0.01:0.17;
>> pred_y = interp1(Data(:,1), Data(:,2), x);
Edit follows:
If you data you posted is named Data, and your x and y data exist on {0,1} you might want to do this:
>> X = Data(:,1);
>> Y = Data(:,2);
>> pred_x = 0.0:0.01:1.0;
>> pred_y = interp1(X,Y,pred_x);
See the literature on interp1 for all of the options.