wolffd@0
|
1 function draw_dot(adj,varargin);
|
wolffd@0
|
2 %DRAW_DOT Draw a graph.
|
wolffd@0
|
3 % DRAW_DOT(ADJ) plots the graph ADJ in the current figure window, using
|
wolffd@0
|
4 % 'neato' to optimize the layout.
|
wolffd@0
|
5 %
|
wolffd@0
|
6 % Optional arguments can be passed as name/value pairs: [default]
|
wolffd@0
|
7 %
|
wolffd@0
|
8 % 'isbox' - a vector specifying which nodes should be boxed [0]
|
wolffd@0
|
9 % 'rotate' - rotate the graph so that nodes are vertically aligned [1]
|
wolffd@0
|
10 % 'tolerance' - alignment tolerance for 'rotate' [0.001]
|
wolffd@0
|
11 % 'start' - a random seed (to select different solutions)
|
wolffd@0
|
12 % 'options' - a string of command-line options for 'neato' ['']
|
wolffd@0
|
13 % All of the optional arguments to graph_to_dot are also supported, such as
|
wolffd@0
|
14 % 'node_label'.
|
wolffd@0
|
15 %
|
wolffd@0
|
16 % See also GRAPH_TO_DOT.
|
wolffd@0
|
17 %
|
wolffd@0
|
18 % Example:
|
wolffd@0
|
19 % size=15; Adj = rand(size) > .8;
|
wolffd@0
|
20 % Adj2 = triu(Adj,1)+ triu(Adj,1)' + diag(zeros(size,1));
|
wolffd@0
|
21 % draw_dot(Adj2)
|
wolffd@0
|
22
|
wolffd@0
|
23 % Original: Leon Peshkin
|
wolffd@0
|
24 % Modified by Tom Minka
|
wolffd@0
|
25
|
wolffd@0
|
26 % minka
|
wolffd@0
|
27 N = size(adj,1);
|
wolffd@0
|
28 unique_labels = cellstr(num2str((1:N)','%-1d'));
|
wolffd@0
|
29 labels = unique_labels;
|
wolffd@0
|
30 isbox = zeros(N,1);
|
wolffd@0
|
31 rotate_flag = 1;
|
wolffd@0
|
32 tolerance = 0.001;
|
wolffd@0
|
33 options = '';
|
wolffd@0
|
34 for i = 1:2:length(varargin)
|
wolffd@0
|
35 switch varargin{i}
|
wolffd@0
|
36 case 'node_label', labels = varargin{i+1};
|
wolffd@0
|
37 % replace with unique labels
|
wolffd@0
|
38 varargin{i+1} = unique_labels;
|
wolffd@0
|
39 case 'isbox', isbox = varargin{i+1};
|
wolffd@0
|
40 case 'rotate', rotate_flag = varargin{i+1};
|
wolffd@0
|
41 case 'tolerance', tolerance = varargin{i+1};
|
wolffd@0
|
42 case 'start', start = varargin{i+1};
|
wolffd@0
|
43 options = [options ' -Gstart=' num2str(start)];
|
wolffd@0
|
44 case 'options', options = [options ' ' varargin{i+1}];
|
wolffd@0
|
45 end
|
wolffd@0
|
46 end
|
wolffd@0
|
47
|
wolffd@0
|
48 if ispc, shell = 'dos'; else, shell = 'unix'; end % Which OS ?
|
wolffd@0
|
49
|
wolffd@0
|
50 cmdline = strcat(shell,'(''neato -V'')');
|
wolffd@0
|
51 status = eval(cmdline);
|
wolffd@0
|
52 %[status, result] = dos('neato -V'); % request version to check NEATO
|
wolffd@0
|
53 if status == 1, fprintf('Complaining \n'); exit, end
|
wolffd@0
|
54
|
wolffd@0
|
55 tmpDOTfile = '_GtDout.dot'; % to be platform independant no use of directories
|
wolffd@0
|
56 tmpLAYOUT = '_LAYout.dot';
|
wolffd@0
|
57 graph_to_dot(adj > 0, 'filename', tmpDOTfile, 'node_label', unique_labels, varargin{:}); % save in file
|
wolffd@0
|
58
|
wolffd@0
|
59 cmdline = strcat([shell '(''neato -Tdot ' tmpDOTfile options ' -o ' tmpLAYOUT ''')']); % preserve trailing spaces
|
wolffd@0
|
60 status = eval(cmdline); % get NEATO todo layout
|
wolffd@0
|
61
|
wolffd@0
|
62 [adj, permuted_labels, x, y] = dot_to_graph(tmpLAYOUT); % load layout
|
wolffd@0
|
63 delete(tmpLAYOUT); delete(tmpDOTfile); % clean up temporary files
|
wolffd@0
|
64
|
wolffd@0
|
65 % permute the original arguments to match permuted_labels.
|
wolffd@0
|
66 order = [];
|
wolffd@0
|
67 for i = 1:length(permuted_labels)
|
wolffd@0
|
68 j = strmatch(permuted_labels{i},unique_labels,'exact');
|
wolffd@0
|
69 order(i) = j(1);
|
wolffd@0
|
70 end
|
wolffd@0
|
71 labels = labels(order);
|
wolffd@0
|
72 isbox = isbox(order);
|
wolffd@0
|
73 if rotate_flag
|
wolffd@0
|
74 [x,y] = best_rotation(x,y,tolerance);
|
wolffd@0
|
75 end
|
wolffd@0
|
76
|
wolffd@0
|
77 figure(1); clf; axis square % now plot
|
wolffd@0
|
78 [x, y, h] = draw_graph(adj>0, labels, isbox, x, y, varargin{:});
|
wolffd@0
|
79
|
wolffd@0
|
80
|
wolffd@0
|
81 function [x,y] = best_rotation(x,y,h)
|
wolffd@0
|
82 % Rotate the points to maximize the horizontal and vertical alignment.
|
wolffd@0
|
83 % Written by Tom Minka.
|
wolffd@0
|
84
|
wolffd@0
|
85 xm = mean(x);
|
wolffd@0
|
86 ym = mean(y);
|
wolffd@0
|
87 xr = max(x)-min(x);
|
wolffd@0
|
88 yr = max(y)-min(y);
|
wolffd@0
|
89 x = (x-xm)/xr;
|
wolffd@0
|
90 y = (y-ym)/yr;
|
wolffd@0
|
91
|
wolffd@0
|
92 xy = [x(:) y(:)];
|
wolffd@0
|
93 if 1
|
wolffd@0
|
94 angle = fminbnd(@rotation_cost,-pi/4,pi/4,[],xy,h);
|
wolffd@0
|
95 else
|
wolffd@0
|
96 angles = linspace(-pi/4,pi/4,40);
|
wolffd@0
|
97 e = [];
|
wolffd@0
|
98 for i = 1:length(angles)
|
wolffd@0
|
99 e(i) = rotation_cost(angles(i),xy,h);
|
wolffd@0
|
100 end
|
wolffd@0
|
101 %figure(2)
|
wolffd@0
|
102 %plot(angles*180/pi,e)
|
wolffd@0
|
103 angle = angles(argmin(e));
|
wolffd@0
|
104 end
|
wolffd@0
|
105 %angle*180/pi
|
wolffd@0
|
106 c = cos(angle); s = sin(angle);
|
wolffd@0
|
107 xy = xy*[c s; -s c];
|
wolffd@0
|
108
|
wolffd@0
|
109 x = xy(:,1)*xr+xm;
|
wolffd@0
|
110 y = xy(:,2)*yr+ym;
|
wolffd@0
|
111
|
wolffd@0
|
112
|
wolffd@0
|
113 function e = rotation_cost(angle,xy,h)
|
wolffd@0
|
114 % xy is 2-column matrix.
|
wolffd@0
|
115 % e is small if many x's and y's are aligned.
|
wolffd@0
|
116
|
wolffd@0
|
117 c = cos(angle); s = sin(angle);
|
wolffd@0
|
118 xy = xy*[c s; -s c];
|
wolffd@0
|
119 dx = sqdist(xy(:,1)',xy(:,1)');
|
wolffd@0
|
120 dy = sqdist(xy(:,2)',xy(:,2)');
|
wolffd@0
|
121 dx = setdiag(dx,Inf);
|
wolffd@0
|
122 dy = setdiag(dy,Inf);
|
wolffd@0
|
123 e = sum(exp(-dx(:)/h))+sum(exp(-dy(:)/h));
|
wolffd@0
|
124 e = -e;
|