How to properly combine heat map over an image using coordinates from an excel file

10 views (last 30 days)
Hello!
I am trying to create a heatmap over an image using x,y coordinates. I took a square-sized screenshot of the image (729 x 728) and assigned it to the variable 'img' in matlab. I also have x,y coordinates in an excel file representing where the person was looking at in each every frame. However, when I run the script, the heatmap do not represent the same points (from my data) in the image (see below image for reference). Can anyone tell me how I can properly add a heatmap over an image that represent correct points?
The codes I used are shown below:
function hAxes = dscatter_JS(X,Y, varargin)
% DSCATTER creates a scatter plot coloured by density.
%
% DSCATTER(X,Y) creates a scatterplot of X and Y at the locations
% specified by the vectors X and Y (which must be the same size), colored
% by the density of the points.
%
% DSCATTER(...,'MARKER',M) allows you to set the marker for the
% scatter plot. Default is 's', square.
%
% DSCATTER(...,'MSIZE',MS) allows you to set the marker size for the
% scatter plot. Default is 10.
%
% DSCATTER(...,'FILLED',false) sets the markers in the scatter plot to be
% outline. The default is to use filled markers.
%
% DSCATTER(...,'PLOTTYPE',TYPE) allows you to create other ways of
% plotting the scatter data. Options are "surf','mesh' and 'contour'.
% These create surf, mesh and contour plots colored by density of the
% scatter data.
%
% DSCATTER(...,'BINS',[NX,NY]) allows you to set the number of bins used
% for the 2D histogram used to estimate the density. The default is to
% use the number of unique values in X and Y up to a maximum of 200.
%
% DSCATTER(...,'SMOOTHING',LAMBDA) allows you to set the smoothing factor
% used by the density estimator. The default value is 20 which roughly
% means that the smoothing is over 20 bins around a given point.
%
% DSCATTER(...,'LOGY',true) uses a log scale for the yaxis.
%
% Examples:
%
% [data, params] = fcsread('SampleFACS');
% dscatter(data(:,1),10.^(data(:,2)/256),'log',1)
% % Add contours
% hold on
% dscatter(data(:,1),10.^(data(:,2)/256),'log',1,'plottype','contour')
% hold off
% xlabel(params(1).LongName); ylabel(params(2).LongName);
%
% See also FCSREAD, SCATTER.
% Copyright 2003-2004 The MathWorks, Inc.
% $Revision: $ $Date: $
% Reference:
% Paul H. C. Eilers and Jelle J. Goeman
% Enhancing scatterplots with smoothed densities
% Bioinformatics, Mar 2004; 20: 623 - 628.
lambda = [];
nbins = [];
plottype = 'scatter';
contourFlag = false;
msize = 100; % increased marker from 10 to 100
marker = 'o'; % changed from s (square) to o (circle)
logy = false;
filled = true;
if nargin > 2
if rem(nargin,2) == 1
error('Bioinfo:IncorrectNumberOfArguments',...
'Incorrect number of arguments to %s.',mfilename);
end
okargs = {'smoothing','bins','plottype','logy','marker','msize','filled'};
for j=1:2:nargin-2
pname = varargin{j};
pval = varargin{j+1};
k = strmatch(lower(pname), okargs); %#ok
if isempty(k)
error('Bioinfo:UnknownParameterName',...
'Unknown parameter name: %s.',pname);
elseif length(k)>1
error('Bioinfo:AmbiguousParameterName',...
'Ambiguous parameter name: %s.',pname);
else
switch(k)
case 1 % smoothing factor
if isnumeric(pval)
lambda = pval;
else
error('Bioinfo:InvalidScoringMatrix','Invalid smoothing parameter.');
end
case 2
if isscalar(pval)
nbins = [ pval pval];
else
nbins = pval;
end
case 3
plottype = pval;
case 4
logy = pval;
Y = log10(Y);
case 5
contourFlag = pval;
case 6
marker = pval;
case 7
msize = pval;
case 8
filled = pval;
end
end
end
end
minx = min(X,[],1);
maxx = max(X,[],1);
miny = min(Y,[],1);
maxy = max(Y,[],1);
if isempty(nbins)
nbins = [min(numel(unique(X)),200) ,min(numel(unique(Y)),200) ];
end
if isempty(lambda)
lambda = 20;
end
edges1 = linspace(minx, maxx, nbins(1)+1);
ctrs1 = edges1(1:end-1) + .5*diff(edges1);
edges1 = [-Inf edges1(2:end-1) Inf];
edges2 = linspace(miny, maxy, nbins(2)+1);
ctrs2 = edges2(1:end-1) + .5*diff(edges2);
edges2 = [-Inf edges2(2:end-1) Inf];
[n,p] = size(X);
bin = zeros(n,2);
% Reverse the columns to put the first column of X along the horizontal
% axis, the second along the vertical.
[dum,bin(:,2)] = histc(X,edges1);
[dum,bin(:,1)] = histc(Y,edges2);
H = accumarray(bin,1,nbins([2 1])) ./ n;
G = smooth1D(H,nbins(2)/lambda);
F = smooth1D(G',nbins(1)/lambda)';
% = filter2D(H,lambda);
if logy
ctrs2 = 10.^ctrs2;
Y = 10.^Y;
end
okTypes = {'surf','mesh','contour','image','scatter'};
k = strmatch(lower(plottype), okTypes); %#ok
if isempty(k)
error('dscatter:UnknownPlotType',...
'Unknown plot type: %s.',plottype);
elseif length(k)>1
error('dscatter:AmbiguousPlotType',...
'Ambiguous plot type: %s.',plottype);
else
switch(k)
case 1 %'surf'
h = surf(ctrs1,ctrs2,F,'edgealpha',0);
case 2 % 'mesh'
h = mesh(ctrs1,ctrs2,F);
case 3 %'contour'
[dummy, h] =contour(ctrs1,ctrs2,F);
case 4 %'image'
nc = 256;
F = F./max(F(:));
colormap(repmat(linspace(1,0,nc)',1,3));
h =image(ctrs1,ctrs2,floor(nc.*F) + 1);
case 5 %'scatter'
F = F./max(F(:));
ind = sub2ind(size(F),bin(:,1),bin(:,2));
col = F(ind);
if filled
h = scatter(X,Y,msize,col,marker,'filled');
else
h = scatter(X,Y,msize,col,marker);
end
end
end
if logy
set(gca,'yscale','log');
end
if nargout > 0
hAxes = get(h,'parent');
end
%%%% This method is quicker for symmetric data.
% function Z = filter2D(Y,bw)
% z = -1:(1/bw):1;
% k = .75 * (1 - z.^2);
% k = k ./ sum(k);
% Z = filter2(k'*k,Y);
function Z = smooth1D(Y,lambda)
[m,n] = size(Y);
E = eye(m);
D1 = diff(E,1);
D2 = diff(D1,1);
P = lambda.^2 .* D2'*D2 + 2.*lambda .* D1'*D1;
Z = (E + P) \ Y;
And..
GazeMatrix = readmatrix('eyedata_P1_S1_CLEANED.xlsx');
img = imread('1x1.PNG');
img = flip(img,2);
img = imrotate(img,180);
x_data = GazeMatrix(:,33);
y_data = GazeMatrix(:,34);
image('CData',img,'XData',[-1000 1000],'YData',[-1000 1000])
hold on
dscatter_JS(x_data,y_data);
hold off
colorbar();
axis off

Answers (1)

Abhishek
Abhishek on 30 Jun 2025
I understand you are aiming to overlay a heatmap of gaze coordinates over an image. When dealing with heatmaps on images, the most important thing is to have both the image and the gaze data share the same coordinate system, particularly if the numerical range of the gaze data is less than the pixel dimensions of the image. In case of improper alignment, the plotted gaze points will be off or misrepresented.
From your data in ROGRMSDData.xlsx, the X and Y values are in a custom range (X: approximately 0 to 2, Y: approximately 38 to 41), whereas your image size is 729 × 728 pixels. To overlay these points meaningfully, the coordinate data needs to be rescaled to match the pixel dimensions of the image.
To rescale, you can use the below code snipped:
% Rescale the coordinates to match image dimensions
x_data = rescale(x_raw, 1, size(img,2)); % Map X to [1, image width]
y_data = rescale(y_raw, 1, size(img,1)); % Map Y to [1, image height]
% Flip Y if needed to align with image top-left origin
y_data = size(img,1) - y_data;
This method ensures your heatmap accurately reflects the gaze points over the image. The use of rescale allows to translate coordinate values from their original range into the scale of the image pixel space.
Flipping the y_data aligns it with the image coordinate system of MATLAB, which begins at the top-left corner.
Furthermore, the usage of scatter function is not correct inside the ‘dscatter_JS’. Below is the correct implementation:
if filled
h = scatter(X, Y, msize, col, 'Marker', marker, 'MarkerFaceColor', 'flat');
else
h = scatter(X, Y, msize, col, 'filled');
end
I executed the code on MATLAB R2024b. Below is the resulting figure, after making the above changes in the code:
You can find additional information in the official documentation of MATLAB:
Thanks.

Categories

Find more on Data Distribution Plots in Help Center and File Exchange

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!