wolffd@0: function Coords = som_unit_coords(topol,lattice,shape) wolffd@0: wolffd@0: %SOM_UNIT_COORDS Locations of units on the SOM grid. wolffd@0: % wolffd@0: % Co = som_unit_coords(topol, [lattice], [shape]) wolffd@0: % wolffd@0: % Co = som_unit_coords(sMap); wolffd@0: % Co = som_unit_coords(sMap.topol); wolffd@0: % Co = som_unit_coords(msize, 'hexa', 'cyl'); wolffd@0: % Co = som_unit_coords([10 4 4], 'rect', 'toroid'); wolffd@0: % wolffd@0: % Input and output arguments ([]'s are optional): wolffd@0: % topol topology of the SOM grid wolffd@0: % (struct) topology or map struct wolffd@0: % (vector) the 'msize' field of topology struct wolffd@0: % [lattice] (string) map lattice, 'rect' by default wolffd@0: % [shape] (string) map shape, 'sheet' by default wolffd@0: % wolffd@0: % Co (matrix, size [munits k]) coordinates for each map unit wolffd@0: % wolffd@0: % For more help, try 'type som_unit_coords' or check out online documentation. wolffd@0: % See also SOM_UNIT_DISTS, SOM_UNIT_NEIGHS. wolffd@0: wolffd@0: %%%%%%%%%%%%% DETAILED DESCRIPTION %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% wolffd@0: % wolffd@0: % som_unit_coords wolffd@0: % wolffd@0: % PURPOSE wolffd@0: % wolffd@0: % Returns map grid coordinates for the units of a Self-Organizing Map. wolffd@0: % wolffd@0: % SYNTAX wolffd@0: % wolffd@0: % Co = som_unit_coords(sTopol); wolffd@0: % Co = som_unit_coords(sM.topol); wolffd@0: % Co = som_unit_coords(msize); wolffd@0: % Co = som_unit_coords(msize,'hexa'); wolffd@0: % Co = som_unit_coords(msize,'rect','toroid'); wolffd@0: % wolffd@0: % DESCRIPTION wolffd@0: % wolffd@0: % Calculates the map grid coordinates of the units of a SOM based on wolffd@0: % the given topology. The coordinates are such that they can be used to wolffd@0: % position map units in space. In case of 'sheet' shape they can be wolffd@0: % (and are) used to measure interunit distances. wolffd@0: % wolffd@0: % NOTE: for 'hexa' lattice, the x-coordinates of every other row are shifted wolffd@0: % by +0.5, and the y-coordinates are multiplied by sqrt(0.75). This is done wolffd@0: % to make distances of a unit to all its six neighbors equal. It is not wolffd@0: % possible to use 'hexa' lattice with higher than 2-dimensional map grids. wolffd@0: % wolffd@0: % 'cyl' and 'toroid' shapes: the coordinates are initially determined as wolffd@0: % in case of 'sheet' shape, but are then bended around the x- or the wolffd@0: % x- and then y-axes to get the desired shape. wolffd@0: % wolffd@0: % POSSIBLE BUGS wolffd@0: % wolffd@0: % I don't know if the bending operation works ok for high-dimensional wolffd@0: % map grids. Anyway, if anyone wants to make a 4-dimensional wolffd@0: % toroid map, (s)he deserves it. wolffd@0: % wolffd@0: % REQUIRED INPUT ARGUMENTS wolffd@0: % wolffd@0: % topol Map grid dimensions. wolffd@0: % (struct) topology struct or map struct, the topology wolffd@0: % (msize, lattice, shape) of the map is taken from wolffd@0: % the appropriate fields (see e.g. SOM_SET) wolffd@0: % (vector) the vector which gives the size of the map grid wolffd@0: % (msize-field of the topology struct). wolffd@0: % wolffd@0: % OPTIONAL INPUT ARGUMENTS wolffd@0: % wolffd@0: % lattice (string) The map lattice, either 'rect' or 'hexa'. Default wolffd@0: % is 'rect'. 'hexa' can only be used with 1- or wolffd@0: % 2-dimensional map grids. wolffd@0: % shape (string) The map shape, either 'sheet', 'cyl' or 'toroid'. wolffd@0: % Default is 'sheet'. wolffd@0: % wolffd@0: % OUTPUT ARGUMENTS wolffd@0: % wolffd@0: % Co (matrix) coordinates for each map units, size is [munits k] wolffd@0: % where k is 2, or more if the map grid is higher wolffd@0: % dimensional or the shape is 'cyl' or 'toroid' wolffd@0: % wolffd@0: % EXAMPLES wolffd@0: % wolffd@0: % Simplest case: wolffd@0: % Co = som_unit_coords(sTopol); wolffd@0: % Co = som_unit_coords(sMap.topol); wolffd@0: % Co = som_unit_coords(msize); wolffd@0: % Co = som_unit_coords([10 10]); wolffd@0: % wolffd@0: % If topology is given as vector, lattice is 'rect' and shape is 'sheet' wolffd@0: % by default. To change these, you can use the optional arguments: wolffd@0: % Co = som_unit_coords(msize, 'hexa', 'toroid'); wolffd@0: % wolffd@0: % The coordinates can also be calculated for high-dimensional grids: wolffd@0: % Co = som_unit_coords([4 4 4 4 4 4]); wolffd@0: % wolffd@0: % SEE ALSO wolffd@0: % wolffd@0: % som_unit_dists Calculate interunit distance along the map grid. wolffd@0: % som_unit_neighs Calculate neighborhoods of map units. wolffd@0: wolffd@0: % Copyright (c) 1997-2000 by the SOM toolbox programming team. wolffd@0: % http://www.cis.hut.fi/projects/somtoolbox/ wolffd@0: wolffd@0: % Version 1.0beta juuso 110997 wolffd@0: % Version 2.0beta juuso 101199 070600 wolffd@0: wolffd@0: %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% wolffd@0: %% Check arguments wolffd@0: wolffd@0: error(nargchk(1, 3, nargin)); wolffd@0: wolffd@0: % default values wolffd@0: sTopol = som_set('som_topol','lattice','rect'); wolffd@0: wolffd@0: % topol wolffd@0: if isstruct(topol), wolffd@0: switch topol.type, wolffd@0: case 'som_map', sTopol = topol.topol; wolffd@0: case 'som_topol', sTopol = topol; wolffd@0: end wolffd@0: elseif iscell(topol), wolffd@0: for i=1:length(topol), wolffd@0: if isnumeric(topol{i}), sTopol.msize = topol{i}; wolffd@0: elseif ischar(topol{i}), wolffd@0: switch topol{i}, wolffd@0: case {'rect','hexa'}, sTopol.lattice = topol{i}; wolffd@0: case {'sheet','cyl','toroid'}, sTopol.shape = topol{i}; wolffd@0: end wolffd@0: end wolffd@0: end wolffd@0: else wolffd@0: sTopol.msize = topol; wolffd@0: end wolffd@0: if prod(sTopol.msize)==0, error('Map size is 0.'); end wolffd@0: wolffd@0: % lattice wolffd@0: if nargin>1 & ~isempty(lattice) & ~isnan(lattice), sTopol.lattice = lattice; end wolffd@0: wolffd@0: % shape wolffd@0: if nargin>2 & ~isempty(shape) & ~isnan(shape), sTopol.shape = shape; end wolffd@0: wolffd@0: %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% wolffd@0: %% Action wolffd@0: wolffd@0: msize = sTopol.msize; wolffd@0: lattice = sTopol.lattice; wolffd@0: shape = sTopol.shape; wolffd@0: wolffd@0: % init variables wolffd@0: wolffd@0: if length(msize)==1, msize = [msize 1]; end wolffd@0: munits = prod(msize); wolffd@0: mdim = length(msize); wolffd@0: Coords = zeros(munits,mdim); wolffd@0: wolffd@0: % initial coordinates for each map unit ('rect' lattice, 'sheet' shape) wolffd@0: k = [1 cumprod(msize(1:end-1))]; wolffd@0: inds = [0:(munits-1)]'; wolffd@0: for i = mdim:-1:1, wolffd@0: Coords(:,i) = floor(inds/k(i)); % these are subscripts in matrix-notation wolffd@0: inds = rem(inds,k(i)); wolffd@0: end wolffd@0: % change subscripts to coordinates (move from (ij)-notation to (xy)-notation) wolffd@0: Coords(:,[1 2]) = fliplr(Coords(:,[1 2])); wolffd@0: wolffd@0: % 'hexa' lattice wolffd@0: if strcmp(lattice,'hexa'), wolffd@0: % check wolffd@0: if mdim > 2, wolffd@0: error('You can only use hexa lattice with 1- or 2-dimensional maps.'); wolffd@0: end wolffd@0: % offset x-coordinates of every other row wolffd@0: inds_for_row = (cumsum(ones(msize(2),1))-1)*msize(1); wolffd@0: for i=2:2:msize(1), wolffd@0: Coords(i+inds_for_row,1) = Coords(i+inds_for_row,1) + 0.5; wolffd@0: end wolffd@0: end wolffd@0: wolffd@0: % shapes wolffd@0: switch shape, wolffd@0: case 'sheet', wolffd@0: if strcmp(lattice,'hexa'), wolffd@0: % this correction is made to make distances to all wolffd@0: % neighboring units equal wolffd@0: Coords(:,2) = Coords(:,2)*sqrt(0.75); wolffd@0: end wolffd@0: wolffd@0: case 'cyl', wolffd@0: % to make cylinder the coordinates must lie in 3D space, at least wolffd@0: if mdim<3, Coords = [Coords ones(munits,1)]; mdim = 3; end wolffd@0: wolffd@0: % Bend the coordinates to a circle in the plane formed by x- and wolffd@0: % and z-axis. Notice that the angle to which the last coordinates wolffd@0: % are bended is _not_ 360 degrees, because that would be equal to wolffd@0: % the angle of the first coordinates (0 degrees). wolffd@0: wolffd@0: Coords(:,1) = Coords(:,1)/max(Coords(:,1)); wolffd@0: Coords(:,1) = 2*pi * Coords(:,1) * msize(2)/(msize(2)+1); wolffd@0: Coords(:,[1 3]) = [cos(Coords(:,1)) sin(Coords(:,1))]; wolffd@0: wolffd@0: case 'toroid', wolffd@0: wolffd@0: % NOTE: if lattice is 'hexa', the msize(1) should be even, otherwise wolffd@0: % the bending the upper and lower edges of the map do not match wolffd@0: % to each other wolffd@0: if strcmp(lattice,'hexa') & rem(msize(1),2)==1, wolffd@0: warning('Map size along y-coordinate is not even.'); wolffd@0: end wolffd@0: wolffd@0: % to make toroid the coordinates must lie in 3D space, at least wolffd@0: if mdim<3, Coords = [Coords ones(munits,1)]; mdim = 3; end wolffd@0: wolffd@0: % First bend the coordinates to a circle in the plane formed wolffd@0: % by x- and z-axis. Then bend in the plane formed by y- and wolffd@0: % z-axis. (See also the notes in 'cyl'). wolffd@0: wolffd@0: Coords(:,1) = Coords(:,1)/max(Coords(:,1)); wolffd@0: Coords(:,1) = 2*pi * Coords(:,1) * msize(2)/(msize(2)+1); wolffd@0: Coords(:,[1 3]) = [cos(Coords(:,1)) sin(Coords(:,1))]; wolffd@0: wolffd@0: Coords(:,2) = Coords(:,2)/max(Coords(:,2)); wolffd@0: Coords(:,2) = 2*pi * Coords(:,2) * msize(1)/(msize(1)+1); wolffd@0: Coords(:,3) = Coords(:,3) - min(Coords(:,3)) + 1; wolffd@0: Coords(:,[2 3]) = Coords(:,[3 3]) .* [cos(Coords(:,2)) sin(Coords(:,2))]; wolffd@0: wolffd@0: end wolffd@0: wolffd@0: return; wolffd@0: wolffd@0: %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% wolffd@0: %% subfunctions wolffd@0: wolffd@0: function C = bend(cx,cy,angle,xishexa) wolffd@0: wolffd@0: dx = max(cx) - min(cx); wolffd@0: if dx ~= 0, wolffd@0: % in case of hexagonal lattice it must be taken into account that wolffd@0: % coordinates of every second row are +0.5 off to the right wolffd@0: if xishexa, dx = dx-0.5; end wolffd@0: cx = angle*(cx - min(cx))/dx; wolffd@0: end wolffd@0: C(:,1) = (cy - min(cy)+1) .* cos(cx); wolffd@0: C(:,2) = (cy - min(cy)+1) .* sin(cx); wolffd@0: wolffd@0: % end of bend wolffd@0: wolffd@0: %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% wolffd@0: