function varargout = valcolor(varargin)
%VALCOLOR - Change colormap entry for specified value to a chosen color
% valcolor(VAL,CLR)
% Updates current figure's colormap so values VAL get color CLR.
% This includes values mapped to the same color as VAL.
% CLR is either a vector between 0-1, e.g. [.4 .2 .9] or
% a standard MATLAB color string shorthand, e.g. 'r'.
% Based on Clim and CDataMapping value of current axes and image.
%
% valcolor(H,VAL,CLR) uses figure handle H instead of current.
%
% cmap = valcolor(...)
% Returns modified cmap based on figure's colormap.
% Does not apply it to figure. Apply with colormap().
%
% cmap = valcolor(VAL,CLR,oldmap,clims)
% Outputs colored cmap based on input map and clims.
% May supply data instead of clims, gets [min max] to create clims.
% If clims = false, assumes indexed colormap.
%
%
% --- Notes:
% Does nothing with RGB images. Made for real 2D intensity matrices, but
% also handles indexed images. See the CDataMapping image property.
%
% Other values will be affected if they are mapped to the same color as
% VAL. To affect *only* VAL there are some options (not included):
% 1 Convert to indexed type such that VAL has a unique index.
% 2 Manipulate the affected data values near VAL.
% 3 Increase the colormap size. Feasibility depends on data.
% 4 Change VAL value to e.g. NaN/inf, then change CLims so other data
% uses 99% of the colormap. Make the last color your custom color.
%
% Currently only takes 1 value-color pair for input. For mapping a range
% of values to specific colors, see customcolormap (FEX#36501).
%
% ~~~~Jurgen
if nargout
out = true;
else
out = false;
end
% --- Parse VAL, H, CLR, oldmap, clims, data
[VAL H CLR clims oldmap] = parse_args(varargin);
% --- convert shorthand to [R G B]
if ischar(CLR)
CLR = convert_to_rgb(CLR);
else
assert(iscolor(CLR),...
'input value CLR isn''t a color!')
end
% if indexed:
if clims == false
cmap = oldmap;
cmap(VAL,:) = CLR;
finish
return
end
% --- find entry to make cmap
idx = findclr(VAL,oldmap,clims);
cmap = oldmap;
cmap(idx,:) = CLR;
finish
function finish
if out
varargout{1} = cmap;
else
colormap(get(H,'CurrentAxes'),cmap)
end
end %Nested
end
function idx = findclr(VAL,oldmap,clims)
% Assumes CLim range gets linearly quantized when mapping
a = linspace(clims(1),clims(2),size(oldmap,1)+1);
if any(a == VAL)
idx = find(a == VAL);
else
idx = sum(a<VAL);
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 c = iscolor(CLR)
if all(CLR<=1) && all(CLR>=0) && (length(CLR)==3) && (numel(CLR)==3)
c = true;
else
c = false;
end
end
function [VAL H CLR clims oldmap] = parse_args(args)
nargin = length(args);
if nargin == 3
H = args{1};
VAL = args{2};
CLR = args{3};
assert(ishandle(H) && (H ~= 0) && strcmp(get(H,'Type'),'figure')...
,'Wrong handle for H or wrong syntax');
elseif nargin == 4 %custom input
VAL = args{1};
CLR = args{2};
H = [];
oldmap = args{3};
clims = args{4};
if clims ~= false %intensity
clims = [min(clims(:)) max(clims(:))];
check_clims(VAL,clims);
else %indexed
VAL = min(size(oldmap,1),VAL);
VAL = max(1,VAL);
VAL = round(VAL);
end
return
else
H = gcf;
VAL = args{1};
CLR = args{2};
end
% For figure based mapping, get oldmap and clims.
% Base mapping on current axes(clim) and image(cdatamapping)
[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');
if ~isempty(findobj(ax,'CDataMapping','direct','-depth',1))
clims = false; %identifier for indexed types
VAL = min(size(oldmap,1),VAL);
VAL = max(1,VAL);
VAL = round(VAL);
warning('Image is indexed');
else
check_clims(VAL,clims);
end
end
function check_clims(VAL,clims)
%Final clim checks
assert(clims(1)~=clims(2),'Wrong clim values, can not be equal');
try
assert(clims(1) <= (VAL+eps) && clims(2) >= (VAL-eps))
catch
display(clims);
disp(['Failing boundary (zero fails): ' num2str([(clims(1) <= eps(1)) (clims(2) >= eps(1))])]);
disp(' ');
error('parseargs:limitcheck',...
[' CLim Check: No explicit VAL value in colormap range!\n'...
' i.e. values are / were being clipped--if they exist at all.\n'...
' Change CLim property vector to contain VAL (see caxis)']);
end
end