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

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;

Related

Interpolating Shading in Circular Colormap

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));

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:

how to change color of sphere in matlab

how to change color of sphere in matlab my code for plotting sphere is
figure;
plotOnSphere(Xem,Yem,Zem);
%// Plot a unit sphere for reference
sphere()
s = findall(gca, 'type', 'surf');
set(s, 'FaceColor', 'k', 'FaceAlpha', 0.01, 'EdgeAlpha', 0.1)
my question is that i want to get the plot of the sphere with only lines and not these colors attached to the spherical sections .
can someone please help me.
function plotOnSphere(x,y,z,varargin)
%// Vectors representing each point
xyz = [x(:), y(:), z(:)].'; %'
%// One vector of the "first" points and one of the "next" points
v1 = xyz(:, 1:end-1);
v2 = xyz(:, 2:end);
%// Cross product between the vectors of one point and the next
cv1v2 = cross(v1, v2);
%// Compute unit vector in the plane defined by v1 and v2
v3 = normc(cross(cv1v2, v1));
%// Figure out the range of the inner angle between v1 and v2
nc = sqrt(sum(cv1v2.^2, 1));
t = atan2(nc, dot(v1, v2, 1));
%// Number of points to sample between any two points on the sphere
nPoints = 100;
%// Compute the interpolant
V = zeros([nPoints, fliplr(size(v1))]);
for k = 1:numel(t)
T = linspace(0, t(k), 100);
V(:,k,:) = (v1(:,k) * cos(T) + v3(:,k) * sin(T)).'; %'
end
%// Break the result out into x,y,z parts
xx = V(:,:,1);
yy = V(:,:,2);
zz = V(:,:,3);
%// Plot the lines
h = plot3(xx(:), yy(:), zz(:), varargin{:});
hold on
%// Plot the original data points
plot3(x,y,z, 'o', ...
'Color', get(h, 'Color'), ...
'Parent', get(h, 'Parent'), varargin{:});
end

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')

MATLAB Simple Point Plots

In a while loop, I need to plot the positions (x,y) of two entities. That is, all I need to do is generate a plot with two points on it. I need to scale the plot to a specific maximum x and y value. An additional requirement is the fact that one of the points needs to have three concentric rings placed around it, each with a given radius. Additionally, this all is to happen in a loop, thus I'm hoping that only a single plot window opens and that I don't get a whole slew of windows opening (one for each loop iteration).
Basically here's the pseudo-code I'm trying (and failing!) to implement:
-> Open new plot window, with a given x and y axis
while (running) {
-> Clear the plot, so figure is nice and clean
-> Plot the two points
-> Plot the three circles around point A
}
I found several items in MATLAB's documentation, but no single plotting functions seems to do what I want, or there are instances where I inadvertently create multiple plots with only some of the data (i.e., one plot has the points and another has the circles).
here's a sample code you can use in your while loop
x0=1; y0=4;
x1=2; y1=3; % the x-y points
r=[1 2 3]; % 3 radii of concentrating rings
ang=0:0.01:2*pi;
xc=cos(ang)'*r;
yc=sin(ang)'*r;
plot(x0,y0,'.',x1,y1,'.'); % plot the point A
hold on
plot(x1+xc,y1+yc); % plot the 3 circles
% set the limits of the plots (though Matlab does it for you already)
xlim([min([x0 x1])-max(r) max([x0 x1])+max(r)]);
ylim([min([y0 y1])-max(r) max([y0 y1])+max(r)]);
hold off
you can make this work in a loop quite easily, read matlab's documentation on how to do that.
Try something like this:
r = [0.25 0.125 0.0625];
d = (1:360) / 180 * pi;
xy_circle = [cos(d)' sin(d)'];
xy_circle_1 = r(1) * xy_circle;
xy_circle_2 = r(2) * xy_circle;
xy_circle_3 = r(3) * xy_circle;
h_plot = plot(0, 0, '.k');
hold on
h_circle_1 = plot(xy_circle_1(:, 1), xy_circle_1(:, 2), '-b');
h_circle_2 = plot(xy_circle_2(:, 1), xy_circle_2(:, 2), '-r');
h_circle_3 = plot(xy_circle_3(:, 1), xy_circle_3(:, 2), '-g');
axis equal
for hh = 1:100
xy = rand(2, 2) / 4 + 0.375;
xlim = [0 1];
ylim = [0 1];
set(h_plot, 'XData', xy(:, 1));
set(h_plot, 'YData', xy(:, 2));
set(gca, 'XLim', xlim)
set(gca, 'YLim', ylim)
set(h_circle_1, 'XData', xy_circle_1(:, 1) + xy(1, 1));
set(h_circle_1, 'YData', xy_circle_1(:, 2) + xy(1, 2));
set(h_circle_2, 'XData', xy_circle_2(:, 1) + xy(1, 1));
set(h_circle_2, 'YData', xy_circle_2(:, 2) + xy(1, 2));
set(h_circle_3, 'XData', xy_circle_3(:, 1) + xy(1, 1));
set(h_circle_3, 'YData', xy_circle_3(:, 2) + xy(1, 2));
pause(1)
end
You can change the parameters as you wish.
You can use the following functions
figure; %creates a figure
hold on; %overlays points and circles
clf; %clear the figure
and use two types of markers (. and o) of various sizes for the points and circles
plot(x,y, 'b.', 'MarkerSize', 4);
plot(x,y, 'ro', 'MarkerSize', 10);
plot(x,y, 'go', 'MarkerSize', 14);
plot(x,y, 'bo', 'MarkerSize', 18);