-
Notifications
You must be signed in to change notification settings - Fork 8
Expand file tree
/
Copy pathsexy_graph.m
More file actions
189 lines (157 loc) · 5.59 KB
/
sexy_graph.m
File metadata and controls
189 lines (157 loc) · 5.59 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
function I = sexy_graph(A, params)
% Create a graph visualization of a matrix using graphviz via sfdp mode
% Input:
% A: a symmetric binary adjacency matrix
% params: an optional set of parameters, calls
% [params]=sexy_graph_params(A), if params is not present
% params.sfdp_coloring=1 will enable sfdp edge coloring based on
% sfdp emedding distance
% Output:
% I: the graph image
%
% If no output arguments are specified, then a pdf file is
% written to disk.
%
% Examples:
% To write a PDF, call function without output parameters
% >> sexy_graph(A);
% To write an image, just call with output
% >> I = sexy_graph(A);
% To write a PDF with sfdp coloring
% >> params = sexy_graph_params(A);
% >> params.sfdp_coloring = 1;
% >> sexy_graph(A,params);
% To write a PDF with eigenvector coloring
% >> params = sexy_graph_params(A);
% >> params = eigenvector_node_coloring(A, params, 2);
% >> sexy_graph(A,params);
%
% Graphviz needs to be installed! Try running the command "dot" on
% the command line to see if it is installed or not.
%
% NOTE: A should be symmetric and have 1 component (not enforced)
%
% Tomasz Malisiewicz (tomasz@csail.mit.edu)
% turn diagonal off
A = A - diag(diag(A));
if ~exist('params','var')
params = sexy_graph_params(A);
end
params.gv_file = [params.tmpdir params.file_prefix '.gv'];
params.png_file = [params.tmpdir params.file_prefix '.png'];
params.pdf_file = [params.tmpdir params.file_prefix '.pdf'];
for i = 1:size(A,1)
params.colstring{i} = sprintf('fillcolor="%.3f %.3f %.3f"',...
params.colors(i,1), ...
params.colors(i,2),...
params.colors(i,3));
params.node_names{i} = sprintf('label="%s"',params.node_names{i});
end
[u,v] = write_dot_file(A, params);
if params.sfdp_coloring == 1
positions = load_positions_from_sfdp(params.gv_file);
params.edge_colors = edge_colors_from_positions(u,v,positions);
fprintf(1,'Re-dumping graph with colors\n');
write_dot_file(A, params);
end
if nargout == 0
%If no outputs are specified, we write a pdf file.
fprintf(1,'creating pdf file %s\n', params.pdf_file);
[basedir,tmp,tmp] = fileparts(params.pdf_file);
[~,~]=unix(sprintf('cd %s && dot -Ksfdp -Tpdf %s > %s', ...
basedir,params.gv_file, params.pdf_file));
else
fprintf(1,'Creating png file and loading\n');
[aaa,bbb,ccc] = fileparts(params.gv_file);
[~,~]=unix(sprintf('cd %s && dot -Ksfdp -Tpng %s > %s', ...
aaa, params.gv_file, params.png_file));
I = imread(params.png_file);
delete(params.png_file);
end
% delete graphviz file
delete(params.gv_file);
function [u,v] = write_dot_file(A, params)
% Writes the dot file which graphviz will use as input, and return
% the indices of the edges
gv_file = params.gv_file;
[u,v] = find(A>0);
goods = (v>=u);
u = u(goods);
v = v(goods);
fid = fopen(gv_file,'w');
fprintf(fid,'// Dotfile written by make_memex_graph.m\n');
fprintf(fid,['// Matlab wrapper by Tomasz Malisiewicz (tomasz@' ...
'csail.mit.edu)\n']);
fprintf(fid,['// Code available: https://github.com/quantombone/' ...
'graphviz_matlab_magic\n']);
fprintf(fid,'graph G {\n');
fprintf(fid,['node [shape=circle style="filled" width=1.0 height=.5' ...
' penwidth=10 labelloc="t" fontsize="30"' ...
' labelfontcolor="black"]\n']);
fprintf(fid,'graph [outputorder="edgesfirst" size="20,20"]\n');
fprintf(fid,'edge [fontsize="10.0" penwidth=10 weight=10]\n');
fprintf(fid,'overlap="scale"\n');
for i = 1:size(A,1)
fprintf(fid,'%d [%s %s %s %s];\n',i,...
params.shapestring{i},...
params.colstring{i},...
params.node_names{i},...
params.icon_string{i});
end
for i = 1:length(u)
if u(i)>v(i)
continue
end
en = '';
if isfield(params,'edge_names')
en = params.edge_names{u(i),v(i)};
end
if isfield(params,'edge_colors')
ec = params.edge_colors(i,:);
else
ec = [1 1 1];
end
fprintf(fid,'%d -- %d [weight=%.5f color="%.3f %.3f %.3f" %s];\n',...
u(i), v(i), full(A(u(i),v(i))),...
ec(1),ec(2),ec(3),...
en);
end
fprintf(fid,'}\n');
fclose(fid);
function positions = load_positions_from_sfdp(gv_file)
% Use some simple shell tricks to grep out the positions of nodes
% after we run graphviz on the input file and return a simple ascii
% output file.
plain_file = [gv_file '.plain'];
nodes_file = [gv_file '.nodes'];
[~,~]=unix(sprintf('dot -Ksfdp -Tplain %s > %s', ...
gv_file, plain_file));
fprintf(1,'creating colors\n');
[~,~]=unix(sprintf('grep node %s | awk ''{print($2,$3,$4)}'' > %s',...
plain_file, nodes_file));
r = load(nodes_file,'-ascii');
positions = r(:,2:3);
ids = r(:,1);
[aa,bb] = sort(ids);
positions = positions(bb,:);
% Clean up files
delete(plain_file);
delete(nodes_file);
function edge_colors = edge_colors_from_positions(u,v,positions)
%Given the [u,v] indices of connected nodes as well as their
%positions, compute the 2D distance between connected nodes. Then
%create edge colors which map the shortest edge to red and the
%longest edge to blue using Matlab's jet color scheme.
% Compute the euclided distances between connected nodes
dists = sqrt(sum( (positions(u,:)-positions(v,:)).^2,2));
%quantize colors into 200 different discrete colors
NC = 200;
colorsheet = jet(NC);
colorsheet = colorsheet(end:-1:1,:);
% map dists to [0,1] range
dists = dists - min(dists);
dists = dists / (max(dists)+eps);
dists = round(dists*(NC-1)+1);
%graphviz needs colors in hsv format
edge_colors = colorsheet(dists,:);
edge_colors = rgb2hsv(edge_colors);