wolffd@0: function graph_to_dot(G, varargin) wolffd@0: % DAG_TO_DOT Make a file representing the directed graph in dotty format. wolffd@0: % dag_to_dot(G, ...) wolffd@0: % wolffd@0: % Optional arguments should be passed as name/value pairs [default] wolffd@0: % wolffd@0: % 'filename' - if omitted, we write to 'tmp.dot', convert this to 'tmp.ps', wolffd@0: % and then call ghostview automatically wolffd@0: % 'arc_label' - arc_label{i,j} is a string attached to the i->j arc. [""] wolffd@0: % 'node_label' - node_label{i} is a string attached to node i. ["i"] wolffd@0: % 'width' - width in inches [10] wolffd@0: % 'height' - height in inches [10] wolffd@0: % 'leftright' - 1 means layout left-to-right, 0 means top-to-bottom [0] wolffd@0: % 'directed' - 1 means use directed arcs, 0 means undirected [1] wolffd@0: % wolffd@0: % For details on dotty, See http://www.research.att.com/sw/tools/graphviz wolffd@0: % wolffd@0: % Example: wolffd@0: % G = rand(5,5); wolffd@0: % names = cell(5,5); wolffd@0: % names{1,2} = 'arc 1-2'; wolffd@0: % graph_to_dot(G, 'arc_label', names) wolffd@0: % or graph_to_dot(G, 'arc_label', 'numbers') % prints value of G(i,j) on i->j arc wolffd@0: wolffd@0: % Kevin Murphy, 1998 wolffd@0: wolffd@0: % set default args wolffd@0: filename = []; wolffd@0: node_label = []; wolffd@0: arc_label = []; wolffd@0: width = 10; wolffd@0: height = 10; wolffd@0: leftright = 0; wolffd@0: directed = 1; wolffd@0: % get optional args wolffd@0: args = varargin; wolffd@0: for i=1:2:length(args) wolffd@0: switch args{i} wolffd@0: case 'filename', filename = args{i+1}; wolffd@0: case 'node_label', node_label = args{i+1}; wolffd@0: case 'arc_label', arc_label = args{i+1}; wolffd@0: case 'width', width = args{i+1}; wolffd@0: case 'height', height = args{i+1}; wolffd@0: case 'leftright', leftright = args{i+1}; wolffd@0: case 'directed', directed = args{i+1}; wolffd@0: end wolffd@0: end wolffd@0: wolffd@0: if isstr(arc_label) & strcmp(arc_label, 'numbers') wolffd@0: N = length(G); wolffd@0: arc_label = cell(N,N); wolffd@0: for i=1:N wolffd@0: for j=1:N wolffd@0: arc_label{i,j} = sprintf('%4.2f', G(i,j)); wolffd@0: end wolffd@0: end wolffd@0: end wolffd@0: wolffd@0: if isempty(filename) wolffd@0: make_file(G, 'tmp.dot', node_label, arc_label, width, height, leftright, directed); wolffd@0: if isunix wolffd@0: !dot -Tps tmp.dot -o tmp.ps wolffd@0: wolffd@0: !gs tmp.ps & wolffd@0: else wolffd@0: dos('dot -Tps tmp.dot -o tmp.ps'); wolffd@0: dos('gsview32 tmp.ps &'); wolffd@0: end wolffd@0: else wolffd@0: wolffd@0: wolffd@0: make_file(G, filename, node_label, arc_label, width, height, leftright, directed); wolffd@0: end wolffd@0: wolffd@0: wolffd@0: %%%%%% wolffd@0: wolffd@0: function make_file(G, filename, node_label, arc_label, width, height, leftright, directed) wolffd@0: wolffd@0: n = length(G); wolffd@0: fid = fopen(filename, 'w'); wolffd@0: if directed wolffd@0: fprintf(fid, 'digraph G {\n'); wolffd@0: else wolffd@0: fprintf(fid, 'graph G {\n'); wolffd@0: end wolffd@0: fprintf(fid, 'center = 1;\n'); wolffd@0: fprintf(fid, 'size=\"%d,%d\";\n', width, height); wolffd@0: if leftright wolffd@0: fprintf(fid, 'rankdir=LR;\n'); wolffd@0: end wolffd@0: for i=1:n wolffd@0: if isempty(node_label) wolffd@0: fprintf(fid, '%d;\n', i); wolffd@0: else wolffd@0: fprintf(fid, '%d [ label = "%s" ];\n', i, node_label{i}); wolffd@0: end wolffd@0: end wolffd@0: if directed wolffd@0: for i=1:n wolffd@0: cs = children(G,i); wolffd@0: for j=1:length(cs) wolffd@0: c = cs(j); wolffd@0: if isempty(arc_label) wolffd@0: fprintf(fid, '%d -> %d;\n', i, c); wolffd@0: else wolffd@0: fprintf(fid, '%d -> %d [label="%s"];\n', i, c, arc_label{i,c}); wolffd@0: end wolffd@0: end wolffd@0: end wolffd@0: else wolffd@0: for i=1:n wolffd@0: ns = intersect(neighbors(G,i), i+1:n); % remove duplicate arcs wolffd@0: for j=1:length(ns) wolffd@0: c = ns(j); wolffd@0: if isempty(arc_label) wolffd@0: fprintf(fid, '%d -- %d [dir=none];\n', i, c); wolffd@0: else wolffd@0: fprintf(fid, '%d -- %d [label="%s",dir=none];\n', i, c, arc_label{i,c}); wolffd@0: end wolffd@0: end wolffd@0: end wolffd@0: end wolffd@0: fprintf(fid, '\n}'); wolffd@0: fclose(fid); wolffd@0: wolffd@0: wolffd@0: wolffd@0: %%%%%%%%%%%%%%% wolffd@0: wolffd@0: function cs = children(adj_mat, i, t) wolffd@0: % CHILDREN Return the indices of a node's children in sorted order wolffd@0: % c = children(adj_mat, i, t) wolffd@0: % wolffd@0: % t is an optional argument: if present, dag is assumed to be a 2-slice DBN wolffd@0: wolffd@0: if nargin < 3 wolffd@0: cs = find(adj_mat(i,:)); wolffd@0: else wolffd@0: if t==1 wolffd@0: cs = find(adj_mat(i,:)); wolffd@0: else wolffd@0: ss = length(adj_mat)/2; wolffd@0: j = i+ss; wolffd@0: cs = find(adj_mat(j,:)) + (t-2)*ss; wolffd@0: end wolffd@0: end wolffd@0: wolffd@0: %%%%%%%%%%%% wolffd@0: wolffd@0: function ps = parents(adj_mat, i) wolffd@0: % PARENTS Return the list of parents of node i wolffd@0: % ps = parents(adj_mat, i) wolffd@0: wolffd@0: ps = find(adj_mat(:,i))'; wolffd@0: wolffd@0: %%%%%%%%%%%%% wolffd@0: wolffd@0: function ns = neighbors(adj_mat, i) wolffd@0: % NEIGHBORS Find the parents and children of a node in a graph. wolffd@0: % ns = neighbors(adj_mat, i) wolffd@0: wolffd@0: ns = union(children(adj_mat, i), parents(adj_mat, i)); wolffd@0: wolffd@0: wolffd@0: