I'm working on a project which includes use of accelerometer and gyroscope to get the orientation an object. I can pass the 3d orientation vector from arduino to matlab via serial communication.
I want to plot the vector in matlab to make real time analysis. I'm using quiver3d and drawnow functions in a loop to plot the vector but quiver3d function is very slow so I can see the orientation of object after like 20 seconds later.
Is there any way to plot 3d vectors faster?
Thanks.
quiver plot may be too much for plotting only one vector in 3-D. You can achieve a similar plot by using a simple plot3 such as the one plotted below.
In this plot, the origin of the vector is the blue dot, and the direction is given by the red line.
The code
%v is the direction of the vector (3 cartesian coordinates)
v = sort(randn(100,3));
v = bsxfun(#rdivide,v,sqrt(sum(v.^2,2)));
%xyz the origin of the vector
ind = linspace(-pi,pi,100);
x = cos(ind);
y = sin(ind);
z = ind;
%the plotting function
figure
for ii = 1:numel(ind)
plot3(x(ii),y(ii),z(ii),'bo'); %origin in blue
set(gca,'XLim', [-3 3], 'YLim', [-3 3], 'ZLim', [-3 3]);
hold on;
hl = plot3( linspace(x(ii), x(ii)+v(ii,1),10), ...
linspace(y(ii), y(ii)+v(ii,2),10), ...
linspace(z(ii), z(ii)+v(ii,3),10), ...
'r'); %direction in red
view(80,10);
pause(0.1);
%clf
end
Related
I have a set of n=8000 cartesian coordinates X,Y and Z as vectors and also a vector V of same size which I want to use as values to create a heatmap on a sphere.
I saw this link (visualization of scattered data over a sphere surface MATLAB), but I don't understand how I convert this set of data into a meshgrid for plotting using surf.
Almost every example I saw uses meshgrids.
Right now, I am doing by plotting a sphere and then use scatter3 to plot my points as big balls and try to smooth them later. I looks like this:
I would like to get the figure as the plotting of the example in that link, where he uses:
k = 5;
n = 2^k-1;
[x,y,z] = sphere(n);
c = hadamard(2^k);
surf(x,y,z,c);
colormap([1 1 0; 0 1 1])
axis equal
EDIT:
(Sorry for taking so long to reply, the corona crises kept away from work)
What I am actually doing is:
for i=1:numel(pop0n)
ori(i,:)=ori(i,:)/norm(ori(i,:));
end
x = ori(:,1);
y = ori(:,2);
z = ori(:,3);
%// plot
m=100;
[aa,bb,cc] = sphere(m);
surf(aa,bb,cc,ones(m+1,m+1)*min(pop0n))
hold on
colormap jet;
scatter3(x,y,z,400,pop0n/norm(pop0n),'filled');
colorbar
shading interp
The array 'ori' is 8000x3, and contains the x, y and z coordinates of the points I want to plot and pop0n is a 8000 sized vector with the intensities of each coordinate.
My main question is how do I transform my x, y, z and pop0n, that are vectors, into 2D arrays (meshgrid) to use surf?
Because I cannot simply do surf(x,y,z,pop0n) if they are vectors.
Thanks in advance
As David suggested, griddata does the job.
What I did was:
for i=1:numel(pop0n)
ori(i,:)=ori(i,:)/norm(ori(i,:));
end
x = ori(:,1);
y = ori(:,2);
z = ori(:,3);
%// plot
m=100;
[aa,bb,cc] = sphere(m);
v = griddata(x,y,z,pop0n,aa,bb,cc,'nearest');
surf(aa,bb,cc,v)
colormap jet;
colorbar
shading interp
I am working on creating 3D images from 3 individual binary images, that were taken with 3 cameras. I have a corresponding calibration and know the setup (see below). Since the image preprocessing is mostly done in MATLAB I would like to implement everything there.
The current idea of my code is to extrude the 2D binary image according to the camera calibration. Here's what a typical binary image looks like:
And an extruded image looks like this in MATLAB:
With all 3 cameras extruded and a binning algorithm, I can create my final 3D-shape. This works fine so far, but takes a long time to compute, since I need to create a lot of extrusion steps to get a good surface.
I was thinking now to speed this up by recreating the process I would do in a 3D-modeling software like Blender. There I also extrude the outline of the binary image and create an intersection easily by just creating a spline for the outline, extrude them and use a boolean operator. Here's a Blender example with 2 extruded images:
I have no idea how to implement something like this in MATLAB. I wanted to create two instances of my binary contour at the top and bottom end of the extrusion "tube" and then define faces between the individual points and create an intersection afterwards. The point creation is no problem but the face definition and the intersection (boolean operator) are. Does anyone have an idea how this could be implemented?
This might not be an easy thing to do in MATLAB, but it's possible. I'll outline one set of steps here, using two intersecting cylinders as an example...
Creating a tetrahedral mesh:
The first step is to create a tetrahedral mesh for your extrusion. If your 2D binary image that you're extruding is convex and has no holes, you could do this using the delaunayTriangulation function:
DT = delaunayTriangulation(P);
Here, P contains the coordinate points of the "end caps" of your extrusion (i.e. the faces on each end of your tube). However, when generating tetrahedral meshes, delaunayTriangulation doesn't allow you to specify constrained edges, and as such it can end up filling in holes or concavities in your extrusion. There may be some better mesh-generation alternatives in other toolboxes, such as the Partial Differential Equations Toolbox, but I don't have access to them and can't speak to their applicability.
If automated mesh-generation options don't work, you'll have to build your tetrahedral mesh yourself and pass that data to triangulation. This could be tricky, but I'll show you some steps for how you can do this for a cylinder, which may help you figure it out for more involved shapes. Below, we build a set of coordinate points P1 and an M-by-4 matrix T1 where each row contains indices into the rows of P1 which define one tetrahedron:
% Create circle coordinates for the end caps:
N = 21;
theta = linspace(0, 2*pi, N).';
x = sin(theta(1:(end-1)));
y = cos(theta(1:(end-1)))+0.5;
z = ones(N-1, 1);
% Build tetrahedrons for first cylinder, aligned along the z axis:
P1 = [0 0.5 -1; ... % Center point of bottom face
x y -z; ... % Edge coordinates of bottom face
0 0.5 1; ... % Center point of top face
x y z]; % Edge coordinates of top face
cBottom = ones(N-1, 1); % Row indices for bottom center coordinate
cEdgeBottom1 = (2:N).'; % Row indices for bottom edge coordinates
cEdgeBottom2 = [3:N 2].'; % Shifted row indices for bottom edge coordinates
cTop = cBottom+N; % Row indices for top center coordinate
cEdgeTop1 = cEdgeBottom1+N; % Row indices for top edge coordinates
cEdgeTop2 = cEdgeBottom2+N; % Shifted row indices for top edge coordinates
% There are 3 tetrahedrons per radial slice of the cylinder: one that includes the
% bottom face and half of the side face (all generated simultaneously by the first row
% below), one that includes the other half of the side face (second row below), and one
% that includes the top face (third row below):
T1 = [cEdgeBottom1 cEdgeBottom2 cEdgeTop1 cBottom; ...
cEdgeBottom2 cEdgeTop1 cEdgeTop2 cBottom; ...
cEdgeTop1 cEdgeTop2 cTop cBottom];
TR1 = triangulation(T1, P1);
To better visualize how the cylinder is being divided into tetrahedrons, here's an animation of an exploded view:
Now we can create a second cylinder, offset and rotated so it aligns with the x axis and intersecting the first:
% Build tetrahedrons for second cylinder:
P2 = [P1(:, 3) -P1(:, 2) P1(:, 1)];
T2 = T1;
TR2 = triangulation(T2, P2);
% Plot cylinders:
tetramesh(TR1, 'FaceColor', 'r', 'FaceAlpha', 0.6);
hold on;
tetramesh(TR2, 'FaceColor', 'g', 'FaceAlpha', 0.6);
axis equal;
xlabel('x');
ylabel('y');
zlabel('z');
And here's the plot to visualize them:
Finding the region of intersection:
Once we have tetrahedral representations of the volumes, we can generate a grid of points covering the region of intersection and use the pointLocation function to determine which points are within both cylinders:
nGrid = 101;
[X, Y, Z] = meshgrid(linspace(-1, 1, nGrid));
QP = [X(:) Y(:) Z(:)];
indexIntersect = (~isnan(pointLocation(TR1, QP))) & ...
(~isnan(pointLocation(TR2, QP)));
mask = double(reshape(indexIntersect, [nGrid nGrid nGrid]));
We now have volume data mask that contains zeroes and ones, with the ones defining the region of intersection. The finer you make your grid (by adjusting nGrid), the more accurately this will represent the true region of intersection between the cylinders.
Generating a 3D surface:
You may want to create a surface from this data, defining the boundary of the intersection region. There are a couple ways to do this. One is to generate the surface with isosurface, which you could then visualize using featureEdges. For example:
[F, V] = isosurface(mask, 0.5);
TR = triangulation(F, V);
FE = featureEdges(TR, pi/6).';
xV = V(:, 1);
yV = V(:, 2);
zV = V(:, 3);
trisurf(TR, 'FaceColor', 'c', 'FaceAlpha', 0.8, 'EdgeColor', 'none');
axis equal;
xlabel('x');
ylabel('y');
zlabel('z');
hold on;
plot3(xV(FE), yV(FE), zV(FE), 'k');
And the resulting plot:
Another option is to create a "voxelated" Minecraft-like surface, as I illustrate here:
[X, Y, Z, C] = build_voxels(permute(mask, [2 1 3]));
hSurface = patch(X, Y, Z, 'c', ...
'AmbientStrength', 0.5, ...
'BackFaceLighting', 'unlit', ...
'EdgeColor', 'none', ...
'FaceLighting', 'flat');
axis equal;
view(-37.5, 30);
set(gca, 'XLim', [0 101], 'YLim', [25 75], 'ZLim', [0 102]);
xlabel('x');
ylabel('y');
zlabel('z');
grid on;
light('Position', get(gca, 'CameraPosition'), 'Style', 'local');
And the resulting plot:
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:
I've got the following code which works for plotting an x-y slice of the Hydrogen 2pz orbital:
%probability densities
pd_psi_210 = #(r,theta,phi) exp(-r).*(r.^2).*(cos(theta).^2)/(32*pi);
%configuring the range
[x y z] = meshgrid(-10:.1:10,-10:.1:10,-2:.1:2);
[THETA,PHI,R] = cart2sph(x,y,z);
%create array of probability density magnitudes
psi_210_vals = pd_psi_210(R,THETA,PHI);
%plotting
imagesc(psi_210_vals(:,:,1)); %x-y plane
I'd like to plot the 3d contour plot of the orbital. I've tried this (and it doesn't seem to get me what I wanted):
isosurface(psi_210_vals(:,:,:)); %3D contour
How can I get this to work?
You just have to specify the underlying grid, and the level you want. For example:
>> isosurface(-10:.1:10, -10:.1:10, -2:.1:2, psi_210_vals, 0.001);
>> axis equal
I have a problem dealing with 3rd dimension plot for three variables.
I have three matrices: Temperature, Humidity and Power. During one year, at every hour, each one of the above were measured. So, we have for each matrix 365*24 = 8760 points. Then, one average point is taken every day. So,
Tavg = 365 X 1
Havg = 365 X 1
Pavg = 365 X 1
In electrical point of veiw, the power depends on the temperature and humidity. I want to discover this relation using a three dimensional plot.
I tried using mesh, meshz, surf, plot3, and many other commands in MATLAB but unfortunately I couldn't get what I want. For example, let us take first 10 days. Here, every day is represented by average temperature, average humidity and average power.
Tavg = [18.6275
17.7386
15.4330
15.4404
16.4487
17.4735
19.4582
20.6670
19.8246
16.4810];
Havg = [75.7105
65.0892
40.7025
45.5119
47.9225
62.8814
48.1127
62.1248
73.0119
60.4168];
Pavg = [13.0921
13.7083
13.4703
13.7500
13.7023
10.6311
13.5000
12.6250
13.7083
12.9286];
How do I represent these matrices by three dimension plot?
The challenge is that the 3-D surface plotting functions (mesh, surf, etc.) are looking for a 2-D matrix of z values. So to use them you need to construct such a matrix from the data.
Currently the data is sea of points in 3-D space, so, you have to map these points to a surface. A simple approach to this is to divide up the X-Y (temperature-humidity) plane into bins and then take the average of all of the Z (power) data. Here is some sample code for this that uses accumarray() to compute the averages for each bin:
% Specify bin sizes
Tbin = 3;
Hbin = 20;
% Create binned average array
% First create a two column array of bin indexes to use as subscripts
subs = [round(Havg/Hbin)+1, round(Tavg/Tbin)+1];
% Now create the Z (power) estimate as the average value in each bin
Pest = accumarray(subs,Pavg,[],#mean);
% And the corresponding X (temp) & Y (humidity) vectors
Tval = Tbin/2:Tbin:size(Pest,2)*Tbin;
Hval = Hbin/2:Hbin:size(Pest,1)*Hbin;
% And create the plot
figure(1)
surf(Tval, Hval, Pest)
xlabel('Temperature')
ylabel('Humidity')
zlabel('Power')
title('Simple binned average')
xlim([14 24])
ylim([40 80])
The graph is a bit coarse (can't post image yet, since I am new) because we only have a few data points. We can enhance the visualization by removing any empty bins by setting their value to NaN. Also the binning approach hides any variation in the Z (power) data so we can also overlay the orgional point cloud using plot3 without drawing connecting lines. (Again no image b/c I am new)
Additional code for the final plot:
%% Expanded Plot
% Remove zeros (useful with enough valid data)
%Pest(Pest == 0) = NaN;
% First the original points
figure(2)
plot3(Tavg, Havg, Pavg, '.')
hold on
% And now our estimate
% The use of 'FaceColor' 'Interp' uses colors that "bleed" down the face
% rather than only coloring the faces away from the origin
surfc(Tval, Hval, Pest, 'FaceColor', 'Interp')
% Make this plot semi-transparent to see the original dots anb back side
alpha(0.5)
xlabel('Temperature')
ylabel('Humidity')
zlabel('Power')
grid on
title('Nicer binned average')
xlim([14 24])
ylim([40 80])
I think you're asking for a surface fit for your data. The Curve Fitting Toolbox handles this nicely:
% Fit model to data.
ft = fittype( 'poly11' );
fitresult = fit( [Tavg, Havg], Pavg, ft);
% Plot fit with data.
plot( fitresult, [xData, yData], zData );
legend( 'fit 1', 'Pavg vs. Tavg, Havg', 'Location', 'NorthEast' );
xlabel( 'Tavg' );
ylabel( 'Havg' );
zlabel( 'Pavg' );
grid on
If you don't have the Curve Fitting Toolbox, you can use the backslash operator:
% Find the coefficients.
const = ones(size(Tavg));
coeff = [Tavg Havg const] \ Pavg;
% Plot the original data points
clf
plot3(Tavg,Havg,Pavg,'r.','MarkerSize',20);
hold on
% Plot the surface.
[xx, yy] = meshgrid( ...
linspace(min(Tavg),max(Tavg)) , ...
linspace(min(Havg),max(Havg)) );
zz = coeff(1) * xx + coeff(2) * yy + coeff(3);
surf(xx,yy,zz)
title(sprintf('z=(%f)*x+(%f)*y+(%f)',coeff))
grid on
axis tight
Both of these fit a linear polynomial surface, i.e. a plane, but you'll probably want to use something more complicated. Both of these techniques can be adapted to this situation. There's more information on this subject at mathworks.com: How can I determine the equation of the best-fit line, plane, or N-D surface using MATLAB?.
You might want to look at Delaunay triangulation:
tri = delaunay(Tavg, Havg);
trisurf(tri, Tavg, Havg, Pavg);
Using your example data, this code generates an interesting 'surface'. But I believe this is another way of doing what you want.
You might also try the GridFit tool by John D'Errico from MATLAB Central. This tool produces a surface similar to interpolating between the data points (as is done by MATLAB's griddata) but with cleaner results because it smooths the resulting surface. Conceptually multiple datapoints for nearby or overlapping X,Y coordinates are averaged to produce a smooth result rather than noisy "ripples." The tool also allows for some extrapolation beyond the data points. Here is a code example (assuming the GridFit Tool has already been installed):
%Establish points for surface
num_points = 20;
Tval = linspace(min(Tavg),max(Tavg),num_points);
Hval = linspace(min(Havg),max(Havg),num_points);
%Do the fancy fitting with smoothing
Pest = gridfit(Tavg, Havg, Pavg, Tval, Hval);
%Plot results
figure(5)
surfc(XI,YI,Pest, 'FaceColor', 'Interp')
To produce an even nicer plot, you can add labels, some transparancy and overlay the original points:
alpha(0.5)
hold on
plot3(Tavg,Havg,Pavg,'.')
xlabel('Temperature')
ylabel('Humidity')
zlabel('Power')
grid on
title('GridFit')
PS: #upperBound: Thanks for the Delaunay triangulation tip. That seems like the way to go if you want to go through each of the points. I am a newbie so can't comment yet.
Below is your solution:
Save/write the Myplot3D function
function [x,y,V]=Myplot3D(X,Y,Z)
x=linspace(X(1),X(end),100);
y=linspace(Y(1),Y(end),100);
[Xt,Yt]=meshgrid(x,y);
V=griddata(X,Y,Z,Xt,Yt);
Call the following from your command line (or script)
[Tavg_new,Pavg_new,V]=Myplot3D(Tavg,Pavg,Havg);
surf(Tavg_new,Pavg_new,V)
colormap jet;
xlabel('Temperature')
ylabel('Power/Pressure')
zlabel('Humidity')