Sait
Sait

Reputation: 19825

igraph select function for generic attributes

I am learning igraph, by following this tutorial.

Here is a syntax from the tutorial that I was not familiar before:

# g is a Graph object
# g.vs are vertices of g
>>> g.vs.select(age_lt=30)
# this returns vertices which has "age" attribute less than 30

I need something more generic.

More specifically, I want to get the vertices whose attribute atr is smaller than c. Say, atr is string and c is int.

I tried:

>>> atr = 'age'
>>> c = 30
>>> g.vs.select(atr + '_lt'= c)

However, I get a SyntaxError:

SyntaxError: keyword can't be an expression

I don't want to do it manually, like:

>>> [v for v in g.vs if v[atr] < c]

because my graph is big.

Upvotes: 1

Views: 1669

Answers (2)

A_A
A_A

Reputation: 2368

When the first parameter to select is a callable, the vertex is selected if the callable returns True.

In this way, you can apply relatively more complex queries. For example:

import igraph

G = igraph.Graph() 
G.add_vertex("John", age=22) 
G.add_vertex("Vilma", age=20) 
G.add_edge("John", "Vilma") 
vRes = G.vs.select(lambda x:x["name"]=="John" and x["age"]>20)
#Or, with query parameters as below
#someAttribute = "age"
#someValue = 20
#vRes = G.vs.select(lambda x:x[someAttribute] > someValue)

Within the lambda above, argument x is an igraph::Vertex which provides access to all vertex attributes.

A similar interface exists to select edges.

Hope this helps.

Upvotes: 3

Padraic Cunningham
Padraic Cunningham

Reputation: 180502

You could use a dict and str.format:

atr = 'age'
c = 30

g.vs(**{'{}_lt'.format(atr): c}

If you were worried about memory you could also use a gen exp:

(v for v in g.vs if v[atr] < c)

Both return the same output:

In [2]: g = Graph([(0,1), (0,2), (2,3), (3,4), (4,2), (2,5), (5,0), (6,3), (5,6)])

In [3]: g.vs["name"] = ["Alice", "Bob", "Claire", "Dennis", "Esther", "Frank", "George"]   
In [4]: g.vs["age"] = [25, 31, 18, 47, 22, 23, 50]   
In [5]: g.vs["gender"] = ["f", "m", "f", "m", "f", "m", "m"]   
In [6]: g.es["is_formal"] = [False, False, True, True, True, False, True, False, False]  
In [7]: atr = 'age'    
In [8]: c = 30    
In [9]: list(g.vs(**{'{}_lt'.format(atr): c}))
Out[9]: 
[igraph.Vertex(<igraph.Graph object at 0x7f06ae24f810>,0,{'gender': 'f', 'age': 25, 'name': 'Alice'}),
 igraph.Vertex(<igraph.Graph object at 0x7f06ae24f810>,2,{'gender': 'f', 'age': 18, 'name': 'Claire'}),
 igraph.Vertex(<igraph.Graph object at 0x7f06ae24f810>,4,{'gender': 'f', 'age': 22, 'name': 'Esther'}),
 igraph.Vertex(<igraph.Graph object at 0x7f06ae24f810>,5,{'gender': 'm', 'age': 23, 'name': 'Frank'})]

In [10]: list(v for v in g.vs if v[atr] < c)
Out[10]: 
[igraph.Vertex(<igraph.Graph object at 0x7f06ae24f810>,0,{'gender': 'f', 'age': 25, 'name': 'Alice'}),
 igraph.Vertex(<igraph.Graph object at 0x7f06ae24f810>,2,{'gender': 'f', 'age': 18, 'name': 'Claire'}),
 igraph.Vertex(<igraph.Graph object at 0x7f06ae24f810>,4,{'gender': 'f', 'age': 22, 'name': 'Esther'}),
 igraph.Vertex(<igraph.Graph object at 0x7f06ae24f810>,5,{'gender': 'm', 'age': 23, 'name': 'Frank'})]

You won't all len etc.. on the gen exp but it seems pretty efficient if you just want the filtered elements:

In [14]: timeit list(v for v in g.vs if v[atr] < c)
100000 loops, best of 3: 4.7 µs per loop

In [15]: timeit list(g.vs(**{'{}_lt'.format(atr): c}))
100000 loops, best of 3: 14.5 µs per loop

Upvotes: 2

Related Questions