wolffd@0
|
1 function [h,Coord,Color,height] = som_dendrogram(Z,varargin)
|
wolffd@0
|
2
|
wolffd@0
|
3 %SOM_DENDROGRAM Visualize a dendrogram.
|
wolffd@0
|
4 %
|
wolffd@0
|
5 % [h,Coord,Color,height] = som_dendrogram(Z, [[argID,] value, ...])
|
wolffd@0
|
6 %
|
wolffd@0
|
7 % Z = som_linkage(sM);
|
wolffd@0
|
8 % som_dendrogram(Z);
|
wolffd@0
|
9 % som_dendrogram(Z,sM);
|
wolffd@0
|
10 % som_dendrogram(Z,'coord',co);
|
wolffd@0
|
11 %
|
wolffd@0
|
12 % Input and output arguments ([]'s are optional):
|
wolffd@0
|
13 % h (vector) handle to the arc lines
|
wolffd@0
|
14 % Z (matrix) size n-1 x 1, the hierarchical cluster matrix
|
wolffd@0
|
15 % returned by functions like LINKAGE and SOM_LINKAGE
|
wolffd@0
|
16 % n is the number of original data samples.
|
wolffd@0
|
17 % [argID, (string) See below. The values which are unambiguous can
|
wolffd@0
|
18 % value] (varies) be given without the preceeding argID.
|
wolffd@0
|
19 % Coord (matrix) size 2*n-1 x {1,2}, the coordinates of the
|
wolffd@0
|
20 % original data samples and cluster nodes used
|
wolffd@0
|
21 % in the visualization
|
wolffd@0
|
22 % Color (matrix) size 2*n-1 x 3, the colors of ...
|
wolffd@0
|
23 % height (vector) size 2*n-1 x 1, the heights of ...
|
wolffd@0
|
24 %
|
wolffd@0
|
25 % Here are the valid argument IDs and corresponding values. The values
|
wolffd@0
|
26 % which are unambiguous (marked with '*') can be given without the
|
wolffd@0
|
27 % preceeding argID.
|
wolffd@0
|
28 % 'data' *(struct) map or data struct: many other optional
|
wolffd@0
|
29 % arguments require this
|
wolffd@0
|
30 % (matrix) data matrix
|
wolffd@0
|
31 % 'coord' (matrix) size n x 1 or n x 2, the coordinates of
|
wolffd@0
|
32 % the original data samples either in 1D or 2D
|
wolffd@0
|
33 % (matrix) size 2*n-1 x {1,2}, the coordinates of both
|
wolffd@0
|
34 % original data samples and each cluster
|
wolffd@0
|
35 % *(string) 'SOM', 'pca#', 'sammon#', or 'cca#': the coordinates
|
wolffd@0
|
36 % are calculated using the given data and the
|
wolffd@0
|
37 % required projection algorithm. The '#' at the
|
wolffd@0
|
38 % end of projection algorithms refers to the
|
wolffd@0
|
39 % desired output dimension and can be either 1 or 2
|
wolffd@0
|
40 % (2 by default). In case of 'SOM', the unit
|
wolffd@0
|
41 % coordinates (given by SOM_VIS_COORDS) are used.
|
wolffd@0
|
42 % 'color' (matrix) size n x 3, the color of the original data samples
|
wolffd@0
|
43 % (matrix) size 2*n-1 x 3, the colors of both original
|
wolffd@0
|
44 % data samples and each cluster
|
wolffd@0
|
45 % (string) color specification, e.g. 'r.', used for each node
|
wolffd@0
|
46 % 'height' (vector) size n-1 x 1, the heights used for each cluster
|
wolffd@0
|
47 % (vector) size 2*n-1 x 1, the heights used for both original
|
wolffd@0
|
48 % data samples and each cluster
|
wolffd@0
|
49 % *(string) 'order', the order of combination determines height
|
wolffd@0
|
50 % 'depth', the depth at which the combination
|
wolffd@0
|
51 % happens determines height
|
wolffd@0
|
52 % 'linecolor' (string) color specification for the arc color, 'k' by default
|
wolffd@0
|
53 % (vector) size 1 x 3
|
wolffd@0
|
54 %
|
wolffd@0
|
55 % See also SOM_LINKAGE, DENDROGRAM.
|
wolffd@0
|
56
|
wolffd@0
|
57 % Copyright (c) 2000 by Juha Vesanto
|
wolffd@0
|
58 % Contributed to SOM Toolbox on June 16th, 2000 by Juha Vesanto
|
wolffd@0
|
59 % http://www.cis.hut.fi/projects/somtoolbox/
|
wolffd@0
|
60
|
wolffd@0
|
61 % Version 2.0beta juuso 160600
|
wolffd@0
|
62
|
wolffd@0
|
63 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
wolffd@0
|
64 %% read the arguments
|
wolffd@0
|
65
|
wolffd@0
|
66 % Z
|
wolffd@0
|
67 nd = size(Z,1)+1;
|
wolffd@0
|
68 nc = size(Z,1);
|
wolffd@0
|
69
|
wolffd@0
|
70 % varargin
|
wolffd@0
|
71 Coordtype = 'natural'; Coord = []; codim = 1;
|
wolffd@0
|
72 Colortype = 'none'; Color = [];
|
wolffd@0
|
73 height = [zeros(nd,1); Z(:,3)];
|
wolffd@0
|
74 M = [];
|
wolffd@0
|
75 linecol = 'k';
|
wolffd@0
|
76
|
wolffd@0
|
77 i=1;
|
wolffd@0
|
78 while i<=length(varargin),
|
wolffd@0
|
79 argok = 1;
|
wolffd@0
|
80 if ischar(varargin{i}),
|
wolffd@0
|
81 switch varargin{i},
|
wolffd@0
|
82 case 'data', i = i + 1; M = varargin{i};
|
wolffd@0
|
83 case 'coord',
|
wolffd@0
|
84 i=i+1;
|
wolffd@0
|
85 if isnumeric(varargin{i}), Coord = varargin{i}; Coordtype = 'given';
|
wolffd@0
|
86 else
|
wolffd@0
|
87 if strcmp(varargin{i},'SOM'), Coordtype = 'SOM';
|
wolffd@0
|
88 else Coordtype = 'projection'; Coord = varargin{i};
|
wolffd@0
|
89 end
|
wolffd@0
|
90 end
|
wolffd@0
|
91 case 'color',
|
wolffd@0
|
92 i=i+1;
|
wolffd@0
|
93 if isempty(varargin{i}), Colortype = 'none';
|
wolffd@0
|
94 elseif ischar(varargin{i}), Colortype = 'colorspec'; Color = varargin{i};
|
wolffd@0
|
95 else Colortype = 'given'; Color = varargin{i};
|
wolffd@0
|
96 end
|
wolffd@0
|
97 case 'height', i=i+1; height = varargin{i};
|
wolffd@0
|
98 case 'linecolor', i=i+1; linecol = varargin{i};
|
wolffd@0
|
99 case 'SOM',
|
wolffd@0
|
100 Coordtype = 'SOM';
|
wolffd@0
|
101 case {'pca','pca1','pca2','sammon','sammon1','sammon2','cca','cca1','cca2'},
|
wolffd@0
|
102 Coordtype = 'projection'; Coord = varargin{i};
|
wolffd@0
|
103 case {'order','depth'}, height = varargin{i};
|
wolffd@0
|
104 end
|
wolffd@0
|
105 elseif isstruct(varargin{i}), M = varargin{i};
|
wolffd@0
|
106 else
|
wolffd@0
|
107 argok = 0;
|
wolffd@0
|
108 end
|
wolffd@0
|
109 if ~argok,
|
wolffd@0
|
110 disp(['(som_dendrogram) Ignoring invalid argument #' num2str(i+1)]);
|
wolffd@0
|
111 end
|
wolffd@0
|
112 i = i+1;
|
wolffd@0
|
113 end
|
wolffd@0
|
114
|
wolffd@0
|
115 switch Coordtype,
|
wolffd@0
|
116 case 'SOM',
|
wolffd@0
|
117 if isempty(M) | ~any(strcmp(M.type,{'som_map','som_topol'})) ,
|
wolffd@0
|
118 error('Cannot determine SOM coordinates without a SOM.');
|
wolffd@0
|
119 end
|
wolffd@0
|
120 if strcmp(M.type,'som_map'), M = M.topol; end
|
wolffd@0
|
121 case 'projection',
|
wolffd@0
|
122 if isempty(M), error('Cannot do projection without the data.'); end
|
wolffd@0
|
123 if isstruct(M),
|
wolffd@0
|
124 if strcmp(M.type,'som_data'), M = M.data;
|
wolffd@0
|
125 elseif strcmp(M.type,'som_map'), M = M.codebook;
|
wolffd@0
|
126 end
|
wolffd@0
|
127 end
|
wolffd@0
|
128 if size(M,1) ~= nd,
|
wolffd@0
|
129 error('Given data must be equal in length to the number of original data samples.')
|
wolffd@0
|
130 end
|
wolffd@0
|
131 case 'given',
|
wolffd@0
|
132 if size(Coord,1) ~= nd & size(Coord,1) ~= nd+nc,
|
wolffd@0
|
133 error('Size of given coordinate matrix does not match the cluster hierarchy.');
|
wolffd@0
|
134 end
|
wolffd@0
|
135 end
|
wolffd@0
|
136
|
wolffd@0
|
137 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
wolffd@0
|
138 %% initialization
|
wolffd@0
|
139
|
wolffd@0
|
140 % Coordinates
|
wolffd@0
|
141 switch Coordtype,
|
wolffd@0
|
142 case 'natural', o = leavesorder(Z)'; [dummy,Coord] = sort(o); codim = 1;
|
wolffd@0
|
143 case 'SOM', Coord = som_vis_coords(M.lattice,M.msize); codim = 2;
|
wolffd@0
|
144 case 'projection',
|
wolffd@0
|
145 switch Coord,
|
wolffd@0
|
146 case {'pca','pca2'}, Coord = pcaproj(M,2); codim = 2;
|
wolffd@0
|
147 case 'pca1', Coord = pcaproj(M,1); codim = 1;
|
wolffd@0
|
148 case {'cca','cca2'}, Coord = cca(M,2,20); codim = 2;
|
wolffd@0
|
149 case 'cca1', Coord = cca(M,1,20); codim = 1;
|
wolffd@0
|
150 case {'sammon','sammon2'}, Coord = sammon(M,2,50); codim = 2;
|
wolffd@0
|
151 case 'sammon1', Coord = sammon(M,1,50); codim = 1;
|
wolffd@0
|
152 end
|
wolffd@0
|
153 case 'given', codim = min(size(Coord,2),2); % nill
|
wolffd@0
|
154 end
|
wolffd@0
|
155
|
wolffd@0
|
156 if size(Coord,1) == nd,
|
wolffd@0
|
157 Coord = [Coord; zeros(nc,size(Coord,2))];
|
wolffd@0
|
158 for i=(nd+1):(nd+nc),
|
wolffd@0
|
159 leaves = leafnodes(Z,i,nd);
|
wolffd@0
|
160 if any(leaves), Coord(i,:) = mean(Coord(leaves,:),1); else Coord(i,:) = Inf; end
|
wolffd@0
|
161 end
|
wolffd@0
|
162 end
|
wolffd@0
|
163
|
wolffd@0
|
164 % Colors
|
wolffd@0
|
165 switch Colortype,
|
wolffd@0
|
166 case 'colorspec', % nill
|
wolffd@0
|
167 case 'none', Color = '';
|
wolffd@0
|
168 case 'given',
|
wolffd@0
|
169 if size(Color,1) == nd,
|
wolffd@0
|
170 Color = [Color; zeros(nc,3)];
|
wolffd@0
|
171 for i=(nd+1):(nd+nc),
|
wolffd@0
|
172 leaves = leafnodes(Z,i,nd);
|
wolffd@0
|
173 if any(leaves), Color(i,:) = mean(Color(leaves,:),1);
|
wolffd@0
|
174 else Color(i,:) = 0.8;
|
wolffd@0
|
175 end
|
wolffd@0
|
176 end
|
wolffd@0
|
177 end
|
wolffd@0
|
178 end
|
wolffd@0
|
179
|
wolffd@0
|
180 % height
|
wolffd@0
|
181 if ischar(height),
|
wolffd@0
|
182 switch height,
|
wolffd@0
|
183 case 'order', height = [zeros(nd,1); [1:nc]'];
|
wolffd@0
|
184 case 'depth', height = nodedepth(Z); height = max(height) - height;
|
wolffd@0
|
185 end
|
wolffd@0
|
186 else
|
wolffd@0
|
187 if length(height)==nc, height = [zeros(nd,1); height]; end
|
wolffd@0
|
188 end
|
wolffd@0
|
189
|
wolffd@0
|
190 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
wolffd@0
|
191 %% draw
|
wolffd@0
|
192
|
wolffd@0
|
193 % the arcs
|
wolffd@0
|
194 lfrom = []; lto = [];
|
wolffd@0
|
195 for i=1:nd+nc,
|
wolffd@0
|
196 if i<=nd, ch = [];
|
wolffd@0
|
197 elseif ~isfinite(Z(i-nd,3)), ch = [];
|
wolffd@0
|
198 else ch = Z(i-nd,1:2)';
|
wolffd@0
|
199 end
|
wolffd@0
|
200 if any(ch),
|
wolffd@0
|
201 lfrom = [lfrom; i*ones(length(ch),1)];
|
wolffd@0
|
202 lto = [lto; ch];
|
wolffd@0
|
203 end
|
wolffd@0
|
204 end
|
wolffd@0
|
205
|
wolffd@0
|
206 % the coordinates of the arcs
|
wolffd@0
|
207 if codim == 1,
|
wolffd@0
|
208 Lx = [Coord(lfrom), Coord(lto), Coord(lto)];
|
wolffd@0
|
209 Ly = [height(lfrom), height(lfrom), height(lto)];
|
wolffd@0
|
210 Lz = [];
|
wolffd@0
|
211 else
|
wolffd@0
|
212 Lx = [Coord(lfrom,1), Coord(lto,1), Coord(lto,1)];
|
wolffd@0
|
213 Ly = [Coord(lfrom,2), Coord(lto,2), Coord(lto,2)];
|
wolffd@0
|
214 Lz = [height(lfrom), height(lfrom), height(lto)];
|
wolffd@0
|
215 end
|
wolffd@0
|
216
|
wolffd@0
|
217 washold = ishold;
|
wolffd@0
|
218 if ~washold, cla; end
|
wolffd@0
|
219
|
wolffd@0
|
220 % plot the lines
|
wolffd@0
|
221 if isempty(Lz),
|
wolffd@0
|
222 h = line(Lx',Ly','color',linecol);
|
wolffd@0
|
223 else
|
wolffd@0
|
224 h = line(Lx',Ly',Lz','color',linecol);
|
wolffd@0
|
225 if ~washold, view(3); end
|
wolffd@0
|
226 rotate3d on
|
wolffd@0
|
227 end
|
wolffd@0
|
228
|
wolffd@0
|
229 % plot the nodes
|
wolffd@0
|
230 hold on
|
wolffd@0
|
231 switch Colortype,
|
wolffd@0
|
232 case 'none', % nill
|
wolffd@0
|
233 case 'colorspec',
|
wolffd@0
|
234 if codim == 1, plot(Coord,height,Color);
|
wolffd@0
|
235 else plot3(Coord(:,1), Coord(:,2), height, Color);
|
wolffd@0
|
236 end
|
wolffd@0
|
237 case 'given',
|
wolffd@0
|
238 som_grid('rect',[nd+nc 1],'line','none','Coord',[Coord, height],...
|
wolffd@0
|
239 'Markersize',10,'Markercolor',Color);
|
wolffd@0
|
240 end
|
wolffd@0
|
241 if ~washold, hold off, end
|
wolffd@0
|
242
|
wolffd@0
|
243 return;
|
wolffd@0
|
244
|
wolffd@0
|
245
|
wolffd@0
|
246 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
wolffd@0
|
247 %% subfunctions
|
wolffd@0
|
248
|
wolffd@0
|
249 function depth = nodedepth(Z)
|
wolffd@0
|
250
|
wolffd@0
|
251 nd = size(Z,1)+1;
|
wolffd@0
|
252 nc = size(Z,1);
|
wolffd@0
|
253 depth = zeros(nd+nc,1);
|
wolffd@0
|
254 ch = nc+nd-1;
|
wolffd@0
|
255 while any(ch),
|
wolffd@0
|
256 c = ch(1); ch = ch(2:end);
|
wolffd@0
|
257 if c>nd & isfinite(Z(c-nd,3)),
|
wolffd@0
|
258 chc = Z(c-nd,1:2);
|
wolffd@0
|
259 depth(chc) = depth(c) + 1;
|
wolffd@0
|
260 ch = [ch, chc];
|
wolffd@0
|
261 end
|
wolffd@0
|
262 end
|
wolffd@0
|
263 return;
|
wolffd@0
|
264
|
wolffd@0
|
265 function inds = leafnodes(Z,i,nd)
|
wolffd@0
|
266
|
wolffd@0
|
267 inds = [];
|
wolffd@0
|
268 ch = i;
|
wolffd@0
|
269 while any(ch),
|
wolffd@0
|
270 c = ch(1); ch = ch(2:end);
|
wolffd@0
|
271 if c>nd & isfinite(Z(c-nd,3)), ch = [ch, Z(c-nd,1:2)]; end
|
wolffd@0
|
272 if c<=nd, inds(end+1) = c; end
|
wolffd@0
|
273 end
|
wolffd@0
|
274 return;
|
wolffd@0
|
275
|
wolffd@0
|
276 function order = leavesorder(Z)
|
wolffd@0
|
277
|
wolffd@0
|
278 nd = size(Z,1)+1;
|
wolffd@0
|
279 order = 2*nd-1;
|
wolffd@0
|
280 nonleaves = 1;
|
wolffd@0
|
281 while any(nonleaves),
|
wolffd@0
|
282 j = nonleaves(1);
|
wolffd@0
|
283 ch = Z(order(j)-nd,1:2);
|
wolffd@0
|
284 if j==1, oleft = []; else oleft = order(1:(j-1)); end
|
wolffd@0
|
285 if j==length(order), oright = []; else oright = order((j+1):length(order)); end
|
wolffd@0
|
286 order = [oleft, ch, oright];
|
wolffd@0
|
287 nonleaves = find(order>nd);
|
wolffd@0
|
288 end
|
wolffd@0
|
289 return;
|
wolffd@0
|
290
|
wolffd@0
|
291
|
wolffd@0
|
292 |