cptcmap

PURPOSE ^

CPTCMAP Apply a .cpt file as colormap to an axis

SYNOPSIS ^

function varargout = cptcmap(varargin)

DESCRIPTION ^

CPTCMAP Apply a .cpt file as colormap to an axis

 cptcmap(name);
 cptcmap(name, ax);
 cptcmap(... param, val, ...);
 [cmap, lims, ticks, bfncol, ctable] = cptcmap(...)

 This function creates and applies a colormap defined in a color palette
 table (.cpt file).  For a full description of the cpt file format, see
 the Generic Mapping Tools documentation (http://gmt.soest.hawaii.edu/).
 Color palette files provide more flexible colormapping than Matlab's
 default schemes, including both discrete and continuous gradients, as
 well as easier direct color mapping.

 Limitations: X11 color names not supported, patterns not supported, CMYK
 not supported yet

 Input variables:

   name:       .cpt file name.  You may either specify either the full
               path, or just the file name.  In the latter case, the
               function will look for the file in the folder specified by
               the cptpath variable in the first line of code; by default
               this folder is located in the same location as cptcmap.m
               and is called cptfiles.

   ax:         handle of axis or axes where colormap should be applied
               (colormaps will effect the entire figure(s), but axis clim
               adjustments for direct scaling will only affect the
               specified axes).  If no axis is specified and no output
               variables are supplied, colormap will be applied to the
               current axis.  If no axis is specified and output variables
               are supplied, the colormap will not be applied to any axes.

   'showall':  When this option is used, a figure is created displaying
               colorbars for all colormaps contained in the .cpt folder.
               Color limits of each colormap are listed along with the
               names of each.  A small tick mark indicates the location of
               0, where applicable.  NOTE: the number of columns to use
               for display is hard-coded.  As you start collecting more
               color palettes, the figure may get too cluttered and you
               may have to adjust this (variable ncol is the plotcmaps
               subfunction). 

 Optional input variables (passed as parameter/value pairs):

   'mapping':  'scaled' or 'direct'.  Scaled mapping spreads the colormap
               to cover the color limits of the figure.  Direct mapping
               resets the color limits of the axes so that colors are
               mapped to the levels specified by the .cpt file. ['scaled']

   'ncol':     number of colors in final colormap. If not included or NaN,
               this function will try to choose the fewest number of
               blocks needed to display the colormap as accurately as
               possible. I have arbitrarily chosen that it will not try to
               create more than 256 colors in the final colormap when
               using this automatic scheme.  However, you can manually set
               ncol higher if necessary to resolve all sharp breaks and
               gradients in the colormap.

   'flip':     if true, reverse the colormap order [false]

 Output variables:

   cmap:       ncol x 3 colormap array

   lims:       1 x 2 array holding minimum and maximum values for which
               the colormap is defined.  

   ticks:      vector of tick values specifying where colors were defined
               in the original file

   bfncol:     3 x 3 colormap array specifying the colors defined for
               background (values lower than lowest color limit),
               foreground (values higher than highest color limit), and
               NaN values.  These do not affect the resulting colormap,
               but can be applied by the user to replicate the behavior
               seen in GMT.

   ctable:     n x 8 color palette table, translated to Matlab color
               space. Column 1 holds the lower limit of each color cell,
               columns 2-4 the RGB values corresponding to the lower
               limit, column 5 the upper limit of the color cell, and
               columns 6-8 the RGB values of the upper limit.  When the
               lower and upper colors are the same, this defines a
               solid-colored cell; when they are different, colors are
               linearly interpolated between the endpoints.

 Example:

   [lat, lon, z] = satbath(10);
   pcolor(lon, lat, z);
   shading flat;
   cptcmap('GMT_globe', 'mapping', 'direct');
   colorbar;

CROSS-REFERENCE INFORMATION ^

This function calls: This function is called by:

SUBFUNCTIONS ^

SOURCE CODE ^

0001 function varargout = cptcmap(varargin)
0002 %CPTCMAP Apply a .cpt file as colormap to an axis
0003 %
0004 % cptcmap(name);
0005 % cptcmap(name, ax);
0006 % cptcmap(... param, val, ...);
0007 % [cmap, lims, ticks, bfncol, ctable] = cptcmap(...)
0008 %
0009 % This function creates and applies a colormap defined in a color palette
0010 % table (.cpt file).  For a full description of the cpt file format, see
0011 % the Generic Mapping Tools documentation (http://gmt.soest.hawaii.edu/).
0012 % Color palette files provide more flexible colormapping than Matlab's
0013 % default schemes, including both discrete and continuous gradients, as
0014 % well as easier direct color mapping.
0015 %
0016 % Limitations: X11 color names not supported, patterns not supported, CMYK
0017 % not supported yet
0018 %
0019 % Input variables:
0020 %
0021 %   name:       .cpt file name.  You may either specify either the full
0022 %               path, or just the file name.  In the latter case, the
0023 %               function will look for the file in the folder specified by
0024 %               the cptpath variable in the first line of code; by default
0025 %               this folder is located in the same location as cptcmap.m
0026 %               and is called cptfiles.
0027 %
0028 %   ax:         handle of axis or axes where colormap should be applied
0029 %               (colormaps will effect the entire figure(s), but axis clim
0030 %               adjustments for direct scaling will only affect the
0031 %               specified axes).  If no axis is specified and no output
0032 %               variables are supplied, colormap will be applied to the
0033 %               current axis.  If no axis is specified and output variables
0034 %               are supplied, the colormap will not be applied to any axes.
0035 %
0036 %   'showall':  When this option is used, a figure is created displaying
0037 %               colorbars for all colormaps contained in the .cpt folder.
0038 %               Color limits of each colormap are listed along with the
0039 %               names of each.  A small tick mark indicates the location of
0040 %               0, where applicable.  NOTE: the number of columns to use
0041 %               for display is hard-coded.  As you start collecting more
0042 %               color palettes, the figure may get too cluttered and you
0043 %               may have to adjust this (variable ncol is the plotcmaps
0044 %               subfunction).
0045 %
0046 % Optional input variables (passed as parameter/value pairs):
0047 %
0048 %   'mapping':  'scaled' or 'direct'.  Scaled mapping spreads the colormap
0049 %               to cover the color limits of the figure.  Direct mapping
0050 %               resets the color limits of the axes so that colors are
0051 %               mapped to the levels specified by the .cpt file. ['scaled']
0052 %
0053 %   'ncol':     number of colors in final colormap. If not included or NaN,
0054 %               this function will try to choose the fewest number of
0055 %               blocks needed to display the colormap as accurately as
0056 %               possible. I have arbitrarily chosen that it will not try to
0057 %               create more than 256 colors in the final colormap when
0058 %               using this automatic scheme.  However, you can manually set
0059 %               ncol higher if necessary to resolve all sharp breaks and
0060 %               gradients in the colormap.
0061 %
0062 %   'flip':     if true, reverse the colormap order [false]
0063 %
0064 % Output variables:
0065 %
0066 %   cmap:       ncol x 3 colormap array
0067 %
0068 %   lims:       1 x 2 array holding minimum and maximum values for which
0069 %               the colormap is defined.
0070 %
0071 %   ticks:      vector of tick values specifying where colors were defined
0072 %               in the original file
0073 %
0074 %   bfncol:     3 x 3 colormap array specifying the colors defined for
0075 %               background (values lower than lowest color limit),
0076 %               foreground (values higher than highest color limit), and
0077 %               NaN values.  These do not affect the resulting colormap,
0078 %               but can be applied by the user to replicate the behavior
0079 %               seen in GMT.
0080 %
0081 %   ctable:     n x 8 color palette table, translated to Matlab color
0082 %               space. Column 1 holds the lower limit of each color cell,
0083 %               columns 2-4 the RGB values corresponding to the lower
0084 %               limit, column 5 the upper limit of the color cell, and
0085 %               columns 6-8 the RGB values of the upper limit.  When the
0086 %               lower and upper colors are the same, this defines a
0087 %               solid-colored cell; when they are different, colors are
0088 %               linearly interpolated between the endpoints.
0089 %
0090 % Example:
0091 %
0092 %   [lat, lon, z] = satbath(10);
0093 %   pcolor(lon, lat, z);
0094 %   shading flat;
0095 %   cptcmap('GMT_globe', 'mapping', 'direct');
0096 %   colorbar;
0097 
0098 % Copyright 2011 Kelly Kearney
0099 % File Exchange update: 4/12/2011
0100 
0101 %------------------------------
0102 % Parse input
0103 %------------------------------
0104 
0105 % The .cpt file folder.  By default, the cptfiles folder is located in
0106 % the same place as the cptcmap.m file.  If you change this on your
0107 % computer, change the cptpath definition to reflect the new location.
0108 
0109 % cptpath = [pwd '\utils\colormaps\'];%fullfile(fileparts(which('cptcmap')), 'cptfiles');
0110 % if ~exist(cptpath, 'dir')
0111 %     error('You have moved the cptfiles directory.  Please modify the cptpath variable in this code to point to the directory where your.cpt files are stored');
0112 % end
0113 %
0114 % % Check for 'showall' option first
0115 %
0116 % if nargin == 1 & strcmp(varargin{1}, 'showall')
0117 %     plotcmaps(cptpath);
0118 %     return;
0119 % end
0120 
0121 % Name of file
0122 
0123 [blah, blah, ext] = fileparts(varargin{1});
0124 if isempty(ext)
0125     varargin{1} = [varargin{1} '.cpt'];
0126 end
0127 
0128 if exist(varargin{1}, 'file')   % full filename and path given
0129     filename = varargin{1};
0130 else                            % only file name given
0131     [blah,blah,ext] = fileparts(varargin{1});
0132     if ~isempty(ext)            % with extension
0133         filename = fullfile(cptpath, varargin{1});
0134     else                        % without extension
0135         filename = fullfile(cptpath, [varargin{1} '.cpt']);   
0136     end
0137     if ~exist(filename, 'file')
0138         error('Specified .cpt file not found');
0139     end
0140 end
0141 
0142 % Axes to which colormap will be applied
0143 
0144 if nargin > 1 && isnumeric(varargin{2}) && all(ishandle(varargin{2}(:)))
0145     ax = varargin{2};
0146     pv = varargin(3:end);
0147     applycmap = true;
0148 elseif nargout == 0
0149     ax = gca;
0150     pv = varargin(2:end);
0151     applycmap = true;
0152 else
0153     pv = varargin(2:end);
0154     applycmap = false;
0155 end
0156 
0157 % Optional paramter/value pairs
0158     
0159 p = inputParser;
0160 p.addParamValue('mapping', 'scaled', @(x) any(strcmpi(x, {'scaled', 'direct'})));
0161 p.addParamValue('ncol', NaN, @(x) isscalar(x) && isnumeric(x));
0162 p.addParamValue('flip', false, @(x) isscalar(x) && islogical(x));
0163 
0164 p.parse(pv{:});
0165 Opt = p.Results;
0166      
0167 %------------------------------
0168 % Calculate colormap and apply
0169 %------------------------------
0170 
0171 [cmap, lims,ticks,bfncol,ctable] = cpt2cmap(filename, Opt.ncol);
0172 if Opt.flip
0173     if strcmp(Opt.mapping, 'direct')
0174         warning('Flipping colormap with direct mapping may lead to odd color breaks');
0175     end
0176     cmap = flipud(cmap);
0177 end
0178 
0179 if applycmap
0180     for iax = 1:numel(ax)
0181         axes(ax(iax));
0182         if strcmp(Opt.mapping, 'direct')
0183             set(ax(iax), 'clim', lims);
0184         end
0185         colormap(cmap);
0186     end
0187 end
0188 
0189 %------------------------------
0190 % Output
0191 %------------------------------
0192 
0193 allout = {cmap, lims, ticks, bfncol, ctable};
0194 varargout(1:nargout) = allout(1:nargout);
0195 
0196 
0197 %------------------------------
0198 % Subfunction: Read colormap
0199 % from file
0200 %------------------------------
0201 
0202 function [cmap, lims, ticks, bfncol, ctable] = cpt2cmap(file, ncol)
0203 
0204 % Read file
0205 
0206 fid = fopen(file);
0207 txt = textscan(fid, '%s', 'delimiter', '\n');
0208 txt = txt{1};
0209 fclose(fid);
0210 
0211 isheader = strncmp(txt, '#', 1);
0212 isfooter = strncmp(txt, 'B', 1) | strncmp(txt, 'F', 1) | strncmp(txt, 'N', 1); 
0213 
0214 % Extract color data, ignore labels (errors if other text found)
0215 
0216 ctabletxt = txt(~isheader & ~isfooter);
0217 ctable = str2num(strvcat(txt(~isheader & ~isfooter)));
0218 if isempty(ctable)
0219     nr = size(ctabletxt,1);
0220     ctable = cell(nr,1);
0221     for ir = 1:nr
0222         ctable{ir} = str2num(strvcat(regexp(ctabletxt{ir}, '[\d\.-]*', 'match')))';
0223     end
0224     try 
0225         ctable = cell2mat(ctable);
0226     catch
0227         error('Cannot parse this format .cpt file yet');
0228     end 
0229 end
0230 
0231 % Determine which color model is used (RGB, HSV, CMYK, names, patterns,
0232 % mixed)
0233 
0234 [nr, nc] = size(ctable);
0235 iscolmodline = cellfun(@(x) ~isempty(x), regexp(txt, 'COLOR_MODEL'));
0236 if any(iscolmodline)
0237     colmodel = regexprep(txt{iscolmodline}, 'COLOR_MODEL', '');
0238     colmodel = strtrim(lower(regexprep(colmodel, '[#=]', '')));
0239 else
0240     if nc == 8
0241         colmodel = 'rgb';
0242     elseif nc == 10
0243         colmodel = 'cmyk';
0244     else
0245         error('Cannot parse this format .cpt file yet');
0246     end
0247 end
0248 %     try
0249 %         temp = str2num(strvcat(txt(~isheader & ~isfooter)));
0250 %         if size(temp,2) == 8
0251 %             colmodel = 'rgb';
0252 %         elseif size(temp,2) == 10
0253 %             colmodel = 'cmyk';
0254 %         else % grayscale, maybe others
0255 %             error('Cannot parse this format .cpt file yet');
0256 %         end
0257 %     catch % color names, mixed formats, dash placeholders
0258 %         error('Cannot parse this format .cpt file yet');
0259 %     end
0260 % end
0261 %
0262 
0263 %
0264 % iscmod = strncmp(txt, '# COLOR_MODEL', 13);
0265 %
0266 %
0267 % if ~any(iscmod)
0268 %     isrgb = true;
0269 % else
0270 %     cmodel = strtrim(regexprep(txt{iscmod}, '# COLOR_MODEL =', ''));
0271 %     if strcmp(cmodel, 'RGB')
0272 %         isrgb = true;
0273 %     elseif strcmp(cmodel, 'HSV')
0274 %         isrgb = false;
0275 %     else
0276 %         error('Unknown color model: %s', cmodel);
0277 %     end
0278 % end
0279 
0280 % Reformat color table into one column of colors
0281 
0282 cpt = zeros(nr*2, 4);
0283 cpt(1:2:end,:) = ctable(:,1:4);
0284 cpt(2:2:end,:) = ctable(:,5:8);
0285 
0286 % Ticks
0287 
0288 ticks = unique(cpt(:,1));
0289 
0290 % Choose number of colors for output
0291 
0292 if isnan(ncol)
0293     
0294     endpoints = unique(cpt(:,1));
0295     
0296     % For gradient-ed blocks, ensure at least 4 steps between endpoints
0297     
0298     issolid = all(ctable(:,2:4) == ctable(:,6:8), 2);
0299     
0300     for ie = 1:length(issolid)
0301         if ~issolid(ie)
0302             temp = linspace(endpoints(ie), endpoints(ie+1), 11)';
0303             endpoints = [endpoints; temp(2:end-1)];
0304         end
0305     end
0306     
0307     endpoints = sort(endpoints);
0308     
0309     % Determine largest step size that resolves all endpoints
0310     
0311     space = diff(endpoints);
0312     space = unique(space);
0313     space = roundn(space, -3); % To avoid floating point issues when converting to integers
0314     
0315     nspace = length(space);
0316     if ~isscalar(space)
0317         
0318         fac = 1;
0319         tol = .001;
0320         while 1
0321             if all(space >= 1 & (space - round(space)) < tol)
0322                 space = round(space);
0323                 break;
0324             else
0325                 space = space * 10;
0326                 fac = fac * 10;
0327             end
0328         end
0329         
0330         pairs = nchoosek(space, 2);
0331         np = size(pairs,1);
0332         commonsp = zeros(np,1);
0333         for ip = 1:np
0334             commonsp(ip) = gcd(pairs(ip,1), pairs(ip,2));
0335         end
0336         
0337         space = min(commonsp);
0338         space = space/fac;
0339     end
0340             
0341     ncol = (max(endpoints) - min(endpoints))./space;
0342     ncol = min(ncol, 256);
0343     
0344 end
0345 
0346 % Remove replicates and mimic sharp breaks
0347 
0348 isrep =  [false; ~any(diff(cpt),2)];
0349 cpt = cpt(~isrep,:);
0350 
0351 difc = diff(cpt(:,1));
0352 minspace = min(difc(difc > 0));
0353 isbreak = [false; difc == 0];
0354 cpt(isbreak,1) = cpt(isbreak,1) + .01*minspace;
0355 
0356 % Parse background, foreground, and nan colors
0357 
0358 footer = txt(isfooter);
0359 bfncol = nan(3,3);
0360 for iline = 1:length(footer)
0361     if strcmp(footer{iline}(1), 'B')
0362         bfncol(1,:) = str2num(regexprep(footer{iline}, 'B', ''));
0363     elseif strcmp(footer{iline}(1), 'F')
0364         bfncol(2,:) = str2num(regexprep(footer{iline}, 'F', ''));
0365     elseif strcmp(footer{iline}(1), 'N')
0366         bfncol(3,:) = str2num(regexprep(footer{iline}, 'N', ''));
0367     end
0368 end
0369 
0370 % Convert to Matlab-format colormap and color limits
0371 
0372 lims = [min(cpt(:,1)) max(cpt(:,1))];
0373 endpoints = linspace(lims(1), lims(2), ncol+1);
0374 midpoints = (endpoints(1:end-1) + endpoints(2:end))/2;
0375 
0376 cmap = interp1(cpt(:,1), cpt(:,2:4), midpoints);
0377 
0378 switch colmodel
0379     case 'rgb'
0380         cmap = cmap ./ 255;
0381         bfncol = bfncol ./ 255;
0382         ctable(:,[2:4 6:8]) = ctable(:,[2:4 6:8]) ./ 255;
0383         
0384     case 'hsv'
0385         cmap(:,1) = cmap(:,1)./300;
0386         cmap = hsv2rgb(cmap);
0387         
0388         bfncol(:,1) = bfncol(:,1)./300;
0389         bfncol = hsv2rgb(bfncol);
0390         
0391         ctable(:,2) = ctable(:,2)./300;
0392         ctable(:,6) = ctable(:,6)./300;
0393         
0394         ctable(:,2:4) = hsv2rgb(ctable(:,2:4));
0395         ctable(:,6:8) = hsv2rgb(ctable(:,6:8));
0396         
0397     case 'cmyk'
0398         error('CMYK color conversion not yet supported');
0399 end
0400 
0401 %------------------------------
0402 % Subfunction: Display all
0403 % colormaps
0404 %------------------------------
0405 
0406 function plotcmaps(folder)
0407 
0408 Files = dir(fullfile(folder, '*.cpt'));
0409 nfile = length(Files);
0410 ncol = 3; 
0411 nr = ceil(nfile/ncol);
0412 width = (1 - .05*2)/ncol;
0413 height = (1-.05*2)/nr;
0414 left = .05 + (0:ncol-1)*width;
0415 bot = .05 + (0:nr-1)*height;
0416 
0417 [l, b] = meshgrid(left, bot);
0418 w = width * .8;
0419 h = height * .4;
0420 
0421 figure('color','w');
0422 ax = axes('position', [0 0 1 1]);
0423 hold on;
0424 
0425 for ifile = 1:nfile
0426     [cmap,blah,blah,blah,ctable] = cptcmap(Files(ifile).name);
0427     [x,y,c] = ctable2patch(ctable);
0428     
0429     xtick = unique(x);
0430     dx = max(x(:)) - min(x(:));
0431     
0432     xsc = ((x-min(xtick))./dx).*w + l(ifile);
0433     ysc = y.*h + b(ifile);
0434     
0435     xrect = [0 1 1 0 0] .*w + l(ifile);
0436     yrect = [1 1 0 0 1] .*h + b(ifile);
0437     
0438     xticksc = ((xtick-min(xtick))./dx).*w + l(ifile);
0439     x0 = interp1(xtick, xticksc, 0);
0440     y0 = b(ifile) + [0 .2*h NaN .8*h h];
0441     x0 = ones(size(y0))*x0;
0442 
0443     lbl = sprintf('%s [%g, %g]', regexprep(Files(ifile).name,'\.cpt',''), min(x(:)), max(x(:)));
0444     
0445     patch(xsc, ysc, c, 'edgecolor', 'none');
0446     line(xrect, yrect, 'color', 'k');
0447     line(x0, y0, 'color', 'k');
0448     text(l(ifile), b(ifile)+h, lbl, 'interpreter', 'none', 'fontsize', 8, 'verticalalignment', 'bottom', 'horizontalalignment', 'left');
0449     
0450 end
0451 
0452 set(ax, 'ylim', [0 1], 'xlim', [0 1], 'visible', 'off');
0453 
0454 % Determine patch coordinates
0455 
0456 function [x,y,c] = ctable2patch(ctable)
0457 
0458 np = size(ctable,1);
0459 
0460 x = zeros(4, np);
0461 y = zeros(4, np);
0462 c = zeros(4, np, 3);
0463 
0464 y(1:2,:) = 1;
0465 
0466 for ip = 1:np
0467     x(:,ip) = [ctable(ip,1) ctable(ip,5) ctable(ip,5) ctable(ip,1)];
0468     c(:,ip,:) = [ctable(ip,2:4); ctable(ip,6:8); ctable(ip,6:8); ctable(ip,2:4)];
0469 end
0470 
0471

Generated on Thu 21-Aug-2014 10:40:31 by m2html © 2005