Jebathon
Jebathon

Reputation: 4561

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

Given a N x N array I want to generate a heat map that visualizes data in such a way:

enter image description here

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.

enter image description here

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.

enter image description here

What other alternatives do I have to make my image above resemble the top one?

Upvotes: 8

Views: 21177

Answers (2)

gnovice
gnovice

Reputation: 125864

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:

enter image description here

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:

enter image description here

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:

enter image description here

Upvotes: 10

beesleep
beesleep

Reputation: 1362

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;

Upvotes: 1

Related Questions