I'm trying to visualise a function into a more intuitive color-coded plot, which can be used into a image. I try to visualise the range in which fluorescent proteins can efficiently transfer energy from one to another. A very important factor in this process is the distance between the two proteins. Therefore I want to plot the theoretical graph of energy transfer as a function of distance on top of one of these proteins.
I would like to have an 2D intensity plot which I can use to incorporate into my protein model.
The function describing efficient energy transfer is:
E = R^6/(R^6+r^6)
E = efficiency of energy transfer
R = Förster distance 50% chance of transfer
r = actual distance between the fluorescent proteins
Low values for r cause high values of E, meaning efficient energy transfer --> Green
High values for r cause low values of E, inefficient energy transfer --> red
My question is if someone can help me to transform the graph into a color-coded circle, where the middle of the circle corresponds with high E (green) and the borders are more red.
So far, I tried the mesh + surf function, but these require a matrix so that doesn't work.
I appreciate all your help, thank you for your replies!
Cheers,
Reinier
If I understand correctly then
[R r] = meshgrid( 0.1:0.1:5 ); % define 2D inputs
E = (R.^6)./( R.^6 + r.^6 ); % compute 2D function
figure;
surf( R, r, E, 'EdgeColor','none'); % plot using surf
xlabel('R');
ylabel('r');
colormap( [ 1:-0.05:0; 0:.05:1; zeros( 1, numel(0:.05:1) )]' ); % colormap red->green
What you get is
If you want to plot the 2D function E( x,y ; R=5.1 ) with r(x,y) = || x - y || then you can try
[X Y] = meshgrid(-120:1:120); % x,y range -120:120 nm
r = sqrt( X.^2 + Y.^2 );
R=5.1; % fixing R to 5.1 nm
figure;
surf( X, Y, (R.^6)./( R.^6 + r.^6 ), 'EdgeColor','none');
xlabel('X[nm]');
ylabel('Y[nm]');
zlabel('E');
colormap( [ 1:-0.05:0; 0:.05:1; zeros( 1, numel(0:.05:1) )]' );
colorbar;
In that case you'll get
Related
I am using MATLAB to print my simulation results. The results concerns a UAV's trajectory and waypoints that the UAV has to visit. The UAV is supposed to be equipped with a camera, whose range view is 10x10. Right now, the diagram shows the UAV's trajectory as a line visiting the waypoints. Is it possible, to show the camera's footprint, instead of the actual trajectory? I would like it to plot the rectangular camera's view to show the exhaustive coverage of the area. There is the option to plot the points as square, or cross, or cyrcles, but is it possible to set the boundaries of those?
Thank you in advance
The problem with using the marker size to indicate the range view is that there is no direct relation between the data units of your waypoints and the marker size. In other words, a value of 10 for the marker size doesn't necessarily mean that a side of a square marker is going to be 10 data units long (as defined by the scaling and limits of the axes).
An alternative is to plot square patches at each of your waypoints where the patch is aligned with the trajectory of the UAV. Here's how you can do this:
% Generate some sample data:
N = 20; % Number of waypoints
x = cumsum(5.*rand(1, N)); % X coordinates of UAV
y = cumsum(5.*rand(1, N)); % Y coordinates of UAV
% Compute vectors parallel and perpendicular to the trajectory at each point:
v = [diff(x); diff(y); zeros(1, N-1)]; % Vectors (1 per column)
v = bsxfun(#rdivide, v, sqrt(sum(v.^2, 1))); % Normalize each column to a unit vector
v = v(:, [1 1:end]); % Replicate a vector for starting point
vCross = cross(v, [zeros(2, N); ones(1, N)]); % Perpendicular vector
% Generate patch coordinates:
R = 10; % Range view
xPatch = [x+(R/2).*(v(1, :)+vCross(1, :)); ...
x+(R/2).*(v(1, :)-vCross(1, :)); ...
x-(R/2).*(v(1, :)+vCross(1, :)); ...
x-(R/2).*(v(1, :)-vCross(1, :))];
yPatch = [y+(R/2).*(v(2, :)+vCross(2, :)); ...
y+(R/2).*(v(2, :)-vCross(2, :)); ...
y-(R/2).*(v(2, :)+vCross(2, :)); ...
y-(R/2).*(v(2, :)-vCross(2, :))];
% Plot the patches and trajectory:
patch(xPatch, yPatch, [0 0.3 0], 'FaceAlpha', 0.25, 'EdgeColor', 'none');
hold on;
plot(x, y, '-', 'Color', [0.8 0 0], 'Marker', '.', 'MarkerSize', 12);
axis equal;
And here's a sample plot:
As a first attempt you can specify marker shape as square and set constant marker size, e.g.
plot(x,y,'s','markersize',10)
Here x and y are the vectors, holding the UAV coordinates. The letter 's' sets marker shape as square, and size is set to 10.
In reality, UAV trajectory is defined in a 3d space, where varying height above the ground corresponds to varying footprint size and shape. Taking this into account would require a bit more effort.
Also this assumes that the points are spaced closely enough otherwise there would be empty areas between markers.
I have polar coordinates, radius 0.05 <= r <= 1 and 0 ≤ θ ≤ 2π. The radius r is 50 values between 0.05 to 1, and polar angle θ is 24 values between 0 to 2π.
How do I interpolate r = 0.075 and theta = pi/8?
I dunno what you have tried, but interp2 works just as well on polar data as it does on Cartesian. Here is some evidence:
% Coordinates
r = linspace(0.05, 1, 50);
t = linspace(0, 2*pi, 24);
% Some synthetic data
z = sort(rand(50, 24));
% Values of interest
ri = 0.075;
ti = pi/8;
% Manually interpolate
rp = find(ri <= r, 1, 'first');
rm = find(ri >= r, 1, 'last');
tp = find(ti <= t, 1, 'first');
tm = find(ti >= t, 1, 'last');
drdt = (r(rp) - r(rm)) * (t(tp) - t(tm));
dr = [r(rp)-ri ri-r(rm)];
dt = [t(tp)-ti ti-t(tm)];
fZ = [z(rm, tm) z(rm, tp)
z(rp, tm) z(rp, tp)];
ZI_manual = (dr * fZ * dt.') / drdt
% Interpolate with MATLAB
ZI_MATLAB = interp2(r, t, z', ri, ti, 'linear')
Result:
ZI_manual =
2.737907208525297e-002
ZI_MATLAB =
2.737907208525298e-002
Based on comments you have the following information
%the test point
ri=0.53224;
ti = pi/8;
%formula fo generation of Z
g=9.81
z0=#(r)0.01*(g^2)*((2*pi)^-4)*(r.^-5).*exp(-1.25*(r/0.3).^-4);
D=#(t)(2/pi)*cos(t).^2;
z2=#(r,t)z0(r).*D(t) ;
%range of vlaues of r and theta
r=[0.05,0.071175,0.10132,0.14422,0.2053, 0.29225,0.41602,0.5922,0.84299,1.2];
t=[0,0.62832,1.2566,1.885, 2.5133,3.1416,3.7699,4.3982,5.0265,5.6549,6.2832];
and you want interplation of the test point.
When you sample some data to use them for interpolation you should consider how to sample data according to your requirements.
So when you are sampling a regular grid of polar coordinates ,those coordinates when converted to rectangular will form a circular shape that
most of the points are concentrated in the center of the cricle and when we move from the center to outer regions distance between the points increased.
%regular grid generated for r and t
[THETA R] = meshgrid(t ,r);
% Z for polar grid
Z=z2(R,THETA);
%convert coordinate from polar to cartesian(rectangular):
[X, Y] = pol2cart (THETA, R);
%plot points
plot(X, Y, 'k.');
axis equal
So when you use those point for interpolation the accuracy of the interpolation is greater in the center and lower in the outer regions where the distance between points increased.
In the other word with this sampling method you place more importance on the center region related to outer ones.
To increase accuracy density of grid points (r and theta) should be increased so if length of r and theta is 11 you can create r and theta with size 20 to increase accuracy.
In the other hand if you create a regular grid in rectangular coordinates an equal importance is given to each region . So accuracy of the interpolation will be the same in all regions.
For it first you create a regular grid in the polar coordinates then convert the grid to rectangular coordinates so you can calculate the extents (min max) of the sampling points in the rectangular coordinates. Based on this extents you can create a regular grid in the rectangular coordinates
Regular grid of rectangular coordinates then converted to polar coordinated to get z for grid points using z2 formula.
%get the extent of points
extentX = [min(X(:)) max(X(:))];
extentY = [min(Y(:)) max(Y(:))];
%sample 100 points(or more or less) inside a region specified be the extents
X_samples = linspace(extentX(1),extentX(2),100);
Y_samples = linspace(extentY(1),extentY(2),100);
%create regular grid in rectangular coordinates
[XX YY] = meshgrid(X_samples, Y_samples);
[TT RR] = cart2pol(XX,YY);
Z_rect = z2(RR,TT);
For interpolation of a test point say [ri ti] first it converted to rectangular then using XX ,YY value of z is interpolated
[xi yi] = pol2cart (ti, ri);
z=interp2(XX,YY,Z_rect,xi,yi);
If you have no choice to change how you sample the data and only have a grid of polar points as discussed with #RodyOldenhuis you can do the following:
Interpolate polar coordinates with interp2 (interpolation for gridded data)
this approach is straightforward but has the shortcoming that r and theta are not of the same scale and this may affect the accuracy of the interpolation.
z = interp2(THETA, R, Z, ti, ri)
convert polar coordinates to rectangular and then apply an interpolation method that is for scattered data.
this approach requires more computations but result of it is more reliable.
MATLAB has griddata function that given scattered points first generates a triangulation of points and then creates a regular grid on top of the triangles and interpolates values of grid points.
So if you want to interpolate value of point [ri ti] you should then apply a second interpolation to get value of the point from the interpolated grid.
With the help of some information from spatialanalysisonline and Wikipedia linear interpolation based on triangulation calculated this way (tested in Octave. In newer versions of MATLAB use of triangulation and pointLocation recommended instead of delaunay and tsearch ):
ri=0.53224;
ti = pi/8;
[THETA R] = meshgrid(t ,r);
[X, Y] = pol2cart (THETA, R);
[xi yi] = pol2cart (ti, ri);
%generate triangulation
tri = delaunay (X, Y);
%find the triangle that contains the test point
idx = tsearch (X, Y, tri, xi, yi);
pts= tri(idx,:);
%create a matrix that repesents equation of a plane (triangle) given its 3 points
m=[X(pts);Y(pts);Z(pts);ones(1,3)].';
%calculate z based on det(m)=0;
z= (-xi*det(m(:,2:end)) + yi*det([m(:,1) m(:,3:end)]) + det(m(:,1:end-1)))/det([m(:,1:2) m(:,end)]);
More refinement:
Since it is known that the search point is surrounded by 4 points we can use only those point for triangulation. these points form a trapezoid. Each diagonal of trapezoid forms two triangles so using vertices of the trapezoid we can form 4 triangles, also a point inside a trapezoid can lie in at least 2 triangles.
the previous method based on triangulation only uses information from one triangle but here z of the test point can be interpolated two times from data of two triangles and the calculated z values can be averaged to get a better approximation.
%find 4 points surrounding the test point
ft= find(t<=ti,1,'last');
fr= find(cos(abs(diff(t(ft+(0:1))))/2) .* r < ri,1,'last');
[T4 R4] = meshgrid(t(ft+(0:1)), r(fr+(0:1)));
[X4, Y4] = pol2cart (T4, R4);
Z4 = Z(fr+(0:1),ft+(0:1));
%form 4 triangles
tri2= nchoosek(1:4,3);
%empty vector of z values that will be interpolated from 4 triangles
zv = NaN(4,1);
for h = 1:4
pts = tri2(h,:);
% test if the point lies in the triangle
if ~isnan(tsearch(X4(:),Y4(:),pts,xi,yi))
m=[X4(pts) ;Y4(pts) ;Z4(pts); [1 1 1]].';
zv(h)= (-xi*det(m(:,2:end)) + yi*det([m(:,1) m(:,3:end)]) + det(m(:,1:end-1)))/det([m(:,1:2) m(:,end)]);
end
end
z= mean(zv(~isnan(zv)))
Result:
True z:
(0.0069246)
Linear Interpolation of (Gridded) Polar Coordinates :
(0.0085741)
Linear Interpolation with Triangulation of Rectangular Coordinates:
(0.0073774 or 0.0060992) based on triangulation
Linear Interpolation with Triangulation of Rectangular Coordinates(average):
(0.0067383)
Conclusion:
Result of interpolation related to structure of original data and the sampling method. If the sampling method matches pattern of original data result of interpolation is more accurate, so in cases that grid points of polar coordinates follow pattern of data result of interpolation of regular polar coordinate can be more reliable. But if regular polar coordinates do not match the structure of data or structure of data is such as an irregular terrain, method of interpolation based on triangulation can better represent the data.
please check this example, i used two for loops, inside for loop i used condition statement, if u comment this condition statement and run the program, u'll get correct answer, after u uncomment this condition statement and run the program, u'll get wrong answer. please check it.
% Coordinates
r = linspace(0.05, 1, 10);
t = linspace(0, 2*pi, 8);
% Some synthetic data
%z = sort(rand(50, 24));
z=zeros();
for i=1:10
for j=1:8
if r(i)<0.5||r(i)>1
z(i,j)=0;
else
z(i,j) = r(i).^3'*cos(t(j)/2);
end
end
end
% Values of interest
ri = 0.55;
ti = pi/8;
% Manually interpolate
rp = find(ri <= r, 1, 'first');
rm = find(ri >= r, 1, 'last');
tp = find(ti <= t, 1, 'first');
tm = find(ti >= t, 1, 'last');
drdt = (r(rp) - r(rm)) * (t(tp) - t(tm));
dr = [r(rp)-ri ri-r(rm)];
dt = [t(tp)-ti ti-t(tm)];
fZ = [z(rm, tm) z(rm, tp)
z(rp, tm) z(rp, tp)];
ZI_manual = (dr * fZ * dt.') / drdt
% Interpolate with MATLAB
ZI_MATLAB = interp2(r, t, z', ri, ti, 'linear')
Result:
z1 =
0.1632
ZI_manual =
0.1543
ZI_MATLAB =
0.1582
I have this Binary image bw:
edges of an object to carry out some measurements. But firstly I have to do curve fitting for both edges. The result should be two smooth curves representing edges.
I have the indices for each edge but I can not use them in making x-y data to be input data to a fitting function. I mean they are not x and f(x), actually, they all have the same value (1) with different positions. It is not right to say [x y]=find(BW) ; y here is not the value at x, but for sure there should be a way to use them to some kind of scale the binary image. I seem confused and I'm stuck here.
Any recommendations?
Why not use polyfit?
[y x] = find( bw ); %// get x y coordinates of all curve points
There are two small "tricks" you need to use here:
You have two curves, thus you need to split your data points to the left and right curves
right = x<300;
xr = x(right);
yr = y(right);
xl = x(~right);
yl = y(~right);
Since your curves are close to vertical, it would be better to fit x=f(y) rather than the "classic" y=f(x):
pr = polyfit( yr, xr, 3 ); %// fit 3rd deg poly
pl = polyfit( yl, xl, 3 );
Now you can plot them
yy = linspace( 1, size(bw,1), 50 );
figure; imshow(bw, 'border', 'tight' );
hold all
plot( polyval( pr, yy ), yy, '.-', 'LineWidth', 1 );
plot( polyval( pl, yy ), yy, '.-', 'LineWidth', 1 );
And you get:
If you want to create a new refined mask from the estimated curves, you can do the following:
yy = 1:size(bw,1); %// single value per row
xxr=polyval(pr,yy); %// corresponding column values
xxl=polyval(pl,yy);
Set a new mask of the same size
nbw = false(size(bw));
nbw( sub2ind(size(bw),yy,round(xxr)) )=true;
nbw( sub2ind(size(bw), yy, round(xxl) )) = true;
And the result
figure;imshow(nbw,'border','tight');
After constructing the point cloud I want to get the normal of each point and I used the built-in matlab function surfnorm but its takes a lot of processing time. So if anyone could assist me do this a better and more efficient way.
I wonder if the following code would help you. There are three steps here.
Create 500 randomly spaced points (x,y), and compute a corresponding value z (the height of the surface) for which I chose a sinc like function
Resample the random points using the TriScatteredInterp function - this permits me to obtain points on an evenly sampled grid that "roughly correspond" to the initial surface
Compute the normal to "some points" on that grid (since there are 480x640 points, computing the normal at every point would just create an impossibly dense "forest of vectors"; by sampling "every 10th point" you can actually see what you are doing
The code I used was as follows:
randomX = rand(1,500);
randomY = rand(1,500);
r = 5*sqrt(randomX.^2 + randomY.^2);
randomZ = sin(r) ./ r;
% resample the data:
[xx yy] = meshgrid(linspace(0,1,640), linspace(0,1,480));
F = TriScatteredInterp(randomX(:), randomY(:), randomZ(:));
zz = F(xx, yy);
%% at each point, the normal is cross product of vectors to neighbors
xyz=reshape([xx yy zz],[size(xx) 3]);
xv = 10:30:479; yv = 10:30:639; % points at which to compute normals
dx = xyz(xv, yv+1, :) - xyz(xv, yv, :);
dy = xyz(xv+1, yv, :) - xyz(xv, yv, :);
normVecs = cross(dx, dy); % here we compute the normals.
normVecs = normVecs ./ repmat(sqrt(sum(normVecs.^2, 3)), [1 1 3]);
figure;
quiver3(xx(xv, yv), yy(xv, yv), zz(xv, yv), ...
normVecs(:,:,1), normVecs(:,:,2), normVecs(:,:,3));
axis equal
view([56 22]);
And the resulting plot:
I have a problem and maybe you will be able to help me. Like in the title i have cross section data of a symmetric lens - coordinates s=-100:1:100 and height y - and I would like to create 3D plot the whole lens (x,y,z). Is there any build in function that helps with that? Thanks for help in advance!
If I'm understanding correctly, you have a 1-D array that you'd effectively like to 'sweep' around a circle to produce a 3-D plot. Here is an example of how to do that
% Some dummy data
Npts = 100;
z = sin(linspace(0, pi, Npts));
Nreps = 100; % How many times to repeat around circle
% Create polar meshgrid and convert to Cartesian
[r, theta] = meshgrid( ...
linspace(-length(z)/2, length(z)/2, Npts), ...
linspace(0, pi, Nreps));
[X, Y] = pol2cart(theta, r);
% Copy data Nreps times
Z = repmat(z, Nreps, 1);
% Plot!
surf(X, Y, Z)
Without more specs (such as if your y is a 2D matrix or a 1D array), it's not possible to give you the exact answer. However here is how you draw a surface in Matlab:
% create a meshgrid used as the independent variables of your surface
[sx, sy] = meshgrid(-100:100);
% if you have your own 2D matrix, ignore this line.
% if you have a formula, replace this line with your own formula
y = cos(sqrt(((sx/100).^2+(sy/100).^2)/2)*(pi/2));
% draw the surface
surf(sx, sy, y);
To have the opposite side as well, draw another surf on the same figure:
hold on;
surf(sx, sy, -y);