wolffd@0: function som_trajectory(bmus,varargin) wolffd@0: wolffd@0: %SOM_TRAJECTORY Launch a "comet" trajectory visualization GUI. wolffd@0: % wolffd@0: % som_show(sM,'umat','all') wolffd@0: % bmus = som_bmus(sM,sD); wolffd@0: % som_trajectory(bmus) wolffd@0: % som_trajectory(bmus, 'data1', sD, 'trajsize', [12 6 3 1]') wolffd@0: % som_trajectory(bmus, 'data1', sD.data(:,[1 2 3]), 'name1', {'fii' 'faa' 'foo'}) wolffd@0: % wolffd@0: % Input arguments ([]'s are optional): wolffd@0: % bmus (matrix) size Nx1, vector of BMUS wolffd@0: % ['argID', (string) Other arguments can be given as 'argID', value wolffd@0: % value] (varies) pairs. See list below for valid values. wolffd@0: % wolffd@0: % NOTE: the GUI only works on a figure which has been made with SOM_SHOW. wolffd@0: % wolffd@0: % Here are the valid argument IDs (case insensitive) and associated values: wolffd@0: % 'color' string 'xor' or ColorSpec, default: 'xor'. wolffd@0: % (default: according to lattice as in som_cplane) wolffd@0: % 'TrajSize' vector of size Nx1 to define the length of comet wolffd@0: % (N) and size of the comet dots in points. wolffd@0: % default: [16 12 10 8 6 4]' wolffd@0: % 'Data1' SOM Toolbox data struct or matrix. The size of wolffd@0: % data matrix (in data struct the field .data) is wolffd@0: % Nxd, where N must be the same as the amount of wolffd@0: % BMUS given in the first input argument 'bmus' wolffd@0: % This data is shown in a new window in d subplots. wolffd@0: % Default: BMU indices (first input argument) wolffd@0: % 'Name1' cell array of d strings which contains names wolffd@0: % for the components in 'Data1'. If 'Data1' is a SOM wolffd@0: % Toolbox data struct, the existing component names wolffd@0: % are overdone. wolffd@0: % 'Figure' scalar that must be a handle to an existing figure wolffd@0: % which has been made using SOM_SHOW function. wolffd@0: % Default: current active figure (gcf). wolffd@0: % wolffd@0: % The following tools can be found in the 'Tools' -menu. wolffd@0: % wolffd@0: % Remove Trajectory: removes trajectory from the map. wolffd@0: % Dye Nodes : opens GUI for selecting color for the nodes wolffd@0: % and points selected. wolffd@0: % Clear Markers : removes markers from map and data figure. wolffd@0: % Save : saves the current situation as a struct. wolffd@0: % Load : loads the struct from workspace and draws markers. wolffd@0: % wolffd@0: % Mouse operation wolffd@0: % wolffd@0: % In data window: Left button is used to drag the operation point ruler wolffd@0: % if left button is on blank area, it starts wolffd@0: % In map window : Left button starts a polygon; right button wolffd@0: % finishes; middle button toggles a unit. wolffd@0: % wolffd@0: % SOM_TRAJECTORY is an application for observing trajectory behavior. wolffd@0: % wolffd@0: % Using mouse the line in data figure can be dragged and the wolffd@0: % trajectory moves in the SOM SHOW figure. It is also possible to move wolffd@0: % trajectory by pressing keys '>' and '<' when mouse pointer is above wolffd@0: % data figure. wolffd@0: % wolffd@0: % Regions can be chosen from the data and the points in that region wolffd@0: % are mapped to the component planes. Regions can be chosen also in wolffd@0: % the map. In this situation data points and map nodes are also wolffd@0: % marked (Left mouse button adds point to the polygon indicating the wolffd@0: % region and right button finals the polygon). By clicking a node (the wolffd@0: % middle button) that node is either added or removed from selection. wolffd@0: % wolffd@0: % It should be noticed that choosing intervals from data may cause wolffd@0: % situations that seem to be bugs. If there exisist marks of different wolffd@0: % color, removing them by clicking the map may left some marks in the wolffd@0: % data, because more than one point in the data is mapped to the same wolffd@0: % node in the map and the removing operation depends on the color of wolffd@0: % the marks. However, all the marks can be removed by using the 'Clear wolffd@0: % Markers' -operation. wolffd@0: % wolffd@0: % FEATURES wolffd@0: % wolffd@0: % The first input argument 'bmus' may also be a munits x N matrix wolffd@0: % In this case each column defines a "fuzzy response". That is, wolffd@0: % each column defines a hit histogram function). The element wolffd@0: % bmus(i,t) sets the size of marker on unit i at time t. wolffd@0: % NOTE: - in this case no regions can be selcted on the map! wolffd@0: % - only > and < keys can be used to move the operation point wolffd@0: % line: it can't be dragged wolffd@0: % - "fuzzy response is always black (hope this will be fixed) wolffd@0: % wolffd@0: % It is possible to open a second data window showing different data: wolffd@0: % use indetifiers 'Data2' (and 'Name2'). The argument syntax is wolffd@0: % identical to 'Data1' (and 'Name1'). wolffd@0: % wolffd@0: % See also SOM_SHOW, SOM_SHOW_ADD, SOM_BMUS. wolffd@0: wolffd@0: % Contributed to SOM Toolbox 2.0, February 11th, 2000 by Johan wolffd@0: % Himberg and Juha Parhankangas wolffd@0: % Copyright (c) 2000 by the Johan Himberg and Juha Parhankangas wolffd@0: % http://www.cis.hut.fi/projects/somtoolbox/ wolffd@0: wolffd@0: % Check arguments wolffd@0: wolffd@0: error(nargchk(1,Inf,nargin)); % Check no. of input arguments wolffd@0: wolffd@0: %% Init input argument struct (see subfunction) wolffd@0: Traj=iniTraj(bmus); wolffd@0: wolffd@0: % Check tentative BMU input validity wolffd@0: wolffd@0: if ~vis_valuetype(bmus,{'nxm'}), wolffd@0: error(['First input should be a vector of BMU indices or' ... wolffd@0: ' a "response matrix"']); wolffd@0: end wolffd@0: wolffd@0: %% Check optional arguments wolffd@0: for i=1:2:length(varargin) wolffd@0: identifier=lower(varargin{i}); wolffd@0: value=varargin{i+1}; wolffd@0: wolffd@0: % Trajectory color wolffd@0: switch identifier wolffd@0: case 'color' wolffd@0: if isempty(value) wolffd@0: value='xor'; wolffd@0: end wolffd@0: if vis_valuetype(value,{'colorstyle','xor'}) wolffd@0: Traj.color=value; wolffd@0: else wolffd@0: error('''Color'' has to be ColorSpec or string ''xor''.'); wolffd@0: end wolffd@0: wolffd@0: % 1st data wolffd@0: case 'data1' wolffd@0: if isempty(value), wolffd@0: value=[]; wolffd@0: elseif vis_valuetype(value,{'nxm'}) wolffd@0: Traj.primary_data=value; wolffd@0: elseif isstruct(value) & isfield(value,'type') & ... wolffd@0: ischar(value.type) & strcmp(value.type,'som_data'), wolffd@0: Traj.primary_data=value.data; wolffd@0: if isempty(Traj.primary_names), wolffd@0: Traj.primary_names=value.comp_names; wolffd@0: end wolffd@0: end wolffd@0: wolffd@0: % 2nd data wolffd@0: case 'data2' wolffd@0: if isempty(value), wolffd@0: value=[]; wolffd@0: elseif vis_valuetype(value,{'nxm'}) wolffd@0: Traj.secondary_data=value; wolffd@0: elseif isstruct(value) & isfield(value,'type') & ... wolffd@0: ischar(value.type) & strcmp(value.type,'som_data'), wolffd@0: Traj.secondary_data=value.data; wolffd@0: if isempty(Traj.secondary_names), wolffd@0: Traj.secondary_names=value.comp_names; wolffd@0: end wolffd@0: end wolffd@0: wolffd@0: % Trajectory length & size wolffd@0: case 'trajsize' wolffd@0: if isempty(value), wolffd@0: Traj.size=[16 12 10 8 6 4]'; wolffd@0: end wolffd@0: if vis_valuetype(value,{'nx1'}) wolffd@0: Traj.size=value wolffd@0: else wolffd@0: error('''TrajSize'' has to be a nx1 vector.'); wolffd@0: end wolffd@0: wolffd@0: % Names for first data variables wolffd@0: case 'name1' wolffd@0: if isempty(value), wolffd@0: Traj.primary_names=[]; wolffd@0: elseif ~vis_valuetype(value,{'cellcolumn_of_char'}), wolffd@0: error('''Name1'': variable names must be in a cell column array.') wolffd@0: else wolffd@0: Traj.primary_names = value; wolffd@0: end wolffd@0: % Names for 2nd data variables wolffd@0: case 'name2' wolffd@0: if isempty(value), wolffd@0: Traj.secondary_names=[]; wolffd@0: elseif ~vis_valuetype(value,{'cellcolumn_of_char'}), wolffd@0: error('''Name2'': variable names must be in a cell column array.') wolffd@0: else wolffd@0: Traj.secondary_names = value; wolffd@0: end wolffd@0: wolffd@0: % Figure number wolffd@0: case 'figure' wolffd@0: if isempty(value) wolffd@0: Traj.figure='gcf'; wolffd@0: end wolffd@0: if vis_valuetype(value,{'1x1'}) wolffd@0: Traj.figure=value; wolffd@0: else wolffd@0: error('''Figure'' should be number of an existing figure.') wolffd@0: end wolffd@0: end wolffd@0: end wolffd@0: wolffd@0: %% Get SOM data from figure wolffd@0: [h,msg,lattice,msize,dim]=vis_som_show_data('all',Traj.figure); wolffd@0: wolffd@0: %% Not a SOM_SHOW figure? wolffd@0: if ~isempty(msg); wolffd@0: error('Figure is invalid: use SOM_SHOW to draw the figure.'); wolffd@0: end wolffd@0: wolffd@0: % Get map size from figure data wolffd@0: Traj.lattice=lattice; wolffd@0: Traj.msize=msize; wolffd@0: if length(msize)>2, wolffd@0: error(['This function works only with 2D maps: figure contains' ... wolffd@0: ' something else.']); wolffd@0: end wolffd@0: munits=prod(msize); wolffd@0: wolffd@0: % Check BMU (or response) and map match wolffd@0: wolffd@0: if vis_valuetype(bmus,{'nx1'}); wolffd@0: if max(bmus)>prod(msize) | min(bmus) <1 wolffd@0: error('BMU indexes out of range.') wolffd@0: elseif any(round(bmus)~=bmus) wolffd@0: error('BMU indexes must be integer.'); wolffd@0: elseif isempty(Traj.primary_data), wolffd@0: Traj.primary_data=bmus; wolffd@0: end wolffd@0: elseif size(bmus,1) ~= munits wolffd@0: error(['Response matrix column number must match with the number of' ... wolffd@0: ' map units.']); wolffd@0: else wolffd@0: bmus=bmus'; wolffd@0: if isempty(Traj.primary_data), wolffd@0: Traj.primary_data=[1:size(bmus,1)]'; wolffd@0: Traj.primary_names={'BMU Index'}; wolffd@0: end wolffd@0: end wolffd@0: wolffd@0: size1=size(Traj.primary_data); wolffd@0: size2=size(Traj.secondary_data); wolffd@0: wolffd@0: % Data2 must not be defined alone wolffd@0: wolffd@0: if isempty(Traj.primary_data)&~isempty(Traj.secondary_data), wolffd@0: error('If ''Data2'' is specified ''Data1'' must be specified, too.'); wolffd@0: elseif ~isempty(Traj.secondary_data) ... wolffd@0: & size1~= size2 wolffd@0: % If data1 and data2 exist both, check data1 and data2 match wolffd@0: error('''Data1'' and ''Data2'' have different amount of data vectors.') wolffd@0: end wolffd@0: wolffd@0: % Check BMU and data1 match (data2 matches with 1 anyway) wolffd@0: wolffd@0: if ~isempty(Traj.primary_data) & size(bmus,1) ~= size1, wolffd@0: error(['The number of data vectors in ''data1'' must match with' ... wolffd@0: ' the number of rows in the first input argument (bmus).']); wolffd@0: end wolffd@0: wolffd@0: % Check that number of names and data dimension is consistent wolffd@0: wolffd@0: if ~isempty(Traj.primary_names) & (size1(2)~=length(Traj.primary_names)), wolffd@0: error('Number of component names and ''Data1'' dimension mismatch.'); wolffd@0: end wolffd@0: if ~isempty(Traj.secondary_names) & ... wolffd@0: (size2(2)~=length(Traj.secondary_names)), wolffd@0: error('Number of component names and ''Data2'' dimension mismatch.'); wolffd@0: end wolffd@0: wolffd@0: %% Call the function that does the job wolffd@0: vis_trajgui(Traj); wolffd@0: wolffd@0: %%% Subfunctions %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% wolffd@0: wolffd@0: function Traj=iniTraj(bmus) wolffd@0: wolffd@0: Traj.figure=gcf; wolffd@0: Traj.primary_data=[]; wolffd@0: Traj.secondary_data=[]; wolffd@0: Traj.primary_names = []; wolffd@0: Traj.secondary_names = []; wolffd@0: Traj.size=[16 12 10 8 6 4]'; wolffd@0: Traj.bmus=bmus; wolffd@0: Traj.color='xor'; wolffd@0: Traj.msize=[]; wolffd@0: Traj.lattice=[]; wolffd@0: