Matlab - Creating a heatmap to visualize density of 2D point data - matlab

Given a N x N array I want to generate a heat map that visualizes data in such a way:
Given the source image below I created a sparsely populated N X N array that contained the points listed below. 90 points in a 1000x800 array.
When researching online how to generate such a heatmap I stumbled on using colormap only to get disappointing results.
colormap('hot'); % set colormap
imagesc(points); % draw image and scale colormap to values range
colorbar;
I got rather disappointing results.
What other alternatives do I have to make my image above resemble the top one?

There are a few different ways you can convert scattered or sparse matrix data into a heatmap that provides some better visualization of the point density. The examples I'll show here will start with scattered data, so if you already have data in a 2D matrix/histogram you can skip the initial steps...
Histogram:
If your scattered data is rather dense, a simple 2D histogram may be all you need. You can create a grid covering your scattered points (at a resolution of your choosing) and bin your data in the x and y directions using histcounts2:
% Normally distributed sample points:
x = randn(1, 10000);
y = randn(1, 10000);
% Bin the data:
pts = linspace(-4, 4, 101);
N = histcounts2(y(:), x(:), pts, pts);
% Plot scattered data (for comparison):
subplot(1, 2, 1);
scatter(x, y, 'r.');
axis equal;
set(gca, 'XLim', pts([1 end]), 'YLim', pts([1 end]));
% Plot heatmap:
subplot(1, 2, 2);
imagesc(pts, pts, N);
axis equal;
set(gca, 'XLim', pts([1 end]), 'YLim', pts([1 end]), 'YDir', 'normal');
And here's the resulting plot:
Histogram + filtering:
If your scattered data is rather sparse, you can still create a histogram as above, but then filter the result to smooth it out. You could use imdilate if you have the Image Processing Toolbox, or create a filter matrix and use conv2. Here's an example of the latter:
% Normally distributed sample points:
x = randn(1, 100);
y = randn(1, 100);
% Bin the data:
pts = linspace(-3, 3, 101);
N = histcounts2(y(:), x(:), pts, pts);
% Create Gaussian filter matrix:
[xG, yG] = meshgrid(-5:5);
sigma = 2.5;
g = exp(-xG.^2./(2.*sigma.^2)-yG.^2./(2.*sigma.^2));
g = g./sum(g(:));
% Plot scattered data (for comparison):
subplot(1, 2, 1);
scatter(x, y, 'r.');
axis equal;
set(gca, 'XLim', pts([1 end]), 'YLim', pts([1 end]));
% Plot heatmap:
subplot(1, 2, 2);
imagesc(pts, pts, conv2(N, g, 'same'));
axis equal;
set(gca, 'XLim', pts([1 end]), 'YLim', pts([1 end]), 'YDir', 'normal');
And here's the resulting plot:
Distance transform:
Starting with a sparse histogram from above, you could use bwdist from the Image Processing Toolbox to create a distance transform of the data. This would assign each pixel a value based on its distance from the nearest nonzero pixel.
Alternatively, you could avoid computing the 2D histogram by creating a grid covering your scattered points and computing the minimum distance from each grid point to one of your scattered points using pdist2 from the Statistics Toolbox. Here's an example (using the same sample data as above):
% Generate grid and compute minimum distance:
pts = linspace(-3, 3, 101);
[X, Y] = meshgrid(pts);
D = pdist2([x(:) y(:)], [X(:) Y(:)], 'euclidean', 'Smallest', 1);
% Plot scattered data:
subplot(1, 2, 1);
scatter(x, y, 'r.');
axis equal;
set(gca, 'XLim', pts([1 end]), 'YLim', pts([1 end]));
% Plot heatmap:
subplot(1, 2, 2);
imagesc(pts, pts, reshape(D, size(X)));
axis equal;
set(gca, 'XLim', pts([1 end]), 'YLim', pts([1 end]), 'YDir', 'normal');
colormap(flip(parula(), 1));
And here's the resulting plot:

You first need to calculate the density of points on a xy grid. Here you are just plotting an "image version" of any scatter plot in matlab. So, before plotting, you need to process the data and obtaining the density map derived from you points.
You could use for example the ksdensity function, that will estimate the density of points on a grid base. If this function is not available to you, there is a lot of function on the fileexchage that will do the same thing.
% get the x y coordinates of your points
[y,x] = find(points);
P = [x,y];
% estimate and plot the density
[Est,XY] = ksdensity(P);
imagesc(XY(:,1), XY(:,2),Est);
colormap('hot');
colorbar;

Related

Figure created from contour changes to be in raster format when the number of rows and columns larger than some threshold

A 2D data matrix (data, 100 rows by 100 cols) was plotted using 'contour' function in matlab, and the figure was saved as *.emf file. Expectedly when I insert the emf figure into MS word file, the figure is a vector graphic. But when I improve the resolution of the data, i.e. using imresize in matlab to scale the data matrix with factor 2, and did the same thing as before (plot, save as emf and insert it into word), the figure change to raster format. Is there any settings in matlab that can improve the threshold that keeps vector graphics? The code used is as follows:
path = 'C:\Users\Administrator\Desktop\';
data = importdata([path, 'lsa2.txt'], ' ', 6);
cdata = data.data;
% scale = 2;
% cdata = imresize(cdata, scale);
n = 25;
contourf(cdata,n, 'LineStyle', 'none');
colormap(jet);
axis equal;
First of all don't use imresize if you want a vector image. Imresize is by default raster based and can act weird. Also be more specific with what you want please. If you already have a vector file you can just change it to any size.
Also if you have only a limited data set, you can never really get a true higher resolution, you can only interpolate inbetween points. So use interp2 to resize your data matrix.
[sx,sy] = size(cdata);
fact=1/4; %factor to interpolate over so 4 points per 1
[X,Y]=meshgrid(1:sx); %you can only use this because cdate is square, same size for sx and sy
[xq,yq]=meshgrid(1:fact:sx); %create a new mesh with more points
Cnew=interp2(X,Y,cdata,xq,yq,'spline'); %I suggest spline, probably does what you want
This is the entire code to generate the plot, make sure to save it as an .emf, .svg or .eps if you want a vector image
data = importdata('lsa2.txt', ' ', 6);
cdata = data.data;
rws=3
cls=2;
xl=[22 33]; yl=[13 23];
n = 25;
subplot(rws,cls,1)
contourf(cdata,n, 'LineStyle', 'none');
title('Subplot 1: Original no scaling')
colormap(jet);
axis equal;
xlim(xl);
ylim(yl);
scale = 4;
cresi = imresize(cdata, scale);
subplot(rws,cls,2)
contourf(cresi,n, 'LineStyle', 'none');
title('Subplot 2: Imresize function, scale 4')
colormap(jet);
axis equal;
xlim(scale*xl);
ylim(scale*yl);
[sx,sy] = size(cdata);
fact=1/4; %factor to interpolate over so 4 points per 1
[X,Y]=meshgrid(1:sx); %you can only use this because cdate is square, same size for sx and sy
[xq,yq]=meshgrid(1:fact:sx); %create a new mesh with more points
Cnew=interp2(X,Y,cdata,xq,yq);
subplot(rws,cls,3)
contourf(Cnew,n, 'LineStyle', 'none');
title('Subplot 3: Interp2 "linear", scale 4')
colormap(jet);
axis equal;
xlim(xl/fact);
ylim(yl/fact);
[sx,sy] = size(cdata);
fact=1/4; %factor to interpolate over so 4 points per 1
[X,Y]=meshgrid(1:sx);
[xq,yq]=meshgrid(1:fact:sx);
Cnew=interp2(X,Y,cdata,xq,yq,'spline');
subplot(rws,cls,4)
contourf(Cnew,n, 'LineStyle', 'none');
title('Subplot 4: Interp2 "spline", scale 4')
colormap(jet);
axis equal;
xlim(xl/fact);
ylim(yl/fact);
Cnew=interp2(X,Y,cdata,xq,yq,'cubic');
subplot(rws,cls,5)
contourf(Cnew,n, 'LineStyle', 'none');
title('Subplot 5: Interp2 "cubic", scale 4')
colormap(jet);
axis equal;
xlim(xl/fact);
ylim(yl/fact);
Cnew=interp2(X,Y,cdata,xq,yq,'nearest');
subplot(rws,cls,6)
contourf(Cnew,n, 'LineStyle', 'none');
title('Subplot 6: Interp2 "nearest", scale 4')
colormap(jet);
axis equal;
xlim(xl/fact);
ylim(yl/fact);

How to plot a histogram as a scatter plot in matlab?

The y axis should be frequency (which is the histogram part) while the x axis is the xdata used to plot the histogram. Essentially what I need is exactly a histogram but instead of bars, there should be points.
I'd do that using the histcounts command. It's like the histogram command, but instead of plotting the data, it returns the number in each bin and the bin edges. You can then plot that as points using the general plot command.
x = randn(1,1000); %Generate some data to plot
figure(1); clf;
subplot(2,1,1); hold on;
h = histogram(x,'normalization','probability');
title('Plotted as a histogram');
ylabel('Frequency');
subplot(2,1,2); hold on;
[N, edges] = histcounts(x,'normalization','probability');
centers = (edges(1:end-1) + edges(2:end))./2; %histcounts gives the bin edges, but we want to plot the bin centers
plot(centers,N,'ko');
title('Plotted as points');
ylabel('Frequency');

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 create mesh on cylindrical surface after generating random points on cylindrical surface

Now I can generate random points on cylindrical surface.
But I cannot create correctly the mesh on cylindrical surface by using generated points.
When I use this code, the triangle mesh created by delaunay triangulation becomes vertically long.
So I want to solve this problem.
I show my code here.
I don't want to change the parameters except for number of points
clear all
close all
clc
n =1000; % Number of points
% Radius
c = 3.0*10^8; % Speed of lgiht
f = 5.2*10^9; % Frequency
lambda = c/f; % Wavelength
r = 3*lambda; % Radius of circular cylinder
theta = rand(1,n)*(2*pi);
% Equation
x = r.*cos(theta);
y = r.*sin(theta);
z = 2*rand(n,1)-1;
% Plot
figure(1)
scatter3(x(:), y(:), z(:),'.')
% axis equal
xlabel('x-length','Fontname','Times New Roman','fontsize',25)
ylabel('y-length','Fontname','Times New Roman','fontsize',25)
zlabel('z-length','Fontname','Times New Roman','fontsize',25)
title('Randomly distributed point cloud on surface of cylinder','Fontname','Times New Roman','fontsize',25)
% Plot range
xlim([-1 1]) % Plot range of x-axis
ylim([-1 1]) % Plot range of y-axis
zlim([-1 1]) % Plot range of z-axis
set(gca,'Fontname','Times New Roman','fontsize',20)
% Create mesh
figure(2)
dt = delaunayTriangulation(x(:),y(:),z(:));
[tri, Xb] = freeBoundary(dt);
tr = TriRep(tri, Xb);
P = incenters(tr);
fn = faceNormals(tr);
trisurf(tri,Xb(:,1),Xb(:,2),Xb(:,3), ...
'FaceColor', 'g', 'faceAlpha', 0.8);
axis equal;
hold on;
quiver3(P(:,1),P(:,2),P(:,3), ...
fn(:,1),fn(:,2),fn(:,3),0.5, 'color','r');
hold off;
xlabel('x-length','Fontname','Times New Roman','fontsize',25)
ylabel('y-length','Fontname','Times New Roman','fontsize',25)
zlabel('z-length','Fontname','Times New Roman','fontsize',25)
title('Randamly distributed point cloud on surface of cylinder','Fontname','Times New Roman','fontsize',25)
% Plot range
xlim([-1 1]) % Plot range of x-axis
ylim([-1 1]) % Plot range of y-axis
zlim([-1 1]) % Plot range of z-axis
set(gca,'Fontname','Times New Roman','fontsize',20)
Please teach me the cause that the mesh becomes vertically long.

Adding space between cells in Matlab imagesc output

I am creating a 2D plot in Matlab by calling this command: imagesc(vector1, vector2, mat_weights). Then, I run the colorbar command.
I now have a smooth 2D plot, but I want to add space between the cells. Here's how I want it to look:
How do I add such spacing between the cells/boxes?
You can add spaces between patches of color using another function than imagesc. Here, scatter provides a straightforward solution when used with option 'filled' and marker 'square'.
Note that you need to transform your 2-D matrix into a vector, but you don't have to scale your data: scatter takes the min and max values from your data and assign them to the min and max colors of the colormap.
The code
% 2-D in 1-D:
Z = diag(1:10); %example of 2-D matrix to be plotted
C = reshape(Z,1,[]); %1-D transform for vector color
% input definition
sz_matrix = 10;
X = repmat( (1:sz_matrix), 1, sz_matrix);
Y = kron(1:sz_matrix,ones(1,sz_matrix));
S = 1000; % size of marker (handle spaces between patches)
%C = (X.^2 + Y.^2); % second color scheme
%plot
figure('Color', 'w', 'position', [10 10 600 400]);
scatter(X, Y, S, C, 'fill', 's');
set(gca, 'XLim', [0 11], 'YLim', [0 11]);
axis square;
colormap summer
colorbar
will give
EDIT
Here is a piece of code for a rectangular matrix. Please note the inversion of the Y axis direction so that the graphical representation matches disp(Z). To have similar (x,y) proportion in the white area separating color patches, one may try to resize manually the figure.
Z = diag(1:10); %example of 2-D matrix to be plotted
Z = Z(1:end-2,:); %trim for rectangular
% input definition
X = repmat(1:size(Z,2), 1, size(Z,1));
Y = kron(1:size(Z,1),ones(1,size(Z,2)));
C = reshape(Z',1,[]); %1-D transform for vector color
S = 1000; % size of marker (handle spaces between patches)
%plot
figure('Color', 'w');
scatter(X, Y, S, C, 'fill', 's');
set(gca, 'XLim', [0 size(Z,2)+1], 'YLim', [0 size(Z,1)+1]);
colormap jet
colorbar
set(gca, 'YDir','reverse');
The ouput: