| wolffd@0 | 1 function som_trajectory(bmus,varargin) | 
| wolffd@0 | 2 | 
| wolffd@0 | 3 %SOM_TRAJECTORY Launch a "comet" trajectory visualization GUI. | 
| wolffd@0 | 4 % | 
| wolffd@0 | 5 %  som_show(sM,'umat','all') | 
| wolffd@0 | 6 %  bmus = som_bmus(sM,sD); | 
| wolffd@0 | 7 %  som_trajectory(bmus) | 
| wolffd@0 | 8 %  som_trajectory(bmus, 'data1', sD, 'trajsize', [12 6 3 1]') | 
| wolffd@0 | 9 %  som_trajectory(bmus, 'data1', sD.data(:,[1 2 3]), 'name1', {'fii' 'faa' 'foo'}) | 
| wolffd@0 | 10 % | 
| wolffd@0 | 11 % Input arguments ([]'s are optional): | 
| wolffd@0 | 12 %   bmus      (matrix) size Nx1, vector of BMUS | 
| wolffd@0 | 13 %   ['argID', (string) Other arguments can be given as 'argID', value | 
| wolffd@0 | 14 %    value]   (varies) pairs. See list below for valid values. | 
| wolffd@0 | 15 % | 
| wolffd@0 | 16 % NOTE: the GUI only works on a figure which has been made with SOM_SHOW. | 
| wolffd@0 | 17 % | 
| wolffd@0 | 18 % Here are the valid argument IDs (case insensitive) and associated values: | 
| wolffd@0 | 19 %  'color'      string 'xor' or ColorSpec, default: 'xor'. | 
| wolffd@0 | 20 %               (default: according to lattice as in som_cplane) | 
| wolffd@0 | 21 %  'TrajSize'   vector of size Nx1 to define the length of comet | 
| wolffd@0 | 22 %               (N) and size of the comet dots in points. | 
| wolffd@0 | 23 %               default: [16 12 10 8 6 4]' | 
| wolffd@0 | 24 %  'Data1'      SOM Toolbox data struct or matrix. The size of | 
| wolffd@0 | 25 %               data matrix (in data struct the field .data) is | 
| wolffd@0 | 26 %               Nxd, where N must be the same as the amount of | 
| wolffd@0 | 27 %               BMUS given in the first input argument 'bmus' | 
| wolffd@0 | 28 %               This data is shown in a new window in d subplots. | 
| wolffd@0 | 29 %               Default: BMU indices (first input argument) | 
| wolffd@0 | 30 %  'Name1'      cell array of d strings which contains names | 
| wolffd@0 | 31 %               for the components in 'Data1'. If 'Data1' is a SOM | 
| wolffd@0 | 32 %               Toolbox data struct, the existing component names | 
| wolffd@0 | 33 %               are overdone. | 
| wolffd@0 | 34 %  'Figure'     scalar that must be a handle to an existing figure | 
| wolffd@0 | 35 %               which has been made using SOM_SHOW function. | 
| wolffd@0 | 36 %               Default: current active figure (gcf). | 
| wolffd@0 | 37 % | 
| wolffd@0 | 38 % The following tools can be found in the 'Tools' -menu. | 
| wolffd@0 | 39 % | 
| wolffd@0 | 40 %  Remove Trajectory: removes trajectory from the map. | 
| wolffd@0 | 41 %  Dye Nodes        : opens GUI for selecting color for the nodes | 
| wolffd@0 | 42 %                     and points selected. | 
| wolffd@0 | 43 %  Clear Markers    : removes markers from map and data figure. | 
| wolffd@0 | 44 %  Save             : saves the current situation as a struct. | 
| wolffd@0 | 45 %  Load             : loads the struct from workspace and draws markers. | 
| wolffd@0 | 46 % | 
| wolffd@0 | 47 % Mouse operation | 
| wolffd@0 | 48 % | 
| wolffd@0 | 49 %  In data window: Left button is used to drag the operation point ruler | 
| wolffd@0 | 50 %                  if left button is on blank area, it starts | 
| wolffd@0 | 51 %  In map window : Left button starts a polygon; right button | 
| wolffd@0 | 52 %                  finishes; middle button toggles a unit. | 
| wolffd@0 | 53 % | 
| wolffd@0 | 54 % SOM_TRAJECTORY is an application for observing trajectory behavior. | 
| wolffd@0 | 55 % | 
| wolffd@0 | 56 % Using mouse the line in data figure can be dragged and the | 
| wolffd@0 | 57 % trajectory moves in the SOM SHOW figure. It is also possible to move | 
| wolffd@0 | 58 % trajectory by pressing keys '>' and '<' when mouse pointer is above | 
| wolffd@0 | 59 % data figure. | 
| wolffd@0 | 60 % | 
| wolffd@0 | 61 % Regions can be chosen from the data and the points in that region | 
| wolffd@0 | 62 % are mapped to the component planes. Regions can be chosen also in | 
| wolffd@0 | 63 % the map.  In this situation data points and map nodes are also | 
| wolffd@0 | 64 % marked (Left mouse button adds point to the polygon indicating the | 
| wolffd@0 | 65 % region and right button finals the polygon). By clicking a node (the | 
| wolffd@0 | 66 % middle button) that node is either added or removed from selection. | 
| wolffd@0 | 67 % | 
| wolffd@0 | 68 % It should be noticed that choosing intervals from data may cause | 
| wolffd@0 | 69 % situations that seem to be bugs. If there exisist marks of different | 
| wolffd@0 | 70 % color, removing them by clicking the map may left some marks in the | 
| wolffd@0 | 71 % data, because more than one point in the data is mapped to the same | 
| wolffd@0 | 72 % node in the map and the removing operation depends on the color of | 
| wolffd@0 | 73 % the marks. However, all the marks can be removed by using the 'Clear | 
| wolffd@0 | 74 % Markers' -operation. | 
| wolffd@0 | 75 % | 
| wolffd@0 | 76 % FEATURES | 
| wolffd@0 | 77 % | 
| wolffd@0 | 78 % The first input argument 'bmus' may also be a munits x N matrix | 
| wolffd@0 | 79 % In this case each column defines a "fuzzy response". That is, | 
| wolffd@0 | 80 % each column defines a hit histogram function). The element | 
| wolffd@0 | 81 % bmus(i,t) sets the size of marker on unit i at time t. | 
| wolffd@0 | 82 % NOTE: - in this case no regions can be selcted on the map! | 
| wolffd@0 | 83 %       - only > and < keys can be used to move the operation point | 
| wolffd@0 | 84 %         line: it can't be dragged | 
| wolffd@0 | 85 %       - "fuzzy response is always black (hope this will be fixed) | 
| wolffd@0 | 86 % | 
| wolffd@0 | 87 % It is possible to open a second data window showing different data: | 
| wolffd@0 | 88 % use indetifiers 'Data2' (and 'Name2'). The argument syntax is | 
| wolffd@0 | 89 % identical to 'Data1' (and 'Name1'). | 
| wolffd@0 | 90 % | 
| wolffd@0 | 91 % See also SOM_SHOW, SOM_SHOW_ADD, SOM_BMUS. | 
| wolffd@0 | 92 | 
| wolffd@0 | 93 % Contributed to SOM Toolbox 2.0, February 11th, 2000 by Johan | 
| wolffd@0 | 94 % Himberg and Juha Parhankangas | 
| wolffd@0 | 95 % Copyright (c) 2000 by the Johan Himberg and Juha Parhankangas | 
| wolffd@0 | 96 % http://www.cis.hut.fi/projects/somtoolbox/ | 
| wolffd@0 | 97 | 
| wolffd@0 | 98 % Check arguments | 
| wolffd@0 | 99 | 
| wolffd@0 | 100 error(nargchk(1,Inf,nargin)); % Check no. of input arguments | 
| wolffd@0 | 101 | 
| wolffd@0 | 102 %% Init input argument struct (see subfunction) | 
| wolffd@0 | 103 Traj=iniTraj(bmus); | 
| wolffd@0 | 104 | 
| wolffd@0 | 105 % Check tentative BMU input validity | 
| wolffd@0 | 106 | 
| wolffd@0 | 107 if ~vis_valuetype(bmus,{'nxm'}), | 
| wolffd@0 | 108   error(['First input should be a vector of BMU indices or' ... | 
| wolffd@0 | 109 	 ' a "response matrix"']); | 
| wolffd@0 | 110 end | 
| wolffd@0 | 111 | 
| wolffd@0 | 112 %% Check optional arguments | 
| wolffd@0 | 113 for i=1:2:length(varargin) | 
| wolffd@0 | 114   identifier=lower(varargin{i}); | 
| wolffd@0 | 115   value=varargin{i+1}; | 
| wolffd@0 | 116 | 
| wolffd@0 | 117   % Trajectory color | 
| wolffd@0 | 118   switch identifier | 
| wolffd@0 | 119    case 'color' | 
| wolffd@0 | 120     if isempty(value) | 
| wolffd@0 | 121       value='xor'; | 
| wolffd@0 | 122     end | 
| wolffd@0 | 123     if vis_valuetype(value,{'colorstyle','xor'}) | 
| wolffd@0 | 124       Traj.color=value; | 
| wolffd@0 | 125     else | 
| wolffd@0 | 126       error('''Color'' has to be ColorSpec or string ''xor''.'); | 
| wolffd@0 | 127     end | 
| wolffd@0 | 128 | 
| wolffd@0 | 129    % 1st data | 
| wolffd@0 | 130    case 'data1' | 
| wolffd@0 | 131     if isempty(value), | 
| wolffd@0 | 132       value=[]; | 
| wolffd@0 | 133     elseif vis_valuetype(value,{'nxm'}) | 
| wolffd@0 | 134       Traj.primary_data=value; | 
| wolffd@0 | 135     elseif isstruct(value) & isfield(value,'type') & ... | 
| wolffd@0 | 136 	  ischar(value.type) & strcmp(value.type,'som_data'), | 
| wolffd@0 | 137       Traj.primary_data=value.data; | 
| wolffd@0 | 138       if isempty(Traj.primary_names), | 
| wolffd@0 | 139 	Traj.primary_names=value.comp_names; | 
| wolffd@0 | 140       end | 
| wolffd@0 | 141     end | 
| wolffd@0 | 142 | 
| wolffd@0 | 143     % 2nd data | 
| wolffd@0 | 144    case 'data2' | 
| wolffd@0 | 145     if isempty(value), | 
| wolffd@0 | 146       value=[]; | 
| wolffd@0 | 147     elseif vis_valuetype(value,{'nxm'}) | 
| wolffd@0 | 148       Traj.secondary_data=value; | 
| wolffd@0 | 149     elseif isstruct(value) & isfield(value,'type') & ... | 
| wolffd@0 | 150 	  ischar(value.type) & strcmp(value.type,'som_data'), | 
| wolffd@0 | 151       Traj.secondary_data=value.data; | 
| wolffd@0 | 152       if isempty(Traj.secondary_names), | 
| wolffd@0 | 153 	Traj.secondary_names=value.comp_names; | 
| wolffd@0 | 154       end | 
| wolffd@0 | 155      end | 
| wolffd@0 | 156 | 
| wolffd@0 | 157    % Trajectory length & size | 
| wolffd@0 | 158    case 'trajsize' | 
| wolffd@0 | 159     if isempty(value), | 
| wolffd@0 | 160       Traj.size=[16 12 10 8 6 4]'; | 
| wolffd@0 | 161     end | 
| wolffd@0 | 162     if vis_valuetype(value,{'nx1'}) | 
| wolffd@0 | 163       Traj.size=value | 
| wolffd@0 | 164     else | 
| wolffd@0 | 165       error('''TrajSize'' has to be a nx1 vector.'); | 
| wolffd@0 | 166     end | 
| wolffd@0 | 167 | 
| wolffd@0 | 168    % Names for first data variables | 
| wolffd@0 | 169    case 'name1' | 
| wolffd@0 | 170     if isempty(value), | 
| wolffd@0 | 171       Traj.primary_names=[]; | 
| wolffd@0 | 172     elseif ~vis_valuetype(value,{'cellcolumn_of_char'}), | 
| wolffd@0 | 173       error('''Name1'': variable names must be in a cell column array.') | 
| wolffd@0 | 174     else | 
| wolffd@0 | 175       Traj.primary_names = value; | 
| wolffd@0 | 176     end | 
| wolffd@0 | 177    % Names for 2nd data variables | 
| wolffd@0 | 178    case 'name2' | 
| wolffd@0 | 179     if isempty(value), | 
| wolffd@0 | 180       Traj.secondary_names=[]; | 
| wolffd@0 | 181     elseif ~vis_valuetype(value,{'cellcolumn_of_char'}), | 
| wolffd@0 | 182       error('''Name2'': variable names must be in a cell column array.') | 
| wolffd@0 | 183     else | 
| wolffd@0 | 184       Traj.secondary_names = value; | 
| wolffd@0 | 185     end | 
| wolffd@0 | 186 | 
| wolffd@0 | 187    % Figure number | 
| wolffd@0 | 188    case 'figure' | 
| wolffd@0 | 189     if isempty(value) | 
| wolffd@0 | 190       Traj.figure='gcf'; | 
| wolffd@0 | 191     end | 
| wolffd@0 | 192     if vis_valuetype(value,{'1x1'}) | 
| wolffd@0 | 193       Traj.figure=value; | 
| wolffd@0 | 194     else | 
| wolffd@0 | 195       error('''Figure'' should be number of an existing figure.') | 
| wolffd@0 | 196     end | 
| wolffd@0 | 197   end | 
| wolffd@0 | 198 end | 
| wolffd@0 | 199 | 
| wolffd@0 | 200 %% Get SOM data from figure | 
| wolffd@0 | 201 [h,msg,lattice,msize,dim]=vis_som_show_data('all',Traj.figure); | 
| wolffd@0 | 202 | 
| wolffd@0 | 203 %% Not a SOM_SHOW figure? | 
| wolffd@0 | 204 if ~isempty(msg); | 
| wolffd@0 | 205   error('Figure is invalid: use SOM_SHOW to draw the figure.'); | 
| wolffd@0 | 206 end | 
| wolffd@0 | 207 | 
| wolffd@0 | 208 % Get map size from figure data | 
| wolffd@0 | 209 Traj.lattice=lattice; | 
| wolffd@0 | 210 Traj.msize=msize; | 
| wolffd@0 | 211 if length(msize)>2, | 
| wolffd@0 | 212   error(['This function works only with 2D maps: figure contains' ... | 
| wolffd@0 | 213 	 ' something else.']); | 
| wolffd@0 | 214 end | 
| wolffd@0 | 215 munits=prod(msize); | 
| wolffd@0 | 216 | 
| wolffd@0 | 217 % Check BMU (or response) and map match | 
| wolffd@0 | 218 | 
| wolffd@0 | 219 if vis_valuetype(bmus,{'nx1'}); | 
| wolffd@0 | 220   if max(bmus)>prod(msize) | min(bmus) <1 | 
| wolffd@0 | 221     error('BMU indexes out of range.') | 
| wolffd@0 | 222   elseif any(round(bmus)~=bmus) | 
| wolffd@0 | 223     error('BMU indexes must be integer.'); | 
| wolffd@0 | 224   elseif isempty(Traj.primary_data), | 
| wolffd@0 | 225     Traj.primary_data=bmus; | 
| wolffd@0 | 226   end | 
| wolffd@0 | 227 elseif size(bmus,1) ~= munits | 
| wolffd@0 | 228   error(['Response matrix column number must match with the number of' ... | 
| wolffd@0 | 229 	 ' map units.']); | 
| wolffd@0 | 230 else | 
| wolffd@0 | 231   bmus=bmus'; | 
| wolffd@0 | 232   if isempty(Traj.primary_data), | 
| wolffd@0 | 233     Traj.primary_data=[1:size(bmus,1)]'; | 
| wolffd@0 | 234     Traj.primary_names={'BMU Index'}; | 
| wolffd@0 | 235   end | 
| wolffd@0 | 236 end | 
| wolffd@0 | 237 | 
| wolffd@0 | 238 size1=size(Traj.primary_data); | 
| wolffd@0 | 239 size2=size(Traj.secondary_data); | 
| wolffd@0 | 240 | 
| wolffd@0 | 241 % Data2 must not be defined alone | 
| wolffd@0 | 242 | 
| wolffd@0 | 243 if isempty(Traj.primary_data)&~isempty(Traj.secondary_data), | 
| wolffd@0 | 244   error('If ''Data2'' is specified ''Data1'' must be specified, too.'); | 
| wolffd@0 | 245 elseif ~isempty(Traj.secondary_data) ... | 
| wolffd@0 | 246       & size1~= size2 | 
| wolffd@0 | 247   % If data1 and data2 exist both, check data1 and data2 match | 
| wolffd@0 | 248   error('''Data1'' and ''Data2'' have different amount of data vectors.') | 
| wolffd@0 | 249 end | 
| wolffd@0 | 250 | 
| wolffd@0 | 251 % Check BMU and data1 match (data2 matches with 1 anyway) | 
| wolffd@0 | 252 | 
| wolffd@0 | 253 if ~isempty(Traj.primary_data) & size(bmus,1) ~= size1, | 
| wolffd@0 | 254   error(['The number of data vectors in ''data1'' must match with' ... | 
| wolffd@0 | 255 	 ' the number of rows in the first input argument (bmus).']); | 
| wolffd@0 | 256 end | 
| wolffd@0 | 257 | 
| wolffd@0 | 258 % Check that number of names and data dimension is consistent | 
| wolffd@0 | 259 | 
| wolffd@0 | 260 if ~isempty(Traj.primary_names) & (size1(2)~=length(Traj.primary_names)), | 
| wolffd@0 | 261   error('Number of component names and ''Data1'' dimension mismatch.'); | 
| wolffd@0 | 262 end | 
| wolffd@0 | 263 if ~isempty(Traj.secondary_names) & ... | 
| wolffd@0 | 264       (size2(2)~=length(Traj.secondary_names)), | 
| wolffd@0 | 265   error('Number of component names and ''Data2'' dimension mismatch.'); | 
| wolffd@0 | 266 end | 
| wolffd@0 | 267 | 
| wolffd@0 | 268 %% Call the function that does the job | 
| wolffd@0 | 269 vis_trajgui(Traj); | 
| wolffd@0 | 270 | 
| wolffd@0 | 271 %%% Subfunctions %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | 
| wolffd@0 | 272 | 
| wolffd@0 | 273 function Traj=iniTraj(bmus) | 
| wolffd@0 | 274 | 
| wolffd@0 | 275 Traj.figure=gcf; | 
| wolffd@0 | 276 Traj.primary_data=[]; | 
| wolffd@0 | 277 Traj.secondary_data=[]; | 
| wolffd@0 | 278 Traj.primary_names = []; | 
| wolffd@0 | 279 Traj.secondary_names = []; | 
| wolffd@0 | 280 Traj.size=[16 12 10 8 6 4]'; | 
| wolffd@0 | 281 Traj.bmus=bmus; | 
| wolffd@0 | 282 Traj.color='xor'; | 
| wolffd@0 | 283 Traj.msize=[]; | 
| wolffd@0 | 284 Traj.lattice=[]; | 
| wolffd@0 | 285 |