Skip to content

Commit 91fe832

Browse files
author
cindeem
committed
Merge pull request #8 from cindeem/graphpart_fixnodes
RF: Fix GraphPartition Class Change GraphPartition from using node_names to using integers representing nodes since it is used in indexing into adjacency_matrix
2 parents 7c8998f + cc6c42b commit 91fe832

File tree

3 files changed

+59
-24
lines changed

3 files changed

+59
-24
lines changed

brainx/modularity.py

Lines changed: 27 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -75,9 +75,7 @@ def __init__(self, graph, index):
7575
## add quick check to make sure the passed index is
7676
## a dict of sets
7777
self._check_index_contains_sets()
78-
## raise useful error if index is missing nodes in graph
79-
self._check_allnodes_in_index(graph)
80-
78+
8179
# We'll need the graph's adjacency matrix often, so store it once
8280
self.graph_adj_matrix = nx.adj_matrix(graph)
8381

@@ -91,11 +89,16 @@ def __init__(self, graph, index):
9189
self.num_edges = graph.number_of_edges()
9290

9391
if self.num_edges == 0:
94-
raise ValueError("TODO: Cannot create a graph partition of only one node.")
95-
96-
# Store the nodes as a set, needed for many operations
97-
self._node_set = set(graph.nodes())
92+
raise ValueError("Cannot create a graph partition "\
93+
"if graph has no edges")
9894

95+
# Store the nodes as a set of contiguous integers (indices into
96+
#the adjacency_matrix), needed for many operations
97+
self._node_set = set(range(self.num_nodes))
98+
self._node_names = graph.nodes()
99+
## raise useful error if index is missing nodes in graph
100+
self._check_allnodes_in_index()
101+
99102
# Now, build the edge information used in modularity computations
100103
self.mod_e, self.mod_a = self._edge_info()
101104

@@ -114,16 +117,13 @@ def _check_index_contains_sets(self):
114117
if not all([ x== type(set()) for x in index_types]):
115118
raise TypeError('index values should be of type set():: %s'%(index_types))
116119

117-
def _check_allnodes_in_index(self, graph):
120+
def _check_allnodes_in_index(self):
118121
"""Check that index contains all nodes in graph"""
119122
sets = self.index.values()
120-
all = []
121-
for item in sets:
122-
all += list(item)
123-
if not sorted(all) == sorted(graph.nodes()):
124-
missing = [x for x in all if not x in graph.nodes()]
125-
raise ValueError('index does not contain all nodes: missing %s'%missing)
126-
123+
indexnodes = set.union(*sets)
124+
missing = self._node_set.difference(indexnodes)
125+
if missing:
126+
raise ValueError('index does not contain all graph nodes: missing %s'%missing)
127127

128128
def _edge_info(self, mod_e=None, mod_a=None, index=None):
129129
"""Create the vectors of edge information.
@@ -508,8 +508,9 @@ def random_mod(self):
508508
num_mods=len(self)
509509

510510

511-
# Make a random choice bounded between 0 and 1, less than 0.5 means we will split the modules
512-
# greater than 0.5 means we will merge the modules.
511+
# Make a random choice bounded between 0 and 1,
512+
# less than 0.5 means we will split the modules
513+
# greater than 0.5 means we will merge the modules.
513514

514515
if num_mods >= self.num_nodes-1: ### CG: why are we subtracting 1 here?
515516
coin_flip = 1 #always merge if each node is in a separate module
@@ -609,6 +610,15 @@ def store_best(self):
609610
#Store references to the original graph and label dict
610611
self.bestindex = copy.deepcopy(self.index)
611612

613+
def index_as_node_names(self):
614+
""" index by default contains references to integers represented the
615+
nodes as indexed in the adjacency matrix defined in the original graph.
616+
This will return the index (partition) using the graph node names"""
617+
named_part = []
618+
for nmod, part in self.index.iteritems():
619+
named_part.append( [self._node_names[x] for x in part] )
620+
return named_part
621+
612622
def check_integrity(self, partition):
613623
""" Raises error if partition structure contains
614624
empty partitions or Nan values"""

brainx/tests/test_modularity.py

Lines changed: 31 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,26 @@ def betweenness_to_modularity(g,ppart):
4747
#-----------------------------------------------------------------------------
4848
# Tests
4949
#-----------------------------------------------------------------------------
50+
def test_graphpartition():
51+
""" test GraphPartition correctly handles graph whose
52+
nodes are strings"""
53+
graph = nx.Graph()
54+
graph.add_edge('a','b')
55+
graph.add_edge('c','d')
56+
index = {0:set([0,1]), 1:set([2,3])}
57+
gpart = mod.GraphPartition(graph, index)
58+
assert gpart._node_set == set([0,1,2,3])
59+
60+
def test_index_as_node_names():
61+
graph = nx.Graph()
62+
graph.add_edge('a','b')
63+
graph.add_edge('c','d')
64+
## NOTE network x does not store names as added
65+
## for this graph ['a', 'c', 'b', 'd']
66+
index = {0:set([0,2]), 1:set([1,3])}
67+
gpart = mod.GraphPartition(graph, index)
68+
named_index = gpart.index_as_node_names()
69+
assert ['a','b'] in named_index
5070

5171
def test_random_modular_graph_between_fraction():
5272
"""Test for graphs with non-zero between_fraction"""
@@ -428,16 +448,20 @@ def test_mutual_information():
428448
n1 = set(list(graph_partition3.index[0])[::2])
429449
n2 = set(list(graph_partition3.index[0])[1::2])
430450

431-
split_modules,e_new,a_new,d,t,m,n1,n2 = graph_partition3.compute_module_split(0,n1,n2)
432-
graph_partition3.apply_module_split(m,n1,n2,split_modules,e_new,a_new)
433-
mi3 = mod.mutual_information(ppart,graph_partition3.index)
451+
(split_modules, e_new,
452+
a_new, d, t, m,
453+
n1,n2) = graph_partition3.compute_module_split(0,n1,n2)
454+
graph_partition3.apply_module_split(m, n1, n2,
455+
split_modules,
456+
e_new, a_new)
457+
mi3 = mod.mutual_information(ppart, graph_partition3.index)
434458
npt.assert_array_less(mi3,mi_orig)
435459
## NOTE: CORRECTNESS NOT TESTED YET
436460

437461

438462
def test_random_mod():
439-
""" Test the GraphPartition operation that selects random modules to merge
440-
and split
463+
""" Test the GraphPartition operation that selects random modules
464+
to merge and split
441465
XXX not working yet"""
442466

443467
#nnod_mod, av_degrees, nmods
@@ -767,7 +791,8 @@ def test_badindex_graphpartition():
767791
gp = mod.GraphPartition(g, index)
768792
nt.assert_true(gp.index == index)
769793
npt.assert_raises(TypeError, mod.GraphPartition, g, {0: g.nodes()})
770-
npt.assert_raises(ValueError, mod.GraphPartition, g, {0:set(g.nodes()[:-1])})
794+
npt.assert_raises(ValueError, mod.GraphPartition, g,
795+
{0:set(g.nodes()[:-1])})
771796
npt.assert_raises(TypeError, mod.GraphPartition, g, g.nodes())
772797

773798

brainx/util.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ def format_matrix(data,s,b,lk,co,idc = [],costlist=[],nouptri = False):
2727
"""
2828

2929
cmat = data[b,s]
30-
th = cost2thresh(co,s,b,lk,[],idc,costlist) #get the right threshold
30+
th = cost2thresh(co,s,b,lk,idc,costlist) #get the right threshold
3131

3232
#cmat = replace_diag(cmat) #replace diagonals with zero
3333
cmat = thresholded_arr(cmat,th,fill_val=0)

0 commit comments

Comments
 (0)