wolffd@0: function draw_dot(adj,varargin); wolffd@0: %DRAW_DOT Draw a graph. wolffd@0: % DRAW_DOT(ADJ) plots the graph ADJ in the current figure window, using wolffd@0: % 'neato' to optimize the layout. wolffd@0: % wolffd@0: % Optional arguments can be passed as name/value pairs: [default] wolffd@0: % wolffd@0: % 'isbox' - a vector specifying which nodes should be boxed [0] wolffd@0: % 'rotate' - rotate the graph so that nodes are vertically aligned [1] wolffd@0: % 'tolerance' - alignment tolerance for 'rotate' [0.001] wolffd@0: % 'start' - a random seed (to select different solutions) wolffd@0: % 'options' - a string of command-line options for 'neato' [''] wolffd@0: % All of the optional arguments to graph_to_dot are also supported, such as wolffd@0: % 'node_label'. wolffd@0: % wolffd@0: % See also GRAPH_TO_DOT. wolffd@0: % wolffd@0: % Example: wolffd@0: % size=15; Adj = rand(size) > .8; wolffd@0: % Adj2 = triu(Adj,1)+ triu(Adj,1)' + diag(zeros(size,1)); wolffd@0: % draw_dot(Adj2) wolffd@0: wolffd@0: % Original: Leon Peshkin wolffd@0: % Modified by Tom Minka wolffd@0: wolffd@0: % minka wolffd@0: N = size(adj,1); wolffd@0: unique_labels = cellstr(num2str((1:N)','%-1d')); wolffd@0: labels = unique_labels; wolffd@0: isbox = zeros(N,1); wolffd@0: rotate_flag = 1; wolffd@0: tolerance = 0.001; wolffd@0: options = ''; wolffd@0: for i = 1:2:length(varargin) wolffd@0: switch varargin{i} wolffd@0: case 'node_label', labels = varargin{i+1}; wolffd@0: % replace with unique labels wolffd@0: varargin{i+1} = unique_labels; wolffd@0: case 'isbox', isbox = varargin{i+1}; wolffd@0: case 'rotate', rotate_flag = varargin{i+1}; wolffd@0: case 'tolerance', tolerance = varargin{i+1}; wolffd@0: case 'start', start = varargin{i+1}; wolffd@0: options = [options ' -Gstart=' num2str(start)]; wolffd@0: case 'options', options = [options ' ' varargin{i+1}]; wolffd@0: end wolffd@0: end wolffd@0: wolffd@0: if ispc, shell = 'dos'; else, shell = 'unix'; end % Which OS ? wolffd@0: wolffd@0: cmdline = strcat(shell,'(''neato -V'')'); wolffd@0: status = eval(cmdline); wolffd@0: %[status, result] = dos('neato -V'); % request version to check NEATO wolffd@0: if status == 1, fprintf('Complaining \n'); exit, end wolffd@0: wolffd@0: tmpDOTfile = '_GtDout.dot'; % to be platform independant no use of directories wolffd@0: tmpLAYOUT = '_LAYout.dot'; wolffd@0: graph_to_dot(adj > 0, 'filename', tmpDOTfile, 'node_label', unique_labels, varargin{:}); % save in file wolffd@0: wolffd@0: cmdline = strcat([shell '(''neato -Tdot ' tmpDOTfile options ' -o ' tmpLAYOUT ''')']); % preserve trailing spaces wolffd@0: status = eval(cmdline); % get NEATO todo layout wolffd@0: wolffd@0: [adj, permuted_labels, x, y] = dot_to_graph(tmpLAYOUT); % load layout wolffd@0: delete(tmpLAYOUT); delete(tmpDOTfile); % clean up temporary files wolffd@0: wolffd@0: % permute the original arguments to match permuted_labels. wolffd@0: order = []; wolffd@0: for i = 1:length(permuted_labels) wolffd@0: j = strmatch(permuted_labels{i},unique_labels,'exact'); wolffd@0: order(i) = j(1); wolffd@0: end wolffd@0: labels = labels(order); wolffd@0: isbox = isbox(order); wolffd@0: if rotate_flag wolffd@0: [x,y] = best_rotation(x,y,tolerance); wolffd@0: end wolffd@0: wolffd@0: figure(1); clf; axis square % now plot wolffd@0: [x, y, h] = draw_graph(adj>0, labels, isbox, x, y, varargin{:}); wolffd@0: wolffd@0: wolffd@0: function [x,y] = best_rotation(x,y,h) wolffd@0: % Rotate the points to maximize the horizontal and vertical alignment. wolffd@0: % Written by Tom Minka. wolffd@0: wolffd@0: xm = mean(x); wolffd@0: ym = mean(y); wolffd@0: xr = max(x)-min(x); wolffd@0: yr = max(y)-min(y); wolffd@0: x = (x-xm)/xr; wolffd@0: y = (y-ym)/yr; wolffd@0: wolffd@0: xy = [x(:) y(:)]; wolffd@0: if 1 wolffd@0: angle = fminbnd(@rotation_cost,-pi/4,pi/4,[],xy,h); wolffd@0: else wolffd@0: angles = linspace(-pi/4,pi/4,40); wolffd@0: e = []; wolffd@0: for i = 1:length(angles) wolffd@0: e(i) = rotation_cost(angles(i),xy,h); wolffd@0: end wolffd@0: %figure(2) wolffd@0: %plot(angles*180/pi,e) wolffd@0: angle = angles(argmin(e)); wolffd@0: end wolffd@0: %angle*180/pi wolffd@0: c = cos(angle); s = sin(angle); wolffd@0: xy = xy*[c s; -s c]; wolffd@0: wolffd@0: x = xy(:,1)*xr+xm; wolffd@0: y = xy(:,2)*yr+ym; wolffd@0: wolffd@0: wolffd@0: function e = rotation_cost(angle,xy,h) wolffd@0: % xy is 2-column matrix. wolffd@0: % e is small if many x's and y's are aligned. wolffd@0: wolffd@0: c = cos(angle); s = sin(angle); wolffd@0: xy = xy*[c s; -s c]; wolffd@0: dx = sqdist(xy(:,1)',xy(:,1)'); wolffd@0: dy = sqdist(xy(:,2)',xy(:,2)'); wolffd@0: dx = setdiag(dx,Inf); wolffd@0: dy = setdiag(dy,Inf); wolffd@0: e = sum(exp(-dx(:)/h))+sum(exp(-dy(:)/h)); wolffd@0: e = -e;