end of lines
parent
06176caf64
commit
ba7802204f
File diff suppressed because it is too large
Load Diff
|
@ -1,176 +1,176 @@
|
|||
function colors = distinguishable_colors(n_colors,bg,func)
|
||||
% DISTINGUISHABLE_COLORS: pick colors that are maximally perceptually distinct
|
||||
%
|
||||
% When plotting a set of lines, you may want to distinguish them by color.
|
||||
% By default, Matlab chooses a small set of colors and cycles among them,
|
||||
% and so if you have more than a few lines there will be confusion about
|
||||
% which line is which. To fix this problem, one would want to be able to
|
||||
% pick a much larger set of distinct colors, where the number of colors
|
||||
% equals or exceeds the number of lines you want to plot. Because our
|
||||
% ability to distinguish among colors has limits, one should choose these
|
||||
% colors to be "maximally perceptually distinguishable."
|
||||
%
|
||||
% This function generates a set of colors which are distinguishable
|
||||
% by reference to the "Lab" color space, which more closely matches
|
||||
% human color perception than RGB. Given an initial large list of possible
|
||||
% colors, it iteratively chooses the entry in the list that is farthest (in
|
||||
% Lab space) from all previously-chosen entries. While this "greedy"
|
||||
% algorithm does not yield a global maximum, it is simple and efficient.
|
||||
% Moreover, the sequence of colors is consistent no matter how many you
|
||||
% request, which facilitates the users' ability to learn the color order
|
||||
% and avoids major changes in the appearance of plots when adding or
|
||||
% removing lines.
|
||||
%
|
||||
% Syntax:
|
||||
% colors = distinguishable_colors(n_colors)
|
||||
% Specify the number of colors you want as a scalar, n_colors. This will
|
||||
% generate an n_colors-by-3 matrix, each row representing an RGB
|
||||
% color triple. If you don't precisely know how many you will need in
|
||||
% advance, there is no harm (other than execution time) in specifying
|
||||
% slightly more than you think you will need.
|
||||
%
|
||||
% colors = distinguishable_colors(n_colors,bg)
|
||||
% This syntax allows you to specify the background color, to make sure that
|
||||
% your colors are also distinguishable from the background. Default value
|
||||
% is white. bg may be specified as an RGB triple or as one of the standard
|
||||
% "ColorSpec" strings. You can even specify multiple colors:
|
||||
% bg = {'w','k'}
|
||||
% or
|
||||
% bg = [1 1 1; 0 0 0]
|
||||
% will only produce colors that are distinguishable from both white and
|
||||
% black.
|
||||
%
|
||||
% colors = distinguishable_colors(n_colors,bg,rgb2labfunc)
|
||||
% By default, distinguishable_colors uses the image processing toolbox's
|
||||
% color conversion functions makecform and applycform. Alternatively, you
|
||||
% can supply your own color conversion function.
|
||||
%
|
||||
% Example:
|
||||
% c = distinguishable_colors(25);
|
||||
% figure
|
||||
% image(reshape(c,[1 size(c)]))
|
||||
%
|
||||
% Example using the file exchange's 'colorspace':
|
||||
% func = @(x) colorspace('RGB->Lab',x);
|
||||
% c = distinguishable_colors(25,'w',func);
|
||||
|
||||
% Copyright 2010-2011 by Timothy E. Holy
|
||||
% All rights reserved.
|
||||
%
|
||||
% Redistribution and use in source and binary forms, with or without
|
||||
% modification, are permitted provided that the following conditions are
|
||||
% met:
|
||||
%
|
||||
% * Redistributions of source code must retain the above copyright
|
||||
% notice, this list of conditions and the following disclaimer.
|
||||
% * Redistributions in binary form must reproduce the above copyright
|
||||
% notice, this list of conditions and the following disclaimer in
|
||||
% the documentation and/or other materials provided with the distribution
|
||||
%
|
||||
% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
% POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
|
||||
% Parse the inputs
|
||||
if (nargin < 2)
|
||||
bg = [1 1 1]; % default white background
|
||||
else
|
||||
if iscell(bg)
|
||||
% User specified a list of colors as a cell aray
|
||||
bgc = bg;
|
||||
for i = 1:length(bgc)
|
||||
bgc{i} = parsecolor(bgc{i});
|
||||
end
|
||||
bg = cat(1,bgc{:});
|
||||
else
|
||||
% User specified a numeric array of colors (n-by-3)
|
||||
bg = parsecolor(bg);
|
||||
end
|
||||
end
|
||||
|
||||
% Generate a sizable number of RGB triples. This represents our space of
|
||||
% possible choices. By starting in RGB space, we ensure that all of the
|
||||
% colors can be generated by the monitor.
|
||||
n_grid = 30; % number of grid divisions along each axis in RGB space
|
||||
x = linspace(0,1,n_grid);
|
||||
[R,G,B] = ndgrid(x,x,x);
|
||||
rgb = [R(:) G(:) B(:)];
|
||||
if (n_colors > size(rgb,1)/3)
|
||||
error('You can''t readily distinguish that many colors');
|
||||
end
|
||||
|
||||
% Convert to Lab color space, which more closely represents human
|
||||
% perception
|
||||
if (nargin > 2)
|
||||
lab = func(rgb);
|
||||
bglab = func(bg);
|
||||
else
|
||||
C = makecform('srgb2lab');
|
||||
lab = applycform(rgb,C);
|
||||
bglab = applycform(bg,C);
|
||||
end
|
||||
|
||||
% If the user specified multiple background colors, compute distances
|
||||
% from the candidate colors to the background colors
|
||||
mindist2 = inf(size(rgb,1),1);
|
||||
for i = 1:size(bglab,1)-1
|
||||
dX = bsxfun(@minus,lab,bglab(i,:)); % displacement all colors from bg
|
||||
dist2 = sum(dX.^2,2); % square distance
|
||||
mindist2 = min(dist2,mindist2); % dist2 to closest previously-chosen color
|
||||
end
|
||||
|
||||
% Iteratively pick the color that maximizes the distance to the nearest
|
||||
% already-picked color
|
||||
colors = zeros(n_colors,3);
|
||||
lastlab = bglab(end,:); % initialize by making the "previous" color equal to background
|
||||
for i = 1:n_colors
|
||||
dX = bsxfun(@minus,lab,lastlab); % displacement of last from all colors on list
|
||||
dist2 = sum(dX.^2,2); % square distance
|
||||
mindist2 = min(dist2,mindist2); % dist2 to closest previously-chosen color
|
||||
[~,index] = max(mindist2); % find the entry farthest from all previously-chosen colors
|
||||
colors(i,:) = rgb(index,:); % save for output
|
||||
lastlab = lab(index,:); % prepare for next iteration
|
||||
end
|
||||
end
|
||||
|
||||
function c = parsecolor(s)
|
||||
if ischar(s)
|
||||
c = colorstr2rgb(s);
|
||||
elseif isnumeric(s) && size(s,2) == 3
|
||||
c = s;
|
||||
else
|
||||
error('MATLAB:InvalidColorSpec','Color specification cannot be parsed.');
|
||||
end
|
||||
end
|
||||
|
||||
function c = colorstr2rgb(c)
|
||||
% Convert a color string to an RGB value.
|
||||
% This is cribbed from Matlab's whitebg function.
|
||||
% Why don't they make this a stand-alone function?
|
||||
rgbspec = [1 0 0;0 1 0;0 0 1;1 1 1;0 1 1;1 0 1;1 1 0;0 0 0];
|
||||
cspec = 'rgbwcmyk';
|
||||
k = find(cspec==c(1));
|
||||
if isempty(k)
|
||||
error('MATLAB:InvalidColorString','Unknown color string.');
|
||||
end
|
||||
if k~=3 || length(c)==1,
|
||||
c = rgbspec(k,:);
|
||||
elseif length(c)>2,
|
||||
if strcmpi(c(1:3),'bla')
|
||||
c = [0 0 0];
|
||||
elseif strcmpi(c(1:3),'blu')
|
||||
c = [0 0 1];
|
||||
else
|
||||
error('MATLAB:UnknownColorString', 'Unknown color string.');
|
||||
end
|
||||
end
|
||||
end
|
||||
function colors = distinguishable_colors(n_colors,bg,func)
|
||||
% DISTINGUISHABLE_COLORS: pick colors that are maximally perceptually distinct
|
||||
%
|
||||
% When plotting a set of lines, you may want to distinguish them by color.
|
||||
% By default, Matlab chooses a small set of colors and cycles among them,
|
||||
% and so if you have more than a few lines there will be confusion about
|
||||
% which line is which. To fix this problem, one would want to be able to
|
||||
% pick a much larger set of distinct colors, where the number of colors
|
||||
% equals or exceeds the number of lines you want to plot. Because our
|
||||
% ability to distinguish among colors has limits, one should choose these
|
||||
% colors to be "maximally perceptually distinguishable."
|
||||
%
|
||||
% This function generates a set of colors which are distinguishable
|
||||
% by reference to the "Lab" color space, which more closely matches
|
||||
% human color perception than RGB. Given an initial large list of possible
|
||||
% colors, it iteratively chooses the entry in the list that is farthest (in
|
||||
% Lab space) from all previously-chosen entries. While this "greedy"
|
||||
% algorithm does not yield a global maximum, it is simple and efficient.
|
||||
% Moreover, the sequence of colors is consistent no matter how many you
|
||||
% request, which facilitates the users' ability to learn the color order
|
||||
% and avoids major changes in the appearance of plots when adding or
|
||||
% removing lines.
|
||||
%
|
||||
% Syntax:
|
||||
% colors = distinguishable_colors(n_colors)
|
||||
% Specify the number of colors you want as a scalar, n_colors. This will
|
||||
% generate an n_colors-by-3 matrix, each row representing an RGB
|
||||
% color triple. If you don't precisely know how many you will need in
|
||||
% advance, there is no harm (other than execution time) in specifying
|
||||
% slightly more than you think you will need.
|
||||
%
|
||||
% colors = distinguishable_colors(n_colors,bg)
|
||||
% This syntax allows you to specify the background color, to make sure that
|
||||
% your colors are also distinguishable from the background. Default value
|
||||
% is white. bg may be specified as an RGB triple or as one of the standard
|
||||
% "ColorSpec" strings. You can even specify multiple colors:
|
||||
% bg = {'w','k'}
|
||||
% or
|
||||
% bg = [1 1 1; 0 0 0]
|
||||
% will only produce colors that are distinguishable from both white and
|
||||
% black.
|
||||
%
|
||||
% colors = distinguishable_colors(n_colors,bg,rgb2labfunc)
|
||||
% By default, distinguishable_colors uses the image processing toolbox's
|
||||
% color conversion functions makecform and applycform. Alternatively, you
|
||||
% can supply your own color conversion function.
|
||||
%
|
||||
% Example:
|
||||
% c = distinguishable_colors(25);
|
||||
% figure
|
||||
% image(reshape(c,[1 size(c)]))
|
||||
%
|
||||
% Example using the file exchange's 'colorspace':
|
||||
% func = @(x) colorspace('RGB->Lab',x);
|
||||
% c = distinguishable_colors(25,'w',func);
|
||||
|
||||
% Copyright 2010-2011 by Timothy E. Holy
|
||||
% All rights reserved.
|
||||
%
|
||||
% Redistribution and use in source and binary forms, with or without
|
||||
% modification, are permitted provided that the following conditions are
|
||||
% met:
|
||||
%
|
||||
% * Redistributions of source code must retain the above copyright
|
||||
% notice, this list of conditions and the following disclaimer.
|
||||
% * Redistributions in binary form must reproduce the above copyright
|
||||
% notice, this list of conditions and the following disclaimer in
|
||||
% the documentation and/or other materials provided with the distribution
|
||||
%
|
||||
% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
% POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
|
||||
% Parse the inputs
|
||||
if (nargin < 2)
|
||||
bg = [1 1 1]; % default white background
|
||||
else
|
||||
if iscell(bg)
|
||||
% User specified a list of colors as a cell aray
|
||||
bgc = bg;
|
||||
for i = 1:length(bgc)
|
||||
bgc{i} = parsecolor(bgc{i});
|
||||
end
|
||||
bg = cat(1,bgc{:});
|
||||
else
|
||||
% User specified a numeric array of colors (n-by-3)
|
||||
bg = parsecolor(bg);
|
||||
end
|
||||
end
|
||||
|
||||
% Generate a sizable number of RGB triples. This represents our space of
|
||||
% possible choices. By starting in RGB space, we ensure that all of the
|
||||
% colors can be generated by the monitor.
|
||||
n_grid = 30; % number of grid divisions along each axis in RGB space
|
||||
x = linspace(0,1,n_grid);
|
||||
[R,G,B] = ndgrid(x,x,x);
|
||||
rgb = [R(:) G(:) B(:)];
|
||||
if (n_colors > size(rgb,1)/3)
|
||||
error('You can''t readily distinguish that many colors');
|
||||
end
|
||||
|
||||
% Convert to Lab color space, which more closely represents human
|
||||
% perception
|
||||
if (nargin > 2)
|
||||
lab = func(rgb);
|
||||
bglab = func(bg);
|
||||
else
|
||||
C = makecform('srgb2lab');
|
||||
lab = applycform(rgb,C);
|
||||
bglab = applycform(bg,C);
|
||||
end
|
||||
|
||||
% If the user specified multiple background colors, compute distances
|
||||
% from the candidate colors to the background colors
|
||||
mindist2 = inf(size(rgb,1),1);
|
||||
for i = 1:size(bglab,1)-1
|
||||
dX = bsxfun(@minus,lab,bglab(i,:)); % displacement all colors from bg
|
||||
dist2 = sum(dX.^2,2); % square distance
|
||||
mindist2 = min(dist2,mindist2); % dist2 to closest previously-chosen color
|
||||
end
|
||||
|
||||
% Iteratively pick the color that maximizes the distance to the nearest
|
||||
% already-picked color
|
||||
colors = zeros(n_colors,3);
|
||||
lastlab = bglab(end,:); % initialize by making the "previous" color equal to background
|
||||
for i = 1:n_colors
|
||||
dX = bsxfun(@minus,lab,lastlab); % displacement of last from all colors on list
|
||||
dist2 = sum(dX.^2,2); % square distance
|
||||
mindist2 = min(dist2,mindist2); % dist2 to closest previously-chosen color
|
||||
[~,index] = max(mindist2); % find the entry farthest from all previously-chosen colors
|
||||
colors(i,:) = rgb(index,:); % save for output
|
||||
lastlab = lab(index,:); % prepare for next iteration
|
||||
end
|
||||
end
|
||||
|
||||
function c = parsecolor(s)
|
||||
if ischar(s)
|
||||
c = colorstr2rgb(s);
|
||||
elseif isnumeric(s) && size(s,2) == 3
|
||||
c = s;
|
||||
else
|
||||
error('MATLAB:InvalidColorSpec','Color specification cannot be parsed.');
|
||||
end
|
||||
end
|
||||
|
||||
function c = colorstr2rgb(c)
|
||||
% Convert a color string to an RGB value.
|
||||
% This is cribbed from Matlab's whitebg function.
|
||||
% Why don't they make this a stand-alone function?
|
||||
rgbspec = [1 0 0;0 1 0;0 0 1;1 1 1;0 1 1;1 0 1;1 1 0;0 0 0];
|
||||
cspec = 'rgbwcmyk';
|
||||
k = find(cspec==c(1));
|
||||
if isempty(k)
|
||||
error('MATLAB:InvalidColorString','Unknown color string.');
|
||||
end
|
||||
if k~=3 || length(c)==1,
|
||||
c = rgbspec(k,:);
|
||||
elseif length(c)>2,
|
||||
if strcmpi(c(1:3),'bla')
|
||||
c = [0 0 0];
|
||||
elseif strcmpi(c(1:3),'blu')
|
||||
c = [0 0 1];
|
||||
else
|
||||
error('MATLAB:UnknownColorString', 'Unknown color string.');
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Reference in New Issue