Home > utils > freezeColors.m

freezeColors

PURPOSE ^

freezeColors Lock colors of plot, enabling multiple colormaps per figure. (v2.3)

SYNOPSIS ^

function freezeColors(varargin)

DESCRIPTION ^

 freezeColors  Lock colors of plot, enabling multiple colormaps per figure. (v2.3)

   Problem: There is only one colormap per figure. This function provides
       an easy solution when plots using different colomaps are desired 
       in the same figure.

   freezeColors freezes the colors of graphics objects in the current axis so 
       that subsequent changes to the colormap (or caxis) will not change the
       colors of these objects. freezeColors works on any graphics object 
       with CData in indexed-color mode: surfaces, images, scattergroups, 
       bargroups, patches, etc. It works by converting CData to true-color rgb
       based on the colormap active at the time freezeColors is called.

   The original indexed color data is saved, and can be restored using
       unfreezeColors, making the plot once again subject to the colormap and
       caxis.


   Usage:
       freezeColors        applies to all objects in current axis (gca),
       freezeColors(axh)   same, but works on axis axh. Useful for colorbar.

   Example:
       subplot(2,1,1); imagesc(X); colormap hot; freezeColors
       subplot(2,1,2); imagesc(Y); colormap hsv; freezeColors etc...

       Note: colorbars must also be frozen
           hc = colorbar; freezeColors(hc), or simply freezeColors(colorbar)

       For additional examples, see freezeColors_demo.

   Side effect on render mode: freezeColors does not work with the painters
       renderer, because Matlab doesn't support rgb color data in
       painters mode. If the current renderer is painters, freezeColors
       changes it to zbuffer.

       See also unfreezeColors, freezeColors_pub.html


   John Iversen (iversen@nsi.edu) 3/23/05

CROSS-REFERENCE INFORMATION ^

This function calls: This function is called by:

SUBFUNCTIONS ^

SOURCE CODE ^

0001 function freezeColors(varargin)
0002 % freezeColors  Lock colors of plot, enabling multiple colormaps per figure. (v2.3)
0003 %
0004 %   Problem: There is only one colormap per figure. This function provides
0005 %       an easy solution when plots using different colomaps are desired
0006 %       in the same figure.
0007 %
0008 %   freezeColors freezes the colors of graphics objects in the current axis so
0009 %       that subsequent changes to the colormap (or caxis) will not change the
0010 %       colors of these objects. freezeColors works on any graphics object
0011 %       with CData in indexed-color mode: surfaces, images, scattergroups,
0012 %       bargroups, patches, etc. It works by converting CData to true-color rgb
0013 %       based on the colormap active at the time freezeColors is called.
0014 %
0015 %   The original indexed color data is saved, and can be restored using
0016 %       unfreezeColors, making the plot once again subject to the colormap and
0017 %       caxis.
0018 %
0019 %
0020 %   Usage:
0021 %       freezeColors        applies to all objects in current axis (gca),
0022 %       freezeColors(axh)   same, but works on axis axh. Useful for colorbar.
0023 %
0024 %   Example:
0025 %       subplot(2,1,1); imagesc(X); colormap hot; freezeColors
0026 %       subplot(2,1,2); imagesc(Y); colormap hsv; freezeColors etc...
0027 %
0028 %       Note: colorbars must also be frozen
0029 %           hc = colorbar; freezeColors(hc), or simply freezeColors(colorbar)
0030 %
0031 %       For additional examples, see freezeColors_demo.
0032 %
0033 %   Side effect on render mode: freezeColors does not work with the painters
0034 %       renderer, because Matlab doesn't support rgb color data in
0035 %       painters mode. If the current renderer is painters, freezeColors
0036 %       changes it to zbuffer.
0037 %
0038 %       See also unfreezeColors, freezeColors_pub.html
0039 %
0040 %
0041 %   John Iversen (iversen@nsi.edu) 3/23/05
0042 %
0043 
0044 %   Changes:
0045 %   JRI (iversen@nsi.edu) 4/19/06   Correctly handles scaled integer cdata
0046 %   JRI 9/1/06   should now handle all objects with cdata: images, surfaces,
0047 %                scatterplots. (v 2.1)
0048 %   JRI 11/11/06 Preserves NaN colors. Hidden option (v 2.2, not uploaded)
0049 %   JRI 3/17/07  Preserve caxis after freezing--maintains colorbar scale (v 2.3)
0050 %   JRI 4/12/07  Check for painters mode as Matlab doesn't support rgb in it.
0051 %
0052 
0053 % Hidden option for NaN colors:
0054 %   Missing data are often represented by NaN in the indexed color
0055 %   data, which renders transparently. This transparency will be preserved
0056 %   when freezing colors. If instead you wish such gaps to be filled with
0057 %   a real color, add 'nancolor',[r g b] to the end of the arguments. E.g.
0058 %   freezeColors('nancolor',[r g b]) or freezeColors(axh,'nancolor',[r g b]),
0059 %   where [r g b] is a color vector. This works on images & pcolor, but not on
0060 %   surfaces.
0061 %   Thanks to Fabiano Busdraghi and Jody Klymak for the suggestions.
0062 
0063 %   Note: Special handling of patches: For some reason, setting
0064 %   cdata on patches created by bar() yields an error,
0065 %   so instead set facevertexcdata instead for patches.
0066 
0067 
0068 % Free for all uses, but please retain the following:
0069 %   Original Author:
0070 %   John Iversen, 2005-7
0071 %   john_iversen@post.harvard.edu
0072 
0073 appdatacode = 'JRI__freezeColorsData';
0074 
0075 [h, nancolor] = checkArgs(varargin);
0076 
0077 %gather all children with scaled or indexed CData
0078 cdatah = getCDataHandles(h);
0079 
0080 %current colormap
0081 cmap = colormap;
0082 nColors = size(cmap,1);
0083 cax = caxis;
0084 
0085 % convert object color indexes into colormap to true-color data using
0086 %  current colormap
0087 for hh = cdatah',
0088     g = get(hh);
0089     
0090     %preserve parent axis clim
0091     if strcmp(get(g.Parent,'type'),'axes'),
0092         originalClim = get(g.Parent,'clim');
0093     else
0094         originalClim = [];
0095     end
0096    
0097     %special handling for patch (see note above)
0098     if ~strcmp(g.Type,'patch'),
0099         cdata = g.CData;
0100     else
0101         cdata = g.FaceVertexCData; 
0102     end
0103     
0104     %get cdata mapping (most objects (except scattergroup) have it)
0105     if isfield(g,'CDataMapping'),
0106         scalemode = g.CDataMapping;
0107     else
0108         scalemode = 'scaled';
0109     end
0110     
0111     %save original indexed data for use with unfreezeColors
0112     siz = size(cdata);
0113     setappdata(hh, appdatacode, {cdata scalemode});
0114 
0115     %convert cdata to indexes into colormap
0116     if strcmp(scalemode,'scaled'),
0117         %4/19/06 JRI, Accommodate scaled display of integer cdata:
0118         %       in MATLAB, uint * double = uint, so must coerce cdata to double
0119         %       Thanks to O Yamashita for pointing this need out
0120         idx = ceil( (double(cdata) - cax(1)) / (cax(2)-cax(1)) * nColors);
0121     else %direct mapping
0122         idx = cdata;
0123     end
0124     
0125     %clamp to [1, nColors]
0126     idx(idx<1) = 1;
0127     idx(idx>nColors) = nColors;
0128 
0129     %handle nans in idx
0130     nanmask = isnan(idx);
0131     idx(nanmask)=1; %temporarily replace w/ a valid colormap index
0132 
0133     %make true-color data--using current colormap
0134     realcolor = zeros(siz);
0135     for i = 1:3,
0136         c = cmap(idx,i);
0137         c = reshape(c,siz);
0138         c(nanmask) = nancolor(i); %restore Nan (or nancolor if specified)
0139         realcolor(:,:,i) = c;
0140     end
0141     
0142     %apply new true-color color data
0143     
0144     %true-color is not supported in painters renderer, so switch out of that
0145     if strcmp(get(gcf,'renderer'), 'painters'),
0146         set(gcf,'renderer','zbuffer');
0147     end
0148     
0149     %replace original CData with true-color data
0150     if ~strcmp(g.Type,'patch'),
0151         set(hh,'CData',realcolor);
0152     else
0153         set(hh,'faceVertexCData',permute(realcolor,[1 3 2]))
0154     end
0155     
0156     %restore clim (so colorbar will show correct limits)
0157     if ~isempty(originalClim),
0158         set(g.Parent,'clim',originalClim)
0159     end
0160     
0161 end %loop on indexed-color objects
0162 
0163 
0164 % ============================================================================ %
0165 % Local functions
0166 
0167 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
0168 %% getCDataHandles -- get handles of all descendents with indexed CData
0169 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
0170 
0171 function hout = getCDataHandles(h)
0172 % getCDataHandles  Find all objects with indexed CData
0173 
0174 %recursively descend object tree, finding objects with indexed CData
0175 % An exception: don't include children of objects that themselves have CData:
0176 %   for example, scattergroups are non-standard hggroups, with CData. Changing
0177 %   such a group's CData automatically changes the CData of its children,
0178 %   (as well as the children's handles), so there's no need to act on them.
0179 
0180 error(nargchk(1,1,nargin,'struct'))
0181 
0182 hout = [];
0183 if isempty(h),return;end
0184 
0185 ch = get(h,'children');
0186 for hh = ch'
0187     g = get(hh);
0188     if isfield(g,'CData'),     %does object have CData?
0189         %is it indexed/scaled?
0190         if ~isempty(g.CData) && isnumeric(g.CData) && size(g.CData,3)==1, 
0191             hout = [hout; hh]; %#ok<AGROW> %yes, add to list
0192         end
0193     else %no CData, see if object has any interesting children
0194             hout = [hout; getCDataHandles(hh)]; %#ok<AGROW>
0195     end
0196 end
0197 
0198 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
0199 %% checkArgs -- Validate input arguments
0200 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
0201 
0202 function [h, nancolor] = checkArgs(args)
0203 % checkArgs  Validate input arguments to freezeColors
0204 
0205 nargs = length(args);
0206 error(nargchk(0,3,nargs,'struct'))
0207 
0208 %grab handle from first argument if we have an odd number of arguments
0209 if mod(nargs,2),
0210     h = args{1};
0211     if ~ishandle(h),
0212         error('JRI:freezeColors:checkArgs:invalidHandle',...
0213             'The first argument must be a valid graphics handle (to an axis)')
0214     end
0215     args{1} = [];
0216     nargs = nargs-1;
0217 else
0218     h = gca;
0219 end
0220 
0221 %set nancolor if that option was specified
0222 nancolor = [nan nan nan];
0223 if nargs == 2,
0224     if strcmpi(args{end-1},'nancolor'),
0225         nancolor = args{end};
0226         if ~all(size(nancolor)==[1 3]),
0227             error('JRI:freezeColors:checkArgs:badColorArgument',...
0228                 'nancolor must be [r g b] vector');
0229         end
0230         nancolor(nancolor>1) = 1; nancolor(nancolor<0) = 0;
0231     else
0232         error('JRI:freezeColors:checkArgs:unrecognizedOption',...
0233             'Unrecognized option (%s). Only ''nancolor'' is valid.',args{end-1})
0234     end
0235 end
0236 
0237

Generated on Wed 20-Sep-2023 04:00:50 by m2html © 2003