Networkx Examples#
On this page, we visualize several examples of networkx graphs as hive plots.
[1]:
import matplotlib.pyplot as plt
import networkx as nx
import numpy as np
import pandas as pd
from flexitext import flexitext
from hiveplotlib import HivePlot
from hiveplotlib.converters import networkx_to_nodes_edges
Tripartite Graph#
By definition, a multipartite graph should not have any connections within a group. This is easy to visualize by drawing a hive plot with repeat axes.
[2]:
G = nx.complete_multipartite_graph(10, 10, 10)
[3]:
nodes, edges = networkx_to_nodes_edges(G)
# split node IDs into separate lists based on which "subset" they're in
partition_variable = nodes.create_partition_variable(
data_column="subset",
cutoffs=3, # split into our 3 groups
labels=["Group 1", "Group 2", "Group 3"],
)
# not concerned with on-axis patterns, place nodes on axes randomly
rng = np.random.default_rng(0)
nodes.data["val"] = rng.uniform(size=len(nodes.data))
[4]:
hp = HivePlot(
nodes=nodes,
edges=edges,
partition_variable=partition_variable,
sorting_variables="val",
repeat_axes=True,
)
[5]:
fig, ax = hp.plot(color="C0")
ax.set_title(
"By definition, a multipartite graph has no within-group connections",
y=1.1,
size=20,
x=0,
ha="left",
)
plt.show()
Ring of Cliques#
By construction, the ring of cliques graph is fully connected among nodes within each group, with a single connection between each group.
[6]:
rng = np.random.default_rng(0)
G = nx.ring_of_cliques(num_cliques=3, clique_size=10)
[7]:
nodes, edges = networkx_to_nodes_edges(G)
# not concerned with on-axis patterns, place nodes on axes randomly
rng = np.random.default_rng(0)
nodes.data["val"] = rng.uniform(size=len(nodes.data))
networkx generates the groups in order, so the first 10 node IDs are in the first clique, then the next 10 are in the second clique, and the last 10 are in the third clique. There is no underlying data in the resulting nodes generated by the networkx graph for us to split on, so we will manually generate the separate lists of node IDs with numpy.
[8]:
partition_variable = nodes.create_partition_variable(
data_column="unique_id",
cutoffs=3, # split into our 3 groups
labels=["Group 1", "Group 2", "Group 3"],
)
[9]:
hp = HivePlot(
nodes=nodes,
edges=edges,
partition_variable=partition_variable,
sorting_variables="val",
repeat_axes=True,
non_repeat_edge_kwargs={"color": "royalblue", "lw": 4, "alpha": 1},
repeat_edge_kwargs={"color": "darkgrey", "lw": 1},
)
[10]:
fig, ax = hp.plot()
# embed legend in the title
flexitext(
x=0.55,
y=0.95,
s="<size:18>By construction, each clique is connected by "
"<color:royalblue, weight: bold>a single edge</></>",
xycoords="figure fraction",
ha="center",
)
plt.show()
Stochastic Block Model#
Asymmetric relationships between groups can be well-represented with hive plots.
Note, we cover this example in more detail in the Quick Hive Plots notebook.
[11]:
G = nx.stochastic_block_model(
sizes=[10, 10, 10],
p=[
[0.1, 0.5, 0.5],
[0.05, 0.1, 0.2],
[0.05, 0.2, 0.1],
],
directed=True,
seed=0,
)
Above, we have generated 3 cliques of equal size (10 per clique) with the following properties:
Within-group communication is only 10% (
0.1on the diagonal).Group 1 is very social with Groups 2 and 3 (
0.5), but Groups 2 and 3 aren’t very social with Group 1 (0.05).Group 2 and Group 3 are relatively social with each other (
0.2).
[12]:
nodes, edges = networkx_to_nodes_edges(G)
partition_variable = nodes.create_partition_variable(
data_column="block",
cutoffs=3, # split into our 3 groups
labels=["Group 1", "Group 2", "Group 3"],
)
# pull out degree information from nodes
degrees = pd.DataFrame(G.degree, columns=[nodes.unique_id_column, "degree"])
# add degree information to node data
nodes.data = nodes.data.merge(degrees, on=nodes.unique_id_column)
hp = HivePlot(
nodes=nodes,
edges=edges,
partition_variable=partition_variable,
sorting_variables="degree",
repeat_axes=True,
non_repeat_edge_kwargs={"color": "darkorange", "alpha": 1},
repeat_edge_kwargs={"color": "darkgrey"},
)
# update Group 1 *from* edges to blue
# make more transparant (lots of edges)
# and place these edges *behind* orange edges (zorder)
hp.update_edges(
partition_id_1="Group 1",
partition_id_2="Group 2",
p2_to_p1=False,
color="royalblue",
alpha=0.6,
zorder=-1,
)
hp.update_edges(
partition_id_1="Group 1",
partition_id_2="Group 3",
p2_to_p1=False,
color="royalblue",
alpha=0.6,
zorder=-1,
)
[13]:
fig, ax = hp.plot()
# embed legend in the title
flexitext(
x=0.55,
y=1.15,
s="<size:18><color:royalblue, weight: bold>Group 1</> is "
"asymmetrically social with "
"<color:darkorange, weight:bold>Groups 2 and 3</>\n\n"
"<color:darkorange, weight:bold>Groups 2 and 3</> "
"are relatively social with each other\n\n"
"<color:darkgray, weight:bold>Intra-Group activity</> "
"is minimal for all groups</>",
ha="center",
ax=ax,
)
plt.show()