SNAP¶
This Jupyter notebook provides an example of using the Python packages gravis and SNAP (=Stanford Network Analysis Platform). The .ipynb file can be found here.
References¶
Installation¶
Import¶
[1]:
import os
import snap
import gravis as gv
Quick start¶
Example 1¶
[2]:
# Create a random graph
g = snap.GenForestFire(250, 0.35, 0.35)
# Plot it
gv.d3(g, zoom_factor=0.2)
[2]:
Graph construction¶
1) Manual graph construction¶
Tutorial: Graph creation
API reference: Graph and network classes
1.a) TUNGraph¶
undirected, with self-loop (max 1 per node), without parallel edges, without attributes
-
AddNode(NId)
AddNode(NodeI)
AddEdge(SrcNId, DstNId)
AddEdge(EdgeI)
[3]:
ug = snap.TUNGraph.New()
# Node with automatic id (starts from 0 or highest user-defined id)
ug.AddNode(-1) # argument: -1 for auto
# Node with user-defined id
ug.AddNode(5) # argument: int
ug.AddNode(7)
# Nodes
# ~ Not supported (only via node iterator from other graph) ~
# Edge (nodes need to exist already)
ug.AddEdge(0, 5)
ug.AddEdge(5, 7)
ug.AddEdge(7, 0)
ug.AddEdge(5, 5)
ug.AddEdge(7, 7)
# Edges
# ~ Not supported (only via edge iterator from other graph) ~
gv.d3(ug, graph_height=200)
[3]:
1.b) TNGraph¶
directed, with self-loop (max 1), without parallel edges, without attributes
[4]:
dg = snap.TNGraph.New()
# Node with automatic id
dg.AddNode(-1) # argument: -1 for auto
# Node with user-defined id
dg.AddNode(5) # argument: int
dg.AddNode(7)
# Nodes
# ~ Not supported (only via node iterator from other graph) ~
# Edge (nodes need to exist already)
dg.AddEdge(0, 5)
dg.AddEdge(5, 0)
dg.AddEdge(5, 7)
dg.AddEdge(7, 0)
dg.AddEdge(5, 5)
dg.AddEdge(7, 7)
# Edges
# ~ Not supported (only via edge iterator from other graph) ~
gv.d3(dg, graph_height=200)
[4]:
1.c) TUndirNet (similar to TUNGraph)¶
directed, with self-loop (max 1 per node), without parallel edges, without attributes
[5]:
umg = snap.TUndirNet.New()
# Node with automatic id
umg.AddNode(-1) # argument: -1 for auto
# Node with user-defined id
umg.AddNode(5) # argument: int
umg.AddNode(7)
# Nodes
# ~ Not supported (only via node iterator from other graph) ~
# Edge (nodes need to exist already)
umg.AddEdge(0, 5)
umg.AddEdge(5, 0)
umg.AddEdge(5, 7)
umg.AddEdge(7, 0)
umg.AddEdge(5, 5)
umg.AddEdge(7, 7)
# Edges
# ~ Not supported (only via edge iterator from other graph) ~
gv.d3(umg, graph_height=200)
[5]:
1.d) TDirNet (similar to TNGraph)¶
undirected, with self-loop (max 1 per node), without parallel edges, without attributes
[6]:
dmg = snap.TDirNet.New()
# Node with automatic id
dmg.AddNode(-1) # argument: -1 for auto
# Node with user-defined id
dmg.AddNode(5) # argument: int
dmg.AddNode(7)
# Nodes
# ~ Not supported (only via node iterator from other graph) ~
# Edge (nodes need to exist already)
dmg.AddEdge(0, 5)
dmg.AddEdge(5, 0)
dmg.AddEdge(5, 7)
dmg.AddEdge(7, 0)
dmg.AddEdge(5, 5)
dmg.AddEdge(7, 7)
# Edges
# ~ Not supported (only via edge iterator from other graph) ~
gv.d3(dmg, graph_height=200)
[6]:
1.e) TNEANet¶
undirected, with self-loops, with parallel edges, with attributes (no graph attributes, node and edge attributes after explicit declaration)
[7]:
dmg = snap.TNEANet.New()
# Node with automatic id
dmg.AddNode(-1) # argument: -1 for auto
# Node with user-defined id
dmg.AddNode(1) # argument: int
dmg.AddNode(2)
dmg.AddNode()
dmg.AddNode(4)
dmg.AddNode()
dmg.AddNode(6)
dmg.AddNode(7)
# Nodes
# ~ Not supported (only via node iterator from other graph) ~
# Edge (nodes need to exist already)
dmg.AddEdge(0, 1)
dmg.AddEdge(1, 2)
dmg.AddEdge(2, 3)
dmg.AddEdge(3, 4)
dmg.AddEdge(4, 5)
dmg.AddEdge(5, 6)
dmg.AddEdge(6, 7)
dmg.AddEdge(7, 0)
dmg.AddEdge(0, 0)
dmg.AddEdge(0, 0)
dmg.AddEdge(0, 1)
dmg.AddEdge(0, 1)
# Edges
# ~ Not supported (only via edge iterator from other graph) ~
gv.d3(dmg, graph_height=200)
[7]:
Assign attributes to a created graph¶
API reference:
TNEANet class: the only data structure in SNAP which can have node and edge attributes
[8]:
g = snap.TNEANet.New()
for node in [0, 1, 2, 3, 4, 5, 6, 7]:
g.AddNode(node)
for source, target in [(0, 1), (1, 2), (2, 3), (3, 4), (4, 5), (5, 6), (6, 7), (7, 0)]:
g.AddEdge(source, target)
1) Graph attributes¶
[9]:
# ~ Not supported ~
2) Node attributes¶
[10]:
# Define node attributes
g.AddIntAttrN('size') # int
g.AddFltAttrN('opacity') # float
g.AddStrAttrN('color') # str
g.AddStrAttrN('shape') # str
# Nodes
num_nodes = len(list(g.Nodes()))
for i in range(num_nodes):
g.AddIntAttrDatN(i, 5 + i*5, 'size')
g.AddStrAttrDatN(i, 'lightblue', 'color')
# Node
g.AddStrAttrDatN(3, 'darkred', 'color')
g.AddStrAttrDatN(3, 'hexagon', 'shape')
g.AddIntAttrDatN(3, 40, 'size')
g.AddFltAttrDatN(3, 0.3, 'opacity')
[10]:
0
3) Edge attributes¶
[11]:
# Define edge attributes
g.AddIntAttrE('size') # int
# g.AddFltAttrE('opacity') # float
g.AddStrAttrE('color') # str
# Edges
num_edges = len(list(g.Edges()))
for i in range(num_edges):
g.AddIntAttrDatE(i, 1 + i, 'size')
g.AddStrAttrDatE(i, 'lightgreen', 'color')
# Edge
g.AddIntAttrDatE(3, 1, 'size')
# g.AddFltAttrDatE(3, 1.0, 'opacity')
g.AddStrAttrDatE(3, 'red', 'color')
[11]:
0
[12]:
gv.d3(g, graph_height=200)
[12]:
2) Algorithmic graph construction¶
[13]:
num_nodes = 20
num_edges = 10
[14]:
g = snap.GenForestFire(num_nodes, 0.35, 0.35)
# A random Erdos-Renyi directed graph
g = snap.GenRndGnm(snap.PNGraph, num_nodes, num_edges)
# A Preferential Attachment graph with out-degree 3
g = snap.GenPrefAttach(num_nodes, 3)
3) Graph loading from an internal collection¶
[15]:
# TODO
4) Graph import and export¶
Import¶
[16]:
filepath = os.path.join('data', 'snap_graph.net')
g = snap.LoadPajek(snap.PNGraph, filepath)
# TODO
Export¶
[17]:
filepath = os.path.join('data', 'snap_graph.net')
snap.SavePajek(g, filepath)
# Other methods
# snap.SaveEdgeList(g, 'snap_graph_edge_list.txt')
# TODO
Basic graph inspection¶
1) Graph and its properties¶
[18]:
print('Type:', type(g))
print('Directed:', )
print('Number of nodes:', g.GetNodes())
print('Number of edges:', g.GetEdges())
print('Well-formed:', g.IsOk())
print('Approximate graph diameter:', snap.GetBfsFullDiam(g, 10))
print('Number of triads:', snap.GetTriads(g))
print('Clustering coefficient', snap.GetClustCf(g))
Type: <class 'snap.PNGraph'>
Directed:
Number of nodes: 50
Number of edges: 100
Well-formed: True
Approximate graph diameter: 5
Number of triads: 9
Clustering coefficient 0.08790476190476189
2) Nodes and their properties¶
[19]:
#g.AddIntAttrN("NValInt", 0)
for node in g.Nodes():
print('Class:', type(node))
print("Id:", node.GetId())
print("In degree:", node.GetInDeg())
print("Out degree:", node.GetOutDeg())
break
#g.AddIntAttrDatN(node_id, 42, "NValInt")
Class: <class 'snap.TNGraphNodeI'>
Id: 1
In degree: 0
Out degree: 2
3) Edges and their properties¶
[20]:
for edge in g.Edges():
print('Class:', type(edge))
print("Id:", edge.GetId())
print("Source node id:", edge.GetSrcNId())
print("Target node id:", edge.GetDstNId())
break
Class: <class 'snap.TNGraphEdgeI'>
Id: (1, 4)
Source node id: 1
Target node id: 4
Calculating graph measures and metrics¶
1) Quantitative measures¶
[21]:
snap.GetClustCf(g)
[21]:
0.08790476190476189
2) Structure inference¶
Community detection¶
[22]:
g = snap.GenRndGnm(snap.PUNGraph, 50, 100)
CmtyV = snap.TCnComV()
modularity = snap.CommunityGirvanNewman(g, CmtyV)
CmtyV = snap.TCnComV()
modularity = snap.CommunityCNM(g, CmtyV)
Other kinds of groups¶
[23]:
g = snap.GenRndGnm(snap.PUNGraph, 50, 100)
snap.GetTriads(g)
[23]:
4
Graph visualization¶
[24]:
# TODO