Updated for release version: mgui-1.0.10-alpha
This tutorial will explain how to export an adjacency matrix from Matlab to a graph in Pajek format, which can be read into the mgui environment. See here for a tutorial on how to load and visualize a Pajek graph.
Introduction
If you work with graphs in Matlab, but wish to visualize them using ModelGUI, then this nifty little tutorial is for you (if not, you could always go here). The process requires a Matlab script called write_matrix_to_pajek. For the purposes of the tutorial, you'll also need the script get_random_graph.
Note: Pajek is a nifty tool for 2D visualization, as well as computations, on graphs. Check it out here.
The Script
In Matlab, ensuring the required scripts are in your path, type:
>> help write_matrix_to_pajek
WRITE_MATRIX_TO_PAJEK writes an adjacency matrix representing a graph to
Pajek format, which can be read using the Pajek graph visualization tool,
as well as the modelGUI application.
Arguments:
matrix A square adjacency matrix
path The path specify the Pajek output file
varargin Parameters refining the export:
'weighted' [true/false]: whether to use the matrix
values as edge weights (default = true).
'threshold_low': the low threshold at which to
include an edge (default = 0).
'threshold_high': the high threshold at which to
include an edge (default = realmax).
'directed': whether the edges are directed (default
= true); in this case, the rule is column -> row
'labels': an N x 1 vector of vertex labels
(default = none).
'coords': an N x 3 matrix of vertex coordinates
(default = none).
Author: Andrew Reid, BIC, MNI, 2011
This should explain everything you need to know to export your graph in the format you'd like. You can export weighted, unweighted, directed, and undirected graphs. You can set thresholds for edge inclusion, define labels for each vertex, and specify 3D coordinates (which can be the centroids of your regions-of-interest, for example).
The Graph
Let's use an example from neuroscience, since that's what I've been using this for recently. Suppose you have a set of brain regions, R, of size N. For each pair of regions i and j (where i is not j), there may be a projection of axonal fibres of a certain connection strength C(i,j). Let's assume we don't know the directionality of this connection, which means that C(i,j) == C(j,i); in other words, the adjacency matrix is symmetric. This brain network can be described by the adjacency matrix M, which is an N x N square (and symmetric) matrix. Each i,jth element of M contains a value which represents the connection strength between regions i and j; in graph terms, M represents a weighted, undirected graph of size N.
To get this tutorial rolling, let's first create a random graph of size N=20, with an average of number of connections per region K=3 (or, more accurately, a connection probability of 3/20 = 15%), using the script get_random_graph. This will return a symmetric (undirected) random graph:
>> M = get_random_graph(20,3)
M =
0 1 0 1 0 0 0 0 0 0 1 0 0 0 0 1 0 1 0 0
1 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0
0 1 0 0 0 1 0 1 0 0 0 1 0 0 0 1 0 0 0 0
1 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0
0 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 1 0 0 0
0 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 1 0 0
0 0 1 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 1 0
0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0
1 1 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 1 1
0 0 1 1 0 0 0 1 0 1 0 0 0 0 0 0 0 0 1 0
0 0 0 1 0 0 1 0 0 0 1 0 0 0 0 0 0 0 1 0
0 0 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0 1 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0
1 0 1 0 0 0 0 1 0 1 0 0 0 0 1 0 0 0 1 1
0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 1 0 1
1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 1 0 0 0
0 0 0 0 1 0 0 1 0 0 1 1 1 1 0 1 0 0 0 1
0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 1 1 0 1 0
Your graph will be a bit different of course, since it's randomly generated, but it will be comparable to that above. You'll notice, however, that the values are either zeros or ones. Since we want our edges to be weighted, we take an extra step to create random weights:
>> M = M.*rand(20);
Notably, this weighted network is no longer symmetric. To be thorough, we could take the trouble to mirror the top triangle onto the bottom; however, since the export script (when the 'directed' parameter is set to false) will only use the top triangle (elements above the diagonal) to construct the graph, we don't need to do this. Let's just move on…
To visualize our graph in 3D, we need to define coordinates for our vertices. Ideally, for our brain network example, we'd want these to be the physical centroids of our brain regions. For our tutorial, however, we can just settle for generating random coordinates:
>> coords = rand(20,3)
coords =
0.8750 0.6524 0.7437
0.3486 0.5310 0.3020
0.0419 0.7151 0.0896
0.1423 0.5048 0.8260
0.0766 0.4880 0.3896
0.7405 0.4978 0.7753
0.4565 0.9360 0.1794
0.6682 0.3893 0.1094
0.6992 0.1171 0.9052
0.5714 0.2404 0.8764
0.6287 0.6849 0.9998
0.8778 0.8393 0.8643
0.6624 0.9701 0.0369
0.8754 0.2152 0.5447
0.4675 0.7603 0.9976
0.1413 0.5841 0.5110
0.0681 0.4030 0.8735
0.7142 0.5100 0.0702
0.3080 0.4956 0.9875
0.6712 0.6514 0.9227
These will do. We could also now define a list of names for our vertices, corresponding to the names of the regions (as a vector of strings). However, in the absence of this list, the script will use the indices of the regions (1 through N) as labels, and this is fine for our purposes (or mine, anyways). So we are ready to export.
The Export
Having defined our weighted, undirected graph and its coordinates, we can export it with the following command:
>> write_matrix_to_pajek(M,'/some/path/random_graph.net','weighted',true,'directed',false,'coords',coords);
Now, if you open 'random_graph.net' in a text editor, you can see the results:
*vertices 20
1 "1" 0.875033 0.652421 0.743706
2 "2" 0.348575 0.531049 0.301953
3 "3" 0.041921 0.715107 0.089612
4 "4" 0.142340 0.504811 0.825965
5 "5" 0.076593 0.487999 0.389587
6 "6" 0.740527 0.497838 0.775305
7 "7" 0.456525 0.935976 0.179369
8 "8" 0.668249 0.389282 0.109361
9 "9" 0.699246 0.117145 0.905158
10 "10" 0.571357 0.240424 0.876351
11 "11" 0.628693 0.684908 0.999793
12 "12" 0.877764 0.839254 0.864255
13 "13" 0.662352 0.970145 0.036878
14 "14" 0.875414 0.215170 0.544682
15 "15" 0.467517 0.760343 0.997616
16 "16" 0.141336 0.584103 0.511008
17 "17" 0.068134 0.402952 0.873512
18 "18" 0.714242 0.510040 0.070221
19 "19" 0.307986 0.495644 0.987539
20 "20" 0.671164 0.651368 0.922713
*edges
1 2 0.726637
1 4 0.571413
1 11 0.519917
1 16 0.516432
1 18 0.143951
2 3 0.666839
2 11 0.053824
3 6 0.740008
3 8 0.678569
3 12 0.752858
3 16 0.688933
4 12 0.110048
4 13 0.006108
5 19 0.248952
6 7 0.260206
6 17 0.247200
7 13 0.304298
7 18 0.497408
8 12 0.261176
8 16 0.241937
8 19 0.830886
9 14 0.915477
10 12 0.450963
10 16 0.612727
11 13 0.860190
11 14 0.482507
11 19 0.380560
11 20 0.817119
12 19 0.925869
13 19 0.740844
14 19 0.737633
15 16 0.351098
16 19 0.510100
16 20 0.625450
17 18 0.984532
17 20 0.346649
19 20 0.574617
The file is ready to be opened in ModelGUI (or Pajek), which is described in this tutorial. After fiddling around with the scales (hint for 3D: VertexScale=0.05, EdgeCylinderMin=0.005, EdgeWeightScale=0.01), I get a graph that looks like this: