Skip to content

Commit 27b0709

Browse files
committed
Add networkx examples
1 parent 2809c90 commit 27b0709

13 files changed

+901
-1
lines changed

source-code/README.md

+4-1
Original file line numberDiff line numberDiff line change
@@ -20,17 +20,20 @@ to create it. There is some material not covered in the presentation as well.
2020
* networkx
2121
* jupyter
2222
* folium (with conda, use `-c conda-forge`)
23+
* xarray
2324

2425
## What is it?
2526
* [`db-access`](db-access): illustration of accessing SQLite databases and using
2627
SQLAlchemy, including object-relational mapping.
2728
* [`gis`](gis): illustrations of working with geospatial data, including geopandas.
2829
* [`holoviews`](holoviews): illustrations of using HoloViews for convenient
2930
visualizations.
31+
* [`networkx`](networkx): illustration of using the networkx library for graph
32+
representation and algorithms.
3033
* [`pandas`](pandas): illustrations of using pandas and seaborn.
3134
* [`regexes`](regexes): illustrations of using regular expressions for validation
3235
and information extraction from textual data.
33-
* [1seaborn`]:(seaborn): illustrations of using Seaborn to create plots.
36+
* [`seaborn`](seaborn): illustrations of using Seaborn to create plots.
3437
* [`web-scraping`](web-scraping): illustration of web scraping using beautiful soup
3538
and graph representation using networkx.
3639
* [`xarray`](xarray): illustrates the xarray library for pandas-like operations

source-code/networkx/README.md

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
# NetworkX
2+
NetworkX is an excellent library that implements graph representations
3+
and algorithms. Note is is not part of Python's standard library.
4+
5+
## What is it?
6+
1. `generate_random_tree.py`: illustration of how to use the NetworkX
7+
DiGraph class to represent a tree, generates a random tree according
8+
to specifications
9+
1. `add_random_weights.py`: reads a GraphML representation of a tree, and
10+
addds random weights to the edges
11+
1. `compute_leaf_path_length.py`: compute the length of all paths from the
12+
tree's root to each of the leaves
13+
1. `par_compute_leaf_length.py`: compute the length of all paths
14+
from the tree's root to each of the leaves, uses `multiprocessing` for
15+
parallel processing
16+
1. `graph.xml`: example GraphML representation of a tree
17+
1. `graph.txt`: example edge list representation of a tree
18+
1. `weighted_tree.xml`: example GraphML representation of a weighted tree
19+
1. `max_flow.py`: illustration of the maximum flow algorithm on a very
20+
simple case of three parallel flows.
21+
1. `shortest_path.ipynb`: Jupyter notebook illustrating the shortest path
22+
algorithm.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
#!/usr/bin/env python
2+
3+
from argparse import ArgumentParser
4+
import random
5+
import sys
6+
import networkx as nx
7+
8+
9+
def add_edge_weights(tree):
10+
_add_edge_weights(tree, '1')
11+
12+
13+
def _add_edge_weights(tree, node):
14+
for child in tree.neighbors_iter(node):
15+
tree[node][child]['weight'] = random.random()
16+
_add_edge_weights(tree, child)
17+
18+
19+
def main():
20+
arg_parser = ArgumentParser(description='add edge weights to tree')
21+
arg_parser.add_argument('--input', required=True,
22+
help='inpput file')
23+
arg_parser.add_argument('--output', required=True,
24+
help='outpput file')
25+
arg_parser.add_argument('--seed', type=int, default=None,
26+
help='seed for random number generator')
27+
arg_parser.add_argument('--delim', dest='delimiter', default=' ',
28+
help='delimiter for edge list')
29+
arg_parser.add_argument('--no-data', action='store_true',
30+
dest='no_data', help='show edge data')
31+
arg_parser.add_argument('--edge-list', action='store_true',
32+
help='generate edge list output')
33+
options = arg_parser.parse_args()
34+
random.seed(options.seed)
35+
tree = nx.read_graphml(options.input)
36+
add_edge_weights(tree)
37+
if options.edge_list:
38+
nx.write_edgelist(tree, options.output,
39+
delimiter=options.delimiter,
40+
data=not options.no_data)
41+
else:
42+
nx.write_graphml(tree, options.output)
43+
return 0
44+
45+
if __name__ == '__main__':
46+
status = main()
47+
sys.exit(status)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
#!/usr/bin/env python
2+
3+
from argparse import ArgumentParser
4+
import sys
5+
import networkx as nx
6+
7+
8+
def is_leaf(tree, node):
9+
return len(tree.neighbors(node)) == 0
10+
11+
12+
def leaf_path_lengths(tree):
13+
path_lengths = nx.shortest_path_length(tree, '1', weight='weight')
14+
remove = []
15+
for node in path_lengths:
16+
if not is_leaf(tree, node):
17+
remove.append(node)
18+
for node in remove:
19+
del path_lengths[node]
20+
return path_lengths
21+
22+
23+
def main():
24+
arg_parser = ArgumentParser(description='compute leaf path lengths')
25+
arg_parser.add_argument('--input', required=True, help='input file')
26+
options = arg_parser.parse_args()
27+
tree = nx.read_graphml(options.input)
28+
path_lengths = leaf_path_lengths(tree)
29+
for leaf in path_lengths:
30+
print('{0}: {1:.4f}'.format(leaf, path_lengths[leaf]))
31+
return 0
32+
33+
if __name__ == '__main__':
34+
status = main()
35+
sys.exit(status)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
#!/usr/bin/env python
2+
3+
from argparse import ArgumentParser
4+
import random
5+
import sys
6+
import networkx as nx
7+
8+
9+
def random_tree(max_branch, max_height):
10+
G = nx.DiGraph()
11+
random_subtree(G, None, max_branch, max_height)
12+
return G
13+
14+
15+
def random_subtree(G, root, max_branch, max_height):
16+
if max_height:
17+
if root:
18+
nr_branches = random.randrange(0, max_branch + 1)
19+
for i in range(1, nr_branches + 1):
20+
node = root + '.' + str(i)
21+
G.add_edge(root, node)
22+
random_subtree(G, node, max_branch, max_height - 1)
23+
else:
24+
node = '1'
25+
random_subtree(G, node, max_branch, max_height - 1)
26+
27+
28+
def main():
29+
arg_parser = ArgumentParser(description='generate random tree')
30+
arg_parser.add_argument('--output', required=True,
31+
help='output file name')
32+
arg_parser.add_argument('--branching', dest='max_branch', type=int,
33+
default=3, help='maximum node branching')
34+
arg_parser.add_argument('--height', dest='max_height', type=int,
35+
default=4, help='maximum tree height')
36+
arg_parser.add_argument('--seed', type=int, default=None,
37+
help='seed for random number generator')
38+
arg_parser.add_argument('--delim', dest='delimiter', default=' ',
39+
help='delimiter for edge list')
40+
arg_parser.add_argument('--no-data', action='store_true',
41+
dest='no_data', help='show edge data')
42+
arg_parser.add_argument('--edge-list', action='store_true',
43+
dest='edge_list',
44+
help='generate edge list output')
45+
options = arg_parser.parse_args()
46+
random.seed(options.seed)
47+
tree = random_tree(options.max_branch, options.max_height)
48+
if options.edge_list:
49+
nx.write_edgelist(tree, options.output,
50+
delimiter=options.delimiter,
51+
data=not options.no_data)
52+
else:
53+
nx.write_graphml(tree, options.output)
54+
return 0
55+
56+
if __name__ == '__main__':
57+
status = main()
58+
sys.exit(status)

source-code/networkx/graph.txt

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
root child1 {'span': 1.3}
2+
child1 grandchild1 {'span': 0.4}
3+
root child2 {'span': 0.7}
4+
child2 grandchild2 {'span': 0.8}
5+
child2 grandchild3 {'span': 0.2}
6+
grandchild3 greatgrandchild1 {'span': 0.1}

source-code/networkx/graph.xml

+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
<?xml version="1.0" encoding="utf-8"?><graphml xmlns="http://graphml.graphdrawing.org/xmlns" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://graphml.graphdrawing.org/xmlns http://graphml.graphdrawing.org/xmlns/1.0/graphml.xsd">
2+
<key attr.name="span" attr.type="double" for="edge" id="d0" />
3+
<graph edgedefault="directed">
4+
<node id="child1" />
5+
<node id="child2" />
6+
<node id="greatgrandchild1" />
7+
<node id="grandchild3" />
8+
<node id="grandchild2" />
9+
<node id="grandchild1" />
10+
<node id="root" />
11+
<edge source="root" target="child1">
12+
<data key="d0">1.3</data>
13+
</edge>
14+
<edge source="child1" target="grandchild1">
15+
<data key="d0">0.4</data>
16+
</edge>
17+
<edge source="child2" target="grandchild3">
18+
<data key="d0">0.2</data>
19+
</edge>
20+
<edge target="child2" source="root">
21+
<data key="d0">0.7</data>
22+
</edge>
23+
<edge source="child2" target="grandchild2">
24+
<data key="d0">0.8</data>
25+
</edge>
26+
<edge target="greatgrandchild1" source="grandchild3">
27+
<data key="d0">0.1</data>
28+
</edge>
29+
</graph>
30+
</graphml>

source-code/networkx/max_flow.py

+47
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
#!/usr/bin/env python
2+
3+
from argparse import ArgumentParser
4+
import networkx as nx
5+
import random
6+
7+
8+
def create_graph(nr_nodes_per_layer=3):
9+
alpha = 3
10+
beta = 0.5
11+
G = nx.DiGraph()
12+
source = 0
13+
sink = 2*nr_nodes_per_layer + 1
14+
fmt_str = 'capacity {0} -> {1}: {2:.3f}'
15+
# from source to first layter
16+
for i in range(1, nr_nodes_per_layer + 1):
17+
capacity = random.gammavariate(alpha, beta)
18+
G.add_edge(source, i, capacity=capacity)
19+
print(fmt_str.format(source, i, capacity))
20+
# from layter 1 to layer 2
21+
for i in range(1, nr_nodes_per_layer + 1):
22+
j = i + nr_nodes_per_layer
23+
capacity = random.gammavariate(alpha, beta)
24+
G.add_edge(i, j, capacity=capacity)
25+
print(fmt_str.format(i, j, capacity))
26+
# rom layer 2 to sink
27+
for i in range(nr_nodes_per_layer + 1, 2*nr_nodes_per_layer + 1):
28+
capacity = random.gammavariate(alpha, beta)
29+
G.add_edge(i, sink, capacity=capacity)
30+
print(fmt_str.format(i, sink, capacity))
31+
return G, source, sink
32+
33+
34+
def print_flow_dict(G, flow_dict):
35+
for edge in G.edges_iter():
36+
i, j = edge
37+
print('flow {0} -> {1}: {2:.3f}'.format(i, j, flow_dict[i][j]))
38+
39+
if __name__ == '__main__':
40+
arg_parser = ArgumentParser(description='experiment with maximum flow '
41+
'algorithm')
42+
arg_parser.add_argument('--n', type=int, help='number of nodes/layer')
43+
options = arg_parser.parse_args()
44+
G, source, sink = create_graph(options.n)
45+
flow_value, flow_dict = nx.maximum_flow(G, source, sink)
46+
print('value = {0:.3f}'.format(flow_value))
47+
print_flow_dict(G, flow_dict)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
#!/usr/bin/env python
2+
3+
from argparse import ArgumentParser
4+
from multiprocessing import Pool
5+
import networkx as nx
6+
7+
pool = Pool(processes=2)
8+
9+
10+
def _is_leaf(tree, node):
11+
return len(tree.neighbors(node)) == 0
12+
13+
14+
def _leaf_path_lengths(tree, node):
15+
global pool
16+
if _is_leaf(tree, node):
17+
return {node: 0.0}
18+
else:
19+
path_lengths = {}
20+
results = {}
21+
for child in tree.neighbors_iter(node):
22+
results[child] = _leaf_path_lengths(tree, child)
23+
for child in tree.neighbors_iter(node):
24+
weight = tree[node][child]['weight']
25+
# lengths = results[child].get()
26+
lengths = results[child]
27+
for leaf in lengths:
28+
path_lengths[leaf] = lengths[leaf] + weight
29+
return path_lengths
30+
31+
32+
def leaf_path_lengths(tree):
33+
return _leaf_path_lengths(tree, '1')
34+
35+
if __name__ == '__main__':
36+
arg_parser = ArgumentParser(description='compute leaf path lengths')
37+
arg_parser.add_argument('--input', required=True, help='input file')
38+
arg_parser.add_argument('--pool-size', default=1,
39+
dest='pool_size', type=int,
40+
help='pool size for parallel processing')
41+
options = arg_parser.parse_args()
42+
tree = nx.read_graphml(options.input)
43+
path_lengths = leaf_path_lengths(tree)
44+
for leaf in path_lengths:
45+
print('{0}: {1:.4f}'.format(leaf, path_lengths[leaf]))

0 commit comments

Comments
 (0)