Interpolating Shading in Circular Colormap - matlab

I am plotting a phase map and using a circular colormap like hsv. The issue I am having is at the pi/-pi angle interfaces, the interpolation (shading interp command in MATLAB) gives me 0, which leads to strange lines in the resulting figure (see below, the below figure is the 4 tangent arctan function). Is there a way I can get rid of these artifacts? I like the smoothness of interpolated shading as opposed to flat shading, but flat shading avoids these artifacts.
Here is the code that generates the above image:
[x_grid,y_grid] = meshgrid(-31:32,-31:32);
phase = atan2(y_grid,x_grid);
surf(x_grid,y_grid,phase);
view(0,90);
shading interp
colorbar
axis([-31 32 -31 32])
colormap hsv

The problem is that using an N-by-N set of grid points is always going to have a discontinuity at the pi/-pi interface which it will try to interpolate across. You can instead create a 2-by-N strip of coordinates that wrap around the origin and are disconnected at the pi/-pi interface. The following illustrates how the discontinuity looks for the 2 approaches:
% N-by-N grid:
[x_grid, y_grid] = meshgrid(-31:32, -31:32);
phase = atan2(y_grid, x_grid);
subplot(1, 2, 1);
surf(x_grid, y_grid, phase);
title('N-by-N grid');
% 2-by-N strip:
X = [-31.*ones(1, 33) -30:31 32.*ones(1, 64) 31:-1:-30 -31.*ones(1, 32); ...
zeros(1, 253)];
Y = [0:32 32.*ones(1, 62) 32:-1:-31 -31.*ones(1, 62) -31:0; ...
zeros(1, 253)];
phase = atan2(Y([1 1], :), X([1 1], :));
phase(:, end) = -pi;
subplot(1, 2, 2);
surf(X, Y, phase);
title('2-by-N strip');
And here's how the final 2-D view would look (with a higher-resolution colormap):
X = [-31.*ones(1, 33) -30:31 32.*ones(1, 64) 31:-1:-30 -31.*ones(1, 32); ...
zeros(1, 253)];
Y = [0:32 32.*ones(1, 62) 32:-1:-31 -31.*ones(1, 62) -31:0; ...
zeros(1, 253)];
phase = atan2(Y([1 1], :), X([1 1], :));
phase(:, end) = -pi;
surf(X, Y, phase);
view(0, 90);
shading interp;
colorbar;
axis([-31 32 -31 32]);
colormap(hsv(256));

Related

How can I fill an area below a 3D graph in MATLAB?

I created the following 3d plot in MATLAB using the function plot3:
Now, I want to get a hatched area below the "2d sub-graphs" (i.e. below the blue and red curves). Unfortunately, I don't have any idea how to realize that.
I would appreciate it very much if somebody had an idea.
You can do this using the function fill3 and referencing this answer for the 2D case to see how you have to add points on the ends of your data vectors to "close" your filled polygons. Although creating a pattern (i.e. hatching) is difficult if not impossible, an alternative is to simply adjust the alpha transparency of the filled patch. Here's a simple example for just one patch:
x = 1:10;
y = rand(1, 10);
hFill = fill3(zeros(1, 12), x([1 1:end end]), [0 y 0], 'b', 'FaceAlpha', 0.5);
grid on
And here's the plot this makes:
You can also create multiple patches in one call to fill3. Here's an example with 4 sets of data:
nPoints = 10; % Number of data points
nPlots = 4; % Number of curves
data = rand(nPoints, nPlots); % Sample data, one curve per column
% Create data matrices:
[X, Y] = meshgrid(0:(nPlots-1), [1 1:nPoints nPoints]);
Z = [zeros(1, nPlots); data; zeros(1, nPlots)];
patchColor = [0 0.4470 0.7410]; % RGB color for patch edge and face
% Plot patches:
hFill = fill3(X, Y, Z, patchColor, 'LineWidth', 1, 'EdgeColor', patchColor, ...
'FaceAlpha', 0.5);
set(gca, 'YDir', 'reverse', 'YLim', [1 nPoints]);
grid on
And here's the plot this makes:

MATLAB - Smooth heat map from (x, y, z) points within a triangle?

I have many 3D scatter points (x, y, z) that are guaranteed to be within a triangle. I now wish to visualize z as one smooth 2D heat map, where positions are given by (x, y).
I can easily do it with meshgrid and mesh, if (x, y) together form a rectangle. Because I don't want anything falling outside of my triangle, I can't use griddate either.
Then how?
MWE
P = [0 1/sqrt(3); 0.5 -0.5/sqrt(3); -0.5 -0.5/sqrt(3)];
% Vertices
scatter(P(:, 1), P(:, 2), 100, 'ro');
hold on;
% Edges
for idx = 1:size(P, 1)-1
plot([P(idx, 1) P(idx+1, 1)], [P(idx, 2) P(idx+1, 2)], 'r');
end
plot([P(end, 1) P(1, 1)], [P(end, 2) P(1, 2)], 'r');
% Sample points within the triangle
N = 1000; % Number of points
t = sqrt(rand(N, 1));
s = rand(N, 1);
sample_pts = (1-t)*P(1, :)+bsxfun(#times, ((1-s)*P(2, :)+s*P(3, :)), t);
% Colors for demo
C = ones(size(sample_pts, 1), 1).*sample_pts(:, 1);
% Scatter sample points
scatter(sample_pts(:, 1), sample_pts(:, 2), [], C, 'filled');
colorbar;
produces
PS
As suggested by Nitish, increasing number of points will do the trick. But is there a more computationally cheap way of doing so?
Triangulate your 2D data points using delaunayTriangulation, evaluate your function with the points of the triangulation and then plot the resulting surface using trisurf:
After %Colors for demo, add this:
P = [P; sample_pts]; %// Add the edgepoints to the sample points, so we get a triangle.
f = #(X,Y) X; %// Defines the function to evaluate
%// Compute the triangulation
dt = delaunayTriangulation(P(:,1),P(:,2));
%// Plot a trisurf
P = dt.Points;
trisurf(dt.ConnectivityList, ...
P(:,1), P(:,2), f(P(:,1),P(:,2)), ...
'EdgeColor', 'none', ...
'FaceColor', 'interp', ...
'FaceLighting', 'phong');
%// A finer colormap gives more beautiful results:
colormap(jet(2^14)); %// Or use 'parula' instead of 'jet'
view(2);
The trick to make this graphic beautiful is to use 'FaceLighting','phong' instead of 'gouraud' and use a denser colormap than is usually used.
The following uses only N = 100 sample points, but a fine colormap (using the now default parula colormap):
In comparison the default output for:
trisurf(dt.ConnectivityList, ...
P(:,1), P(:,2), f(P(:,1),P(:,2)), ...
'EdgeColor', 'none', ...
'FaceColor', 'interp');
looks really ugly: (I'd say mainly because of the odd interpolation, but the jet colormap also has its downsides)
Why not just increase N to make the grid "more smooth"? It will obviously be more computationally expensive but is probably better than extrapolation. Since this is a simulation where s and t are your inputs, you can alternately create a fine grids for them (depending on how they interact).
P = [0 1/sqrt(3); 0.5 -0.5/sqrt(3); -0.5 -0.5/sqrt(3)];
% Vertices
scatter(P(:, 1), P(:, 2), 100, 'ro');
hold on;
% Edges
for idx = 1:size(P, 1)-1
plot([P(idx, 1) P(idx+1, 1)], [P(idx, 2) P(idx+1, 2)], 'r');
end
plot([P(end, 1) P(1, 1)], [P(end, 2) P(1, 2)], 'r');
% Sample points within the triangle
N = 100000; % Number of points
t = sqrt(rand(N, 1));
s = rand(N, 1);
sample_pts = (1-t)*P(1, :)+bsxfun(#times, ((1-s)*P(2, :)+s*P(3, :)), t);
% Colors for demo
C = ones(size(sample_pts, 1), 1).*sample_pts(:, 1);
% Scatter sample points
scatter(sample_pts(:, 1), sample_pts(:, 2), [], C, 'filled');
colorbar;

Multi dimensional (2d better 3d) scatter-plot with different errorbars in matlab

I am trying to program scatterplot with specific errorbars. The only build in function i found is
errorbar()
but this only enables me to make a 2d plot with errorbars in y direction. What i am asking for is a method to plot this with errorbars in x and y direction.
At the end my goal is to make a 3D-scatter-plot with 3 errorbars.
Perfect would be if the resulting image would be a 3d-plot with 3d geometric shapes (coordinate x,y,z with expansion in the dimension proportional to the errorbars) as 'marker'.
I found this page while searching the internet: http://code.izzid.com/2007/08/19/How-to-make-a-3D-plot-with-errorbars-in-matlab.html
But unfortunately they use only one errorbar.
My data is set of 6 arrays each containing either the x,y or z coordinate or the specific standard derivation i want to show as errorbar.
The code you posted looks very easy to adapt to draw all three error bars. Try this (note that I adapted it also so that you can change the shape and colour etc of the plots as you normally would by using varargin, e.g. you can call plot3d_errorbars(...., '.r'):
function [h]=plot3d_errorbars(x, y, z, ex, ey, ez, varargin)
% create the standard 3d scatterplot
hold off;
h=plot3(x, y, z, varargin{:});
% looks better with large points
set(h, 'MarkerSize', 25);
hold on
% now draw the vertical errorbar for each point
for i=1:length(x)
xV = [x(i); x(i)];
yV = [y(i); y(i)];
zV = [z(i); z(i)];
xMin = x(i) + ex(i);
xMax = x(i) - ex(i);
yMin = y(i) + ey(i);
yMax = y(i) - ey(i);
zMin = z(i) + ez(i);
zMax = z(i) - ez(i);
xB = [xMin, xMax];
yB = [yMin, yMax];
zB = [zMin, zMax];
% draw error bars
h=plot3(xV, yV, zB, '-k');
set(h, 'LineWidth', 2);
h=plot3(xB, yV, zV, '-k');
set(h, 'LineWidth', 2);
h=plot3(xV, yB, zV, '-k');
set(h, 'LineWidth', 2);
end
Example of use:
x = [1, 2];
y = [1, 2];
z = [1, 2];
ex = [0.1, 0.1];
ey = [0.1, 0.5];
ez = [0.1, 0.3];
plot3d_errorbars(x, y, z, ex, ey, ez, 'or')

3D binary matrix/image from a surface mesh in Matlab

How could I create a 3D binary matrix/image from a surface mesh in Matlab?
For instance, when I create ellipsoid using:
[x, y, z] = ellipsoid(0,0,0,5.9,3.25,3.25,30);
X, Y and X are all 2D matrix with size 31 x 31.
Edited based on suggestion of #Magla:
function Create_Mask_Basedon_Ellapsoid3()
close all
SurroundingVol = [50, 50, 20];
%DATA
[MatX,MatY,MatZ] = meshgrid(-24:1:25, -24:1:25, -9:1:10);
[mask1, x, y, z] = DrawEllipsoid([0, -10, 0], [6, 3, 3], MatX,MatY,MatZ);
[mask2, x2, y2, z2] = DrawEllipsoid([15, 14, 6], [6, 3, 3], MatX,MatY,MatZ);
mask = mask1 + mask2;
%Surface PLOT
figure('Color', 'w');
subplot(1,2,1);
%help: Ideally I would like to generate surf plot directly from combined mask= mask1 + mask2;
s = surf(x,y,z); hold on;
s2 = surf(x2,y2,z2); hold off;
title('SURFACE', 'FontSize', 16);
view(-78,22)
subplot(1,2,2);
xslice = median(MatX(:));
yslice = median(MatY(:));
zslice = median(MatZ(:));
%help: Also how do I decide correct "slice" and angles to 3D visualization.
h = slice(MatX, MatY, MatZ, double(mask), xslice, yslice, zslice)
title('BINARY MASK - SLICE VOLUME', 'FontSize', 16);
set(h, 'EdgeColor','none');
view(-78, 22)
%az = 0; el = 90;
%view(az, el);
end
function [mask, Ellipsoid_x, Ellipsoid_y, Ellipsoid_z] = DrawEllipsoid(CenterEllipsoid, SizeEllipsoid, MatX, MatY, MatZ)
[Ellipsoid_x, Ellipsoid_y, Ellipsoid_z] = ellipsoid(CenterEllipsoid(1), CenterEllipsoid(2), CenterEllipsoid(3), SizeEllipsoid(1)/2 , SizeEllipsoid(2)/2 , SizeEllipsoid(3)/2 ,30);
v = [Ellipsoid_x(:), Ellipsoid_y(:), Ellipsoid_z(:)]; %3D points
%v = [x(:), y(:), z(:)]; %3D points
tri = DelaunayTri(v); %triangulation
SI = pointLocation(tri,MatX(:),MatY(:),MatZ(:)); %index of simplex (returns NaN for all points outside the convex hull)
mask = ~isnan(SI); %binary
mask = reshape(mask,size(MatX)); %reshape the mask
end
There you go:
%// Points you want to test. Define as you need. This example uses a grid of 1e6
%// points on a cube of sides [-10,10]:
[x y z] = meshgrid(linspace(-10,10,100));
x = x(:);
y = y(:);
z = z(:); %// linearize
%// Ellipsoid data
center = [0 0 0]; %// center
semiaxes = [5 4 3]; %// semiaxes
%// Actual computation:
inner = (x-center(1)).^2/semiaxes(1).^2 ...
+ (y-center(2)).^2/semiaxes(2).^2 ...
+ (z-center(3)).^2/semiaxes(3).^2 <= 1;
For the n-th point of the grid, whose coordinates are x(n), y(n), z(n), inner(n) is 1 if the point lies in the interior of the ellipsoid and 0 otherwise.
For example: draw the interior points:
plot3(x(inner), y(inner), z(inner), '.' , 'markersize', .5)
Here is a method for creating a binary mask from an ellipsoid. It creates a corresponding volume and sets to NaN the points outside the ellipsoid (ones inside).
It doesn't take into consideration the formula of the ellipsoid, but uses a convex hull. Actually, it works for any volume that can be correctly described by a 3D convex hull. Here, the convexhulln step is bypassed since the ellipsoid is already a convex hull.
All credits go to Converting convex hull to binary mask
The following plot
is produced by
%DATA
[x, y, z] = ellipsoid(0,0,0,5.9,3.25,3.25,30);
%METHOD
v = [x(:), y(:), z(:)]; %3D points
[X,Y,Z] = meshgrid(min(v(:)):0.1:max(v(:))); %volume mesh
tri = DelaunayTri(v); %triangulation
SI = pointLocation(tri,X(:),Y(:),Z(:)); %index of simplex (returns NaN for all points outside the convex hull)
mask = ~isnan(SI); %binary
mask = reshape(mask,size(X)); %reshape the mask
%PLOT
figure('Color', 'w');
subplot(1,2,1);
s = surf(x,y,z);
title('SURFACE', 'FontSize', 16);
view(-78,22)
subplot(1,2,2);
xslice = median(X(:));
yslice = median(Y(:));
zslice = median(Z(:));
h = slice(X, Y, Z, double(mask), xslice, yslice, zslice)
title('BINARY MASK - SLICE VOLUME', 'FontSize', 16);
set(h, 'EdgeColor','none');
view(-78,22)
Several ellipsoids
If you have more than one ellipsoid, one may use this masking method for each of them, and then combine the resulting masks with &.
Choice of slices and angle
"Correct" is a matter of personal choice. You can either
create the unrotated mask and rotate it after (Rotate a 3D array in matlab).
create a mask on already rotated ellipsoid.
create a mask on a slightly rotated ellipsoid (that gives you the choice of a "correct" slicing), and rotate it further to its final position.

Modeling HSV Color Space in MATLAB

I am able to create a 3D cone in MATLAB, but: does anyone know how to paint the cone so that it recreates the HSV color space? I know there is the command:
colormap hsv;
but how do I use it?
Thanks in advance.
I'm guessing you want to create a plot similar to the cone in the following Wikipedia image:
One way to do this is to plot your cone and texture map the surface with an image of the HSV color space. Here's how you could do this:
% First, create a 100-by-100 image to texture the cone with:
H = repmat(linspace(0, 1, 100), 100, 1); % 100-by-100 hues
S = repmat([linspace(0, 1, 50) ... % 100-by-100 saturations
linspace(1, 0, 50)].', 1, 100); %'
V = repmat([ones(1, 50) ... % 100-by-100 values
linspace(1, 0, 50)].', 1, 100); %'
hsvImage = cat(3, H, S, V); % Create an HSV image
C = hsv2rgb(hsvImage); % Convert it to an RGB image
% Next, create the conical surface coordinates:
theta = linspace(0, 2*pi, 100); % Angular points
X = [zeros(1, 100); ... % X coordinates
cos(theta); ...
zeros(1, 100)];
Y = [zeros(1, 100); ... % Y coordinates
sin(theta); ...
zeros(1, 100)];
Z = [2.*ones(2, 100); ... % Z coordinates
zeros(1, 100)];
% Finally, plot the texture-mapped surface:
surf(X, Y, Z, C, 'FaceColor', 'texturemap', 'EdgeColor', 'none');
axis equal
And you should get the following figure: