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;
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