function imgRGB = hotplot(bckgnd, forgnd, position, figNo)
% ImgOut = hotplot(BACKGROUND, FOREGROUND, POSITION, figNo)
%
% show two 2D variables superimposed; the first one (BACKGROUND)
% is represented as a gray level image, while the 2nd one (FOREGROUND)
% as a hue variation of the background, using the same "heat" convention
% as pcolor (blue-low, red-high)
%
% FOREGROUND can include only the interesting regions (i.e. could contain
% holes) or can be of the same size as BACKGROUND
%
% BACKGROUND - MxN variable shown as gray-level, on top of which the
% 2nd variable (FOREGROUND) will be shown
% FOREGROUND - 2nd variable to plot, MxN matrix or P-by-1 (point list)
% POSITION - position of FOREGROUND relative to BACKGROUND
% MxN boolean or P-long array of uint8 (uint16, etc)
%
% FOREGROUND should either be
% - of the same size with BACKGROUND (MxN), in which case POSITION
% will be interpreted as an MxN boolean mask of the points to show
% - or a P-length array that indexes the FOREGND values to their
% position on the BACKGND image, in which case POSITION(i,1:2) will
% be interpreted as the X,Y coordinates of the i-th point;
%
% 14.09.2009 - new, v. 0.1 by tudima at yahoo dot com
% 15.09.2009 - v.0.2
% more flexible call (it now accepts a full FOREGND),
% improved input handling
[nR, nC] = size(bckgnd);
% --- figure out input style ---
if islogical(position) || isempty(position)
ValEntryStyle = 'FullMask';
if ~all(size(forgnd)==size(bckgnd))
error(' hotplot > BACKGROUND and FOREGROUND should have the same size');
end
if isempty(position)
position = true(nR, nC);
elseif ~all(size(position)==size(bckgnd))
error(' hotplot > POSITION should be of the same size with BACKGROUND and FOREGROUND');
end
else % test if PointsList
% orient forgnd and position as nP-by-2
[nPr, nPc] = size(position);
if nPc > nPr, position = position'; end
[nPr, nPc] = size(forgnd);
if nPc > nPr, forgnd = forgnd'; end
if any(size(forgnd)==size(position))
ValEntryStyle = 'PointsList';
else
error(' hotplot > dimensions of values and XY coordinates should agree; type help hotplot')
end
end
% --- alloc output image ---
imgHSV = rgb2hsv(repmat(bckgnd, [1 1 3]));
% --- find the foreground bounds ---
% the colour convention of the hotmap is low to high > blue to red
% in order to reverse
switch ValEntryStyle
case 'PointsList' % forgnd is 1 x nP of Val
H_min = min(forgnd);
H_max = max(forgnd);
% --- actual scaling --- % hi2lo : red2blu
H_scale = (-forgnd +H_max)/(H_max -H_min) *2/3;
% replace 1st term to (forgnd -H_min) for reverse order, i.e. hi2lo : blu2red
% --- alter the wanted points' hue accordingly, adjust saturation ---
nP = size(position,1);
for i = 1:nP
imgHSV(position(i, 2), position(i, 1),1) = H_scale(i);
imgHSV(position(i, 2), position(i, 1),2) = 1;
end
case 'FullMask' % forgnd is nR x nC of Val
H_min = min(forgnd(position));
H_max = max(forgnd(position));
% --- actual scaling --- % hi2lo : red2blu
H_scale = (-forgnd +H_max)/(H_max -H_min) *2/3;
% replace 1st term to (forgnd -H_min) for reverse order, i.e. hi2lo : blu2red
% --- alter the wanted points' hue accordingly, adjust saturation ---
Hue = zeros(nR, nC);
Sat = zeros(nR, nC);
Hue(position) = H_scale(position);
Sat(position) = 1;
imgHSV(:,:,1) = Hue;
imgHSV(:,:,2) = Sat;
end
% --- revert image to RGB ---
imgRGB = hsv2rgb(imgHSV);
if nargin > 3 % --- plot ---
h2 = figure(figNo); % figNo could later be a figure handle... ?
imshow(imgRGB), colorbar
kidz = get(h2, 'children');
% > get the default # of ticks, overwrite strings with proper values
YTickLabel = get(kidz(1), 'YTickLabel');
nTck = size(YTickLabel, 1);
% > re-calculate Ticks on the HUE scale
expD = ceil(log10(double(H_max-H_min)));
ScaleFact = 10^(expD-2); %
% > crude hue scaling, round to 2 ok-looking digits, later better :-)
YTick = linspace(ceil(H_min/ScaleFact), floor(H_max/ScaleFact), nTck)*ScaleFact;
YTickLabel = num2str(YTick(:));
set(kidz(1), 'YTickLabel', YTickLabel)
title('hotplot > variable shown as hue on B/W image background')
end