Matlab - slice 3D volume - matlab

I need to slice a 3D volume (200x200x500 matrix) and plot the result. I tried following the example from Mathworks reported here, but the resulting slice is empty (it shouldn't be)... Do you have suggestions on how to fix this? Thanks!
Here is the code I am using and the resulting slice:
xmin = 1;
ymin = 1;
zmin = 1;
xmax = 200;
ymax = 200;
zmax = 499;
hslice = surf(linspace(xmin,xmax,100),...
linspace(ymin,ymax,100),...
zeros(100));
rotate(hslice,[100,100,250],-45)
xd = get(hslice,'XData');
yd = get(hslice,'YData');
zd = get(hslice,'ZData');
delete(hslice);
x = 1:200;
y = 1:200;
z = 1:499;
figure;
colormap(jet);
h = slice(x,y,z,V1,xd,yd,zd);
h.FaceColor = 'interp';
h.EdgeColor = 'none';
h.DiffuseStrength = 0.8;

This will draw a slice at x=100
v=randn(200,200,500);
[x,y,z] = meshgrid(1:200,1:200,1:500);
h=slice(x,y,z,v,100,[],[]);
set(h,'EdgeColor','none')
like wise you can place additional slices at y or z if you replace the [] with coordinates for e.h. y and z.

Related

Error plotting spherical harmonics in MATLAB: Grid arrays must have NDGRID structure

I am trying to use the spherical harmonics to represent a perturbation of a spherical object in an acoustic and fluid flow in 3D.
So far, I have been able to use a 2D perturbation on a 3D spherical object, however, I would like to extend that.
The current code represents a 3D sphere with a 2D perturbation, so the perturbation is only in x and y:
clearvars; clc; close all;
Nx = 128;
Ny = 128;
Nz = 128;
Lx =128;
Ly = 128;
Lz = 128;
xi = (0:Nx-1)/Nx*2*pi;
xi_x = 2*pi/Lx;
x = xi/xi_x;
yi = (0:Ny-1)/Ny*2*pi;
yi_y = 2*pi/Ly;
y = yi/yi_y;
zi = (0:Nz-1)/Nz*2*pi;
zi_z = 2*pi/Lz;
z = zi/zi_z;
[X,Y,Z] = meshgrid(x,y,z);
A = 2*pi / Lx;
B = 2*pi / Ly;
C = 2*pi / Lz;
x0 = 64;
y0 = 64;
z0 = 64;
rx0 = 20;
ry0 = 20;
rz0 = 20;
p = 3;
b = 0.1; % pert amplitude
c = 12;
d = 1;
a = 4;
theta = atan2(Y -y0, X-x0) - (pi/c);
p0 = ((X-x0) .* (X-x0)) /(rx0 * rx0) + ((Y-y0) .* (Y-y0))/(ry0 * ry0) + ((Z-z0) .* (Z-z0))/(rz0 * rz0);
Test =d + a * exp((-1. * p0 .* (1 - b .* cos(c * theta))).^p) ;
figure
isosurface(X,Y,Z,Test);
shading flat;
grid on;
Which returns the isosurface:
However, I would like to achieve something similar to this plot (perturbation in z as well):
This is my attempt using spherical harmonics to reproduce the above picture:
clearvars; clc; close all;
%in spherical coord
%calculate r
Nx = 128;
Ny = 128;
Nz = 128;
Lx =128;
Ly = 128;
Lz = 128;
xi = (0:Nx-1)/Nx*2*pi;
xi_x = 2*pi/Lx;
x = xi/xi_x;
yi = (0:Ny-1)/Ny*2*pi;
yi_y = 2*pi/Ly;
y = yi/yi_y;
zi = (0:Nz-1)/Nz*2*pi;
zi_z = 2*pi/Lz;
z = zi/zi_z;
r = sqrt(x.^2 + y.^2 + z.^2);
% Create the grid
delta = pi/127;
%Taking for instance l=1, m=-1 you can generate this harmonic on a (azimuth, elevation) grid like this:
azimuths = 0 : delta : pi;
elevations = 0 : 2*delta : 2*pi;
[R, A, E] = ndgrid(r, azimuths, elevations); %A is phi and E is theta
H = 0.25 * sqrt(3/(2*pi)) .* exp(-1j*A) .* sin(E) .* cos(E);
%transform the grid back to cartesian grid like this:
%can also add some radial distortion to make things look nicer:
%the radial part depends on your domain
X = r .* cos(A) .* sin(E);
Y = r .* sin(A) .* sin(E);
Z = r .* cos(E);
%parameters
x0 = 64;
y0 = 64;
z0 = 64;
rx0 = 20;
ry0 = 20;
rz0 = 20;
p = 3;
b = 0.1; % pert amplitude
%c = 12;
d = 1;
a = 4;
p0 = ((X-x0) .* (X-x0)) /(rx0 * rx0) + ((Y-y0) .* (Y-y0))/(ry0 * ry0) + ((Z-z0) .* (Z-z0))/(rz0 * rz0);
Test1 =d + a * exp((-1. * p0 .*H).^p) ;
figure
isosurface(X,Y,Z,real(Test1)); %ERROR
This gives me the following error:
Error using griddedInterpolant
Grid arrays must have NDGRID structure.
Is the issue in the way I am setting up the spherical harmonics? or the functional form of Test1?? Thanks
I think the problem is that you've created a NDGrid in the second code. In the first code that worked you created a meshgrid.
isosurface expects a grid in meshgrid format and transforms it later into an NDGrid format with permute just for the usage of the griddedInterpolant function. By the input of an NDGrid this operation will fail.
Why did you switch to creating a NDGrid? Did you get the same error when using meshgrid?
EDIT
OK, new theory: I think the problem is the grid itsself. Read the documentation on ndgrid for more information but for short: A NDGrid format is a completely rectangular grid where all nodes are exclusivly surrounded by 90° angles. By spanning up a grid with ndgrid(r, azimuths, elevations) or meshgrid(r, azimuths, elevations) you are getting this rectangular grid but of course this grid is meaningless because r, azimuths and elevations represent spherical coordinates. By later converting R, A and E into the carthesian coordinates X, Y and Z you get a propper spherical grid but the grid isn't a NDGrid structure anymore since it's not rectangular anymore.
So you have to find a workaround to calculate with your spherical grid.
Maybe you can use another function to visualize your data that dosn't take any grid format as input
Or maybe you can try working with a rectangular cartesian grid by setting all values outside the sphere to 0. (You have to refine your grid accordingly to achieve a good estimation of the sphere)

Animation of Conformal Mappings

In this movie the conformal mapping fz = -1/z is visualized as a continuous transformation of an image to the distorted result. How was this made? I am working with conformal mappings in Matlab and I would like to know a method to generate the intermediate steps of an arbitrary conformal transformation in analogy to this movie.
One old trick is to use surface with FaceColor = texturemap with Z=0. A texturemapped surface with Z=0 is basically an image, but it lets you mess with the X&Y coordinates of the underlying grid to do this sort of warping.
You'd want 2D arrays for your XData & YData. Those are the ones you'll manipulate with the mapping. Your ZData would be an array of the same size which was all zeros. Then the CData array would be an image. If you wanted to use a 20x20 grid, it might look something like this:
m = 20;
n = 20;
[x,y] = meshgrid(m,n);
img = imread('myimage.png');
h = surf(x,y,zeros(m,n),img,'FaceColor','texturemap');
Then you can manipulate h.XData and h.YData to animate changing the mapping.
for t = 0:.05:1
[newx, newy] = mymapping(x,y,t);
h.XData = newx;
h.YData = newy;
drawnow
end
With the following code I can generate a sequence of images that could be considered as a transformation or animation using the linear equation (1-t) * 1 + t * (1./(a.*(x+1i.*y))); But it is in no way that what is seen in CH56_Clip4.mov. Additionally t = 0.00 delivers a monochrome result.
[h_i, w_i, ~] = size(img);
% INITIALIZE IN-MESHGRID & NORMALIZE [0 1]
[xi,yi] = meshgrid(linspace(0,w_i+1,w_i),linspace(0,h_i+1,h_i));
xi = (xi/w_i); yi = (yi/h_i);
% INITIALIZE OUT-MESHGRID & NORMALIZE [-1 1]
[xo,yo] = meshgrid(1:w_i, 1:h_i);
xo = (xo/w_i)*2 - 1; yo = (yo/h_i)*2 - 1;
% GENERATE SURFACE
h = surf(xo, yo, zeros(w_i, h_i), img, 'FaceColor', 'texturemap');
% INITIALIZE OUT-IMAGE
img_out_t = zeros(h_i, w_i, 3);
for t = 0.00:0.1:1.0
% DISTORTION, SEPARATE & NORMALIZE [0 1]
fxiy = (1-t) * 1 + t * (1./(1.2.*(xo+1i.*yo)));
h.XData = real(fxiy); xo1 = h.XData;
h.YData = imag(fxiy); yo1 = h.YData;
xo1 = (xo1+1)/2; yo1 = (yo1+1)/2;
% INTERPOLATION
for k = 1:3; img_out_t(:,:,k) = uint8(interp2(xi, yi, img(:,:,k), xo1, yo1, interpol_meth)); end; imwrite(uint8(img_out_t), ['img_out_t_', num2str(t), '.jpg'], 'jpg', 'Quality', 98);
end

Output of streamline in Matlab is empty

I want to use streamline to show a vector field. The vector field is singular in a point. I want to remove regions near the singularity (fo example regions which their distance to singularity is less than 1). I wrote below code but it doesn't show anything. Could anyone help me?
clear all;
close all;
r1 = 1; r2 = 5; % Radii of your circles
x_0 = 0; y_0 = 0; % Centre of circles
[x,y] = meshgrid(x_0-r2:0.2:x_0+r2,y_0-r2:0.2:y_0+r2); % meshgrid of points
idx = ((x-x_0).^2 + (y-y_0).^2 > r1^2 & (x-x_0).^2 + (y-y_0).^2 < r2^2);
x = sort(x(idx));
[x, index] = unique(x);
y = sort(y(idx));
[y, index] = unique(y);
U=cos(x)/sqrt(x.^2+y.^2);
V=sin(x)/sqrt(x.^2+y.^2);
streamslice(x,y,U,V);
The problem with your code is that U and V are all zeros, so you get white space. The reason for that is that you don't use elementwise division with ./. So as a first step you should write:
U = cos(x)./sqrt(x.^2+y.^2);
V = sin(x)./sqrt(x.^2+y.^2);
Now U and V are not zeros but are also not matrices anymore, so they are not a valid input for streamslice. The reason for that is that x and y are converted to vectors when calling:
x = sort(x(idx));
y = sort(y(idx));
My guess is that you can remove all this indexing, and simply write:
r1 = 1; r2 = 5; % Radii of your circles
x_0 = 0; y_0 = 0; % Centre of circles
[x,y] = meshgrid(x_0-r2:0.2:x_0+r2,y_0-r2:0.2:y_0+r2); % meshgrid of points
U = cos(x)./sqrt(x.^2+y.^2);
V = sin(x)./sqrt(x.^2+y.^2);
streamslice(x,y,U,V);
so you get:
I think you misunderstood the concept of streamslice. Is this you expecting?
close all;
r1 = 1; r2 = 5; % Radii of your circles
x_0 = 0; y_0 = 0; % Centre of circles
[xx,yy] = meshgrid(x_0-r2:0.2:x_0+r2,y_0-r2:0.2:y_0+r2); % meshgrid of points
% idx = ((xx-x_0).^2 + (yy-y_0).^2 > r1^2 & (xx-x_0).^2 + (yy-y_0).^2 < r2^2);
% x = sort(xx(idx));
% [x, index] = unique(x);
% y = sort(yy(idx));
% [y, index] = unique(y);
U=cos(xx)./sqrt(xx.^2+yy.^2);
V=sin(xx)./sqrt(xx.^2+yy.^2);
streamslice(xx,yy,U,V);

Streamline plot of cylinder

I have made this plot of streamlines around a cylinder with a radius of 1. Is there a way to remove whats inside the cylinder and maybe even high lite the cylinder with a different colour?
clear
% make axes
xymax = 2;
x = linspace(-xymax,xymax,100);
y = linspace(-xymax,xymax,100);
% note that x and y don't include 0
[X,Y] = meshgrid(x,y);
R = sqrt(X.^2 + Y.^2);
sin_th = Y./R;
cos_th = X./R;
U = 1;
a = 1;
psi = U*(R - a*a./R).*sin_th;
figure
contour(X,Y,psi,[-3:.25:3],'-b');
You can mask what you don't want to draw with nan:
psi((Y>0 & psi<0) | (Y<0 & psi>0)) = nan;
and than draw a circle on it:
rectangle('Position', [-1 -1 2 2],'Curvature',[1 1],'EdgeColor','r')
Here is the code and result:
% make axes
xymax = 2;
x = linspace(-xymax,xymax,100);
y = linspace(-xymax,xymax,100);
% note that x and y don't include 0
% [X,Y] = meshgrid(x(x<-1 | x>1),y(y<-1 | y>1));
[X,Y] = meshgrid(x,y);
R = sqrt(X.^2 + Y.^2);
sin_th = Y./R;
cos_th = X./R;
U = 1;
a = 1;
psi = U*(R - a*a./R).*sin_th;
% mask the inner part with nans:
psi((Y>0 & psi<0) | (Y<0 & psi>0)) = nan;
contour(X,Y,psi,[-3:0.25:3],'-b');
% draw a circle:
rectangle('Position', [-1 -1 2 2],'Curvature',[1 1],'EdgeColor','r')
axis equal
You can try also changing directly X and Y (instead of Y and psi):
psi(Y>-1 & X>-1 & Y<1 & X<1) = nan;
but the result is a bit different.
This is counter-intuitive, but the rectangle function can be used to draw a circle!
hold on
rectangle('Position',[-R,-R,2*R,2*R],'Curvature',[1,1],'FaceColor',[1 1 0])
Feel free to play around with the line properties too ('EdgeColor' and 'LineWidth')
https://www.mathworks.com/help/matlab/ref/rectangle.html

Matlab - anti-aliased rendering of figure containing plot lines and surf

I'm looking for a way to export anti-aliased graphics containing lines and "surf" at the same time.
With HG2, the "plot" lines are anti-aliased by default but the anti-aliasing is switched off once I insert a "surf". The closest I could get was by using "export_fig" but it's not exporting dashed lines properly.
r=100;
theta = linspace(0,2*pi,100);
[x,y] = pol2cart(theta,r*ones(1,100));
[x1,y1] = pol2cart(theta,0.9*r*ones(1,100));
rc = 0.1;
h = 0.3;
m = h/rc;
[R,A] = meshgrid(-linspace(0,rc,11),linspace(0,2*pi,50));
X3 = R .* cos(A)*r;
Y3 = R .* sin(A)*r;
Z3 = -(m*R+h)*r;
hold on
plot(x,y)
plot(x1,y1,'-.')
%plots are with anti-aliasing
s = surf(X3,Y3,Z3)
s.FaceLighting = 'gouraud';
s.AmbientStrength = 0.6;
s.DiffuseStrength = 0.8;
s.SpecularStrength = 0.9;
s.SpecularExponent = 25;
s.BackFaceLighting = 'reverselit';
s.FaceColor=[0.25 0.25 0.25];
set(s,'FaceAlpha',0.3);
set(s,'EdgeAlpha',0);
view(2)
%anti-aliasing is gone...