function varargout = zerocolor(varargin)
%ZEROCOLOR - Set colormap entry for zero value to specified RGB color
% zerocolor(CLR)
% updates current figure's colormap so that zeros get color CLR
% CLR is a vector between 0-1, e.g. [.4 .2 .9] or a standard MATLAB color
% string shorthand, e.g. 'r'.
%
% zerocolor(H,CLR) uses figure handle H instead of current.
%
% cmap = zerocolor(...)
% Outputs modified cmap based on figure's colormap.
% Does not apply it to figure. Apply with colormap().
%
% cmap = zerocolor(CLR,oldmap,clims)
% Outputs modified cmap based on oldmap and context data.
% may supply data instead of clims, gets [min max] of data to create clims
%
% --- Examples:
%
% CLR = [0 1 0];
%
% % Create Intensity images:
% DATA1 = randi(10,100)-5; %contains zeros
% DATA2 = DATA1;
% DATA2(DATA2 > 0) = 0; %zero is upper bound
% DATA3 = DATA1;
% DATA3(DATA3 < 0) = 0; %zero is lower bound
% DATA4 = rand(100); %has no zeros--normally speaking
% DATA5 = imread('peppers.png');
%
% % Plot:
% h1 = figure; h11=imagesc(DATA1);colormap(hot(10));colorbar; %Clim contains zero
% h2 = figure; h22=imagesc(DATA2);colormap(hot(10));colorbar; %Clim contains zero
% h3 = figure; h33=imagesc(DATA3);colormap(hot(10));colorbar; %Clim contains zero
% h4 = figure; h44=imagesc(DATA4);colormap(hot(10));colorbar; %Contains no explicit zero mapping
% h5 = figure; h55=imshow(DATA5); %Not an intensity image
%
% zerocolor(h1,CLR);
%
% zerocolor(h2,CLR);
%
% zerocolor(h3,CLR);
%
% zerocolor(h4,CLR);
% set(get(h4,'CurrentAxes'),'CLim',[0 1]); %Now h4 does work
% zerocolor(h4,CLR);
%
% zerocolor(h5,CLR); %Doesn't work with RGB
%
% cmap = zerocolor([0 0 0],jet(10),[-2 1]); %new jet map with a black entry
%
% --- Notes:
% Does nothing with RGB images, only real 2D intensity matrices.
% Does not do anything if zero value lies outside the mapping range.
%
% Note this is not the same as changing the first/last color of the map,
% though that may happen if zero is the first or last indexed value.
% Probably most useful when data has a range: negative<->positive.
% Not hard to adjust for an arbitrary value other than zero.
%
% Inspired by rgbslide from the MATLAB FEX
%
% ~~~~Jurgen
assert(nargin < 4,'Too many input arguments');
if nargout
out = true;
else
out = false;
end
% --- Parse H, CLR, oldmap, clims, data
[H CLR clims oldmap] = parse_args(varargin);
% --- convert shorthand to [R G B]
if ischar(CLR)
CLR = convert_to_rgb(CLR);
else
assert(numel(CLR)==3 && length(CLR) ==3,...
'CLR isn''t a color!')
end
% --- common cases: start/end at zero
if clims(1) == 0
cmap = oldmap;
cmap(1,:) = CLR;
finish
return
elseif clims(2) == 0
cmap = oldmap;
cmap(end,:) = CLR;
finish
return
end
% --- generate new map
zeroidx = findzeroclr(oldmap,clims);
cmap = oldmap;
cmap(zeroidx,:) = CLR;
finish
function finish
if out
varargout{1} = cmap;
else
colormap(get(H,'CurrentAxes'),cmap)
end
end %Nested
end
function zeroidx = findzeroclr(oldmap,clims)
% Assumes CLim range gets linearly quantized when mapping
% Not valid if indexed, only for intensity images.
a = linspace(clims(1),clims(2),size(oldmap,1)+1);
if any(a == 0)
zeroidx = find(a == 0);
else
zeroidx = sum(a<0);
end
end
function CLR = convert_to_rgb(CLR)
switch CLR
case 'r'
CLR = [1 0 0];
case 'c'
CLR = [0 1 1];
case 'y'
CLR = [1 1 0];
case 'm'
CLR = [1 0 1];
case 'g'
CLR = [0 1 0];
case 'b'
CLR = [0 0 1];
case 'k'
CLR = [0 0 0];
case 'w'
CLR = [1 1 1];
otherwise
error(['Unknown color shorthand: ' CLR]);
end
end
function [H CLR clims oldmap] = parse_args(args)
nargin = length(args);
if nargin == 2
Q = args{1};
if numel(Q) == 1
assert(ishandle(Q) && (Q ~= 0) && strcmp(get(Q,'Type'),'figure')...
,'Wrong handle for H');
H = Q;
CLR = args{2};
else
H = gcf;
CLR = Q;
end
clear Q;
elseif nargin == 3
CLR = args{1};
else
H = gcf;
CLR = args{1};
end
if nargin ~= 3
[dum dum dum flag] = getimage(H);
assert(flag ~= 4,'Can not apply colormaps to RGB images');
oldmap = get(H,'Colormap');
ax = get(H,'CurrentAxes');
clims = get(ax,'CLim');
assert(isempty(findobj(ax,'CDataMapping','direct','-depth',1)),...
'Image is indexed, change CDataMapping to ''scaled''');
else
H = [];
oldmap = args{2};
cdata = args{3};
clims = [min(cdata(:)) max(cdata(:))];
end
try
assert(clims(1) <= eps && clims(2) >= -eps)
catch
display(clims);
disp(['Failing boundary: ' num2str([(clims(1) <= eps(2)) (clims(2) >= eps(2))])]);
disp(' ');
error('parseargs:limitcheck',...
[' CLim Check: No explicit zero value in colormap range!\n'...
' i.e. zeros are / were being clipped--if they exist at all.\n'...
' Change CLim property / vector to contain zero']);
end
end