Index: /issm/trunk-jpl/src/m/plot/colormaps/distinguishable_colors.m
===================================================================
--- /issm/trunk-jpl/src/m/plot/colormaps/distinguishable_colors.m	(revision 28167)
+++ /issm/trunk-jpl/src/m/plot/colormaps/distinguishable_colors.m	(revision 28167)
@@ -0,0 +1,152 @@
+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
+
+  % 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
