How do I display an arrow positioned at a specific angle in MATLAB? - matlab

I am working in MATLAB and I'm stuck on a very simple problem: I've got an object defined by its position (x,y) and theta (an angle, in degrees). I would like to plot the point and add an arrow, starting from the point and pointing toward the direction defined by the angle. It actually doesn't even have to be an arrow, anything graphically showing the value of the angle will do!
Here's a picture showing the kind of thing I'm trying to draw:
removed dead ImageShack link

The quiver() plotting function plots arrows like this. Take your theta value and convert it to (x,y) cartesian coordinates representing the vector you want to plot as an arrow and use those as the (u,v) parameters to quiver().
theta = pi/9;
r = 3; % magnitude (length) of arrow to plot
x = 4; y = 5;
u = r * cos(theta); % convert polar (theta,r) to cartesian
v = r * sin(theta);
h = quiver(x,y,u,v);
set(gca, 'XLim', [1 10], 'YLim', [1 10]);
Take a look through online the Matlab documentation to see other plot types; there's a lot, including several radial plots. They're in the MATLAB > Functions > Graphics > Specialized Plotting section. Do "doc quiver" at the command line and browse around.

If you want to try and make something that looks like the image you linked to, here's some code to help you do it (NOTE: you would first have to download the submission arrow.m by Erik Johnson on the MathWorks File Exchange, which I always like to use for generating arrows of any shape and size):
x = 1; % X coordinate of arrow start
y = 2; % Y coordinate of arrow start
theta = pi/4; % Angle of arrow, from x-axis
L = 2; % Length of arrow
xEnd = x+L*cos(theta); % X coordinate of arrow end
yEnd = y+L*sin(theta); % Y coordinate of arrow end
points = linspace(0, theta); % 100 points from 0 to theta
xCurve = x+(L/2).*cos(points); % X coordinates of curve
yCurve = y+(L/2).*sin(points); % Y coordinates of curve
plot(x+[-L L], [y y], '--k'); % Plot dashed line
hold on; % Add subsequent plots to the current axes
axis([x+[-L L] y+[-L L]]); % Set axis limits
axis equal; % Make tick increments of each axis equal
arrow([x y], [xEnd yEnd]); % Plot arrow
plot(xCurve, yCurve, '-k'); % Plot curve
plot(x, y, 'o', 'MarkerEdgeColor', 'k', 'MarkerFaceColor', 'w'); % Plot point
And here's what it would look like:
You can then add text to the plot (for the angle and the coordinate values) using the text function.

Here's a partial answer, I expect you can figure out the rest. I fired up the Figures editor and opened the plot tools. I dragged an arrow from the palette onto my figure. Then I generated an m-file. This included the line:
annotation(figure1,'arrow',[0.1489 0.2945],[0.5793 0.6481]);
So, the first pair of coordinates is the start of the arrow. You're going to have to figure out the pointy end (second pair of coordinates) using a little bit of trigonometry. You might even be able to get the little arc if you do some more fiddling around with plot tools.
Let us know if the trig defeats you. Oh, and I forgot to plot the point, but I guess you can figure that out ?

Related

convert image from Cartesian to Polar

I want to convert an image from Cartesian to Polar and to use it for opengl texture.
So I used matlab referring to the two articles below.
Link 1
Link 2
My code is exactly same with Link 2's anwser
% load image
img = imread('my_image.png');
% convert pixel coordinates from cartesian to polar
[h,w,~] = size(img);
[X,Y] = meshgrid((1:w)-floor(w/2), (1:h)-floor(h/2));
[theta,rho] = cart2pol(X, Y);
Z = zeros(size(theta));
% show pixel locations (subsample to get less dense points)
XX = X(1:8:end,1:4:end);
YY = Y(1:8:end,1:4:end);
tt = theta(1:8:end,1:4:end);
rr = rho(1:8:end,1:4:end);
subplot(121), scatter(XX(:),YY(:),3,'filled'), axis ij image
subplot(122), scatter(tt(:),rr(:),3,'filled'), axis ij square tight
% show images
figure
subplot(121), imshow(img), axis on
subplot(122), warp(theta, rho, Z, img), view(2), axis square
The result was exactly what I wanted, and I was very satisfied except for one thing. It's the area (red circled area) in the picture just below. Considering that the opposite side (blue circled area) is not, I think this part should also be filled. Because of this part is empty, so there is a problem when using it as a texture.
And I wonder how I can fill this part. Thank you.
(little difference from Link 2's answer code like degree<->radian and axis values. but i think it is not important.)
Those issues you show in your question happen because your algorithm is wrong.
What you did (push):
throw a grid on the source image
transform those points
try to plot these colored points and let MATLAB do some magic to make it look like a dense picture
Do it the other way around (pull):
throw a grid on the output
transform that backwards
sample the input at those points
The distinction is called "push" (into output) vs "pull" (from input). Only Pull gives proper results.
Very little MATLAB code is necessary. You just need pol2cart and interp2, and a meshgrid.
With interp2 you get to choose the interpolation (linear, cubic, ...). Nearest-neighbor interpolation leaves visible artefacts.
im = im2single(imread("PQFax.jpg"));
% center of polar map, manually picked
cx = 10 + 409/2;
cy = 7 + 413/2;
% output parameters
radius = 212;
dRho = 1;
dTheta = 2*pi / (2*pi * radius);
Thetas = pi/2 - (0:dTheta:2*pi);
Rhos = (0:dRho:radius);
% polar mesh
[Theta, Rho] = meshgrid(Thetas, Rhos);
% transform...
[Xq,Yq] = pol2cart(Theta, Rho);
% translate to sit on the circle's center
Xq = Xq + cx;
Yq = Yq + cy;
% sample image at those points
Ro = interp2(im(:,:,1), Xq,Yq, "cubic");
Go = interp2(im(:,:,2), Xq,Yq, "cubic");
Bo = interp2(im(:,:,3), Xq,Yq, "cubic");
Vo = cat(3, Ro, Go, Bo);
Vo = imrotate(Vo, 180);
imshow(Vo)
The other way around (get a "torus" from a "ribbon") is quite similar. Throw a meshgrid on the torus space, subtract center, transform from cartesian to polar, and use those to sample from the "ribbon" image into the "torus" image.
I'm more familiar with OpenCV than with MATLAB. Perhaps MATLAB has something like OpenCV's warpPolar(), or a generic remap(). In any case, the operation is trivial to do entirely "by hand" but there are enough supporting functions to take the heavy lifting off your hands (interp2, pol2cart, meshgrid).
1.- The white arcs tell that the used translation pol-cart introduces significant errors.
2.- Reversing the following script solves your question.
It's a script that goes from cart-pol without introducing errors or ignoring input data, which is what happens when such wide white arcs show up upon translation apparently correct.
clear all;clc;close all
clc,cla;
format long;
A=imread('shaffen dass.jpg');
[sz1 sz2 sz3]=size(A);
szx=sz2;szy=sz1;
A1=A(:,:,1);A2=A(:,:,2);A3=A(:,:,3); % working with binary maps or grey scale images this wouldn't be necessary
figure(1);imshow(A);
hold all;
Cx=floor(szx/2);Cy=floor(szy/2);
plot(Cx,Cy,'co'); % because observe image centre not centered
Rmin=80;Rmax=400; % radius search range for imfindcircles
[centers, radii]=imfindcircles(A,[Rmin Rmax],... % outer circle
'ObjectPolarity','dark','Sensitivity',0.9);
h=viscircles(centers,radii);
hold all; % inner circle
[centers2, radii2]=imfindcircles(A,[Rmin Rmax],...
'ObjectPolarity','bright');
h=viscircles(centers2,radii2);
% L=floor(.5*(radii+radii2)); % this is NOT the length X that should have the resulting XY morphed graph
L=floor(2*pi*radii); % expected length of the morphed graph
cx=floor(.5*(centers(1)+centers2(1))); % coordinates of averaged circle centres
cy=floor(.5*(centers(2)+centers2(2)));
plot(cx,cy,'r*'); % check avg centre circle is not aligned to figure centre
plot([cx 1],[cy 1],'r-.');
t=[45:360/L:404+1-360/L]; % if step=1 then we only get 360 points but need an amount of L points
% if angle step 1/L over minute waiting for for loop to finish
R=radii+5;x=R*sind(t)+cx;y=R*cosd(t)+cy; % build outer perimeter
hL1=plot(x,y,'m'); % axis equal;grid on;
% hold all;
% plot(hL1.XData,hL1.YData,'ro');
x_ref=hL1.XData;y_ref=hL1.YData;
% Sx=zeros(ceil(R),1);Sy=zeros(ceil(R),1);
Sx={};Sy={};
for k=1:1:numel(hL1.XData)
Lx=floor(linspace(x_ref(k),cx,ceil(R)));
Ly=floor(linspace(y_ref(k),cy,ceil(R)));
% plot(Lx,Ly,'go'); % check
% plot([cx x(k)],[cy y(k)],'r');
% L1=unique([Lx;Ly]','rows');
Sx=[Sx Lx'];Sy=[Sy Ly'];
end
sx=cell2mat(Sx);sy=cell2mat(Sy);
[s1 s2]=size(sx);
B1=uint8(zeros(s1,s2));
B2=uint8(zeros(s1,s2));
B3=uint8(zeros(s1,s2));
for n=1:1:s2
for k=1:1:s1
B1(k,n)=A1(sx(k,n),sy(k,n));
B2(k,n)=A2(sx(k,n),sy(k,n));
B3(k,n)=A3(sx(k,n),sy(k,n));
end
end
C=uint8(zeros(s1,s2,3));
C(:,:,1)=B1;
C(:,:,2)=B2;
C(:,:,3)=B3;
figure(2);imshow(C);
the resulting
3.- let me know if you'd like some assistance writing pol-cart from this script.
Regards
John BG

Matlab: adding multiple 3D cartesian coordinate axes within a 3D plot

Getting right to the question: How can I make my plot go from looking like this:
to something like this:
where a right-handed Cartesian coordinate system (with axis labels at the end of the arrows, e.g., in this example the x-axis label is = $x_1^G$)
Some elaboration and prefacing: First, I am new to matlab and "matrix math". I tried searching on this site for questions similar to what I have posed above but did not see anything (but I may have missed), so hopefully this is not a duplicate.
Here is the code I have used to develop my rotated ellipsoid (since I'm new to matlab I would appreciate any comments on my code):
%Insert the components of the 3x3 matrix (i.e. the scalar values of the 2nd-rank symmetric tensor)
Pmatrix = [115.9547 12.03765 4.68235; 12.03765 116.3702 -2.47985; 4.68235 -2.47985 134.5488];
[R,D]=eig(Pmatrix); %find the eigenvectors (R) and eigenvalues (D) of the 2nd-rank tensor
[x, y, z] =sphere; %generate coordinates of a sphere, using the sphere command
%Stretch the coordinates of the sphere to form the tensor's representation ellipsoid, do this by multiplying the x, y, z coordinates by the square-roots of the eigenvalues
x1 = x*sqrt(D(1,1));
y1 = y*sqrt(D(2,2));
z1 = z*sqrt(D(3,3));
figure;
hmesh = mesh(x1,y1,z1);
set(hmesh,'FaceColor',[0.5,0.5,0.5],'FaceAlpha',0.5) %set color to gray, make mostly transparent
axis equal; %Make tick mark increments on all axes equal
xlabel('x');
ylabel('y');
zlabel('z');
theta1 = -asind(R(3,1)); %rotation around y-axis in degrees
psi1 = atan2d(R(3,2)/cos(theta1),R(3,3)/cos(theta1)); %rotation around x-axis in degrees
phi1 = atan2d(R(2,1)/cos(theta1),R(1,1)/cos(theta1)); %rotation around z-axis in degress
direction = [1 0 0]; %rotate the surface plot psi1 degrees around its x-axis
rotate(hmesh,direction,psi1)
direction = [0 1 0]; %rotate the surface plot theta1 degrees around its y-axis
rotate(hmesh,direction,theta1)
direction = [0 0 1]; %rotate the surface plot phi1 degrees around its z-axis
rotate(hmesh,direction,phi1)
view([-36 18]); %Change the camera viewpoint
To add to my question, I would like to add other (similar) items to my plot, so that the final product would look like this:
In the development of the image above, a set of axes collinear with the ellipsoid's eigenvectors are added (the red, green, blue arrows):
Then these axes are extended in the opposite direction, through the origin, where these portions of the axes are shown as a dashed lines:
Then, the angles between the global coordinate axes (black arrows) and the ellipsoid's axes (colored arrows) are notated as shown here:
To comment on this last addition, someone has built some matlab code with these features (see youtube video here). In the video's description it says the matlab code can be found here. Being new to matlab, I don't see where the code is, e.g., I don't see where on this page (screenshot below) the code is to build that matlab plot seen in the youtube video. If you can guide me on how to navigate that mathworks-fileexchage page that would be appreciated.

Matlab: How to show sigma and mu on normal curve

I am plotting a normal curve by using y = normpdf(x,mu,sigma); in Matlab.
This draws for me a normal curve. But, I need additional information to be shown on the curve, like having vertical lines on the curve to show the mu and the sigma. Similar to this one:
Is there any Matlab function to draw such vertical lines on the curve?
Thanks,
Aida
There are no built-in function for this, but we can do it easily by the hands:
Create normal curve and plot it:
x = -2:0.05:2;
mu = 0; sigma = 0.5;
y = normpdf(x,mu,sigma);
plot(x,y)
Add lines for sigmas:
hold on;
plot( [mu - sigma mu - sigma],[0 max(y)],'--')
plot( [mu + sigma mu + sigma],[0 max(y)],'--')
You can change it to any sigma you need (2sigma 3sigma).
How to add the text? This way:
text(0.1,-0.05,'mu + sigma');
or if you want it look really beautiful:
text(-0.65,-0.05,'\mu - \sigma')
Result:
The easiest way to draw lines in Matlab is probably using simply plot. The following code segment draws a line from [x1, y1] to [x2, y2]:
plot([x1,y1], [x2,y2], plotoptions)
To make sure that this line is also visible on your current figure use hold on. This results in a code like the following:
y = normpdf(x,mu,sigma)
figure(1)
hold on
plot(x,y) % Your normal distribution
plot([mu,startY], [mu, stopY], plotoptions) % Plot the line at position mu.
% The startY and stopY indicate the bottom and top of your graph.
hold off
The Mathworks documentation page of plot can be a great reference, with a lot of examples and different plot options. For example how to make a dashed or colored line:
http://www.mathworks.com/help/matlab/ref/plot.html?searchHighlight=plot%20line

plotting trajectory data in matlab

I have trajectory information in 3 dimensions in matlab. These are of a gesture someone is making. When I connect the points in matlab by using plot3, I can see the trajectory nicely.
However, the trajectory is a line in the plot, but I don't know in which direction the gesture has been made as the time is not visualized. Is it possible to visualize this in a 3d plot (where the dimensions are x, y and z)? For example, the colour at the start is bright red and the colour at the end is black.
Thanks for your help,
Héctor
You need the comet3 plot (if you don't mind animations).
If you do mind animations, and you're looking for a static figure, I'd use a quiver.
Example:
% value of the parameter in the parametric equation
t = 0:0.5:2*pi;
% modified coordinate axes
u = [1 0 0].';
v = [0 2 0].';
% coordinates of the ellipse
Ell = bsxfun(#plus, bsxfun(#times, u, cos(t)), bsxfun(#times, v, sin(t)));
% difference vectors between all data points will be used as "velocities"
dEll = diff(Ell, 1,2);
% Quiver the ellipse
quiver3(...
Ell(1,1:end-1), Ell(2,1:end-1), Ell(3,1:end-1), ...
dEll(1,:), dEll(2,:), dEll(3,:), ...
2, 'r') % = scale, LineSpec
axis tight equal
Result:

How to plot a second graph instead of color coding in matlab

i just started with my master thesis and i already am in trouble with my capability/understanding of matlab.
The thing is, i have a trajectory on a surface of a planet/moon whatever (a .mat with the time, and the coordinates. Then i have some .mat with time and the measurement at that time.
I am able to plot this as a color coded trajectory (using the measurement and the coordinates) in scatter(). This works awesomely nice.
However my problem is that i need something more sophisticated.
I now need to take the trajectory and instead of color-coding it, i am supposed to add the graph (value) of the measurement (which is given for each point) to the trajectory (which is not always a straight line). I will added a little sketch to explain what i want. The red arrow shows what i want to add to my plot and the green shows what i have.
You can always transform your data yourself: (using the same notation as #Shai)
x = 0:0.1:10;
y = x;
m = 10*sin(x);
So what you need is the vector normal to the curve at each datapoint:
dx = diff(x); % backward finite differences for 2:end points
dx = [dx(1) dx]; % forward finite difference for 1th point
dy = diff(y);
dy = [dy(1) dy];
curve_tang = [dx ; dy];
% rotate tangential vectors 90° counterclockwise
curve_norm = [-dy; dx];
% normalize the vectors:
nrm_cn = sqrt(sum(abs(curve_norm).^2,1));
curve_norm = curve_norm ./ repmat(sqrt(sum(abs(curve_norm).^2,1)),2,1);
Multiply that vector with the measurement (m), offset it with the datapoint coordinates and you're done:
mx = x + curve_norm(1,:).*m;
my = y + curve_norm(2,:).*m;
plot it with:
figure; hold on
axis equal;
scatter(x,y,[],m);
plot(mx,my)
which is imo exactly what you want. This example has just a straight line as coordinates, but this code can handle any curve just fine:
x=0:0.1:10;y=x.^2;m=sin(x);
t=0:pi/50:2*pi;x=5*cos(t);y=5*sin(t);m=sin(5*t);
If I understand your question correctly, what you need is to rotate your actual data around an origin point at a certain angle. This is pretty simple, as you only need to multiply the coordinates by a rotation matrix. You can then use hold on and plot to overlay your plot with the rotated points, as suggested in the comments.
Example
First, let's generate some data that resembles yours and create a scatter plot:
% # Generate some data
t = -20:0.1:20;
idx = (t ~= 0);
y = ones(size(t));
y(idx) = abs(sin(t(idx)) ./ t(idx)) .^ 0.25;
% # Create a scatter plot
x = 1:numel(y);
figure
scatter(x, x, 10, y, 'filled')
Now let's rotate the points (specified by the values of x and y) around (0, 0) at a 45° angle:
P = [x(:) * sqrt(2), y(:) * 100] * [1, 1; -1, 1] / sqrt(2);
and then plot them on top of the scatter plot:
hold on
axis square
plot(P(:, 1), P(:, 2))
Note the additional things have been done here for visualization purposes:
The final x-coordinates have been stretched (by sqrt(2)) to the appropriate length.
The final y-coordinates have been magnified (by 100) so that the rotated plot stands out.
The axes have been squared to avoid distortion.
This is what you should get:
It seems like you are interested in 3D plotting.
If I understand your question correctly, you have a 2D curve represented as [x(t), y(t)].
Additionally, you have some value m(t) for each point.
Thus we are looking at the plot of a 3D curve [x(t) y(t) m(t)].
you can easily achieve this using
plot3( x, y, m ); % assuming x,y, and m are sorted w.r.t t
alternatively, you can use the 3D version of scatter
scatter3( x, y, m );
pick your choice.
Nice plot BTW.
Good luck with your thesis.