Daniel@0: function colors=som_colorcode(m, colorcode, scaling) Daniel@0: Daniel@0: %SOM_COLORCODE Calculates a heuristic color coding for the SOM grid Daniel@0: % Daniel@0: % colors = som_colorcode(m, colorcode, scaling) Daniel@0: % Daniel@0: % Input and output arguments ([]'s are optional): Daniel@0: % m (struct) map or topol struct Daniel@0: % (cell array) of form {str,[m1 m2]} where Daniel@0: % str = 'hexa' or 'rect' and [m1 m2] = msize Daniel@0: % (matrix) size N x 2, unit coordinates Daniel@0: % [colorcode] (string) 'rgb1' (default),'rgb2','rgb3','rgb4','hsv' Daniel@0: % [scaling] (scalar) 1=on (default), 0=off. Has effect only Daniel@0: % if m is a Nx2 matrix of coordinates: Daniel@0: % controls whether these are scaled to Daniel@0: % range [0,1] or not. Daniel@0: % Daniel@0: % colors (matrix) size N x 3, RGB colors for each unit (or point) Daniel@0: % Daniel@0: % The function gives a color coding by location for the map grid Daniel@0: % (or arbitrary set of points). Map grid coordinates are always linearly Daniel@0: % normalized to a unit square (x and y coordinates between [0,1]), except Daniel@0: % if m is a Nx2 matrix and scaling=0. In that case too, the coordinates Daniel@0: % must be in range [0,1]. Daniel@0: % Daniel@0: % Following heuristic color codings are available: Daniel@0: % Daniel@0: % 'rgb1' slice of RGB-cube so that green - yellow Daniel@0: % the corners have colors: | | Daniel@0: % blue - magenta Daniel@0: % Daniel@0: % 'rgb2' slice of RGB-cube so that red - yellow Daniel@0: % the corners have colors: | | Daniel@0: % blue - cyan Daniel@0: % Daniel@0: % 'rgb3' slice of RGB-cube so that mixed_green - orange Daniel@0: % the corners have colors: | | Daniel@0: % light_blue - pink Daniel@0: % Daniel@0: % 'rgb4' has 'rgb1' on the diagonal + additional colors in corners Daniel@0: % (more resolution but visually strongly discontinuous) Daniel@0: % Daniel@0: % 'hsv' angle and radius from map centre are coded by hue and Daniel@0: % intensity (more resoluton but visually discontinuous) Daniel@0: % Daniel@0: % See also SOM_CPLANE, SOM_SHOW, SOM_CLUSTERCOLOR, SOM_KMEANSCOLOR, Daniel@0: % SOM_BMUCOLOR. Daniel@0: Daniel@0: % Contributed to SOM Toolbox 2.0, February 11th, 2000 by Johan Himberg Daniel@0: % Copyright (c) by Johan Himberg Daniel@0: % http://www.cis.hut.fi/projects/somtoolbox/ Daniel@0: Daniel@0: % Version 2.0 Johan 140799 Daniel@0: Daniel@0: %%% Check arguments %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Daniel@0: Daniel@0: error(nargchk(1, 3, nargin)); % check no. of input args is correct Daniel@0: Daniel@0: %% Check m: map, topol, cell or data? Daniel@0: Daniel@0: if vis_valuetype(m,{'nx2'}), Daniel@0: p=m; % explicit coordinates Daniel@0: Daniel@0: else Daniel@0: Daniel@0: % map, topol, cell Daniel@0: Daniel@0: [tmp,ok,tmp]=som_set(m); Daniel@0: if isstruct(m) & all(ok) Daniel@0: switch m.type Daniel@0: case 'som_topol' % topol Daniel@0: msize=m.msize; Daniel@0: lattice=m.lattice; Daniel@0: case 'som_map' Daniel@0: msize=m.topol.msize; % map Daniel@0: lattice=m.topol.lattice; Daniel@0: otherwise Daniel@0: error('Invalid map or topol struct.'); Daniel@0: end Daniel@0: Daniel@0: % cell Daniel@0: Daniel@0: elseif iscell(m) & vis_valuetype(size(m),{[1 2]}), Daniel@0: if vis_valuetype(m{2},{[1 2]}) & vis_valuetype(m{1},{'string'}), Daniel@0: lattice=m{1}; Daniel@0: msize=m{2}; Daniel@0: else Daniel@0: error('Invalid map size information.'); Daniel@0: end Daniel@0: end Daniel@0: Daniel@0: %% Check map parameters Daniel@0: Daniel@0: switch lattice % lattice Daniel@0: case 'hexa' Daniel@0: ; Daniel@0: case 'rect' Daniel@0: ; Daniel@0: otherwise Daniel@0: error('Unknown lattice type'); Daniel@0: end Daniel@0: Daniel@0: if length(msize)>2 % dimension Daniel@0: error('Only 2D maps allowed!'); Daniel@0: end Daniel@0: Daniel@0: Daniel@0: % Calculate coordinates Daniel@0: p=som_unit_coords(msize,lattice,'sheet'); Daniel@0: Daniel@0: % Set scaling to 1 as it is done always in this case Daniel@0: scaling=1; Daniel@0: end Daniel@0: Daniel@0: % Check colorcode Daniel@0: Daniel@0: if nargin < 2 | isempty(colorcode), Daniel@0: colorcode='rgb1'; Daniel@0: end Daniel@0: if ~ischar(colorcode) Daniel@0: error('String value for colorcode mode expected.'); Daniel@0: else Daniel@0: switch colorcode Daniel@0: case { 'rgb1', 'rgb2', 'rgb3' , 'rgb4' ,'hsv'} Daniel@0: otherwise Daniel@0: error([ 'Colorcode mode ' colorcode ' not implemented.']); Daniel@0: end Daniel@0: end Daniel@0: Daniel@0: % Check scaling Daniel@0: Daniel@0: if nargin < 3 | isempty(scaling) Daniel@0: scaling=1; Daniel@0: end Daniel@0: Daniel@0: if ~vis_valuetype(scaling,{'1x1'}) Daniel@0: error('Scaling should be 0 (off) or 1 (on).'); Daniel@0: end Daniel@0: Daniel@0: %% Action %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Daniel@0: Daniel@0: % scale coordintes between [0,1] Daniel@0: Daniel@0: if scaling Daniel@0: n=size(p,1); Daniel@0: mn=min(p); Daniel@0: e=max(p)-mn; Daniel@0: p=(p-repmat(mn,n,1))./repmat(e,n,1); Daniel@0: elseif sum(p(:,1)>1+p(:,1)<0+p(:,2)>1+p(:,2)<0), Daniel@0: error('Coordinates out of range [0,1].'); Daniel@0: end Daniel@0: Daniel@0: switch colorcode Daniel@0: case 'rgb1' Daniel@0: h(:,1)=p(:,1); Daniel@0: h(:,2)=1-p(:,2); Daniel@0: h(:,3)=p(:,2); Daniel@0: case 'rgb2' Daniel@0: h(:,1)=p(:,1); Daniel@0: h(:,2)=1-p(:,2); Daniel@0: h(:,3)=1-p(:,1); Daniel@0: case 'rgb3' Daniel@0: h(:,1)=p(:,1); Daniel@0: h(:,2)=.5; Daniel@0: h(:,3)=p(:,2); Daniel@0: case 'rgb4' Daniel@0: p=rgb4(p); Daniel@0: h(:,1)=p(:,1); Daniel@0: h(:,2)=1-p(:,2); Daniel@0: h(:,3)=p(:,3); Daniel@0: case 'hsv' Daniel@0: munits = n; Daniel@0: Hsv = zeros(munits,3); Daniel@0: for i=1:n, Daniel@0: dx = .5-p(i,1); Daniel@0: dy = .5-p(i,2); Daniel@0: r = sqrt(dx^2+dy^2); Daniel@0: if r==0, Daniel@0: h=1; Daniel@0: elseif dx==0, Daniel@0: h=.5; %h=ay; Daniel@0: elseif dy==0, Daniel@0: h=.5; %h=ax; Daniel@0: else Daniel@0: h = min(abs(.5/(dx/r)),abs(.5/(dy/r))); Daniel@0: end Daniel@0: Daniel@0: if r==0, Daniel@0: angle = 0; Daniel@0: else Daniel@0: angle = acos(dx/r); Daniel@0: if dy<0, Daniel@0: angle = 2*pi-angle; Daniel@0: end Daniel@0: end Daniel@0: Daniel@0: Hsv(i,1) = 1-sin(angle/4); Daniel@0: Hsv(i,2) = 1; Daniel@0: Hsv(i,3) = r/h; Daniel@0: h = hsv2rgb(Hsv); Daniel@0: end Daniel@0: end Daniel@0: Daniel@0: Daniel@0: %% Build output %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Daniel@0: Daniel@0: colors=h; Daniel@0: Daniel@0: %% Subfunctions %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% juha %%%% Daniel@0: Daniel@0: function p=rgb4(coord) Daniel@0: Daniel@0: for i=1:size(coord,1); Daniel@0: p(i,:)=get_coords(coord(i,:))'; Daniel@0: end Daniel@0: Daniel@0: %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Daniel@0: Daniel@0: function coords=get_coords(coords) Daniel@0: Daniel@0: %GET_COORDS Daniel@0: % Daniel@0: % get_coords(coords) Daniel@0: % Daniel@0: % ARGUMENTS Daniel@0: % Daniel@0: % coords (1x2 or 2x1 vector) coords(1) is an x-coordinate and coords(2) Daniel@0: % y-coordinate. Daniel@0: % Daniel@0: % Daniel@0: % RETURNS Daniel@0: % Daniel@0: % coords (3x1 vector) x,y and z-coordinates. Daniel@0: % Daniel@0: Daniel@0: if ~(all(size(coords) == [1 2]) | all(size(coords) == [2 1])) Daniel@0: error('Argument ''coords'' must be an 2x1 or 1x2 vector.'); Daniel@0: end Daniel@0: Daniel@0: if all(size(coords) == [1 2]) Daniel@0: coords=coords'; Daniel@0: end Daniel@0: Daniel@0: if any(coords > 1) any(coords < 0) Daniel@0: error('Coordinates must lay inside the interval [0,1].'); Daniel@0: end Daniel@0: Daniel@0: if coords(1) <= 1/(sqrt(2)+1), Daniel@0: if coords(2) <= line3(coords(1)) Daniel@0: coords=coords_in_base(4,coords); Daniel@0: elseif coords(2) <= line2(coords(1)) Daniel@0: coords=coords_in_base(1,coords); Daniel@0: else Daniel@0: coords=coords_in_base(2,coords); Daniel@0: end Daniel@0: elseif coords(1) <= sqrt(2)/(sqrt(2)+1) Daniel@0: if coords(2) <= line1(coords(1)) Daniel@0: coords=coords_in_base(3,coords); Daniel@0: elseif coords(2) <= line2(coords(1)) Daniel@0: coords=coords_in_base(1,coords); Daniel@0: else Daniel@0: coords=coords_in_base(2,coords); Daniel@0: end Daniel@0: else Daniel@0: if coords(2) <= line1(coords(1)), Daniel@0: coords=coords_in_base(3,coords); Daniel@0: elseif coords(2) <= line4(coords(1)) Daniel@0: coords=coords_in_base(1,coords); Daniel@0: else Daniel@0: coords=coords_in_base(5,coords); Daniel@0: end Daniel@0: end Daniel@0: Daniel@0: Daniel@0: %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Daniel@0: Daniel@0: function coords=coords_in_base(base_no,coords) Daniel@0: Daniel@0: A=[0;1/(sqrt(2)+1)]; Daniel@0: E=[1;1]; Daniel@0: F=[0;0]; Daniel@0: G=[1;0]; Daniel@0: H=[0;1]; Daniel@0: Daniel@0: const=1+1/sqrt(2); Daniel@0: Daniel@0: switch base_no Daniel@0: case 1 Daniel@0: x=(coords-A)*const; Daniel@0: coords=[(1/sqrt(2))*(x(1)-x(2));0.5*(x(1)+x(2));0.5*(x(1)+x(2))]; Daniel@0: case 2 Daniel@0: x=(coords-H)*const; Daniel@0: coords=[0;x(1);1+x(2)]; Daniel@0: case 3 Daniel@0: x=(coords-G)*const; Daniel@0: coords=[1;1+x(1);x(2)]; Daniel@0: case 4 Daniel@0: x=(coords-F)*const; Daniel@0: coords=[0.5+(1/sqrt(2))*(x(1)-x(2));... Daniel@0: 0.5-(1/sqrt(2))*(x(1)+x(2));... Daniel@0: 0]; Daniel@0: case 5 Daniel@0: x=(coords-E)*const; Daniel@0: coords=[0.5+(1/sqrt(2))*(x(1)-x(2));... Daniel@0: 0.5-(1/sqrt(2))*(x(1)+x(2));... Daniel@0: 1]; Daniel@0: end Daniel@0: Daniel@0: %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Daniel@0: Daniel@0: function y=line1(x) Daniel@0: Daniel@0: y = x-1/(sqrt(2)+1); Daniel@0: Daniel@0: %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Daniel@0: Daniel@0: function y=line2(x) Daniel@0: Daniel@0: y = x+1/(sqrt(2)+1); Daniel@0: Daniel@0: %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Daniel@0: Daniel@0: function y=line3(x) Daniel@0: Daniel@0: y = -x+1/(sqrt(2)+1); Daniel@0: Daniel@0: %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Daniel@0: Daniel@0: function y= line4(x) Daniel@0: Daniel@0: y = -x+(2*sqrt(2)+1)/(sqrt(2)+1); Daniel@0: Daniel@0: %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%