quiver not drawing arrows just lots of blue, matlab - matlab

Can somebody tell me what I am doing wrong with the quiver plotting function when I don't really get arrows, it just fills the empty space with lots of blue.Look at the image below and then look at my code.
This is just a part of my contour since this eats up proccessing power if I try to draw it larger. But my function, the contours and everything else works, it's just the quiver I'm having trouble with.
interval = -100:100;
[X Y] = meshgrid(interval, interval);
h = figure;
contour(X, Y, Z);
hold on;
[FX,FY] = gradient(-Z);
quiver(X, Y, FX, FY);
hold off;
If I make my matrix more sparse, e.g. with "interval = linspace(-800, 1600, 1200);" the result will look like this:
EDIT:
What I need are contour lines like that, but the arrows should flow with them. Right now these just look like dots, even if I zoom in further. If I zoom out the entire window will be blue.
Here is the script in its entirety if anyone wants to play with it to figure this out.
m1 = 1;
m2 = 0.4;
r1 = [1167 0 0];
r2 = [-467 0 0];
G = 9.82;
w = sqrt( G*(m1+m2) / norm(r1-r2)^3 );
interval = linspace(-800, 1600, 1200);
% Element-wise 2-norm
ewnorm = #(x,y) ( x.^2 + y.^2 ).^(1/2);
% Element-wise cross squared
ewcross2 = #(w,x,y) w^2.*( x.*x + y.*y );
[X Y] = meshgrid(interval, interval);
Z = - G*m1 ./ ewnorm( X-r1(1), Y-r1(2) ) - G*m2 ./ ewnorm( X-r2(1), Y-r2(2) ) - 1/2*ewcross2(w,X,Y);
h = figure;
contour(Z);
daspect([1 1 1]);
saveas(h, 'star1', 'eps');
hold on;
[FX,FY] = gradient(-Z);
quiver(X, Y, FX,FY);
hold off;

The problem is that the mesh is too dense. You only want to have as few elements as necessary to generate a useful mesh. As such, try reducing the density of the mesh:
interval = -100:2:100
If you're going to be changing the limits often, you probably want to avoid using the X:Y:Z formulation. Use the linspace function instead:
interval = linspace(-100,100,10);
This will ensure that no matter what your limits, your mesh will be 10x10. In the comment below, you mention that the arrows are appearing as dots when you use a very large mesh. This is to be expected. The arrows reflect "velocity" at a given point. When your plot is scaled out to a very large degree, then the velocity at any given point on the plot will be almost 0, hence the very small arrows. Check out the quiver plot documentation, as well as the quivergroup properties, to see more details.
If you absolutely must see arrows at a large scale, you can try setting the AutoScale property to off, or increasing the AutoScaleFactor:
quiver(X, Y, FX, FY, 'AutoScale', 'off');
quiver(X, Y, FX, FY, 'AutoScaleFactor', 10);
You may also want to play with the MarkerSize and MaxHeadSize properties. I really just suggest looking at all the QuiverGroup properties and trying things out.

You could use a threshold
interval = -100:100;
[X Y] = meshgrid(interval, interval);
h = figure;
contour(X, Y, Z);
hold on;
[FX,FY] = gradient(-Z);
GM = sqrt(FX.^2 + FY.^2);
threshold = 0.1;
mask = GM > threshold;
quiver(X(mask), Y(mask), FX(mask), FY(mask));
hold off;
This will show only vectors with a magnitude > 0.1;

Related

Gradient fill of a function inside a circular area Matlab

I'm trying to create a gradient fill inside a circular area according to a given function. I hope the plot below explains it at best
I'm not sure how to approach this, as in the simulation I'm working on the direction of the gradient changes (not always in the x direction as below, but free to be along all the defined angles), so I'm looking for a solution that will be flexible in that manner as well.
The code I have is below
clear t
N=10;
for i=0:N
t(i+1) = 0+(2*i*pi) / N;
end
F = exp(-cos(t))./(2.*pi*besseli(1,1));
figure(1)
subplot(1,3,1)
plot(t*180/pi,F,'-ob')
xlim([0 360])
xlabel('angle')
subplot(1,3,2)
hold on
plot(cos([t 2*pi]), sin([t 2*pi]),'-k','linewidth',2);
plot(cos([t 2*pi]), sin([t 2*pi]),'ob');
plot(cos(t).*F,sin(t).*F,'b','linewidth',2);
subplot(1,3,3)
hold on
plot(cos([t 2*pi]), sin([t 2*pi]),'-k','linewidth',2);
plot(cos([t 2*pi]), sin([t 2*pi]),'ob');
To fill surface, you need to use the patch command.
t = linspace(0, 2*pi, 100);
x = cos(t);
y = sin(t);
c = x; % colored following x value and current colormap
figure
patch(x,y,c)
hold on
scatter(x,y)
hold off
colorbar
Resulting graph:
Colors are defined in c per point, and are interpolated inside the shape, so I'm sure that you should have all freedom to color as you want!
For example, the rotated version:
t = linspace(0, 2*pi, 100);
x = cos(t);
y = sin(t);
c = cos(t+pi/4)
figure
patch(x,y,c)
colorbar
To understand how it is going on, just think that every point has a color, and matlab interpolate inside. So here I just rotated the intensity per point by pi /4.
For this to work you need to have a filled shape, and you may need to customize the color (c) parameter so that it matches your need. For example, if your gradient direction is encoded in a vector, you want to project all your point onto that vector to get the value along the gradient for all points.
For example:
% v controls the direction of the gradient
v = [0.1, 1];
t = linspace(0, 2*pi, 100);
F = exp(-cos(t))./(2.*pi*besseli(1,1));
% reconstructing point coordinate all around the surface
% this closes the path so with enough points so that interpolation works correctly
pts = [[t', F']; [t(end:-1:1)', ones(size(t'))*min(F)]];
% projecting all points on the vector to get the color
c = pts * (v');
clf
patch(pts(:,1),pts(:,2),c)
hold on
scatter(t, F)
hold off

How to fit an elliptic cone to a set of data?

I have a set of 3d data (300 points) that create a surface which looks like two cones or ellipsoids connected to each other. I want a way to find the equation of a best fit ellipsoid or cone to this dataset. The regression method is not important, the easier it is the better. I basically need a way, a code or a matlab function to calculate the constants of the elliptic equation for these data.
You can also try with fminsearch, but to avoid falling on local minima you will need a good starting point given the amount of coefficients (try to eliminate some of them).
Here is an example with a 2D ellipse:
% implicit equation
fxyc = #(x, y, c_) c_(1)*x.^2 + c_(2).*y.^2 + c_(3)*x.*y + c_(4)*x + c_(5).*y - 1; % free term locked to -1
% solution (ellipse)
c_ = [1, 2, 1, 0, 0]; % x^2, y^2, x*y, x, y (free term is locked to -1)
[X,Y] = meshgrid(-2:0.01:2);
figure(1);
fxy = #(x, y) fxyc(x, y, c_);
c = contour(X, Y, fxy(X, Y), [0, 0], 'b');
axis equal;
grid on;
xlabel('x');
ylabel('y');
title('solution');
% we sample the solution to have some data to fit
N = 100; % samples
sample = unique(2 + floor((length(c) - 2)*rand(1, N)));
x = c(1, sample).';
y = c(2, sample).';
x = x + 5e-2*rand(size(x)); % add some noise
y = y + 5e-2*rand(size(y));
fc = #(c_) fxyc(x, y, c_); % function in terms of the coefficients
e = #(c) fc(c).' * fc(c); % squared error function
% we start with a circle
c0 = [1, 1, 0, 0, 0];
copt = fminsearch(e, c0)
figure(2);
plot(x, y, 'rx');
hold on
fxy = #(x, y) fxyc(x, y, copt);
contour(X, Y, fxy(X, Y), [0, 0], 'b');
hold off;
axis equal;
grid on;
legend('data', 'fit');
xlabel('x'); %# Add an x label
ylabel('y');
title('fitted solution');
The matlab function fit can take arbitrary fit expressions. It takes a bit of figuring out the parameters but it can be done.
You would first create a fittype object that has a string representing your expected form. You'll need to work out the expression yourself that best fits what you're expecting, I'm going to take a cone expression from the Mathworld site for an example and rearrange it for z
ft = fittype('sqrt((x^2 + y^2)/c^2) + z_0', ...
'independent', {'x', 'y'}, 'coeff', {'c', 'z_0'});
If it's a simple form matlab can work out which are the variables and which the coefficients but with something more complex like this you'd want to give it a hand.
The 'fitoptions' object holds the configuration for the methods: depending on your dataset you might have to spend some time specifying upper and lower bounds, starting values etc.
fo = fitoptions('Upper', [one, for, each, of, your, coeffs, in, the, order, they, appear, in, the, string], ...
'Lower', [...], `StartPoint', [...]);
then get the output
[fitted, gof] = fit([xvals, yvals], zvals, ft, fo);
Caveat: I've done this plenty with 2D datasets and the docs state it works for three but I haven't done that myself so the above code might not work, check the docs to make sure you've got your syntax right.
It might be worth starting with a simple fit expression, something linear, so that you can get your code working. Then swap the expression out for the cone and play around until you get something that looks like what you're expecting.
After you've got your fit a good trick is that you can use the eval function on the string expression you used in your fit to evaluate the contents of the string as if it was a matlab expression. This means you need to have workspace variables with the same names as the variables and coefficients in your string expression.

Larger subplots in MATLAB

I have 6 Y variables all with the same X Variable (time)
I want to have 6 plots in a column but when I use subplot(6,1,1) the plots become tiny vertically.
I have tried using:
x=0:360;
y1=sind(x);
y2=cosd(x);
h=subplot(6,1,1);
plot(x,y1);
d = get(h,'Position');
d(4)=d(4)*3;
set(h,'Position',d);
h=subplot(6,1,2);
plot(x,y2);
d = get(h,'Position');
d(4)=d(4)*3;
set(h,'Position',d);
....(For 6 subplots)
In the hope that each subplot would be 3 times larger vertically, which works but the spacing between the subplots does not update so the subplots start to overlap:
How can I make it so the subplots are larger vertically but equally spaced out like they were before I changed the height of each subplot?
Also if you could help me hide the xTick labels (numbers) but keep the ticks (lines) themselves on all subplots but the very bottom one that would also be a great help. Thanks!
Matlab sucks pretty hard for easily making this kind of graphs. You either have to do it by hand or search around on the file-exchange to see if someone already implemented something better.
This blog discussed one script that seems to do what you want.
To hide the tick labels:
set(gca, 'XTickLabel', '')
If you want to build your own subplot, you can use something like this (not tested very well):
function ax = mySubplot(nrow, ncol)
% returns a matrix of axis handles
% to plot in the second subplot, you would use plot(ax(1,2), x, y)
% standard x, y, dx, dy for subplot(111)
x0 = 0.1300;
y0 = 0.1100;
w0 = 0.7750;
h0 = 0.8150;
w = w0 / ncol;
h = h0 / nrow;
figure()
ax = nan(nrow, ncol);
for irow = 1:nrow
for icol = 1:ncol
ax(irow, icol) = axes('position', ...
[x0 + (icol - 1) * w, y0 + (nrow - irow) * h, 0.9*w, 0.9*h]);
end
end
Result of mySubplot(6,2):
You could play yourself with the spacings.

PCA on a 3D image to obtain 3 principal axes

I have an anatomical volume image (B), which is an indexed image i,j,k:
B(1,1,1)=0 %for example.
The file contains only 0s and 1s.
I can visualize it correctly with isosurface:
isosurface(B);
I would like to cut the volume at some coordinate in j (it is different for each volume).
The problem is that the volume is tilted vertically, it maybe has 45% degrees, so the cut will not be following the anatomical volume.
I would like to obtain a new orthogonal coordinate system for the data, so my plane in coordinate j would cut the anatomical volume in a more accurate way.
I've been told to do it with PCA, but I don't have a clue how to do it, and reading the help pages haven't been of help. Any direction will be welcome!
EDIT:
I have been following the recommendations, and now I got a new volume, zero-centered, but I think that axes don't follow the anatomical image as they should. These are the pre and post images:
This is the code I used to create the images (I took some code from the answer and the idea from the comments):
clear all; close all; clc;
hippo3d = MRIread('lh_hippo.mgz');
vol = hippo3d.vol;
[I J K] = size(vol);
figure;
isosurface(vol);
% customize view and color-mapping of original volume
daspect([1,1,1])
axis tight vis3d;
camlight; lighting gouraud
camproj perspective
colormap(flipud(jet(16))); caxis([0 1]); colorbar
xlabel x; ylabel y; zlabel z
box on
% create the 2D data matrix
a = 0;
for i=1:K
for j=1:J
for k=1:I
a = a + 1;
x(a) = i;
y(a) = j;
z(a) = k;
v(a) = vol(k, j, i);
end
end
end
[COEFF SCORE] = princomp([x; y; z; v]');
% check that we get exactly the same image when going back
figure;
atzera = reshape(v, I, J, K);
isosurface(atzera);
% customize view and color-mapping for the check image
daspect([1,1,1])
axis tight vis3d;
camlight; lighting gouraud
camproj perspective
colormap(flipud(jet(16))); caxis([0 1]); colorbar
xlabel x; ylabel y; zlabel z
box on
% Convert all columns from SCORE
xx = reshape(SCORE(:,1), I, J, K);
yy = reshape(SCORE(:,2), I, J, K);
zz = reshape(SCORE(:,3), I, J, K);
vv = reshape(SCORE(:,4), I, J, K);
% prepare figure
%clf
figure;
set(gcf, 'Renderer','zbuffer')
% render isosurface at level=0.5 as a wire-frame
isoval = 0.5;
[pf,pv] = isosurface(xx, yy, zz, vv, isoval);
p = patch('Faces',pf, 'Vertices',pv, 'FaceColor','none', 'EdgeColor',[0.5 1 0.5]);
% customize view and color-mapping
daspect([1,1,1])
axis tight vis3d;view(-45,35);
camlight; lighting gouraud
camproj perspective
colormap(flipud(jet(16))); caxis([0 1]); colorbar
xlabel x; ylabel y; zlabel z
box on
Can anybody provide a hint what might be happening? It seems that the problem might be the reshape command, Is it possible that I am canceling out the job previously done?
Not sure about PCA, but here is an example showing how to visualize a 3D scalar volume data, and cutting the volume at a tilted plane (non-axis aligned). Code is inspired by this demo in the MATLAB documentation.
% volume data
[x,y,z,v] = flow();
vv = double(v < -3.2); % threshold to get volume with 0/1 values
vv = smooth3(vv); % smooth data to get nicer visualization :)
xmn = min(x(:)); xmx = max(x(:));
ymn = min(y(:)); ymx = max(y(:));
zmn = min(z(:)); zmx = max(z(:));
% let create a slicing plane at an angle=45 about x-axis,
% get its coordinates, then immediately delete it
n = 50;
h = surface(linspace(xmn,xmx,n), linspace(ymn,ymx,n), zeros(n));
rotate(h, [-1 0 0], -45)
xd = get(h, 'XData'); yd = get(h, 'YData'); zd = get(h, 'ZData');
delete(h)
% prepare figure
clf
set(gcf, 'Renderer','zbuffer')
% render isosurface at level=0.5 as a wire-frame
isoval = 0.5;
[pf,pv] = isosurface(x, y, z, vv, isoval);
p = patch('Faces',pf, 'Vertices',pv, ...
'FaceColor','none', 'EdgeColor',[0.5 1 0.5]);
isonormals(x, y, z, vv, p)
% draw a slice through the volume at the rotated plane we created
hold on
h = slice(x, y, z, vv, xd, yd, zd);
set(h, 'FaceColor','interp', 'EdgeColor','none')
% draw slices at axis planes
h = slice(x, y, z, vv, xmx, [], []);
set(h, 'FaceColor','interp', 'EdgeColor','none')
h = slice(x, y, z, vv, [], ymx, []);
set(h, 'FaceColor','interp', 'EdgeColor','none')
h = slice(x, y, z, vv, [], [], zmn);
set(h, 'FaceColor','interp', 'EdgeColor','none')
% customize view and color-mapping
daspect([1,1,1])
axis tight vis3d; view(-45,35);
camlight; lighting gouraud
camproj perspective
colormap(flipud(jet(16))); caxis([0 1]); colorbar
xlabel x; ylabel y; zlabel z
box on
Below is the result showing the isosurface rendered as wire-frame, in addition to slicing planes both axes-aligned and one rotated. We can see that the volume space on the inside of the isosurface has values equal to 1, and 0 on the outside
I don't think that PCA solves your problem. If you apply PCA to your data it will give you three new axes. These axes are called principal components (PCs). They have the property that the first PC has the largest variance when the data is projected on it. The second PC must also has the largest variance when data is projected on it subject to the constraint that it should be orthogonal to the first, the third PC is similar.
Now the question is when you project your data into the new coordinate system (defined by the PCs) will it match the anatomical volume? Not necessarily and most probably will not. The right axes for your data do not have the optimization objective of PCA.
Sorry, I tried to answer to #Tevfik-Aytekin, but the answer is too long.
Hopefully this answer will be useful for somebody:
Hi #Tevfik, thanks for your answer. I've struggling for days with this same problem, and I think I got it right now.
I think that the difference respect to what you are saying is that I am working with coordinates. When I perform PCA over my coordinates, I get a 3x3 transformation matrix for my data (COEFF matrix, which is unitary and orthogonal, it is just a rotation matrix), so I know that I get exactly the same volume when transformed.
These are the steps I followed:
I had a (I,J,K), 3D volume.
As per #werner suggestion, I changed it to a 4 column matrix (x,y,z,v), size (I*J*K, 4).
Eliminated the coordinates (x,y,z) when v == 0, and v too. So right now, size is (original volume, 3). Only the coordinates with value 1, so the length of the vector is the volume of the figure.
Perform PCA to obtain COEFF and SCORE.
COEFF is a 3x3 matrix. It is unitary and orthogonal, it is a rotation matrix for my volume data.
I did the editing in the PCA1 axis (i.e. delete al values when COEFF(1) is bigger than some-value). This was my problem, I wanted to cut the volume perpendicular to the main axis.
This was enough for me, the reamining coordinates are giving me the volume I wanted. But:
I didn't need to go back, as I just needed the remaining volume, but
In order to go back, I just had to reconstruct the original coordinates. So first I transformed the remaining coordinates with SCORE*COEFF'.
Then I created again a (I*J*K, 4) matrix, making the v column = 1 only when the transformed coordinates matched the new matrix (with ismember, option 'row').
I created the indexed volume back using reshape(v, I, J, K).
If I visualize the new volume back, it is cut perpendicular to the main geometric axes of the figure, just as I needed.
Please, I would really like to hear any comment or suggestion on the method.

MATLAB contourf plot for an irregular domain

I am stuck with this problem for a long time now. I have a polygonal region (lets say, a hexagon). I can calculate the values of certain function at any point inside the polygon. Now I need to create a filled contour (using contourf in MATLAB) of this data. How do I go about it. I found some discussion on this topic at the link below (page 121)
http://www-personal.umich.edu/~jpboyd/eng403_chap4_contourplts.pdf
This works somewhat ok but it still produces jagged edges which I don't want. Anyone has any suggestion on this problem? Thanks. Here is my code
close all
Node = [ 1.0 0
0.5 0.8660
-0.5 0.8660
-1.0 0
-0.5 -0.8660
0.5 -0.8660];
[x,y] = meshgrid(-1:0.1:1,-1:0.1:1);
N = zeros(size(x));
for i=1:size(x,2)
for j=1:size(y,2)
p = [x(i,j) y(i,j)];
IN = inpolygon(p(1),p(2),Node(:,1),Node(:,2));
if IN
N(i,j)= rand;
else
N(i,j)= NaN;
end
end
end
figure
contourf(x,y,N,'LineStyle','none'), hold on;
xlabel('X'), ylabel('Y'), axis equal; axis off; colorbar;
line([Node(:,1);Node(1,1)],[Node(:,2);Node(1,2)],'Color',[1 1 1],'LineWidth',2.0)
clear IN i j p x y
You're using a square grid to sample a hexagonal area. This will indeed lead to boundary problems.
A better solution (but still not quite optimal) is to use a hexagonal grid:
%# define hexagon
Node = [ 1.0 0
0.5 0.8660
-0.5 0.8660
-1.0 0
-0.5 -0.8660
0.5 -0.8660];
%# Generate hexagonal grid
Rad3Over2 = sqrt(3) / 2;
[x, y] = meshgrid(0:51);
n = size(y,1);
x = Rad3Over2 * x;
y = y + repmat([0 0.5],[n,n/2]);
%# re-scale to -1..1
x = 2*x/max(x(:))-1;
y = 2*y/max(y(:))-1;
%# insode-polygon check
N = zeros(size(x));
for i=1:size(x,2)
for j=1:size(y,2)
p = [x(i,j) y(i,j)];
IN = inpolygon(p(1),p(2),Node(:,1),Node(:,2));
if IN
N(i,j)= rand;
else
N(i,j)= NaN;
end
end
end
%# make contour plot
figure(1)
contourf(x,y,N,'LineStyle','none'), hold on;
xlabel('X'), ylabel('Y'), axis equal; axis off; colorbar;
line([Node(:,1);Node(1,1)],[Node(:,2);Node(1,2)],'Color',[1 1 1],'LineWidth',2.0)
If you want even better coverage, you'll have to devise a grid that better covers your area and/or up the number of sample points.
For arbitrary irregular areas, you might want to experiment with irregular/random grids, distributed such that there are more points close to the boundaries, than there are in the middle of the area.
Suppose you have a function defined on a hexagon. Then take some square that contains the hexagon.
A simple first test could be to extend your function on the square to take the value = 0 for points outside of the hexagon.
Depending on the range of your function this may, or may not, give you a good answer.
If this doesn't work, then find the min of the function on the hexagon using min(min(A))) for an nxn matrix A. Then define the function to be min(min(A)) - 1.0 outside of the hexagon but in the square.
Then use contourf(x, y, z, v) where v is a vector of values for the output, so take v(1) = min(min(A)) - 1.0, and v(2:n) = linspace(min(min(A)), max(max(A)), n) for some integer n. You can probably specify the color of the level set min(min(A)) - 1.0 to be white, but I've never done this. I've had to do something like this before, and setting the function = 0 outside of he hexagon was enough.
If your function can only be evaluated inside the polygonal region, then my hexagonal grid answer still stands. However, if your function can be (or modified to be) evaluated outside the polygon, you might want to use a cheat:
figure(1), clf, hold on
%# External contour, square.
x1 = [-3 -3 +3 +3 -3]/2;
y1 = [-3 +3 +3 -3 -3]/2;
%# internal contour, some polygon
x2 = [1.0 0.5 -0.5 -1.0 -0.5 0.5];
y2 = [0 0.8660 0.8660 0 -0.8660 -0.8660];
%# convert to patches
[f, v] = poly2fv({x1, x2}, {y1, y2});
patch(...
'Faces' , f,...
'Vertices' , v,...
'FaceColor', get(0, 'defaultuicontrolbackgroundcolor'), ...
'EdgeColor', 'none'...
);
%# Generate function for contourplot
[x, y] = meshgrid(-2.8/2:0.1:2.8/2);
N = rand(size(x));
%# make contour plot
contourf(x,y,N,'LineStyle','none'), hold on;
xlabel('X'), ylabel('Y'), axis equal;
axis off; colorbar;
It basically creates your contour plot on a square region, and overlays a mask with a hexagonal hole in it, so it looks like it's only a contour of the hexagonal. I suspect it is a lot easier to tweak your function to allow function evaluations outside the region, then it is to (re-)invent some sort of grid that contains the boundaries.