0
# Vertex and Edge Sequences
1
2
Efficient sequence classes for accessing and manipulating collections of vertices and edges with filtering and attribute operations. These classes provide powerful query and manipulation capabilities for graph elements.
3
4
## Capabilities
5
6
### Vertex Sequences
7
8
Collections of vertices with advanced filtering, selection, and attribute manipulation methods.
9
10
```python { .api }
11
class VertexSeq:
12
def __init__(self, graph, vertices=None):
13
"""
14
Create vertex sequence.
15
16
Parameters:
17
- graph: Graph object
18
- vertices: list/range, vertex indices (None for all vertices)
19
"""
20
21
def __len__(self):
22
"""Get number of vertices in sequence."""
23
24
def __getitem__(self, key):
25
"""
26
Access vertices by index or slice.
27
28
Parameters:
29
- key: int/slice/str, vertex index, slice, or attribute name
30
31
Returns:
32
Vertex or VertexSeq or attribute values
33
"""
34
35
def select(self, *args, **kwargs):
36
"""
37
Filter vertices by criteria.
38
39
Parameters:
40
- *args: vertex indices or boolean conditions
41
- **kwargs: attribute-based filters
42
43
Returns:
44
VertexSeq, filtered vertices
45
"""
46
47
def find(self, *args, **kwargs):
48
"""
49
Find first vertex matching criteria.
50
51
Parameters:
52
- *args: search criteria
53
- **kwargs: attribute filters
54
55
Returns:
56
Vertex, first match
57
"""
58
59
def attributes(self):
60
"""
61
Get list of vertex attribute names.
62
63
Returns:
64
list of str, attribute names
65
"""
66
67
@property
68
def indices(self):
69
"""
70
Get vertex indices.
71
72
Returns:
73
list of int, vertex indices in sequence
74
"""
75
```
76
77
**Usage Examples:**
78
79
```python
80
import igraph as ig
81
82
# Create sample graph with attributes
83
g = ig.Graph([(0,1), (1,2), (2,0), (1,3), (3,4)], directed=False)
84
g.vs["name"] = ["Alice", "Bob", "Carol", "Dave", "Eve"]
85
g.vs["age"] = [25, 30, 28, 35, 22]
86
g.vs["city"] = ["NYC", "LA", "NYC", "LA", "Chicago"]
87
88
# Access all vertices
89
all_vertices = g.vs
90
print(f"Total vertices: {len(all_vertices)}")
91
92
# Access by index
93
vertex_0 = g.vs[0]
94
print(f"Vertex 0: {vertex_0}")
95
96
# Access by slice
97
first_three = g.vs[0:3]
98
print(f"First three vertices: {first_three.indices}")
99
100
# Access attributes
101
names = g.vs["name"]
102
ages = g.vs["age"]
103
print(f"Names: {names}")
104
print(f"Ages: {ages}")
105
106
# Get available attributes
107
print(f"Available attributes: {g.vs.attributes()}")
108
```
109
110
### Vertex Selection and Filtering
111
112
Advanced filtering capabilities using attribute values, graph properties, and custom criteria.
113
114
```python { .api }
115
class VertexSeq:
116
def select(self, *args, **kwargs):
117
"""
118
Advanced vertex filtering.
119
120
Selection methods:
121
- By index: vs.select(0, 2, 4)
122
- By range: vs.select(range(5, 10))
123
- By attribute value: vs.select(name="Alice")
124
- By attribute condition: vs.select(age_gt=30)
125
- By degree: vs.select(_degree_gt=5)
126
- By boolean list: vs.select([True, False, True, ...])
127
- By lambda: vs.select(lambda v: v.degree() > 2)
128
129
Attribute conditions:
130
- attr_eq, attr_ne: equal, not equal
131
- attr_lt, attr_le: less than, less or equal
132
- attr_gt, attr_ge: greater than, greater or equal
133
- attr_in, attr_notin: in list, not in list
134
135
Graph property conditions:
136
- _degree, _indegree, _outdegree: vertex degrees
137
- _between: vertices between given vertices
138
139
Returns:
140
VertexSeq, filtered vertices
141
"""
142
```
143
144
**Usage Examples:**
145
146
```python
147
# Select by attribute values
148
nyc_vertices = g.vs.select(city="NYC")
149
print(f"NYC vertices: {nyc_vertices.indices}")
150
151
# Select by attribute conditions
152
older_vertices = g.vs.select(age_gt=27)
153
young_vertices = g.vs.select(age_le=25)
154
print(f"Older than 27: {older_vertices['name']}")
155
print(f"25 or younger: {young_vertices['name']}")
156
157
# Select by multiple conditions
158
nyc_older = g.vs.select(city="NYC", age_gt=27)
159
print(f"NYC and older than 27: {nyc_older['name']}")
160
161
# Select by degree
162
high_degree = g.vs.select(_degree_gt=1)
163
print(f"High degree vertices: {high_degree['name']}")
164
165
# Select by index list
166
specific_vertices = g.vs.select([0, 2, 4])
167
print(f"Specific vertices: {specific_vertices['name']}")
168
169
# Select with lambda function
170
lambda_selection = g.vs.select(lambda v: v["age"] < 30 and v.degree() >= 2)
171
print(f"Lambda selection: {lambda_selection['name']}")
172
173
# Select by attribute list membership
174
la_chicago = g.vs.select(city_in=["LA", "Chicago"])
175
print(f"LA or Chicago: {la_chicago['name']}")
176
177
# Exclude vertices
178
not_bob = g.vs.select(name_ne="Bob")
179
print(f"Not Bob: {not_bob['name']}")
180
```
181
182
### Edge Sequences
183
184
Collections of edges with specialized filtering for network topology analysis.
185
186
```python { .api }
187
class EdgeSeq:
188
def __init__(self, graph, edges=None):
189
"""
190
Create edge sequence.
191
192
Parameters:
193
- graph: Graph object
194
- edges: list/range, edge indices (None for all edges)
195
"""
196
197
def select(self, *args, **kwargs):
198
"""
199
Filter edges by criteria.
200
201
Special edge filters:
202
- _source, _target: source/target vertex conditions
203
- _between: edges between vertex sets
204
- _within: edges within vertex set
205
- _incident: edges incident to vertices
206
207
Returns:
208
EdgeSeq, filtered edges
209
"""
210
211
def find(self, *args, **kwargs):
212
"""
213
Find first edge matching criteria.
214
215
Returns:
216
Edge, first match
217
"""
218
219
def attributes(self):
220
"""
221
Get edge attribute names.
222
223
Returns:
224
list of str, attribute names
225
"""
226
227
@property
228
def indices(self):
229
"""
230
Get edge indices.
231
232
Returns:
233
list of int, edge indices
234
"""
235
```
236
237
**Usage Examples:**
238
239
```python
240
# Add edge attributes
241
g.es["weight"] = [1.0, 2.5, 1.8, 0.9, 3.2]
242
g.es["type"] = ["friend", "work", "family", "friend", "work"]
243
244
# Access all edges
245
all_edges = g.es
246
print(f"Total edges: {len(all_edges)}")
247
248
# Access edge attributes
249
weights = g.es["weight"]
250
types = g.es["type"]
251
print(f"Edge weights: {weights}")
252
print(f"Edge types: {types}")
253
254
# Select by attribute
255
friend_edges = g.es.select(type="friend")
256
heavy_edges = g.es.select(weight_gt=2.0)
257
print(f"Friend edges: {friend_edges.indices}")
258
print(f"Heavy edges (>2.0): {heavy_edges.indices}")
259
260
# Select by source/target vertices
261
from_alice = g.es.select(_source=0) # Alice is vertex 0
262
to_bob = g.es.select(_target=1) # Bob is vertex 1
263
print(f"Edges from Alice: {from_alice.indices}")
264
print(f"Edges to Bob: {to_bob.indices}")
265
266
# Select edges between specific vertices
267
alice_bob = g.es.select(_between=([0], [1]))
268
print(f"Edges between Alice and Bob: {alice_bob.indices}")
269
270
# Select edges within a set (internal edges)
271
core_vertices = [0, 1, 2] # Alice, Bob, Carol
272
internal_edges = g.es.select(_within=core_vertices)
273
print(f"Internal edges in core: {internal_edges.indices}")
274
275
# Select edges incident to vertices
276
incident_to_bob = g.es.select(_incident=1)
277
print(f"Edges incident to Bob: {incident_to_bob.indices}")
278
```
279
280
### Advanced Edge Selection
281
282
Complex edge filtering patterns for network analysis.
283
284
**Usage Examples:**
285
286
```python
287
# Multiple source/target conditions
288
multi_source = g.es.select(_source_in=[0, 1]) # From Alice or Bob
289
multi_target = g.es.select(_target_in=[2, 3]) # To Carol or Dave
290
print(f"From Alice/Bob: {multi_source.indices}")
291
print(f"To Carol/Dave: {multi_target.indices}")
292
293
# Edges between two sets of vertices
294
group1 = [0, 1] # Alice, Bob
295
group2 = [2, 3, 4] # Carol, Dave, Eve
296
between_groups = g.es.select(_between=(group1, group2))
297
print(f"Between groups: {between_groups.indices}")
298
299
# Combine topological and attribute filters
300
heavy_friend_edges = g.es.select(type="friend", weight_gt=1.5)
301
print(f"Heavy friendship edges: {heavy_friend_edges.indices}")
302
303
# Edges involving high-degree vertices
304
high_deg_vertices = g.vs.select(_degree_gt=1).indices
305
edges_with_hubs = g.es.select(_incident_in=high_deg_vertices)
306
print(f"Edges involving hubs: {edges_with_hubs.indices}")
307
308
# Complex lambda selection
309
complex_edges = g.es.select(lambda e: e["weight"] > 1.0 and
310
g.vs[e.source]["age"] + g.vs[e.target]["age"] > 55)
311
print(f"Complex selection: {complex_edges.indices}")
312
```
313
314
### Attribute Access and Manipulation
315
316
Efficient batch operations on vertex and edge attributes.
317
318
```python { .api }
319
class VertexSeq:
320
def __setitem__(self, attr, values):
321
"""
322
Set attribute values for vertices in sequence.
323
324
Parameters:
325
- attr: str, attribute name
326
- values: list/value, attribute values
327
"""
328
329
def __delitem__(self, attr):
330
"""
331
Delete attribute from vertices.
332
333
Parameters:
334
- attr: str, attribute name to delete
335
"""
336
337
class EdgeSeq:
338
def __setitem__(self, attr, values):
339
"""Set attribute values for edges."""
340
341
def __delitem__(self, attr):
342
"""Delete attribute from edges."""
343
```
344
345
**Usage Examples:**
346
347
```python
348
# Set new attributes
349
g.vs["degree"] = g.degree()
350
g.vs["normalized_age"] = [age/max(g.vs["age"]) for age in g.vs["age"]]
351
352
# Set attributes for filtered vertices
353
nyc_vertices = g.vs.select(city="NYC")
354
nyc_vertices["region"] = "East Coast"
355
356
high_degree = g.vs.select(_degree_gt=1)
357
high_degree["is_hub"] = True
358
359
# Set edge attributes
360
g.es["normalized_weight"] = [w/max(g.es["weight"]) for w in g.es["weight"]]
361
362
# Conditional attribute setting
363
for v in g.vs:
364
if v["age"] >= 30:
365
v["generation"] = "Millennial"
366
else:
367
v["generation"] = "Gen Z"
368
369
# Batch attribute operations
370
young_vertices = g.vs.select(age_lt=30)
371
young_vertices["category"] = "Young Adult"
372
373
# Delete attributes
374
del g.vs["normalized_age"] # Remove from all vertices
375
del nyc_vertices["region"] # Remove from filtered set
376
377
# Get attribute statistics
378
ages = g.vs["age"]
379
print(f"Age stats - Min: {min(ages)}, Max: {max(ages)}, Avg: {sum(ages)/len(ages):.1f}")
380
381
weights = g.es["weight"]
382
print(f"Weight stats - Min: {min(weights)}, Max: {max(weights)}, Avg: {sum(weights)/len(weights):.1f}")
383
```
384
385
### Sequence Operations
386
387
Mathematical and set operations on vertex and edge sequences.
388
389
```python { .api }
390
class VertexSeq:
391
def union(self, other):
392
"""Union with another vertex sequence."""
393
394
def intersection(self, other):
395
"""Intersection with another vertex sequence."""
396
397
def difference(self, other):
398
"""Difference from another vertex sequence."""
399
400
# Similar operations available for EdgeSeq
401
```
402
403
**Usage Examples:**
404
405
```python
406
# Set operations on vertex sequences
407
nyc_vertices = g.vs.select(city="NYC")
408
young_vertices = g.vs.select(age_lt=30)
409
high_degree = g.vs.select(_degree_gt=1)
410
411
# Union (vertices in either set)
412
nyc_or_young = nyc_vertices.union(young_vertices)
413
print(f"NYC or young: {nyc_or_young['name']}")
414
415
# Intersection (vertices in both sets)
416
nyc_and_young = nyc_vertices.intersection(young_vertices)
417
print(f"NYC and young: {nyc_and_young['name']}")
418
419
# Difference (vertices in first set but not second)
420
nyc_not_young = nyc_vertices.difference(young_vertices)
421
print(f"NYC but not young: {nyc_not_young['name']}")
422
423
# Chain operations
424
complex_selection = nyc_vertices.union(high_degree).intersection(young_vertices)
425
print(f"Complex selection: {complex_selection['name']}")
426
427
# Edge sequence operations
428
friend_edges = g.es.select(type="friend")
429
heavy_edges = g.es.select(weight_gt=2.0)
430
431
friend_or_heavy = friend_edges.union(heavy_edges)
432
friend_and_heavy = friend_edges.intersection(heavy_edges)
433
print(f"Friend or heavy edges: {friend_or_heavy.indices}")
434
print(f"Heavy friend edges: {friend_and_heavy.indices}")
435
```
436
437
### Sequence Iteration and Comprehensions
438
439
Efficient iteration patterns and list comprehensions with sequences.
440
441
**Usage Examples:**
442
443
```python
444
# Iterate over vertices
445
for vertex in g.vs:
446
print(f"Vertex {vertex.index}: {vertex['name']}, degree: {vertex.degree()}")
447
448
# Iterate over filtered vertices
449
for vertex in g.vs.select(age_gt=28):
450
print(f"Older vertex: {vertex['name']} (age {vertex['age']})")
451
452
# List comprehensions with sequences
453
vertex_info = [(v['name'], v['age'], v.degree()) for v in g.vs]
454
print("Vertex info:", vertex_info)
455
456
# Edge iteration
457
for edge in g.es:
458
source_name = g.vs[edge.source]['name']
459
target_name = g.vs[edge.target]['name']
460
print(f"Edge: {source_name} -- {target_name} ({edge['type']}, {edge['weight']})")
461
462
# Filtered edge iteration
463
for edge in g.es.select(weight_gt=1.5):
464
print(f"Heavy edge: {edge.source} -- {edge.target}")
465
466
# Create derived attributes using comprehensions
467
g.vs["name_length"] = [len(name) for name in g.vs["name"]]
468
g.es["weight_category"] = ["light" if w < 2.0 else "heavy" for w in g.es["weight"]]
469
470
# Complex comprehensions
471
g.vs["connection_strength"] = [
472
sum(g.es.select(_incident=v.index)["weight"])
473
for v in g.vs
474
]
475
476
# Neighborhood analysis
477
for vertex in g.vs.select(_degree_gt=2):
478
neighbors = [g.vs[n]['name'] for n in g.neighbors(vertex.index)]
479
print(f"{vertex['name']} is connected to: {neighbors}")
480
```
481
482
### Performance Optimization
483
484
Efficient patterns for working with large graphs and sequences.
485
486
**Usage Examples:**
487
488
```python
489
# Efficient attribute access patterns
490
def analyze_large_graph(graph):
491
"""Efficient analysis of large graphs using sequences."""
492
493
# Pre-compute commonly used attributes
494
degrees = graph.degree()
495
betweenness = graph.betweenness()
496
497
# Batch attribute setting (more efficient than individual)
498
graph.vs["degree"] = degrees
499
graph.vs["betweenness"] = betweenness
500
graph.vs["normalized_betw"] = [b/max(betweenness) for b in betweenness]
501
502
# Use indices for fast filtering
503
high_degree_indices = [i for i, d in enumerate(degrees) if d > 10]
504
high_degree_vs = graph.vs[high_degree_indices]
505
506
# Efficient edge filtering
507
important_edges = graph.es.select(_source_in=high_degree_indices,
508
_target_in=high_degree_indices)
509
510
return high_degree_vs, important_edges
511
512
# Memory-efficient iteration for very large graphs
513
def process_vertices_in_chunks(graph, chunk_size=1000):
514
"""Process vertices in chunks to manage memory."""
515
n_vertices = graph.vcount()
516
517
for start in range(0, n_vertices, chunk_size):
518
end = min(start + chunk_size, n_vertices)
519
chunk = graph.vs[start:end]
520
521
# Process chunk
522
for vertex in chunk:
523
# Do processing here
524
pass
525
526
print(f"Processed vertices {start} to {end-1}")
527
528
# Efficient neighbor analysis
529
def analyze_neighborhoods(graph):
530
"""Efficient neighborhood analysis."""
531
# Pre-compute all neighborhoods
532
all_neighbors = [set(graph.neighbors(i)) for i in range(graph.vcount())]
533
534
# Analyze without repeated graph queries
535
for i, vertex in enumerate(graph.vs):
536
neighbor_ages = [graph.vs[n]["age"] for n in all_neighbors[i]]
537
vertex["avg_neighbor_age"] = sum(neighbor_ages) / len(neighbor_ages) if neighbor_ages else 0
538
539
# Usage for large graphs
540
if g.vcount() > 1000:
541
high_deg, important_edges = analyze_large_graph(g)
542
process_vertices_in_chunks(g, chunk_size=500)
543
else:
544
# Use simpler patterns for small graphs
545
analyze_neighborhoods(g)
546
```