old htb folders
This commit is contained in:
2023-08-29 21:53:22 +02:00
parent 62ab804867
commit 82b0759f1e
21891 changed files with 6277643 additions and 0 deletions

View File

@@ -0,0 +1,37 @@
NetworkX is distributed with the 3-clause BSD license.
::
Copyright (C) 2004-2023, NetworkX Developers
Aric Hagberg <hagberg@lanl.gov>
Dan Schult <dschult@colgate.edu>
Pieter Swart <swart@lanl.gov>
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following
disclaimer in the documentation and/or other materials provided
with the distribution.
* Neither the name of the NetworkX Developers nor the names of its
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View File

@@ -0,0 +1,43 @@
"""
=======
Mayavi2
=======
"""
import networkx as nx
import numpy as np
from mayavi import mlab
# some graphs to try
# H=nx.krackhardt_kite_graph()
# H=nx.Graph();H.add_edge('a','b');H.add_edge('a','c');H.add_edge('a','d')
# H=nx.grid_2d_graph(4,5)
H = nx.cycle_graph(20)
# reorder nodes from 0,len(G)-1
G = nx.convert_node_labels_to_integers(H)
# 3d spring layout
pos = nx.spring_layout(G, dim=3, seed=1001)
# numpy array of x,y,z positions in sorted node order
xyz = np.array([pos[v] for v in sorted(G)])
# scalar colors
scalars = np.array(list(G.nodes())) + 5
mlab.figure()
pts = mlab.points3d(
xyz[:, 0],
xyz[:, 1],
xyz[:, 2],
scalars,
scale_factor=0.1,
scale_mode="none",
colormap="Blues",
resolution=20,
)
pts.mlab_source.dataset.lines = np.array(list(G.edges()))
tube = mlab.pipeline.tube(pts, tube_radius=0.01)
mlab.pipeline.surface(tube, color=(0.8, 0.8, 0.8))
mlab.orientation_axes()

View File

@@ -0,0 +1,51 @@
"""
================
Basic matplotlib
================
A basic example of 3D Graph visualization using `mpl_toolkits.mplot_3d`.
"""
import networkx as nx
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
# The graph to visualize
G = nx.cycle_graph(20)
# 3d spring layout
pos = nx.spring_layout(G, dim=3, seed=779)
# Extract node and edge positions from the layout
node_xyz = np.array([pos[v] for v in sorted(G)])
edge_xyz = np.array([(pos[u], pos[v]) for u, v in G.edges()])
# Create the 3D figure
fig = plt.figure()
ax = fig.add_subplot(111, projection="3d")
# Plot the nodes - alpha is scaled by "depth" automatically
ax.scatter(*node_xyz.T, s=100, ec="w")
# Plot the edges
for vizedge in edge_xyz:
ax.plot(*vizedge.T, color="tab:gray")
def _format_axes(ax):
"""Visualization options for the 3D axes."""
# Turn gridlines off
ax.grid(False)
# Suppress tick labels
for dim in (ax.xaxis, ax.yaxis, ax.zaxis):
dim.set_ticks([])
# Set axes labels
ax.set_xlabel("x")
ax.set_ylabel("y")
ax.set_zlabel("z")
_format_axes(ax)
fig.tight_layout()
plt.show()

View File

@@ -0,0 +1,8 @@
.. _examples_gallery:
Gallery
=======
General-purpose and introductory examples for NetworkX.
The `tutorial <../tutorial.html>`_ introduces conventions and basic graph
manipulations.

View File

@@ -0,0 +1,338 @@
# source target
1 2
1 10
2 1
2 10
3 7
4 7
4 209
5 132
6 150
7 3
7 4
7 9
8 106
8 115
9 1
9 2
9 7
10 1
10 2
11 133
11 218
12 88
13 214
14 24
14 52
16 10
16 19
17 64
17 78
18 55
18 103
18 163
19 18
20 64
20 180
21 16
21 22
22 21
22 64
22 106
23 20
23 22
23 64
24 14
24 31
24 122
27 115
28 29
29 28
30 19
31 24
31 32
31 122
31 147
31 233
32 31
32 86
34 35
34 37
35 34
35 43
36 132
36 187
37 38
37 90
37 282
38 42
38 43
38 210
40 20
42 15
42 38
43 34
43 35
43 38
45 107
46 61
46 72
48 23
49 30
49 64
49 108
49 115
49 243
50 30
50 47
50 55
50 125
50 163
52 218
52 224
54 111
54 210
55 65
55 67
55 105
55 108
55 222
56 18
56 64
57 65
57 125
58 20
58 30
58 50
58 103
58 180
59 164
63 125
64 8
64 50
64 70
64 256
66 20
66 84
66 106
66 125
67 22
67 50
67 113
68 50
70 50
70 64
71 72
74 29
74 75
74 215
75 74
75 215
76 58
76 104
77 103
78 64
78 68
80 207
80 210
82 8
82 77
82 83
82 97
82 163
83 82
83 226
83 243
84 29
84 154
87 101
87 189
89 90
90 89
90 94
91 86
92 19
92 30
92 106
94 72
94 89
94 90
95 30
96 75
96 256
97 80
97 128
98 86
100 86
101 87
103 77
103 104
104 58
104 77
104 103
106 22
107 38
107 114
107 122
108 49
108 55
111 121
111 128
111 210
113 253
114 107
116 30
116 140
118 129
118 138
120 88
121 128
122 31
123 32
124 244
125 132
126 163
126 180
128 38
128 111
129 118
132 29
132 30
133 30
134 135
134 150
135 134
137 144
138 118
138 129
139 142
141 157
141 163
142 139
143 2
144 137
145 151
146 137
146 165
146 169
146 171
147 31
147 128
148 146
148 169
148 171
148 282
149 128
149 148
149 172
150 86
151 145
152 4
153 134
154 155
156 161
157 141
161 156
165 144
165 148
167 149
169 15
169 148
169 171
170 115
170 173
170 183
170 202
171 72
171 148
171 169
173 170
175 100
176 10
178 181
181 178
182 38
182 171
183 96
185 50
186 127
187 50
187 65
188 30
188 50
189 87
189 89
190 35
190 38
190 122
190 182
191 54
191 118
191 129
191 172
192 149
192 167
195 75
197 50
197 188
198 218
198 221
198 222
200 65
200 220
201 113
202 156
203 232
204 194
207 38
207 122
207 124
208 30
208 50
210 38
210 207
211 37
213 35
213 38
214 13
214 14
214 171
214 213
215 75
217 39
218 68
218 222
221 198
222 198
222 218
223 39
225 3
226 22
229 65
230 68
231 43
232 95
232 203
233 99
234 68
234 230
237 244
238 145
242 3
242 113
244 237
249 96
250 156
252 65
254 65
258 113
268 4
270 183
272 6
275 96
280 183
280 206
282 37
285 75
290 285
293 290

View File

@@ -0,0 +1,112 @@
"""
===========
Beam Search
===========
Beam search with dynamic beam width.
The progressive widening beam search repeatedly executes a beam search
with increasing beam width until the target node is found.
"""
import math
import matplotlib.pyplot as plt
import networkx as nx
def progressive_widening_search(G, source, value, condition, initial_width=1):
"""Progressive widening beam search to find a node.
The progressive widening beam search involves a repeated beam
search, starting with a small beam width then extending to
progressively larger beam widths if the target node is not
found. This implementation simply returns the first node found that
matches the termination condition.
`G` is a NetworkX graph.
`source` is a node in the graph. The search for the node of interest
begins here and extends only to those nodes in the (weakly)
connected component of this node.
`value` is a function that returns a real number indicating how good
a potential neighbor node is when deciding which neighbor nodes to
enqueue in the breadth-first search. Only the best nodes within the
current beam width will be enqueued at each step.
`condition` is the termination condition for the search. This is a
function that takes a node as input and return a Boolean indicating
whether the node is the target. If no node matches the termination
condition, this function raises :exc:`NodeNotFound`.
`initial_width` is the starting beam width for the beam search (the
default is one). If no node matching the `condition` is found with
this beam width, the beam search is restarted from the `source` node
with a beam width that is twice as large (so the beam width
increases exponentially). The search terminates after the beam width
exceeds the number of nodes in the graph.
"""
# Check for the special case in which the source node satisfies the
# termination condition.
if condition(source):
return source
# The largest possible value of `i` in this range yields a width at
# least the number of nodes in the graph, so the final invocation of
# `bfs_beam_edges` is equivalent to a plain old breadth-first
# search. Therefore, all nodes will eventually be visited.
log_m = math.ceil(math.log2(len(G)))
for i in range(log_m):
width = initial_width * pow(2, i)
# Since we are always starting from the same source node, this
# search may visit the same nodes many times (depending on the
# implementation of the `value` function).
for u, v in nx.bfs_beam_edges(G, source, value, width):
if condition(v):
return v
# At this point, since all nodes have been visited, we know that
# none of the nodes satisfied the termination condition.
raise nx.NodeNotFound("no node satisfied the termination condition")
###############################################################################
# Search for a node with high centrality.
# ---------------------------------------
#
# We generate a random graph, compute the centrality of each node, then perform
# the progressive widening search in order to find a node of high centrality.
# Set a seed for random number generation so the example is reproducible
seed = 89
G = nx.gnp_random_graph(100, 0.5, seed=seed)
centrality = nx.eigenvector_centrality(G)
avg_centrality = sum(centrality.values()) / len(G)
def has_high_centrality(v):
return centrality[v] >= avg_centrality
source = 0
value = centrality.get
condition = has_high_centrality
found_node = progressive_widening_search(G, source, value, condition)
c = centrality[found_node]
print(f"found node {found_node} with centrality {c}")
# Draw graph
pos = nx.spring_layout(G, seed=seed)
options = {
"node_color": "blue",
"node_size": 20,
"edge_color": "grey",
"linewidths": 0,
"width": 0.1,
}
nx.draw(G, pos, **options)
# Draw node with high centrality as large and red
nx.draw_networkx_nodes(G, pos, nodelist=[found_node], node_size=100, node_color="r")
plt.show()

View File

@@ -0,0 +1,83 @@
"""
=====================
Betweenness Centrality
=====================
Betweenness centrality measures of positive gene functional associations
using WormNet v.3-GS.
Data from: https://www.inetbio.org/wormnet/downloadnetwork.php
"""
from random import sample
import networkx as nx
import matplotlib.pyplot as plt
# Gold standard data of positive gene functional associations
# from https://www.inetbio.org/wormnet/downloadnetwork.php
G = nx.read_edgelist("WormNet.v3.benchmark.txt")
# remove randomly selected nodes (to make example fast)
num_to_remove = int(len(G) / 1.5)
nodes = sample(list(G.nodes), num_to_remove)
G.remove_nodes_from(nodes)
# remove low-degree nodes
low_degree = [n for n, d in G.degree() if d < 10]
G.remove_nodes_from(low_degree)
# largest connected component
components = nx.connected_components(G)
largest_component = max(components, key=len)
H = G.subgraph(largest_component)
# compute centrality
centrality = nx.betweenness_centrality(H, k=10, endpoints=True)
# compute community structure
lpc = nx.community.label_propagation_communities(H)
community_index = {n: i for i, com in enumerate(lpc) for n in com}
#### draw graph ####
fig, ax = plt.subplots(figsize=(20, 15))
pos = nx.spring_layout(H, k=0.15, seed=4572321)
node_color = [community_index[n] for n in H]
node_size = [v * 20000 for v in centrality.values()]
nx.draw_networkx(
H,
pos=pos,
with_labels=False,
node_color=node_color,
node_size=node_size,
edge_color="gainsboro",
alpha=0.4,
)
# Title/legend
font = {"color": "k", "fontweight": "bold", "fontsize": 20}
ax.set_title("Gene functional association network (C. elegans)", font)
# Change font color for legend
font["color"] = "r"
ax.text(
0.80,
0.10,
"node color = community structure",
horizontalalignment="center",
transform=ax.transAxes,
fontdict=font,
)
ax.text(
0.80,
0.06,
"node size = betweenness centrality",
horizontalalignment="center",
transform=ax.transAxes,
fontdict=font,
)
# Resize figure for label readability
ax.margins(0.1, 0.05)
fig.tight_layout()
plt.axis("off")
plt.show()

View File

@@ -0,0 +1,79 @@
"""
==========
Blockmodel
==========
Example of creating a block model using the quotient_graph function in NX. Data
used is the Hartford, CT drug users network::
@article{weeks2002social,
title={Social networks of drug users in high-risk sites: Finding the connections},
url = {https://doi.org/10.1023/A:1015457400897},
doi = {10.1023/A:1015457400897},
author={Weeks, Margaret R and Clair, Scott and Borgatti, Stephen P and Radda, Kim and Schensul, Jean J},
journal={{AIDS and Behavior}},
volume={6},
number={2},
pages={193--206},
year={2002},
publisher={Springer}
}
"""
from collections import defaultdict
import matplotlib.pyplot as plt
import networkx as nx
import numpy as np
from scipy.cluster import hierarchy
from scipy.spatial import distance
def create_hc(G):
"""Creates hierarchical cluster of graph G from distance matrix"""
path_length = nx.all_pairs_shortest_path_length(G)
distances = np.zeros((len(G), len(G)))
for u, p in path_length:
for v, d in p.items():
distances[u][v] = d
# Create hierarchical cluster
Y = distance.squareform(distances)
Z = hierarchy.complete(Y) # Creates HC using farthest point linkage
# This partition selection is arbitrary, for illustrive purposes
membership = list(hierarchy.fcluster(Z, t=1.15))
# Create collection of lists for blockmodel
partition = defaultdict(list)
for n, p in zip(list(range(len(G))), membership):
partition[p].append(n)
return list(partition.values())
G = nx.read_edgelist("hartford_drug.edgelist")
# Extract largest connected component into graph H
H = G.subgraph(next(nx.connected_components(G)))
# Makes life easier to have consecutively labeled integer nodes
H = nx.convert_node_labels_to_integers(H)
# Create partitions with hierarchical clustering
partitions = create_hc(H)
# Build blockmodel graph
BM = nx.quotient_graph(H, partitions, relabel=True)
# Draw original graph
pos = nx.spring_layout(H, iterations=100, seed=83) # Seed for reproducibility
plt.subplot(211)
nx.draw(H, pos, with_labels=False, node_size=10)
# Draw block model with weighted edges and nodes sized by number of internal nodes
node_size = [BM.nodes[x]["nnodes"] * 10 for x in BM.nodes()]
edge_width = [(2 * d["weight"]) for (u, v, d) in BM.edges(data=True)]
# Set positions to mean of positions of internal nodes from original graph
posBM = {}
for n in BM:
xy = np.array([pos[u] for u in BM.nodes[n]["graph"]])
posBM[n] = xy.mean(axis=0)
plt.subplot(212)
nx.draw(BM, posBM, node_size=node_size, width=edge_width, with_labels=False)
plt.axis("off")
plt.show()

View File

@@ -0,0 +1,103 @@
"""
========
Circuits
========
Convert a Boolean circuit to an equivalent Boolean formula.
A Boolean circuit can be exponentially more expressive than an
equivalent formula in the worst case, since the circuit can reuse
subcircuits multiple times, whereas a formula cannot reuse subformulas
more than once. Thus creating a Boolean formula from a Boolean circuit
in this way may be infeasible if the circuit is large.
"""
import matplotlib.pyplot as plt
import networkx as nx
def circuit_to_formula(circuit):
# Convert the circuit to an equivalent formula.
formula = nx.dag_to_branching(circuit)
# Transfer the operator or variable labels for each node from the
# circuit to the formula.
for v in formula:
source = formula.nodes[v]["source"]
formula.nodes[v]["label"] = circuit.nodes[source]["label"]
return formula
def formula_to_string(formula):
def _to_string(formula, root):
# If there are no children, this is a variable node.
label = formula.nodes[root]["label"]
if not formula[root]:
return label
# Otherwise, this is an operator.
children = formula[root]
# If one child, the label must be a NOT operator.
if len(children) == 1:
child = nx.utils.arbitrary_element(children)
return f"{label}({_to_string(formula, child)})"
# NB "left" and "right" here are a little misleading: there is
# no order on the children of a node. That's okay because the
# Boolean AND and OR operators are symmetric. It just means that
# the order of the operands cannot be predicted and hence the
# function does not necessarily behave the same way on every
# invocation.
left, right = formula[root]
left_subformula = _to_string(formula, left)
right_subformula = _to_string(formula, right)
return f"({left_subformula} {label} {right_subformula})"
root = next(v for v, d in formula.in_degree() if d == 0)
return _to_string(formula, root)
###############################################################################
# Create an example Boolean circuit.
# ----------------------------------
#
# This circuit has a ∧ at the output and two s at the next layer.
# The third layer has a variable x that appears in the left , a
# variable y that appears in both the left and right s, and a
# negation for the variable z that appears as the sole node in the
# fourth layer.
circuit = nx.DiGraph()
# Layer 0
circuit.add_node(0, label="", layer=0)
# Layer 1
circuit.add_node(1, label="", layer=1)
circuit.add_node(2, label="", layer=1)
circuit.add_edge(0, 1)
circuit.add_edge(0, 2)
# Layer 2
circuit.add_node(3, label="x", layer=2)
circuit.add_node(4, label="y", layer=2)
circuit.add_node(5, label="¬", layer=2)
circuit.add_edge(1, 3)
circuit.add_edge(1, 4)
circuit.add_edge(2, 4)
circuit.add_edge(2, 5)
# Layer 3
circuit.add_node(6, label="z", layer=3)
circuit.add_edge(5, 6)
# Convert the circuit to an equivalent formula.
formula = circuit_to_formula(circuit)
print(formula_to_string(formula))
labels = nx.get_node_attributes(circuit, "label")
options = {
"node_size": 600,
"alpha": 0.5,
"node_color": "blue",
"labels": labels,
"font_size": 22,
}
plt.figure(figsize=(8, 8))
pos = nx.multipartite_layout(circuit, subset_key="layer")
nx.draw_networkx(circuit, pos, **options)
plt.title(formula_to_string(formula))
plt.axis("equal")
plt.show()

View File

@@ -0,0 +1,43 @@
"""
==========
Davis Club
==========
Davis Southern Club Women
Shows how to make unipartite projections of the graph and compute the
properties of those graphs.
These data were collected by Davis et al. in the 1930s.
They represent observed attendance at 14 social events by 18 Southern women.
The graph is bipartite (clubs, women).
"""
import matplotlib.pyplot as plt
import networkx as nx
import networkx.algorithms.bipartite as bipartite
G = nx.davis_southern_women_graph()
women = G.graph["top"]
clubs = G.graph["bottom"]
print("Biadjacency matrix")
print(bipartite.biadjacency_matrix(G, women, clubs))
# project bipartite graph onto women nodes
W = bipartite.projected_graph(G, women)
print()
print("#Friends, Member")
for w in women:
print(f"{W.degree(w)} {w}")
# project bipartite graph onto women nodes keeping number of co-occurence
# the degree computed is weighted and counts the total number of shared contacts
W = bipartite.weighted_projected_graph(G, women)
print()
print("#Friend meetings, Member")
for w in women:
print(f"{W.degree(w, weight='weight')} {w}")
pos = nx.spring_layout(G, seed=648) # Seed layout for reproducible node positions
nx.draw(G, pos)
plt.show()

View File

@@ -0,0 +1,92 @@
"""
===============
Dedensification
===============
Examples of dedensification of a graph. Dedensification retains the structural
pattern of the original graph and will only add compressor nodes when doing so
would result in fewer edges in the compressed graph.
"""
import matplotlib.pyplot as plt
import networkx as nx
plt.suptitle("Dedensification")
original_graph = nx.DiGraph()
white_nodes = ["1", "2", "3", "4", "5", "6"]
red_nodes = ["A", "B", "C"]
node_sizes = [250 for node in white_nodes + red_nodes]
node_colors = ["white" for n in white_nodes] + ["red" for n in red_nodes]
original_graph.add_nodes_from(white_nodes + red_nodes)
original_graph.add_edges_from(
[
("1", "C"),
("1", "B"),
("2", "C"),
("2", "B"),
("2", "A"),
("3", "B"),
("3", "A"),
("3", "6"),
("4", "C"),
("4", "B"),
("4", "A"),
("5", "B"),
("5", "A"),
("6", "5"),
("A", "6"),
]
)
base_options = dict(with_labels=True, edgecolors="black")
pos = {
"3": (0, 1),
"2": (0, 2),
"1": (0, 3),
"6": (1, 0),
"A": (1, 1),
"B": (1, 2),
"C": (1, 3),
"4": (2, 3),
"5": (2, 1),
}
ax1 = plt.subplot(1, 2, 1)
plt.title("Original (%s edges)" % original_graph.number_of_edges())
nx.draw_networkx(original_graph, pos=pos, node_color=node_colors, **base_options)
nonexp_graph, compression_nodes = nx.summarization.dedensify(
original_graph, threshold=2, copy=False
)
nonexp_node_colors = list(node_colors)
nonexp_node_sizes = list(node_sizes)
for node in compression_nodes:
nonexp_node_colors.append("yellow")
nonexp_node_sizes.append(600)
plt.subplot(1, 2, 2)
plt.title("Dedensified (%s edges)" % nonexp_graph.number_of_edges())
nonexp_pos = {
"5": (0, 0),
"B": (0, 2),
"1": (0, 3),
"6": (1, 0.75),
"3": (1.5, 1.5),
"A": (2, 0),
"C": (2, 3),
"4": (3, 1.5),
"2": (3, 2.5),
}
c_nodes = list(compression_nodes)
c_nodes.sort()
for spot, node in enumerate(c_nodes):
nonexp_pos[node] = (2, spot + 2)
nx.draw_networkx(
nonexp_graph,
pos=nonexp_pos,
node_color=nonexp_node_colors,
node_size=nonexp_node_sizes,
**base_options
)
plt.tight_layout()
plt.show()

View File

@@ -0,0 +1,210 @@
"""
==========================
Iterated Dynamical Systems
==========================
Digraphs from Integer-valued Iterated Functions
Sums of cubes on 3N
-------------------
The number 153 has a curious property.
Let 3N={3,6,9,12,...} be the set of positive multiples of 3. Define an
iterative process f:3N->3N as follows: for a given n, take each digit
of n (in base 10), cube it and then sum the cubes to obtain f(n).
When this process is repeated, the resulting series n, f(n), f(f(n)),...
terminate in 153 after a finite number of iterations (the process ends
because 153 = 1**3 + 5**3 + 3**3).
In the language of discrete dynamical systems, 153 is the global
attractor for the iterated map f restricted to the set 3N.
For example: take the number 108
f(108) = 1**3 + 0**3 + 8**3 = 513
and
f(513) = 5**3 + 1**3 + 3**3 = 153
So, starting at 108 we reach 153 in two iterations,
represented as:
108->513->153
Computing all orbits of 3N up to 10**5 reveals that the attractor
153 is reached in a maximum of 14 iterations. In this code we
show that 13 cycles is the maximum required for all integers (in 3N)
less than 10,000.
The smallest number that requires 13 iterations to reach 153, is 177, i.e.,
177->687->1071->345->216->225->141->66->432->99->1458->702->351->153
The resulting large digraphs are useful for testing network software.
The general problem
-------------------
Given numbers n, a power p and base b, define F(n; p, b) as the sum of
the digits of n (in base b) raised to the power p. The above example
corresponds to f(n)=F(n; 3,10), and below F(n; p, b) is implemented as
the function powersum(n,p,b). The iterative dynamical system defined by
the mapping n:->f(n) above (over 3N) converges to a single fixed point;
153. Applying the map to all positive integers N, leads to a discrete
dynamical process with 5 fixed points: 1, 153, 370, 371, 407. Modulo 3
those numbers are 1, 0, 1, 2, 2. The function f above has the added
property that it maps a multiple of 3 to another multiple of 3; i.e. it
is invariant on the subset 3N.
The squaring of digits (in base 10) result in cycles and the
single fixed point 1. I.e., from a certain point on, the process
starts repeating itself.
keywords: "Recurring Digital Invariant", "Narcissistic Number",
"Happy Number"
The 3n+1 problem
----------------
There is a rich history of mathematical recreations
associated with discrete dynamical systems. The most famous
is the Collatz 3n+1 problem. See the function
collatz_problem_digraph below. The Collatz conjecture
--- that every orbit returns to the fixed point 1 in finite time
--- is still unproven. Even the great Paul Erdos said "Mathematics
is not yet ready for such problems", and offered $500
for its solution.
keywords: "3n+1", "3x+1", "Collatz problem", "Thwaite's conjecture"
"""
import networkx as nx
nmax = 10000
p = 3
def digitsrep(n, b=10):
"""Return list of digits comprising n represented in base b.
n must be a nonnegative integer"""
if n <= 0:
return [0]
dlist = []
while n > 0:
# Prepend next least-significant digit
dlist = [n % b] + dlist
# Floor-division
n = n // b
return dlist
def powersum(n, p, b=10):
"""Return sum of digits of n (in base b) raised to the power p."""
dlist = digitsrep(n, b)
sum = 0
for k in dlist:
sum += k**p
return sum
def attractor153_graph(n, p, multiple=3, b=10):
"""Return digraph of iterations of powersum(n,3,10)."""
G = nx.DiGraph()
for k in range(1, n + 1):
if k % multiple == 0 and k not in G:
k1 = k
knext = powersum(k1, p, b)
while k1 != knext:
G.add_edge(k1, knext)
k1 = knext
knext = powersum(k1, p, b)
return G
def squaring_cycle_graph_old(n, b=10):
"""Return digraph of iterations of powersum(n,2,10)."""
G = nx.DiGraph()
for k in range(1, n + 1):
k1 = k
G.add_node(k1) # case k1==knext, at least add node
knext = powersum(k1, 2, b)
G.add_edge(k1, knext)
while k1 != knext: # stop if fixed point
k1 = knext
knext = powersum(k1, 2, b)
G.add_edge(k1, knext)
if G.out_degree(knext) >= 1:
# knext has already been iterated in and out
break
return G
def sum_of_digits_graph(nmax, b=10):
def f(n):
return powersum(n, 1, b)
return discrete_dynamics_digraph(nmax, f)
def squaring_cycle_digraph(nmax, b=10):
def f(n):
return powersum(n, 2, b)
return discrete_dynamics_digraph(nmax, f)
def cubing_153_digraph(nmax):
def f(n):
return powersum(n, 3, 10)
return discrete_dynamics_digraph(nmax, f)
def discrete_dynamics_digraph(nmax, f, itermax=50000):
G = nx.DiGraph()
for k in range(1, nmax + 1):
kold = k
G.add_node(kold)
knew = f(kold)
G.add_edge(kold, knew)
while kold != knew and kold << itermax:
# iterate until fixed point reached or itermax is exceeded
kold = knew
knew = f(kold)
G.add_edge(kold, knew)
if G.out_degree(knew) >= 1:
# knew has already been iterated in and out
break
return G
def collatz_problem_digraph(nmax):
def f(n):
if n % 2 == 0:
return n // 2
else:
return 3 * n + 1
return discrete_dynamics_digraph(nmax, f)
def fixed_points(G):
"""Return a list of fixed points for the discrete dynamical
system represented by the digraph G.
"""
return [n for n in G if G.out_degree(n) == 0]
nmax = 10000
print(f"Building cubing_153_digraph({nmax})")
G = cubing_153_digraph(nmax)
print("Resulting digraph has", len(G), "nodes and", G.size(), " edges")
print("Shortest path from 177 to 153 is:")
print(nx.shortest_path(G, 177, 153))
print(f"fixed points are {fixed_points(G)}")

View File

@@ -0,0 +1,31 @@
"""
=====================
Krackhardt Centrality
=====================
Centrality measures of Krackhardt social network.
"""
import matplotlib.pyplot as plt
import networkx as nx
G = nx.krackhardt_kite_graph()
print("Betweenness")
b = nx.betweenness_centrality(G)
for v in G.nodes():
print(f"{v:2} {b[v]:.3f}")
print("Degree centrality")
d = nx.degree_centrality(G)
for v in G.nodes():
print(f"{v:2} {d[v]:.3f}")
print("Closeness centrality")
c = nx.closeness_centrality(G)
for v in G.nodes():
print(f"{v:2} {c[v]:.3f}")
pos = nx.spring_layout(G, seed=367) # Seed layout for reproducibility
nx.draw(G, pos)
plt.show()

View File

@@ -0,0 +1,82 @@
"""
====================
Parallel Betweenness
====================
Example of parallel implementation of betweenness centrality using the
multiprocessing module from Python Standard Library.
The function betweenness centrality accepts a bunch of nodes and computes
the contribution of those nodes to the betweenness centrality of the whole
network. Here we divide the network in chunks of nodes and we compute their
contribution to the betweenness centrality of the whole network.
Note: The example output below shows that the non-parallel implementation is
faster. This is a limitation of our CI/CD pipeline running on a single core.
Depending on your setup, you will likely observe a speedup.
"""
from multiprocessing import Pool
import time
import itertools
import matplotlib.pyplot as plt
import networkx as nx
def chunks(l, n):
"""Divide a list of nodes `l` in `n` chunks"""
l_c = iter(l)
while 1:
x = tuple(itertools.islice(l_c, n))
if not x:
return
yield x
def betweenness_centrality_parallel(G, processes=None):
"""Parallel betweenness centrality function"""
p = Pool(processes=processes)
node_divisor = len(p._pool) * 4
node_chunks = list(chunks(G.nodes(), G.order() // node_divisor))
num_chunks = len(node_chunks)
bt_sc = p.starmap(
nx.betweenness_centrality_subset,
zip(
[G] * num_chunks,
node_chunks,
[list(G)] * num_chunks,
[True] * num_chunks,
[None] * num_chunks,
),
)
# Reduce the partial solutions
bt_c = bt_sc[0]
for bt in bt_sc[1:]:
for n in bt:
bt_c[n] += bt[n]
return bt_c
G_ba = nx.barabasi_albert_graph(1000, 3)
G_er = nx.gnp_random_graph(1000, 0.01)
G_ws = nx.connected_watts_strogatz_graph(1000, 4, 0.1)
for G in [G_ba, G_er, G_ws]:
print("")
print("Computing betweenness centrality for:")
print(G)
print("\tParallel version")
start = time.time()
bt = betweenness_centrality_parallel(G)
print(f"\t\tTime: {(time.time() - start):.4F} seconds")
print(f"\t\tBetweenness centrality for node 0: {bt[0]:.5f}")
print("\tNon-Parallel version")
start = time.time()
bt = nx.betweenness_centrality(G)
print(f"\t\tTime: {(time.time() - start):.4F} seconds")
print(f"\t\tBetweenness centrality for node 0: {bt[0]:.5f}")
print("")
nx.draw(G_ba, node_size=100)
plt.show()

View File

@@ -0,0 +1,40 @@
"""
======================
Reverse Cuthill--McKee
======================
Cuthill-McKee ordering of matrices
The reverse Cuthill--McKee algorithm gives a sparse matrix ordering that
reduces the matrix bandwidth.
"""
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
import networkx as nx
# build low-bandwidth matrix
G = nx.grid_2d_graph(3, 3)
rcm = list(nx.utils.reverse_cuthill_mckee_ordering(G))
print("ordering", rcm)
print("unordered Laplacian matrix")
A = nx.laplacian_matrix(G)
x, y = np.nonzero(A)
# print(f"lower bandwidth: {(y - x).max()}")
# print(f"upper bandwidth: {(x - y).max()}")
print(f"bandwidth: {(y - x).max() + (x - y).max() + 1}")
print(A)
B = nx.laplacian_matrix(G, nodelist=rcm)
print("low-bandwidth Laplacian matrix")
x, y = np.nonzero(B)
# print(f"lower bandwidth: {(y - x).max()}")
# print(f"upper bandwidth: {(x - y).max()}")
print(f"bandwidth: {(y - x).max() + (x - y).max() + 1}")
print(B)
sns.heatmap(B.todense(), cbar=False, square=True, linewidths=0.5, annot=True)
plt.show()

View File

@@ -0,0 +1,108 @@
"""
==================
SNAP Graph Summary
==================
An example of summarizing a graph based on node attributes and edge attributes
using the Summarization by Grouping Nodes on Attributes and Pairwise
edges (SNAP) algorithm (not to be confused with the Stanford Network
Analysis Project). The algorithm groups nodes by their unique
combinations of node attribute values and edge types with other groups
of nodes to produce a summary graph. The summary graph can then be used to
infer how nodes with different attributes values relate to other nodes in the
graph.
"""
import networkx as nx
import matplotlib.pyplot as plt
nodes = {
"A": dict(color="Red"),
"B": dict(color="Red"),
"C": dict(color="Red"),
"D": dict(color="Red"),
"E": dict(color="Blue"),
"F": dict(color="Blue"),
"G": dict(color="Blue"),
"H": dict(color="Blue"),
"I": dict(color="Yellow"),
"J": dict(color="Yellow"),
"K": dict(color="Yellow"),
"L": dict(color="Yellow"),
}
edges = [
("A", "B", "Strong"),
("A", "C", "Weak"),
("A", "E", "Strong"),
("A", "I", "Weak"),
("B", "D", "Weak"),
("B", "J", "Weak"),
("B", "F", "Strong"),
("C", "G", "Weak"),
("D", "H", "Weak"),
("I", "J", "Strong"),
("J", "K", "Strong"),
("I", "L", "Strong"),
]
original_graph = nx.Graph()
original_graph.add_nodes_from(n for n in nodes.items())
original_graph.add_edges_from((u, v, {"type": label}) for u, v, label in edges)
plt.suptitle("SNAP Summarization")
base_options = dict(with_labels=True, edgecolors="black", node_size=500)
ax1 = plt.subplot(1, 2, 1)
plt.title(
"Original (%s nodes, %s edges)"
% (original_graph.number_of_nodes(), original_graph.number_of_edges())
)
pos = nx.spring_layout(original_graph, seed=7482934)
node_colors = [d["color"] for _, d in original_graph.nodes(data=True)]
edge_type_visual_weight_lookup = {"Weak": 1.0, "Strong": 3.0}
edge_weights = [
edge_type_visual_weight_lookup[d["type"]]
for _, _, d in original_graph.edges(data=True)
]
nx.draw_networkx(
original_graph, pos=pos, node_color=node_colors, width=edge_weights, **base_options
)
node_attributes = ("color",)
edge_attributes = ("type",)
summary_graph = nx.snap_aggregation(
original_graph, node_attributes, edge_attributes, prefix="S-"
)
plt.subplot(1, 2, 2)
plt.title(
"SNAP Aggregation (%s nodes, %s edges)"
% (summary_graph.number_of_nodes(), summary_graph.number_of_edges())
)
summary_pos = nx.spring_layout(summary_graph, seed=8375428)
node_colors = []
for node in summary_graph:
color = summary_graph.nodes[node]["color"]
node_colors.append(color)
edge_weights = []
for edge in summary_graph.edges():
edge_types = summary_graph.get_edge_data(*edge)["types"]
edge_weight = 0.0
for edge_type in edge_types:
edge_weight += edge_type_visual_weight_lookup[edge_type["type"]]
edge_weights.append(edge_weight)
nx.draw_networkx(
summary_graph,
pos=summary_pos,
node_color=node_colors,
width=edge_weights,
**base_options
)
plt.tight_layout()
plt.show()

View File

@@ -0,0 +1,170 @@
"""
=========
Subgraphs
=========
Example of partitioning a directed graph with nodes labeled as
supported and unsupported nodes into a list of subgraphs
that contain only entirely supported or entirely unsupported nodes.
Adopted from
https://github.com/lobpcg/python_examples/blob/master/networkx_example.py
"""
import networkx as nx
import matplotlib.pyplot as plt
def graph_partitioning(G, plotting=True):
"""Partition a directed graph into a list of subgraphs that contain
only entirely supported or entirely unsupported nodes.
"""
# Categorize nodes by their node_type attribute
supported_nodes = {n for n, d in G.nodes(data="node_type") if d == "supported"}
unsupported_nodes = {n for n, d in G.nodes(data="node_type") if d == "unsupported"}
# Make a copy of the graph.
H = G.copy()
# Remove all edges connecting supported and unsupported nodes.
H.remove_edges_from(
(n, nbr, d)
for n, nbrs in G.adj.items()
if n in supported_nodes
for nbr, d in nbrs.items()
if nbr in unsupported_nodes
)
H.remove_edges_from(
(n, nbr, d)
for n, nbrs in G.adj.items()
if n in unsupported_nodes
for nbr, d in nbrs.items()
if nbr in supported_nodes
)
# Collect all removed edges for reconstruction.
G_minus_H = nx.DiGraph()
G_minus_H.add_edges_from(set(G.edges) - set(H.edges))
if plotting:
# Plot the stripped graph with the edges removed.
_node_colors = [c for _, c in H.nodes(data="node_color")]
_pos = nx.spring_layout(H)
plt.figure(figsize=(8, 8))
nx.draw_networkx_edges(H, _pos, alpha=0.3, edge_color="k")
nx.draw_networkx_nodes(H, _pos, node_color=_node_colors)
nx.draw_networkx_labels(H, _pos, font_size=14)
plt.axis("off")
plt.title("The stripped graph with the edges removed.")
plt.show()
# Plot the the edges removed.
_pos = nx.spring_layout(G_minus_H)
plt.figure(figsize=(8, 8))
ncl = [G.nodes[n]["node_color"] for n in G_minus_H.nodes]
nx.draw_networkx_edges(G_minus_H, _pos, alpha=0.3, edge_color="k")
nx.draw_networkx_nodes(G_minus_H, _pos, node_color=ncl)
nx.draw_networkx_labels(G_minus_H, _pos, font_size=14)
plt.axis("off")
plt.title("The removed edges.")
plt.show()
# Find the connected components in the stripped undirected graph.
# And use the sets, specifying the components, to partition
# the original directed graph into a list of directed subgraphs
# that contain only entirely supported or entirely unsupported nodes.
subgraphs = [
H.subgraph(c).copy() for c in nx.connected_components(H.to_undirected())
]
return subgraphs, G_minus_H
###############################################################################
# Create an example directed graph.
# ---------------------------------
#
# This directed graph has one input node labeled `in` and plotted in blue color
# and one output node labeled `out` and plotted in magenta color.
# The other six nodes are classified as four `supported` plotted in green color
# and two `unsupported` plotted in red color. The goal is computing a list
# of subgraphs that contain only entirely `supported` or `unsupported` nodes.
G_ex = nx.DiGraph()
G_ex.add_nodes_from(["In"], node_type="input", node_color="b")
G_ex.add_nodes_from(["A", "C", "E", "F"], node_type="supported", node_color="g")
G_ex.add_nodes_from(["B", "D"], node_type="unsupported", node_color="r")
G_ex.add_nodes_from(["Out"], node_type="output", node_color="m")
G_ex.add_edges_from(
[
("In", "A"),
("A", "B"),
("B", "C"),
("B", "D"),
("D", "E"),
("C", "F"),
("E", "F"),
("F", "Out"),
]
)
###############################################################################
# Plot the original graph.
# ------------------------
#
node_color_list = [nc for _, nc in G_ex.nodes(data="node_color")]
pos = nx.spectral_layout(G_ex)
plt.figure(figsize=(8, 8))
nx.draw_networkx_edges(G_ex, pos, alpha=0.3, edge_color="k")
nx.draw_networkx_nodes(G_ex, pos, alpha=0.8, node_color=node_color_list)
nx.draw_networkx_labels(G_ex, pos, font_size=14)
plt.axis("off")
plt.title("The original graph.")
plt.show()
###############################################################################
# Calculate the subgraphs with plotting all results of intemediate steps.
# -----------------------------------------------------------------------
#
subgraphs_of_G_ex, removed_edges = graph_partitioning(G_ex, plotting=True)
###############################################################################
# Plot the results: every subgraph in the list.
# ---------------------------------------------
#
for subgraph in subgraphs_of_G_ex:
_pos = nx.spring_layout(subgraph)
plt.figure(figsize=(8, 8))
nx.draw_networkx_edges(subgraph, _pos, alpha=0.3, edge_color="k")
node_color_list_c = [nc for _, nc in subgraph.nodes(data="node_color")]
nx.draw_networkx_nodes(subgraph, _pos, node_color=node_color_list_c)
nx.draw_networkx_labels(subgraph, _pos, font_size=14)
plt.axis("off")
plt.title("One of the subgraphs.")
plt.show()
###############################################################################
# Put the graph back from the list of subgraphs
# ---------------------------------------------
#
G_ex_r = nx.DiGraph()
# Composing all subgraphs.
for subgraph in subgraphs_of_G_ex:
G_ex_r = nx.compose(G_ex_r, subgraph)
# Adding the previously stored edges.
G_ex_r.add_edges_from(removed_edges.edges())
###############################################################################
# Check that the original graph and the reconstructed graphs are isomorphic.
# --------------------------------------------------------------------------
#
assert nx.is_isomorphic(G_ex, G_ex_r)
###############################################################################
# Plot the reconstructed graph.
# -----------------------------
#
node_color_list = [nc for _, nc in G_ex_r.nodes(data="node_color")]
pos = nx.spectral_layout(G_ex_r)
plt.figure(figsize=(8, 8))
nx.draw_networkx_edges(G_ex_r, pos, alpha=0.3, edge_color="k")
nx.draw_networkx_nodes(G_ex_r, pos, alpha=0.8, node_color=node_color_list)
nx.draw_networkx_labels(G_ex_r, pos, font_size=14)
plt.axis("off")
plt.title("The reconstructed graph.")
plt.show()

View File

@@ -0,0 +1,49 @@
"""
==========
Properties
==========
Compute some network properties for the lollipop graph.
"""
import matplotlib.pyplot as plt
import networkx as nx
G = nx.lollipop_graph(4, 6)
pathlengths = []
print("source vertex {target:length, }")
for v in G.nodes():
spl = dict(nx.single_source_shortest_path_length(G, v))
print(f"{v} {spl} ")
for p in spl:
pathlengths.append(spl[p])
print()
print(f"average shortest path length {sum(pathlengths) / len(pathlengths)}")
# histogram of path lengths
dist = {}
for p in pathlengths:
if p in dist:
dist[p] += 1
else:
dist[p] = 1
print()
print("length #paths")
verts = dist.keys()
for d in sorted(verts):
print(f"{d} {dist[d]}")
print(f"radius: {nx.radius(G)}")
print(f"diameter: {nx.diameter(G)}")
print(f"eccentricity: {nx.eccentricity(G)}")
print(f"center: {nx.center(G)}")
print(f"periphery: {nx.periphery(G)}")
print(f"density: {nx.density(G)}")
pos = nx.spring_layout(G, seed=3068) # Seed layout for reproducibility
nx.draw(G, pos=pos, with_labels=True)
plt.show()

View File

@@ -0,0 +1,24 @@
"""
======================
Read and write graphs.
======================
Read and write graphs.
"""
import matplotlib.pyplot as plt
import networkx as nx
G = nx.grid_2d_graph(5, 5) # 5x5 grid
# print the adjacency list
for line in nx.generate_adjlist(G):
print(line)
# write edgelist to grid.edgelist
nx.write_edgelist(G, path="grid.edgelist", delimiter=":")
# read edgelist from grid.edgelist
H = nx.read_edgelist(path="grid.edgelist", delimiter=":")
pos = nx.spring_layout(H, seed=200)
nx.draw(H, pos)
plt.show()

View File

@@ -0,0 +1,60 @@
"""
============
Simple graph
============
Draw simple graph with manual layout.
"""
import networkx as nx
import matplotlib.pyplot as plt
G = nx.Graph()
G.add_edge(1, 2)
G.add_edge(1, 3)
G.add_edge(1, 5)
G.add_edge(2, 3)
G.add_edge(3, 4)
G.add_edge(4, 5)
# explicitly set positions
pos = {1: (0, 0), 2: (-1, 0.3), 3: (2, 0.17), 4: (4, 0.255), 5: (5, 0.03)}
options = {
"font_size": 36,
"node_size": 3000,
"node_color": "white",
"edgecolors": "black",
"linewidths": 5,
"width": 5,
}
nx.draw_networkx(G, pos, **options)
# Set margins for the axes so that nodes aren't clipped
ax = plt.gca()
ax.margins(0.20)
plt.axis("off")
plt.show()
# %%
# A directed graph
G = nx.DiGraph([(0, 3), (1, 3), (2, 4), (3, 5), (3, 6), (4, 6), (5, 6)])
# group nodes by column
left_nodes = [0, 1, 2]
middle_nodes = [3, 4]
right_nodes = [5, 6]
# set the position according to column (x-coord)
pos = {n: (0, i) for i, n in enumerate(left_nodes)}
pos.update({n: (1, i + 0.5) for i, n in enumerate(middle_nodes)})
pos.update({n: (2, i + 0.5) for i, n in enumerate(right_nodes)})
nx.draw_networkx(G, pos, **options)
# Set margins for the axes so that nodes aren't clipped
ax = plt.gca()
ax.margins(0.20)
plt.axis("off")
plt.show()

View File

@@ -0,0 +1,20 @@
"""
====================
Custom Node Position
====================
Draw a graph with node(s) located at user-defined positions.
When a position is set by the user, the other nodes can still be neatly organised in a layout.
"""
import networkx as nx
import numpy as np
G = nx.path_graph(20) # An example graph
center_node = 5 # Or any other node to be in the center
edge_nodes = set(G) - {center_node}
# Ensures the nodes around the circle are evenly distributed
pos = nx.circular_layout(G.subgraph(edge_nodes))
pos[center_node] = np.array([0, 0]) # manually specify node position
nx.draw(G, pos, with_labels=True)

View File

@@ -0,0 +1,152 @@
"""
=============
Chess Masters
=============
An example of the MultiDiGraph class.
The function `chess_pgn_graph` reads a collection of chess matches stored in
the specified PGN file (PGN ="Portable Game Notation"). Here the (compressed)
default file::
chess_masters_WCC.pgn.bz2
contains all 685 World Chess Championship matches from 1886--1985.
(data from http://chessproblem.my-free-games.com/chess/games/Download-PGN.php)
The `chess_pgn_graph()` function returns a `MultiDiGraph` with multiple edges.
Each node is the last name of a chess master. Each edge is directed from white
to black and contains selected game info.
The key statement in `chess_pgn_graph` below is::
G.add_edge(white, black, game_info)
where `game_info` is a `dict` describing each game.
"""
import matplotlib.pyplot as plt
import networkx as nx
# tag names specifying what game info should be
# stored in the dict on each digraph edge
game_details = ["Event", "Date", "Result", "ECO", "Site"]
def chess_pgn_graph(pgn_file="chess_masters_WCC.pgn.bz2"):
"""Read chess games in pgn format in pgn_file.
Filenames ending in .bz2 will be uncompressed.
Return the MultiDiGraph of players connected by a chess game.
Edges contain game data in a dict.
"""
import bz2
G = nx.MultiDiGraph()
game = {}
with bz2.BZ2File(pgn_file) as datafile:
lines = [line.decode().rstrip("\r\n") for line in datafile]
for line in lines:
if line.startswith("["):
tag, value = line[1:-1].split(" ", 1)
game[str(tag)] = value.strip('"')
else:
# empty line after tag set indicates
# we finished reading game info
if game:
white = game.pop("White")
black = game.pop("Black")
G.add_edge(white, black, **game)
game = {}
return G
G = chess_pgn_graph()
print(
f"Loaded {G.number_of_edges()} chess games between {G.number_of_nodes()} players\n"
)
# identify connected components of the undirected version
H = G.to_undirected()
Gcc = [H.subgraph(c) for c in nx.connected_components(H)]
if len(Gcc) > 1:
print(f"Note the disconnected component consisting of:\n{Gcc[1].nodes()}")
# find all games with B97 opening (as described in ECO)
openings = {game_info["ECO"] for (white, black, game_info) in G.edges(data=True)}
print(f"\nFrom a total of {len(openings)} different openings,")
print("the following games used the Sicilian opening")
print('with the Najdorff 7...Qb6 "Poisoned Pawn" variation.\n')
for (white, black, game_info) in G.edges(data=True):
if game_info["ECO"] == "B97":
summary = f"{white} vs {black}\n"
for k, v in game_info.items():
summary += f" {k}: {v}\n"
summary += "\n"
print(summary)
# make new undirected graph H without multi-edges
H = nx.Graph(G)
# edge width is proportional number of games played
edgewidth = [len(G.get_edge_data(u, v)) for u, v in H.edges()]
# node size is proportional to number of games won
wins = dict.fromkeys(G.nodes(), 0.0)
for (u, v, d) in G.edges(data=True):
r = d["Result"].split("-")
if r[0] == "1":
wins[u] += 1.0
elif r[0] == "1/2":
wins[u] += 0.5
wins[v] += 0.5
else:
wins[v] += 1.0
nodesize = [wins[v] * 50 for v in H]
# Generate layout for visualization
pos = nx.kamada_kawai_layout(H)
# Manual tweaking to limit node label overlap in the visualization
pos["Reshevsky, Samuel H"] += (0.05, -0.10)
pos["Botvinnik, Mikhail M"] += (0.03, -0.06)
pos["Smyslov, Vassily V"] += (0.05, -0.03)
fig, ax = plt.subplots(figsize=(12, 12))
# Visualize graph components
nx.draw_networkx_edges(H, pos, alpha=0.3, width=edgewidth, edge_color="m")
nx.draw_networkx_nodes(H, pos, node_size=nodesize, node_color="#210070", alpha=0.9)
label_options = {"ec": "k", "fc": "white", "alpha": 0.7}
nx.draw_networkx_labels(H, pos, font_size=14, bbox=label_options)
# Title/legend
font = {"fontname": "Helvetica", "color": "k", "fontweight": "bold", "fontsize": 14}
ax.set_title("World Chess Championship Games: 1886 - 1985", font)
# Change font color for legend
font["color"] = "r"
ax.text(
0.80,
0.10,
"edge width = # games played",
horizontalalignment="center",
transform=ax.transAxes,
fontdict=font,
)
ax.text(
0.80,
0.06,
"node size = # games won",
horizontalalignment="center",
transform=ax.transAxes,
fontdict=font,
)
# Resize figure for label readability
ax.margins(0.1, 0.05)
fig.tight_layout()
plt.axis("off")
plt.show()

View File

@@ -0,0 +1,75 @@
"""
=================
Custom node icons
=================
Example of using custom icons to represent nodes with matplotlib.
Images for node icons courtesy of www.materialui.co
"""
import matplotlib.pyplot as plt
import networkx as nx
import PIL
# Image URLs for graph nodes
icons = {
"router": "icons/router_black_144x144.png",
"switch": "icons/switch_black_144x144.png",
"PC": "icons/computer_black_144x144.png",
}
# Load images
images = {k: PIL.Image.open(fname) for k, fname in icons.items()}
# Generate the computer network graph
G = nx.Graph()
G.add_node("router", image=images["router"])
for i in range(1, 4):
G.add_node(f"switch_{i}", image=images["switch"])
for j in range(1, 4):
G.add_node("PC_" + str(i) + "_" + str(j), image=images["PC"])
G.add_edge("router", "switch_1")
G.add_edge("router", "switch_2")
G.add_edge("router", "switch_3")
for u in range(1, 4):
for v in range(1, 4):
G.add_edge("switch_" + str(u), "PC_" + str(u) + "_" + str(v))
# Get a reproducible layout and create figure
pos = nx.spring_layout(G, seed=1734289230)
fig, ax = plt.subplots()
# Note: the min_source/target_margin kwargs only work with FancyArrowPatch objects.
# Force the use of FancyArrowPatch for edge drawing by setting `arrows=True`,
# but suppress arrowheads with `arrowstyle="-"`
nx.draw_networkx_edges(
G,
pos=pos,
ax=ax,
arrows=True,
arrowstyle="-",
min_source_margin=15,
min_target_margin=15,
)
# Transform from data coordinates (scaled between xlim and ylim) to display coordinates
tr_figure = ax.transData.transform
# Transform from display to figure coordinates
tr_axes = fig.transFigure.inverted().transform
# Select the size of the image (relative to the X axis)
icon_size = (ax.get_xlim()[1] - ax.get_xlim()[0]) * 0.025
icon_center = icon_size / 2.0
# Add the respective image to each node
for n in G.nodes:
xf, yf = tr_figure(pos[n])
xa, ya = tr_axes((xf, yf))
# get overlapped axes and plot icon
a = plt.axes([xa - icon_center, ya - icon_center, icon_size, icon_size])
a.imshow(G.nodes[n]["image"])
a.axis("off")
plt.show()

View File

@@ -0,0 +1,50 @@
"""
===============
Degree Analysis
===============
This example shows several ways to visualize the distribution of the degree of
nodes with two common techniques: a *degree-rank plot* and a
*degree histogram*.
In this example, a random Graph is generated with 100 nodes. The degree of
each node is determined, and a figure is generated showing three things:
1. The subgraph of connected components
2. The degree-rank plot for the Graph, and
3. The degree histogram
"""
import networkx as nx
import numpy as np
import matplotlib.pyplot as plt
G = nx.gnp_random_graph(100, 0.02, seed=10374196)
degree_sequence = sorted((d for n, d in G.degree()), reverse=True)
dmax = max(degree_sequence)
fig = plt.figure("Degree of a random graph", figsize=(8, 8))
# Create a gridspec for adding subplots of different sizes
axgrid = fig.add_gridspec(5, 4)
ax0 = fig.add_subplot(axgrid[0:3, :])
Gcc = G.subgraph(sorted(nx.connected_components(G), key=len, reverse=True)[0])
pos = nx.spring_layout(Gcc, seed=10396953)
nx.draw_networkx_nodes(Gcc, pos, ax=ax0, node_size=20)
nx.draw_networkx_edges(Gcc, pos, ax=ax0, alpha=0.4)
ax0.set_title("Connected components of G")
ax0.set_axis_off()
ax1 = fig.add_subplot(axgrid[3:, :2])
ax1.plot(degree_sequence, "b-", marker="o")
ax1.set_title("Degree Rank Plot")
ax1.set_ylabel("Degree")
ax1.set_xlabel("Rank")
ax2 = fig.add_subplot(axgrid[3:, 2:])
ax2.bar(*np.unique(degree_sequence, return_counts=True))
ax2.set_title("Degree histogram")
ax2.set_xlabel("Degree")
ax2.set_ylabel("# of Nodes")
fig.tight_layout()
plt.show()

View File

@@ -0,0 +1,46 @@
"""
==============
Directed Graph
==============
Draw a graph with directed edges using a colormap and different node sizes.
Edges have different colors and alphas (opacity). Drawn using matplotlib.
"""
import matplotlib as mpl
import matplotlib.pyplot as plt
import networkx as nx
seed = 13648 # Seed random number generators for reproducibility
G = nx.random_k_out_graph(10, 3, 0.5, seed=seed)
pos = nx.spring_layout(G, seed=seed)
node_sizes = [3 + 10 * i for i in range(len(G))]
M = G.number_of_edges()
edge_colors = range(2, M + 2)
edge_alphas = [(5 + i) / (M + 4) for i in range(M)]
cmap = plt.cm.plasma
nodes = nx.draw_networkx_nodes(G, pos, node_size=node_sizes, node_color="indigo")
edges = nx.draw_networkx_edges(
G,
pos,
node_size=node_sizes,
arrowstyle="->",
arrowsize=10,
edge_color=edge_colors,
edge_cmap=cmap,
width=2,
)
# set alpha value for each edge
for i in range(M):
edges[i].set_alpha(edge_alphas[i])
pc = mpl.collections.PatchCollection(edges, cmap=cmap)
pc.set_array(edge_colors)
ax = plt.gca()
ax.set_axis_off()
plt.colorbar(pc, ax=ax)
plt.show()

View File

@@ -0,0 +1,23 @@
"""
=============
Edge Colormap
=============
Draw a graph with matplotlib, color edges.
"""
import matplotlib.pyplot as plt
import networkx as nx
G = nx.star_graph(20)
pos = nx.spring_layout(G, seed=63) # Seed layout for reproducibility
colors = range(20)
options = {
"node_color": "#A0CBE2",
"edge_color": colors,
"width": 4,
"edge_cmap": plt.cm.Blues,
"with_labels": False,
}
nx.draw(G, pos, **options)
plt.show()

View File

@@ -0,0 +1,35 @@
"""
=========
Ego Graph
=========
Example using the NetworkX ego_graph() function to return the main egonet of
the largest hub in a Barabási-Albert network.
"""
from operator import itemgetter
import matplotlib.pyplot as plt
import networkx as nx
# Create a BA model graph - use seed for reproducibility
n = 1000
m = 2
seed = 20532
G = nx.barabasi_albert_graph(n, m, seed=seed)
# find node with largest degree
node_and_degree = G.degree()
(largest_hub, degree) = sorted(node_and_degree, key=itemgetter(1))[-1]
# Create ego graph of main hub
hub_ego = nx.ego_graph(G, largest_hub)
# Draw graph
pos = nx.spring_layout(hub_ego, seed=seed) # Seed layout for reproducibility
nx.draw(hub_ego, pos, node_color="b", node_size=50, with_labels=False)
# Draw ego as large and red
options = {"node_size": 300, "node_color": "r"}
nx.draw_networkx_nodes(hub_ego, pos, nodelist=[largest_hub], **options)
plt.show()

View File

@@ -0,0 +1,22 @@
"""
===========
Eigenvalues
===========
Create an G{n,m} random graph and compute the eigenvalues.
"""
import matplotlib.pyplot as plt
import networkx as nx
import numpy.linalg
n = 1000 # 1000 nodes
m = 5000 # 5000 edges
G = nx.gnm_random_graph(n, m, seed=5040) # Seed for reproducibility
L = nx.normalized_laplacian_matrix(G)
e = numpy.linalg.eigvals(L.toarray())
print("Largest eigenvalue:", max(e))
print("Smallest eigenvalue:", min(e))
plt.hist(e, bins=100) # histogram with 100 bins
plt.xlim(0, 2) # eigenvalues between 0 and 2
plt.show()

View File

@@ -0,0 +1,52 @@
"""
==========
Four Grids
==========
Draw a 4x4 graph with matplotlib.
This example illustrates the use of keyword arguments to `networkx.draw` to
customize the visualization of a simple Graph comprising a 4x4 grid.
"""
import matplotlib.pyplot as plt
import networkx as nx
G = nx.grid_2d_graph(4, 4) # 4x4 grid
pos = nx.spring_layout(G, iterations=100, seed=39775)
# Create a 2x2 subplot
fig, all_axes = plt.subplots(2, 2)
ax = all_axes.flat
nx.draw(G, pos, ax=ax[0], font_size=8)
nx.draw(G, pos, ax=ax[1], node_size=0, with_labels=False)
nx.draw(
G,
pos,
ax=ax[2],
node_color="tab:green",
edgecolors="tab:gray", # Node surface color
edge_color="tab:gray", # Color of graph edges
node_size=250,
with_labels=False,
width=6,
)
H = G.to_directed()
nx.draw(
H,
pos,
ax=ax[3],
node_color="tab:orange",
node_size=20,
with_labels=False,
arrowsize=10,
width=2,
)
# Set margins for the axes so that nodes aren't clipped
for a in ax:
a.margins(0.10)
fig.tight_layout()
plt.show()

View File

@@ -0,0 +1,26 @@
"""
=================
House With Colors
=================
Draw a graph with matplotlib.
"""
import matplotlib.pyplot as plt
import networkx as nx
G = nx.house_graph()
# explicitly set positions
pos = {0: (0, 0), 1: (1, 0), 2: (0, 1), 3: (1, 1), 4: (0.5, 2.0)}
# Plot nodes with different properties for the "wall" and "roof" nodes
nx.draw_networkx_nodes(
G, pos, node_size=3000, nodelist=[0, 1, 2, 3], node_color="tab:blue"
)
nx.draw_networkx_nodes(G, pos, node_size=2000, nodelist=[4], node_color="tab:orange")
nx.draw_networkx_edges(G, pos, alpha=0.5, width=6)
# Customize axes
ax = plt.gca()
ax.margins(0.11)
plt.tight_layout()
plt.axis("off")
plt.show()

View File

@@ -0,0 +1,142 @@
"""
===========
Knuth Miles
===========
`miles_graph()` returns an undirected graph over 128 US cities. The
cities each have location and population data. The edges are labeled with the
distance between the two cities.
This example is described in Section 1.1 of
Donald E. Knuth, "The Stanford GraphBase: A Platform for Combinatorial
Computing", ACM Press, New York, 1993.
http://www-cs-faculty.stanford.edu/~knuth/sgb.html
The data file can be found at:
- https://github.com/networkx/networkx/blob/main/examples/drawing/knuth_miles.txt.gz
"""
import gzip
import re
# Ignore any warnings related to downloading shpfiles with cartopy
import warnings
warnings.simplefilter("ignore")
import numpy as np
import matplotlib.pyplot as plt
import networkx as nx
def miles_graph():
"""Return the cites example graph in miles_dat.txt
from the Stanford GraphBase.
"""
# open file miles_dat.txt.gz (or miles_dat.txt)
fh = gzip.open("knuth_miles.txt.gz", "r")
G = nx.Graph()
G.position = {}
G.population = {}
cities = []
for line in fh.readlines():
line = line.decode()
if line.startswith("*"): # skip comments
continue
numfind = re.compile(r"^\d+")
if numfind.match(line): # this line is distances
dist = line.split()
for d in dist:
G.add_edge(city, cities[i], weight=int(d))
i = i + 1
else: # this line is a city, position, population
i = 1
(city, coordpop) = line.split("[")
cities.insert(0, city)
(coord, pop) = coordpop.split("]")
(y, x) = coord.split(",")
G.add_node(city)
# assign position - Convert string to lat/long
G.position[city] = (-float(x) / 100, float(y) / 100)
G.population[city] = float(pop) / 1000
return G
G = miles_graph()
print("Loaded miles_dat.txt containing 128 cities.")
print(G)
# make new graph of cites, edge if less then 300 miles between them
H = nx.Graph()
for v in G:
H.add_node(v)
for (u, v, d) in G.edges(data=True):
if d["weight"] < 300:
H.add_edge(u, v)
# draw with matplotlib/pylab
fig = plt.figure(figsize=(8, 6))
# nodes colored by degree sized by population
node_color = [float(H.degree(v)) for v in H]
# Use cartopy to provide a backdrop for the visualization
try:
import cartopy.crs as ccrs
import cartopy.io.shapereader as shpreader
ax = fig.add_axes([0, 0, 1, 1], projection=ccrs.LambertConformal(), frameon=False)
ax.set_extent([-125, -66.5, 20, 50], ccrs.Geodetic())
# Add map of countries & US states as a backdrop
for shapename in ("admin_1_states_provinces_lakes_shp", "admin_0_countries"):
shp = shpreader.natural_earth(
resolution="110m", category="cultural", name=shapename
)
ax.add_geometries(
shpreader.Reader(shp).geometries(),
ccrs.PlateCarree(),
facecolor="none",
edgecolor="k",
)
# NOTE: When using cartopy, use matplotlib directly rather than nx.draw
# to take advantage of the cartopy transforms
ax.scatter(
*np.array([v for v in G.position.values()]).T,
s=[G.population[v] for v in H],
c=node_color,
transform=ccrs.PlateCarree(),
zorder=100 # Ensure nodes lie on top of edges/state lines
)
# Plot edges between the cities
for edge in H.edges():
edge_coords = np.array([G.position[v] for v in edge])
ax.plot(
edge_coords[:, 0],
edge_coords[:, 1],
transform=ccrs.PlateCarree(),
linewidth=0.75,
color="k",
)
except ImportError:
# If cartopy is unavailable, the backdrop for the plot will be blank;
# though you should still be able to discern the general shape of the US
# from graph nodes and edges!
nx.draw(
H,
G.position,
node_size=[G.population[v] for v in H],
node_color=node_color,
with_labels=False,
)
plt.show()

View File

@@ -0,0 +1,54 @@
"""
=================
Labels And Colors
=================
Use `nodelist` and `edgelist` to apply custom coloring and labels to various
components of a graph.
"""
import matplotlib.pyplot as plt
import networkx as nx
G = nx.cubical_graph()
pos = nx.spring_layout(G, seed=3113794652) # positions for all nodes
# nodes
options = {"edgecolors": "tab:gray", "node_size": 800, "alpha": 0.9}
nx.draw_networkx_nodes(G, pos, nodelist=[0, 1, 2, 3], node_color="tab:red", **options)
nx.draw_networkx_nodes(G, pos, nodelist=[4, 5, 6, 7], node_color="tab:blue", **options)
# edges
nx.draw_networkx_edges(G, pos, width=1.0, alpha=0.5)
nx.draw_networkx_edges(
G,
pos,
edgelist=[(0, 1), (1, 2), (2, 3), (3, 0)],
width=8,
alpha=0.5,
edge_color="tab:red",
)
nx.draw_networkx_edges(
G,
pos,
edgelist=[(4, 5), (5, 6), (6, 7), (7, 4)],
width=8,
alpha=0.5,
edge_color="tab:blue",
)
# some math labels
labels = {}
labels[0] = r"$a$"
labels[1] = r"$b$"
labels[2] = r"$c$"
labels[3] = r"$d$"
labels[4] = r"$\alpha$"
labels[5] = r"$\beta$"
labels[6] = r"$\gamma$"
labels[7] = r"$\delta$"
nx.draw_networkx_labels(G, pos, labels, font_size=22, font_color="whitesmoke")
plt.tight_layout()
plt.axis("off")
plt.show()

View File

@@ -0,0 +1,41 @@
"""
===================
Multipartite Layout
===================
"""
import itertools
import matplotlib.pyplot as plt
import networkx as nx
subset_sizes = [5, 5, 4, 3, 2, 4, 4, 3]
subset_color = [
"gold",
"violet",
"violet",
"violet",
"violet",
"limegreen",
"limegreen",
"darkorange",
]
def multilayered_graph(*subset_sizes):
extents = nx.utils.pairwise(itertools.accumulate((0,) + subset_sizes))
layers = [range(start, end) for start, end in extents]
G = nx.Graph()
for (i, layer) in enumerate(layers):
G.add_nodes_from(layer, layer=i)
for layer1, layer2 in nx.utils.pairwise(layers):
G.add_edges_from(itertools.product(layer1, layer2))
return G
G = multilayered_graph(*subset_sizes)
color = [subset_color[data["layer"]] for v, data in G.nodes(data=True)]
pos = nx.multipartite_layout(G, subset_key="layer")
plt.figure(figsize=(8, 8))
nx.draw(G, pos, node_color=color, with_labels=False)
plt.axis("equal")
plt.show()

View File

@@ -0,0 +1,15 @@
"""
=============
Node Colormap
=============
Draw a graph with matplotlib, color by degree.
"""
import matplotlib.pyplot as plt
import networkx as nx
G = nx.cycle_graph(24)
pos = nx.circular_layout(G)
nx.draw(G, pos, node_color=range(24), node_size=800, cmap=plt.cm.Blues)
plt.show()

View File

@@ -0,0 +1,68 @@
"""
================
Rainbow Coloring
================
Generate a complete graph with 13 nodes in a circular layout with the
edges colored by node distance. The node distance is given by the minimum
number of nodes traversed along an arc between any two nodes on the circle.
Such graphs are the subject of Ringel's conjecture, which states: any complete
graph with ``2n + 1`` nodes can be tiled by any tree with ``n + 1`` nodes
(i.e. copies of the tree can be placed over the complete graph such that each
edge in the complete graph is covered exactly once). The edge coloring is
helpful in determining how to place the tree copies.
References
----------
https://www.quantamagazine.org/mathematicians-prove-ringels-graph-theory-conjecture-20200219/
"""
import matplotlib.pyplot as plt
import networkx as nx
# A rainbow color mapping using matplotlib's tableau colors
node_dist_to_color = {
1: "tab:red",
2: "tab:orange",
3: "tab:olive",
4: "tab:green",
5: "tab:blue",
6: "tab:purple",
}
# Create a complete graph with an odd number of nodes
nnodes = 13
G = nx.complete_graph(nnodes)
# A graph with (2n + 1) nodes requires n colors for the edges
n = (nnodes - 1) // 2
ndist_iter = list(range(1, n + 1))
# Take advantage of circular symmetry in determining node distances
ndist_iter += ndist_iter[::-1]
def cycle(nlist, n):
return nlist[-n:] + nlist[:-n]
# Rotate nodes around the circle and assign colors for each edge based on
# node distance
nodes = list(G.nodes())
for i, nd in enumerate(ndist_iter):
for u, v in zip(nodes, cycle(nodes, i + 1)):
G[u][v]["color"] = node_dist_to_color[nd]
pos = nx.circular_layout(G)
# Create a figure with 1:1 aspect ratio to preserve the circle.
fig, ax = plt.subplots(figsize=(8, 8))
node_opts = {"node_size": 500, "node_color": "w", "edgecolors": "k", "linewidths": 2.0}
nx.draw_networkx_nodes(G, pos, **node_opts)
nx.draw_networkx_labels(G, pos, font_size=14)
# Extract color from edge data
edge_colors = [edgedata["color"] for _, _, edgedata in G.edges(data=True)]
nx.draw_networkx_edges(G, pos, width=2.0, edge_color=edge_colors)
ax.set_axis_off()
fig.tight_layout()
plt.show()

View File

@@ -0,0 +1,44 @@
"""
======================
Random Geometric Graph
======================
Example
"""
import matplotlib.pyplot as plt
import networkx as nx
# Use seed when creating the graph for reproducibility
G = nx.random_geometric_graph(200, 0.125, seed=896803)
# position is stored as node attribute data for random_geometric_graph
pos = nx.get_node_attributes(G, "pos")
# find node near center (0.5,0.5)
dmin = 1
ncenter = 0
for n in pos:
x, y = pos[n]
d = (x - 0.5) ** 2 + (y - 0.5) ** 2
if d < dmin:
ncenter = n
dmin = d
# color by path length from node near center
p = dict(nx.single_source_shortest_path_length(G, ncenter))
plt.figure(figsize=(8, 8))
nx.draw_networkx_edges(G, pos, alpha=0.4)
nx.draw_networkx_nodes(
G,
pos,
nodelist=list(p.keys()),
node_size=80,
node_color=list(p.values()),
cmap=plt.cm.Reds_r,
)
plt.xlim(-0.05, 1.05)
plt.ylim(-0.05, 1.05)
plt.axis("off")
plt.show()

View File

@@ -0,0 +1,47 @@
"""
=======
Sampson
=======
Sampson's monastery data.
Shows how to read data from a zip file and plot multiple frames.
The data file can be found at:
- https://github.com/networkx/networkx/blob/main/examples/drawing/sampson_data.zip
"""
import zipfile
from io import BytesIO as StringIO
import matplotlib.pyplot as plt
import networkx as nx
with zipfile.ZipFile("sampson_data.zip") as zf:
e1 = StringIO(zf.read("samplike1.txt"))
e2 = StringIO(zf.read("samplike2.txt"))
e3 = StringIO(zf.read("samplike3.txt"))
G1 = nx.read_edgelist(e1, delimiter="\t")
G2 = nx.read_edgelist(e2, delimiter="\t")
G3 = nx.read_edgelist(e3, delimiter="\t")
pos = nx.spring_layout(G3, iterations=100, seed=173)
plt.clf()
plt.subplot(221)
plt.title("samplike1")
nx.draw(G1, pos, node_size=50, with_labels=False)
plt.subplot(222)
plt.title("samplike2")
nx.draw(G2, pos, node_size=50, with_labels=False)
plt.subplot(223)
plt.title("samplike3")
nx.draw(G3, pos, node_size=50, with_labels=False)
plt.subplot(224)
plt.title("samplike1,2,3")
nx.draw(G3, pos, edgelist=list(G3.edges()), node_size=50, with_labels=False)
nx.draw_networkx_edges(G1, pos, alpha=0.25)
nx.draw_networkx_edges(G2, pos, alpha=0.25)
plt.tight_layout()
plt.show()

View File

@@ -0,0 +1,29 @@
"""
==========
Self-loops
==========
A self-loop is an edge that originates from and terminates the same node.
This example shows how to draw self-loops with `nx_pylab`.
"""
import networkx as nx
import matplotlib.pyplot as plt
# Create a graph and add a self-loop to node 0
G = nx.complete_graph(3, create_using=nx.DiGraph)
G.add_edge(0, 0)
pos = nx.circular_layout(G)
# As of version 2.6, self-loops are drawn by default with the same styling as
# other edges
nx.draw(G, pos, with_labels=True)
# Add self-loops to the remaining nodes
edgelist = [(1, 1), (2, 2)]
G.add_edges_from(edgelist)
# Draw the newly added self-loops with different formatting
nx.draw_networkx_edges(G, pos, edgelist=edgelist, arrowstyle="<|-", style="dashed")
plt.show()

View File

@@ -0,0 +1,14 @@
"""
===========
Simple Path
===========
Draw a graph with matplotlib.
"""
import matplotlib.pyplot as plt
import networkx as nx
G = nx.path_graph(8)
pos = nx.spring_layout(G, seed=47) # Seed layout for reproducibility
nx.draw(G, pos=pos)
plt.show()

View File

@@ -0,0 +1,58 @@
"""
==================
Spectral Embedding
==================
The spectral layout positions the nodes of the graph based on the
eigenvectors of the graph Laplacian $L = D - A$, where $A$ is the
adjacency matrix and $D$ is the degree matrix of the graph.
By default, the spectral layout will embed the graph in two
dimensions (you can embed your graph in other dimensions using the
``dim`` argument to either :func:`~drawing.nx_pylab.draw_spectral` or
:func:`~drawing.layout.spectral_layout`).
When the edges of the graph represent similarity between the incident
nodes, the spectral embedding will place highly similar nodes closer
to one another than nodes which are less similar.
This is particularly striking when you spectrally embed a grid
graph. In the full grid graph, the nodes in the center of the
graph are pulled apart more than nodes on the periphery.
As you remove internal nodes, this effect increases.
"""
import matplotlib.pyplot as plt
import networkx as nx
options = {"node_color": "C0", "node_size": 100}
G = nx.grid_2d_graph(6, 6)
plt.subplot(332)
nx.draw_spectral(G, **options)
G.remove_edge((2, 2), (2, 3))
plt.subplot(334)
nx.draw_spectral(G, **options)
G.remove_edge((3, 2), (3, 3))
plt.subplot(335)
nx.draw_spectral(G, **options)
G.remove_edge((2, 2), (3, 2))
plt.subplot(336)
nx.draw_spectral(G, **options)
G.remove_edge((2, 3), (3, 3))
plt.subplot(337)
nx.draw_spectral(G, **options)
G.remove_edge((1, 2), (1, 3))
plt.subplot(338)
nx.draw_spectral(G, **options)
G.remove_edge((4, 2), (4, 3))
plt.subplot(339)
nx.draw_spectral(G, **options)
plt.show()

View File

@@ -0,0 +1,52 @@
"""
==========================
Traveling Salesman Problem
==========================
This is an example of a drawing solution of the traveling salesman problem
The function is used to produce the solution is christofides,
where given a set of nodes, it calculates the route of the nodes
that the traveler has to follow in order to minimize the total cost.
"""
import matplotlib.pyplot as plt
import networkx as nx
import networkx.algorithms.approximation as nx_app
import math
G = nx.random_geometric_graph(20, radius=0.4, seed=3)
pos = nx.get_node_attributes(G, "pos")
# Depot should be at (0,0)
pos[0] = (0.5, 0.5)
H = G.copy()
# Calculating the distances between the nodes as edge's weight.
for i in range(len(pos)):
for j in range(i + 1, len(pos)):
dist = math.hypot(pos[i][0] - pos[j][0], pos[i][1] - pos[j][1])
dist = dist
G.add_edge(i, j, weight=dist)
cycle = nx_app.christofides(G, weight="weight")
edge_list = list(nx.utils.pairwise(cycle))
# Draw closest edges on each node only
nx.draw_networkx_edges(H, pos, edge_color="blue", width=0.5)
# Draw the route
nx.draw_networkx(
G,
pos,
with_labels=True,
edgelist=edge_list,
edge_color="red",
node_size=200,
width=3,
)
print("The route of the traveller is:", cycle)
plt.show()

View File

@@ -0,0 +1,62 @@
"""
==========
Unix Email
==========
Create a directed graph, allowing multiple edges and self loops, from a unix
mailbox. The nodes are email addresses with links that point from the sender
to the receivers. The edge data is a Python email.Message object which
contains all of the email message data.
This example shows the power of `DiGraph` to hold edge data of arbitrary Python
objects (in this case a list of email messages).
The sample unix email mailbox called "unix_email.mbox" may be found here:
- https://github.com/networkx/networkx/blob/main/examples/drawing/unix_email.mbox
"""
from email.utils import getaddresses, parseaddr
import mailbox
import matplotlib.pyplot as plt
import networkx as nx
# unix mailbox recipe
# see https://docs.python.org/3/library/mailbox.html
def mbox_graph():
mbox = mailbox.mbox("unix_email.mbox") # parse unix mailbox
G = nx.MultiDiGraph() # create empty graph
# parse each messages and build graph
for msg in mbox: # msg is python email.Message.Message object
(source_name, source_addr) = parseaddr(msg["From"]) # sender
# get all recipients
# see https://docs.python.org/3/library/email.html
tos = msg.get_all("to", [])
ccs = msg.get_all("cc", [])
resent_tos = msg.get_all("resent-to", [])
resent_ccs = msg.get_all("resent-cc", [])
all_recipients = getaddresses(tos + ccs + resent_tos + resent_ccs)
# now add the edges for this mail message
for (target_name, target_addr) in all_recipients:
G.add_edge(source_addr, target_addr, message=msg)
return G
G = mbox_graph()
# print edges with message subject
for (u, v, d) in G.edges(data=True):
print(f"From: {u} To: {v} Subject: {d['message']['Subject']}")
pos = nx.spring_layout(G, iterations=10, seed=227)
nx.draw(G, pos, node_size=0, alpha=0.4, edge_color="r", font_size=16, with_labels=True)
ax = plt.gca()
ax.margins(0.08)
plt.show()

View File

@@ -0,0 +1,44 @@
"""
==============
Weighted Graph
==============
An example using Graph as a weighted network.
"""
import matplotlib.pyplot as plt
import networkx as nx
G = nx.Graph()
G.add_edge("a", "b", weight=0.6)
G.add_edge("a", "c", weight=0.2)
G.add_edge("c", "d", weight=0.1)
G.add_edge("c", "e", weight=0.7)
G.add_edge("c", "f", weight=0.9)
G.add_edge("a", "d", weight=0.3)
elarge = [(u, v) for (u, v, d) in G.edges(data=True) if d["weight"] > 0.5]
esmall = [(u, v) for (u, v, d) in G.edges(data=True) if d["weight"] <= 0.5]
pos = nx.spring_layout(G, seed=7) # positions for all nodes - seed for reproducibility
# nodes
nx.draw_networkx_nodes(G, pos, node_size=700)
# edges
nx.draw_networkx_edges(G, pos, edgelist=elarge, width=6)
nx.draw_networkx_edges(
G, pos, edgelist=esmall, width=6, alpha=0.5, edge_color="b", style="dashed"
)
# node labels
nx.draw_networkx_labels(G, pos, font_size=20, font_family="sans-serif")
# edge weight labels
edge_labels = nx.get_edge_attributes(G, "weight")
nx.draw_networkx_edge_labels(G, pos, edge_labels)
ax = plt.gca()
ax.margins(0.08)
plt.axis("off")
plt.tight_layout()
plt.show()

View File

@@ -0,0 +1,84 @@
From alice@edu Thu Jun 16 16:12:12 2005
From: Alice <alice@edu>
Subject: NetworkX
Date: Thu, 16 Jun 2005 16:12:13 -0700
To: Bob <bob@gov>
Status: RO
Content-Length: 86
Lines: 5
Bob, check out the new networkx release - you and
Carol might really like it.
Alice
From bob@gov Thu Jun 16 18:13:12 2005
Return-Path: <bob@gov>
Subject: Re: NetworkX
From: Bob <bob@gov>
To: Alice <alice@edu>
Content-Type: text/plain
Date: Thu, 16 Jun 2005 18:13:12 -0700
Status: RO
Content-Length: 26
Lines: 4
Thanks for the tip.
Bob
From ted@com Thu Jul 28 09:53:31 2005
Return-Path: <ted@com>
Subject: Graph package in Python?
From: Ted <ted@com>
To: Bob <bob@gov>
Content-Type: text/plain
Date: Thu, 28 Jul 2005 09:47:03 -0700
Status: RO
Content-Length: 90
Lines: 3
Hey Ted - I'm looking for a Python package for
graphs and networks. Do you know of any?
From bob@gov Thu Jul 28 09:59:31 2005
Return-Path: <bob@gov>
Subject: Re: Graph package in Python?
From: Bob <bob@gov>
To: Ted <ted@com>
Content-Type: text/plain
Date: Thu, 28 Jul 2005 09:59:03 -0700
Status: RO
Content-Length: 180
Lines: 9
Check out the NetworkX package - Alice sent me the tip!
Bob
>> bob@gov scrawled:
>> Hey Ted - I'm looking for a Python package for
>> graphs and networks. Do you know of any?
From ted@com Thu Jul 28 15:53:31 2005
Return-Path: <ted@com>
Subject: get together for lunch to discuss Networks?
From: Ted <ted@com>
To: Bob <bob@gov>, Carol <carol@gov>, Alice <alice@edu>
Content-Type: text/plain
Date: Thu, 28 Jul 2005 15:47:03 -0700
Status: RO
Content-Length: 139
Lines: 5
Hey everyrone! Want to meet at that restaurant on the
island in Konigsburg tonight? Bring your laptops
and we can install NetworkX.
Ted

Some files were not shown because too many files have changed in this diff Show More