Spaces:
Sleeping
Sleeping
import streamlit as st | |
import itertools as it | |
import matplotlib.pyplot as plt | |
import networkx as nx | |
import numpy as np | |
from operator import itemgetter | |
import math # Import the math module | |
from matplotlib import animation | |
from mpl_toolkits.mplot3d import Axes3D | |
from streamlit.components.v1 import html | |
# Sidebar for selecting an option | |
sidebar_option = st.sidebar.radio("Select an option", | |
["Select an option", "Basic: Properties", | |
"Basic: Read and write graphs", "Basic: Simple graph", | |
"Basic: Simple graph Directed", "Drawing: Custom Node Position", | |
"Drawing: Cluster Layout", "Drawing: Degree Analysis", | |
"Drawing: Ego Graph", "Drawing: Eigenvalues", "Drawing: Four Grids", | |
"Drawing: House With Colors", "Drawing: Labels And Colors", | |
"Drawing: Multipartite Layout", "Drawing: Node Colormap", | |
"Drawing: Rainbow Coloring", "Drawing: Random Geometric Graph","Drawing: Self-loops", | |
"Drawing: Simple Path", "Drawing: Spectral Embedding", "Drawing: Traveling Salesman Problem", | |
"Drawing: Weighted Graph", "3D Drawing: Animations of 3D Rotation", "3D Drawing: Basic Matplotlib", | |
"Graphviz Layout: Lanl Routes"]) | |
# Helper function to draw and display graph | |
def draw_graph(G, pos=None, title="Graph Visualization"): | |
plt.figure(figsize=(8, 6)) | |
nx.draw(G, pos=pos, with_labels=True, node_color='lightblue', node_size=500, font_size=10, font_weight='bold') | |
st.pyplot(plt) | |
# Default example: Lanl Routes graph | |
def lanl_graph(): | |
"""Return the LANL internet view graph from lanl.edges""" | |
try: | |
fh = open("lanl_routes.edgelist") | |
except OSError: | |
print("lanl.edges not found") | |
raise | |
G = nx.Graph() | |
time = {} | |
time[0] = 0 # assign 0 to center node | |
for line in fh.readlines(): | |
(head, tail, rtt) = line.split() | |
G.add_edge(int(head), int(tail)) | |
time[int(head)] = float(rtt) | |
# get largest component and assign ping times to G0time dictionary | |
Gcc = sorted(nx.connected_components(G), key=len, reverse=True)[0] | |
G0 = G.subgraph(Gcc) | |
G0.rtt = {} | |
for n in G0: | |
G0.rtt[n] = time[n] | |
return G0 | |
# Streamlit Layout for Graphviz Layout: Lanl Routes | |
def graphviz_layout_lanl_routes(): | |
st.title("Graphviz Layout: Lanl Routes") | |
# Sidebar selection for Default Example or Custom Graph | |
graph_mode = st.radio( | |
"Choose a Mode:", | |
("Default Example", "Create Your Own"), | |
help="Default example shows LANL routes, or you can create your own custom graph." | |
) | |
if graph_mode == "Default Example": | |
# Load LANL graph and visualize | |
G = lanl_graph() | |
st.write("Graph Summary:") | |
st.write(G) | |
st.write(f"{nx.number_connected_components(G)} connected components") | |
# Create and display the graph | |
plt.figure(figsize=(8, 8)) | |
# Use graphviz to find radial layout | |
pos = nx.nx_agraph.graphviz_layout(G, prog="twopi", root=0) | |
# Draw nodes, coloring by rtt ping time | |
options = {"with_labels": False, "alpha": 0.5, "node_size": 15} | |
nx.draw(G, pos, node_color=[G.rtt[v] for v in G], **options) | |
# Adjust the plot limits | |
xmax = 1.02 * max(xx for xx, yy in pos.values()) | |
ymax = 1.02 * max(yy for xx, yy in pos.values()) | |
plt.xlim(0, xmax) | |
plt.ylim(0, ymax) | |
st.pyplot(plt) | |
elif graph_mode == "Create Your Own": | |
st.write("### Custom Graph Creation") | |
# Input form for creating custom graph | |
num_nodes = st.slider("Number of Nodes", min_value=2, max_value=50, value=10) | |
num_edges = st.slider("Number of Edges", min_value=1, max_value=num_nodes*(num_nodes-1)//2, value=10) | |
# Generate custom graph | |
G_custom = nx.gnm_random_graph(num_nodes, num_edges) | |
st.write("Generated Custom Graph:") | |
st.write(G_custom) | |
# Use graphviz layout | |
pos = nx.nx_agraph.graphviz_layout(G_custom, prog="twopi") | |
nx.draw(G_custom, pos, with_labels=True, node_size=500, node_color="lightblue", font_size=10) | |
st.pyplot(plt) | |
# Display the corresponding page based on sidebar option | |
if sidebar_option == "Graphviz Layout: Lanl Routes": | |
graphviz_layout_lanl_routes() | |
if sidebar_option == "3D Drawing: Animations of 3D Rotation": | |
st.title("3D Drawing: Animations of 3D Rotation") | |
# Provide options for Default Example or Custom Graph | |
graph_mode = st.radio( | |
"Choose a Mode:", | |
("Default Example", "Create Your Own"), | |
help="Default example shows a dodecahedral graph, or you can create your own custom graph." | |
) | |
# Define the function to create animation | |
def generate_animation(G, pos, frames=100): | |
nodes = np.array([pos[v] for v in G]) | |
edges = np.array([(pos[u], pos[v]) for u, v in G.edges()]) | |
fig = plt.figure() | |
ax = fig.add_subplot(111, projection="3d") | |
def init(): | |
ax.scatter(*nodes.T, alpha=0.2, s=100, color="blue") | |
for vizedge in edges: | |
ax.plot(*vizedge.T, color="gray") | |
ax.grid(False) | |
ax.set_axis_off() | |
plt.tight_layout() | |
return | |
def _frame_update(index): | |
ax.view_init(index * 0.2, index * 0.5) | |
return | |
ani = animation.FuncAnimation( | |
fig, | |
_frame_update, | |
init_func=init, | |
interval=50, | |
cache_frame_data=False, | |
frames=frames, | |
) | |
return ani | |
# Default Example | |
if graph_mode == "Default Example": | |
G = nx.dodecahedral_graph() | |
pos = nx.spectral_layout(G, dim=3) | |
ani = generate_animation(G, pos) | |
# Create Your Own Example | |
else: | |
st.write("### Customize Your Graph") | |
num_nodes = st.slider("Number of Nodes", min_value=5, max_value=50, value=20) | |
edge_prob = st.slider("Edge Probability", min_value=0.1, max_value=1.0, value=0.3) | |
# Generate custom graph | |
G = nx.erdos_renyi_graph(num_nodes, edge_prob) | |
pos = nx.spectral_layout(G, dim=3) | |
ani = generate_animation(G, pos) | |
# Display animation in Streamlit | |
with st.spinner("Rendering animation..."): | |
ani.save("animation.gif", writer="imagemagick") | |
st.image("animation.gif", caption="3D Graph Rotation", use_container_width=True) | |
# Default example code | |
def default_example(): | |
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() | |
st.pyplot(fig) | |
# Create your own graph option | |
def create_own_graph(): | |
# Input fields to customize the graph | |
nodes = st.number_input("Number of nodes", min_value=2, max_value=50, value=20) | |
seed = st.number_input("Seed for layout", value=779) | |
# Add a button to generate the graph | |
generate_button = st.button("Generate Graph") | |
if generate_button: | |
# Generate graph and layout | |
G = nx.cycle_graph(nodes) | |
pos = nx.spring_layout(G, dim=3, seed=seed) | |
# Extract node and edge positions | |
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 | |
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.""" | |
ax.grid(False) | |
for dim in (ax.xaxis, ax.yaxis, ax.zaxis): | |
dim.set_ticks([]) | |
ax.set_xlabel("x") | |
ax.set_ylabel("y") | |
ax.set_zlabel("z") | |
_format_axes(ax) | |
fig.tight_layout() | |
st.pyplot(fig) | |
if sidebar_option == "3D Drawing: Basic Matplotlib": | |
st.title("3D Drawing: Basic Matplotlib") | |
# Provide options for Default Example or Custom Graph | |
graph_mode = st.radio( | |
"Choose a Mode:", | |
("Default Example", "Create Your Own"), | |
help="Default example shows a cycle graph, or you can create your own custom graph." | |
) | |
# Display the chosen option | |
if graph_mode == "Default Example": | |
default_example() | |
elif graph_mode == "Create Your Own": | |
create_own_graph() | |
# Function to display Weighted Graph | |
def display_weighted_graph(): | |
st.title("Drawing: Weighted Graph") | |
option = st.radio("Choose a graph type:", ("Default Example", "Create your own")) | |
if option == "Default Example": | |
# Default weighted graph example | |
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() | |
st.pyplot(plt) | |
elif option == "Create your own": | |
# User can create their own graph with edges and weights | |
edge_input = st.text_area( | |
"Enter edges with weights (format: node1,node2,weight;node1,node2,weight;...)", | |
"a,b,0.6;a,c,0.2;c,d,0.1;c,e,0.7;c,f,0.9;a,d,0.3" | |
) | |
# Parse the input string | |
edges = edge_input.split(";") | |
edge_list = [] | |
for edge in edges: | |
node1, node2, weight = edge.split(",") | |
edge_list.append((node1.strip(), node2.strip(), float(weight.strip()))) | |
# Add a button to generate the graph | |
generate_button = st.button("Generate Graph") | |
if generate_button: | |
G_custom = nx.Graph() | |
# Add edges to the graph | |
for node1, node2, weight in edge_list: | |
G_custom.add_edge(node1, node2, weight=weight) | |
# Create layout for visualization | |
pos = nx.spring_layout(G_custom, seed=7) | |
# Determine edges based on weight | |
elarge = [(u, v) for (u, v, d) in G_custom.edges(data=True) if d["weight"] > 0.5] | |
esmall = [(u, v) for (u, v, d) in G_custom.edges(data=True) if d["weight"] <= 0.5] | |
# Draw the graph | |
nx.draw_networkx_nodes(G_custom, pos, node_size=700) | |
nx.draw_networkx_edges(G_custom, pos, edgelist=elarge, width=6) | |
nx.draw_networkx_edges( | |
G_custom, pos, edgelist=esmall, width=6, alpha=0.5, edge_color="b", style="dashed" | |
) | |
nx.draw_networkx_labels(G_custom, pos, font_size=20, font_family="sans-serif") | |
edge_labels = nx.get_edge_attributes(G_custom, "weight") | |
nx.draw_networkx_edge_labels(G_custom, pos, edge_labels) | |
ax = plt.gca() | |
ax.margins(0.08) | |
plt.axis("off") | |
plt.tight_layout() | |
st.pyplot(plt) | |
# Display Drawing: Weighted Graph if selected | |
if sidebar_option == "Drawing: Weighted Graph": | |
display_weighted_graph() | |
from networkx.algorithms.approximation import christofides | |
# Function to display Traveling Salesman Problem | |
def display_tsp(): | |
st.title("Drawing: Traveling Salesman Problem") | |
option = st.radio("Choose a graph type:", ("Default Example", "Create your own")) | |
if option == "Default Example": | |
# Default example of random geometric graph with TSP solution | |
G = nx.random_geometric_graph(20, radius=0.4, seed=3) | |
pos = nx.get_node_attributes(G, "pos") | |
# Depot should be at (0.5, 0.5) | |
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) | |
# Find TSP cycle using Christofides' approximation | |
cycle = 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, | |
) | |
st.pyplot(plt) | |
st.write("The route of the traveler is:", cycle) | |
elif option == "Create your own": | |
# User can create their own graph | |
num_nodes = st.slider("Number of nodes:", min_value=3, max_value=30, value=20) | |
radius = st.slider("Edge radius:", min_value=0.1, max_value=1.0, value=0.4) | |
# Add a button to generate a new graph | |
generate_button = st.button("Generate Graph") | |
if generate_button: | |
# Create random geometric graph based on user input | |
G_custom = nx.random_geometric_graph(num_nodes, radius, seed=3) | |
pos = nx.get_node_attributes(G_custom, "pos") | |
# Depot should be at (0.5, 0.5) | |
pos[0] = (0.5, 0.5) | |
H = G_custom.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_custom.add_edge(i, j, weight=dist) | |
# Find TSP cycle using Christofides' approximation | |
cycle = christofides(G_custom, 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 TSP route | |
nx.draw_networkx( | |
G_custom, | |
pos, | |
with_labels=True, | |
edgelist=edge_list, | |
edge_color="red", | |
node_size=200, | |
width=3, | |
) | |
st.pyplot(plt) | |
st.write("The route of the traveler is:", cycle) | |
# Display Drawing: Traveling Salesman Problem if selected | |
if sidebar_option == "Drawing: Traveling Salesman Problem": | |
display_tsp() | |
# Function to display Drawing: Spectral Embedding | |
def display_spectral_embedding(): | |
st.title("Drawing: Spectral Embedding") | |
option = st.radio("Choose a graph type:", ("Default Example", "Create your own")) | |
if option == "Default Example": | |
# Default example of spectral embedding with a grid graph | |
options = {"node_color": "C0", "node_size": 100} # No labels | |
G = nx.grid_2d_graph(6, 6) | |
fig, axs = plt.subplots(3, 3, figsize=(12, 12)) | |
axs = axs.flatten() | |
for i in range(7): # Looping over 7 images | |
if i == 0: | |
nx.draw_spectral(G, **options, ax=axs[i]) | |
elif i == 1: | |
G.remove_edge((2, 2), (2, 3)) | |
nx.draw_spectral(G, **options, ax=axs[i]) | |
elif i == 2: | |
G.remove_edge((3, 2), (3, 3)) | |
nx.draw_spectral(G, **options, ax=axs[i]) | |
elif i == 3: | |
G.remove_edge((2, 2), (3, 2)) | |
nx.draw_spectral(G, **options, ax=axs[i]) | |
elif i == 4: | |
G.remove_edge((2, 3), (3, 3)) | |
nx.draw_spectral(G, **options, ax=axs[i]) | |
elif i == 5: | |
G.remove_edge((1, 2), (1, 3)) | |
nx.draw_spectral(G, **options, ax=axs[i]) | |
elif i == 6: | |
G.remove_edge((4, 2), (4, 3)) | |
nx.draw_spectral(G, **options, ax=axs[i]) | |
# Hide the last two subplots (8th and 9th) | |
for j in range(7, 9): | |
fig.delaxes(axs[j]) # Delete the extra axes | |
st.pyplot(fig) | |
elif option == "Create your own": | |
# User can interactively modify the grid and see the results | |
grid_size = st.slider("Choose grid size (n x n):", min_value=3, max_value=10, value=6) | |
G_custom = nx.grid_2d_graph(grid_size, grid_size) | |
# List all edges to allow removal | |
all_edges = list(G_custom.edges()) | |
# Collect user input for edges to remove (before showing the "Generate" button) | |
selected_edges_per_graph = [] | |
for i in range(7): # Loop over 7 graphs | |
selected_edges = st.multiselect(f"Select edges to remove for graph {i+1}:", | |
options=[str(edge) for edge in all_edges]) | |
selected_edges_per_graph.append(selected_edges) | |
# Add "Generate" button after edge selection | |
generate_button = st.button("Generate Graph") | |
if generate_button: | |
fig, axs = plt.subplots(3, 3, figsize=(12, 12)) | |
axs = axs.flatten() | |
# Loop through each subplot and allow edge removal individually | |
for i in range(7): # Loop over 7 graphs | |
edges_to_remove = [tuple(eval(edge)) for edge in selected_edges_per_graph[i]] | |
# Remove the selected edges | |
G_custom_copy = G_custom.copy() | |
G_custom_copy.remove_edges_from(edges_to_remove) | |
# Draw the graph with removed edges | |
nx.draw_spectral(G_custom_copy, **{"node_color": "C0", "node_size": 100}, ax=axs[i]) | |
# Hide the last two subplots (8th and 9th) | |
for j in range(7, 9): | |
fig.delaxes(axs[j]) # Delete the extra axes | |
st.pyplot(fig) | |
# Display Drawing: Spectral Embedding if selected | |
if sidebar_option == "Drawing: Spectral Embedding": | |
display_spectral_embedding() | |
# Function to display Drawing: Simple Path | |
def display_simple_path(): | |
st.title("Drawing: Simple Path") | |
option = st.radio("Choose a graph type:", ("Default Example", "Create your own")) | |
if option == "Default Example": | |
# Default example of a simple path graph | |
G = nx.path_graph(8) | |
pos = nx.spring_layout(G, seed=47) # Seed layout for reproducibility | |
# Draw the graph | |
nx.draw(G, pos=pos) | |
st.pyplot(plt) | |
elif option == "Create your own": | |
# User can create their own path graph with a custom number of nodes | |
num_nodes = st.number_input("Number of nodes in the path:", min_value=2, max_value=50, value=8) | |
if st.button("Generate Graph"): | |
# Generate a path graph with user-specified number of nodes | |
G_custom = nx.path_graph(num_nodes) | |
pos = nx.spring_layout(G_custom, seed=47) # Seed layout for reproducibility | |
# Draw the graph | |
nx.draw(G_custom, pos=pos) | |
st.pyplot(plt) | |
# Display Drawing: Simple Path if selected | |
if sidebar_option == "Drawing: Simple Path": | |
display_simple_path() | |
# Function to display Drawing: Self-loops | |
def display_self_loops(): | |
st.title("Drawing: Self-loops") | |
option = st.radio("Choose a graph type:", ("Default Example", "Create your own")) | |
if option == "Default Example": | |
# Default example of a graph with self-loops | |
G = nx.complete_graph(3, create_using=nx.DiGraph) | |
G.add_edge(0, 0) # Add a self-loop to node 0 | |
pos = nx.circular_layout(G) | |
# Draw the graph | |
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") | |
st.pyplot(plt) | |
elif option == "Create your own": | |
# User can create their own graph with self-loops | |
num_nodes = st.number_input("Number of nodes:", min_value=2, max_value=20, value=3) | |
add_self_loops = st.checkbox("Add self-loops to all nodes?", value=True) | |
if st.button("Generate Graph"): | |
# Generate a complete graph | |
G = nx.complete_graph(num_nodes, create_using=nx.DiGraph) | |
# Optionally add self-loops to all nodes | |
if add_self_loops: | |
for node in G.nodes(): | |
G.add_edge(node, node) | |
pos = nx.circular_layout(G) | |
# Draw the graph with self-loops | |
nx.draw(G, pos, with_labels=True) | |
# Style self-loops differently | |
edgelist = [(node, node) for node in G.nodes()] | |
nx.draw_networkx_edges(G, pos, edgelist=edgelist, arrowstyle="<|-", style="dashed") | |
st.pyplot(plt) | |
# Display Drawing: Self-loops if selected | |
if sidebar_option == "Drawing: Self-loops": | |
display_self_loops() | |
# Function to display Drawing: Random Geometric Graph | |
def display_random_geometric_graph(): | |
st.title("Drawing: Random Geometric Graph") | |
option = st.radio("Choose a graph type:", ("Default Example", "Create your own")) | |
if option == "Default Example": | |
# Default random geometric graph example | |
G = nx.random_geometric_graph(200, 0.125, seed=896803) | |
pos = nx.get_node_attributes(G, "pos") | |
# Find node near the 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") | |
st.pyplot(plt) | |
elif option == "Create your own": | |
# User can create their own random geometric graph | |
num_nodes = st.number_input("Number of nodes:", min_value=2, max_value=500, value=200) | |
distance = st.slider("Edge distance threshold (between 0 and 1):", 0.01, 1.0, 0.125) | |
if st.button("Generate Graph"): | |
# Generate the graph with user input | |
G = nx.random_geometric_graph(num_nodes, distance, seed=896803) | |
pos = nx.get_node_attributes(G, "pos") | |
# Find node near the 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") | |
st.pyplot(plt) | |
# Display Drawing: Random Geometric Graph if selected | |
if sidebar_option == "Drawing: Random Geometric Graph": | |
display_random_geometric_graph() | |
# Function to display Drawing: Rainbow Coloring | |
def display_rainbow_coloring(): | |
st.title("Drawing: Rainbow Coloring") | |
option = st.radio("Choose a graph type:", ("Default Example", "Create your own")) | |
if option == "Default Example": | |
# Rainbow Coloring with default parameters | |
node_dist_to_color = { | |
1: "tab:red", | |
2: "tab:orange", | |
3: "tab:olive", | |
4: "tab:green", | |
5: "tab:blue", | |
6: "tab:purple", | |
} | |
nnodes = 13 | |
G = nx.complete_graph(nnodes) | |
n = (nnodes - 1) // 2 | |
ndist_iter = list(range(1, n + 1)) | |
ndist_iter += ndist_iter[::-1] | |
def cycle(nlist, n): | |
return nlist[-n:] + nlist[:-n] | |
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() | |
st.pyplot(plt) | |
elif option == "Create your own": | |
nnodes = st.number_input("Number of nodes (max=14):", min_value=2, max_value=50, value=13) | |
# Allow users to create their own color map | |
red = st.color_picker("Select a color for Red (1)", "#ff0000") | |
orange = st.color_picker("Select a color for Orange (2)", "#ff7f00") | |
olive = st.color_picker("Select a color for Olive (3)", "#808000") | |
green = st.color_picker("Select a color for Green (4)", "#008000") | |
blue = st.color_picker("Select a color for Blue (5)", "#0000ff") | |
purple = st.color_picker("Select a color for Purple (6)", "#800080") | |
node_dist_to_color = { | |
1: red, | |
2: orange, | |
3: olive, | |
4: green, | |
5: blue, | |
6: purple, | |
} | |
if st.button("Generate Graph"): | |
G = nx.complete_graph(nnodes) | |
n = (nnodes - 1) // 2 | |
ndist_iter = list(range(1, n + 1)) | |
ndist_iter += ndist_iter[::-1] | |
def cycle(nlist, n): | |
return nlist[-n:] + nlist[:-n] | |
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() | |
st.pyplot(plt) | |
# Display Drawing: Rainbow Coloring if selected | |
if sidebar_option == "Drawing: Rainbow Coloring": | |
display_rainbow_coloring() | |
# Function to display Drawing: Node Colormap | |
def display_node_colormap(): | |
st.title("Drawing: Node Colormap") | |
option = st.radio("Choose a graph type:", ("Default Example", "Create your own")) | |
if option == "Default Example": | |
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) | |
st.pyplot(plt) | |
elif option == "Create your own": | |
num_nodes = st.number_input("Number of nodes:", min_value=2, max_value=100, value=24) | |
color_map = st.selectbox("Select a colormap:", plt.colormaps(), index=plt.colormaps().index('Blues')) | |
if st.button("Generate Graph"): | |
# Create cycle graph with custom number of nodes | |
G_custom = nx.cycle_graph(num_nodes) | |
pos = nx.circular_layout(G_custom) | |
nx.draw(G_custom, pos, node_color=range(num_nodes), node_size=800, cmap=plt.get_cmap(color_map)) | |
st.pyplot(plt) | |
# Display Drawing: Node Colormap if selected | |
if sidebar_option == "Drawing: Node Colormap": | |
display_node_colormap() | |
# Function to create a multipartite graph | |
def multilayered_graph(*subset_sizes): | |
G = nx.Graph() | |
layers = len(subset_sizes) | |
node_id = 0 | |
# Create nodes for each subset and add edges between nodes in adjacent layers | |
for i, size in enumerate(subset_sizes): | |
for j in range(size): | |
G.add_node(node_id, layer=i) # Assign a layer attribute | |
node_id += 1 | |
# Add edges between nodes in adjacent layers | |
node_ids = list(G.nodes()) | |
for i in range(layers - 1): | |
layer_nodes = [node for node in node_ids if G.nodes[node]["layer"] == i] | |
next_layer_nodes = [node for node in node_ids if G.nodes[node]["layer"] == i + 1] | |
for node in layer_nodes: | |
for next_node in next_layer_nodes: | |
G.add_edge(node, next_node) | |
return G | |
# Function to display Multipartite Layout | |
def display_multipartite_layout(): | |
st.title("Drawing: Multipartite Layout") | |
option = st.radio("Choose a graph type:", ("Default Example", "Create your own")) | |
if option == "Default Example": | |
subset_sizes = [5, 5, 4, 3, 2, 4, 4, 3] | |
subset_color = [ | |
"gold", "violet", "violet", "violet", "violet", | |
"limegreen", "limegreen", "darkorange" | |
] | |
# Generate and plot multipartite graph | |
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") | |
st.pyplot(plt) | |
elif option == "Create your own": | |
# Let the user input the subset sizes and colors | |
st.write("Enter the subset sizes and colors to create your own multipartite graph.") | |
subset_sizes_input = st.text_area("Enter subset sizes (comma-separated, e.g., 5,5,4,3):", value="5,5,4,3,2,4,4,3") | |
subset_sizes = list(map(int, subset_sizes_input.split(','))) | |
subset_colors_input = st.text_area("Enter subset colors (comma-separated, e.g., gold,violet,green):", value="gold,violet,violet,violet,violet,limegreen,limegreen,darkorange") | |
subset_colors = subset_colors_input.split(',') | |
# Check if the number of colors matches the number of subsets | |
if len(subset_sizes) != len(subset_colors): | |
st.error("The number of colors should match the number of subsets.") | |
else: | |
# Add a button to generate the graph | |
if st.button("Generate Graph"): | |
# Generate and plot multipartite graph | |
G = multilayered_graph(*subset_sizes) | |
color = [subset_colors[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") | |
st.pyplot(plt) | |
# Display Drawing: Multipartite Layout if selected | |
if sidebar_option == "Drawing: Multipartite Layout": | |
display_multipartite_layout() | |
# Function to display Labels and Colors | |
def display_labels_and_colors(): | |
st.title("Drawing: Labels And Colors") | |
option = st.radio("Choose a graph type:", ("Default Example", "Create your own")) | |
if option == "Default Example": | |
# Create a cubical graph | |
G = nx.cubical_graph() | |
pos = nx.spring_layout(G, seed=3113794652) # positions for all nodes | |
# Draw nodes with different colors | |
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) | |
# Draw 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", | |
) | |
# Add labels for nodes | |
labels = {0: r"$a$", 1: r"$b$", 2: r"$c$", 3: r"$d$", 4: r"$\alpha$", 5: r"$\beta$", 6: r"$\gamma$", 7: r"$\delta$"} | |
nx.draw_networkx_labels(G, pos, labels, font_size=22, font_color="whitesmoke") | |
plt.tight_layout() | |
plt.axis("off") | |
st.pyplot(plt) | |
elif option == "Create your own": | |
# Let the user input the nodes and edges of the graph | |
st.write("Enter the nodes and edges to create your own labeled graph.") | |
nodes = st.text_area("Enter node labels (comma-separated, e.g., a,b,c,d):", value="a,b,c,d") | |
node_labels = nodes.split(',') | |
edges = st.text_area("Enter edges (format: node1-node2, comma-separated, e.g., a-b,b-c):", value="a-b,b-c,c-d") | |
edge_list = [tuple(edge.split('-')) for edge in edges.split(',')] | |
# Let user choose colors for nodes and edges | |
node_color = st.color_picker("Pick a color for nodes:", "#FF6347") | |
edge_color = st.color_picker("Pick a color for edges:", "#4682B4") | |
# Add a button to generate the graph | |
if st.button("Generate Graph"): | |
# Generate graph based on user input | |
G_custom = nx.Graph() | |
G_custom.add_nodes_from(node_labels) | |
G_custom.add_edges_from(edge_list) | |
# Generate layout for the nodes | |
pos_custom = nx.spring_layout(G_custom) | |
# Draw the graph | |
nx.draw_networkx_nodes(G_custom, pos_custom, node_color=node_color, node_size=800, edgecolors="gray", alpha=0.9) | |
nx.draw_networkx_edges(G_custom, pos_custom, edge_color=edge_color, width=2, alpha=0.7) | |
# Create custom labels | |
custom_labels = {node: f"${node}$" for node in node_labels} | |
nx.draw_networkx_labels(G_custom, pos_custom, labels=custom_labels, font_size=22, font_color="whitesmoke") | |
plt.tight_layout() | |
plt.axis("off") | |
st.pyplot(plt) | |
# Display Drawing: Labels And Colors if selected | |
if sidebar_option == "Drawing: Labels And Colors": | |
display_labels_and_colors() | |
# Function to display Drawing: House With Colors | |
def display_house_with_colors(): | |
st.title("Drawing: House With Colors") | |
option = st.radio("Choose a graph type:", ("Default Example", "Create your own")) | |
if option == "Default Example": | |
# Create the house graph and explicitly set positions | |
G = nx.house_graph() | |
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") | |
st.pyplot(plt) | |
elif option == "Create your own": | |
# Allow the user to specify node positions and colors | |
st.write("Specify positions for the house graph nodes.") | |
positions = {} | |
for i in range(5): | |
x = st.number_input(f"X-coordinate for node {i}:", min_value=-10.0, max_value=10.0, value=0.0, step=0.1) | |
y = st.number_input(f"Y-coordinate for node {i}:", min_value=-10.0, max_value=10.0, value=0.0, step=0.1) | |
positions[i] = (x, y) | |
# Allow the user to specify colors for wall and roof nodes | |
wall_color = st.color_picker("Wall color:", "#0000FF") | |
roof_color = st.color_picker("Roof color:", "#FFA500") | |
if st.button("Generate"): | |
# Create the house graph with the specified positions | |
G_custom = nx.house_graph() | |
# Plot nodes with user-defined properties for wall and roof nodes | |
nx.draw_networkx_nodes(G_custom, positions, node_size=3000, nodelist=[0, 1, 2, 3], node_color=wall_color) | |
nx.draw_networkx_nodes(G_custom, positions, node_size=2000, nodelist=[4], node_color=roof_color) | |
nx.draw_networkx_edges(G_custom, positions, alpha=0.5, width=6) | |
# Customize axes | |
ax = plt.gca() | |
ax.margins(0.11) | |
plt.tight_layout() | |
plt.axis("off") | |
st.pyplot(plt) | |
# Display Drawing: House With Colors if selected | |
if sidebar_option == "Drawing: House With Colors": | |
display_house_with_colors() | |
# Function to display Four Grids visualization for Drawing: Four Grids | |
def display_four_grids(): | |
st.title("Drawing: Four Grids") | |
option = st.radio("Choose a graph type:", ("Default Example", "Create your own")) | |
if option == "Default Example": | |
# Generate a 4x4 grid graph | |
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 | |
# Draw graphs in 4 different styles | |
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() | |
st.pyplot(fig) | |
elif option == "Create your own": | |
# Allow the user to customize the grid dimensions | |
rows = st.number_input("Number of rows:", min_value=2, max_value=20, value=4) | |
cols = st.number_input("Number of columns:", min_value=2, max_value=20, value=4) | |
if st.button("Generate"): | |
# Generate a custom grid graph | |
G_custom = nx.grid_2d_graph(rows, cols) # Create the grid graph | |
pos = nx.spring_layout(G_custom, iterations=100, seed=39775) | |
# Create a 2x2 subplot | |
fig, all_axes = plt.subplots(2, 2) | |
ax = all_axes.flat | |
# Draw graphs in 4 different styles | |
nx.draw(G_custom, pos, ax=ax[0], font_size=8) | |
nx.draw(G_custom, pos, ax=ax[1], node_size=0, with_labels=False) | |
nx.draw( | |
G_custom, | |
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_custom.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() | |
st.pyplot(fig) | |
# Display Drawing: Four Grids if selected | |
if sidebar_option == "Drawing: Four Grids": | |
display_four_grids() | |
# Function to display Eigenvalue analysis for Drawing: Eigenvalues | |
def display_eigenvalue_analysis(): | |
st.title("Drawing: Eigenvalues") | |
option = st.radio("Choose a graph type:", ("Default Example", "Create your own")) | |
if option == "Default Example": | |
# Generate random graph with 1000 nodes and 5000 edges | |
n = 1000 | |
m = 5000 | |
G = nx.gnm_random_graph(n, m, seed=5040) # Seed for reproducibility | |
# Calculate the normalized Laplacian matrix | |
L = nx.normalized_laplacian_matrix(G) | |
eigenvalues = np.linalg.eigvals(L.toarray()) | |
# Print largest and smallest eigenvalues | |
st.write(f"Largest eigenvalue: {max(eigenvalues)}") | |
st.write(f"Smallest eigenvalue: {min(eigenvalues)}") | |
# Display the histogram of eigenvalues | |
st.write("### Eigenvalue Histogram") | |
plt.hist(eigenvalues, bins=100) | |
plt.xlim(0, 2) # Eigenvalues between 0 and 2 | |
st.pyplot(plt) | |
elif option == "Create your own": | |
# Allow the user to customize the number of nodes and edges | |
n_nodes = st.number_input("Number of nodes:", min_value=2, max_value=1000, value=100) | |
m_edges = st.number_input("Number of edges:", min_value=1, max_value=n_nodes*(n_nodes-1)//2, value=500) | |
if st.button("Generate"): | |
# Generate a random graph with the custom number of nodes and edges | |
G_custom = nx.gnm_random_graph(n_nodes, m_edges, seed=5040) # Seed for reproducibility | |
# Calculate the normalized Laplacian matrix | |
L = nx.normalized_laplacian_matrix(G_custom) | |
eigenvalues = np.linalg.eigvals(L.toarray()) | |
# Print largest and smallest eigenvalues | |
st.write(f"Largest eigenvalue: {max(eigenvalues)}") | |
st.write(f"Smallest eigenvalue: {min(eigenvalues)}") | |
# Display the histogram of eigenvalues | |
st.write("### Eigenvalue Histogram") | |
plt.hist(eigenvalues, bins=100) | |
plt.xlim(0, 2) # Eigenvalues between 0 and 2 | |
st.pyplot(plt) | |
# Display Drawing: Eigenvalues if selected | |
if sidebar_option == "Drawing: Eigenvalues": | |
display_eigenvalue_analysis() | |
# Function to display properties and graph for Basic: Properties | |
def display_graph_properties(G): | |
pathlengths = [] | |
st.write("### Source vertex {target:length, }") | |
for v in G.nodes(): | |
spl = dict(nx.single_source_shortest_path_length(G, v)) | |
st.write(f"Vertex {v}: {spl}") | |
for p in spl: | |
pathlengths.append(spl[p]) | |
avg_path_length = sum(pathlengths) / len(pathlengths) | |
st.write(f"### Average shortest path length: {avg_path_length}") | |
dist = {} | |
for p in pathlengths: | |
dist[p] = dist.get(p, 0) + 1 | |
st.write("### Length #paths") | |
for d in sorted(dist.keys()): | |
st.write(f"Length {d}: {dist[d]} paths") | |
st.write("### Properties") | |
st.write(f"Radius: {nx.radius(G)}") | |
st.write(f"Diameter: {nx.diameter(G)}") | |
st.write(f"Eccentricity: {nx.eccentricity(G)}") | |
st.write(f"Center: {nx.center(G)}") | |
st.write(f"Periphery: {nx.periphery(G)}") | |
st.write(f"Density: {nx.density(G)}") | |
# Visualize the graph | |
st.write("### Graph Visualization") | |
pos = nx.spring_layout(G, seed=3068) # Seed layout for reproducibility | |
draw_graph(G, pos) | |
# Function to display graph for Basic: Read and write graphs | |
def display_read_write_graph(G): | |
st.write("### Adjacency List:") | |
for line in nx.generate_adjlist(G): | |
st.write(line) | |
# Write the graph's edge list to a file | |
st.write("### Writing Edge List to 'grid.edgelist' file:") | |
nx.write_edgelist(G, path="grid.edgelist", delimiter=":") # Save edge list | |
st.write("Edge list written to 'grid.edgelist'") | |
# Read the graph from the edge list | |
st.write("### Reading Edge List from 'grid.edgelist' file:") | |
H = nx.read_edgelist(path="grid.edgelist", delimiter=":") | |
st.write("Edge list read into graph H") | |
# Visualize the graph | |
st.write("### Graph Visualization:") | |
pos = nx.spring_layout(H, seed=200) # Seed for reproducibility | |
draw_graph(H, pos) | |
# Function to display Simple Graphs for Basic: Simple graph | |
def display_simple_graph(G, pos=None): | |
options = { | |
"font_size": 36, | |
"node_size": 3000, | |
"node_color": "white", | |
"edgecolors": "black", | |
"linewidths": 5, | |
"width": 5, | |
} | |
# Draw the network | |
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") | |
st.pyplot(plt) | |
# Function to display Simple Directed Graphs for Basic: Simple graph Directed | |
def display_simple_directed_graph(G, pos=None): | |
options = { | |
"node_size": 500, | |
"node_color": "lightblue", | |
"arrowsize": 20, | |
"width": 2, | |
"edge_color": "gray", | |
} | |
# Draw the directed graph with the given positions and options | |
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") | |
st.pyplot(plt) | |
# Function to display Custom Node Position Graphs for Drawing: Custom Node Position | |
def display_custom_node_position(): | |
st.title("Drawing: Custom Node Position") | |
# Default example graph (path graph with custom node position) | |
G = nx.path_graph(20) | |
center_node = 5 | |
edge_nodes = set(G) - {center_node} | |
# Ensure 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 | |
# Draw the graph | |
draw_graph(G, pos) | |
# Function to display Cluster Layout for Drawing: Cluster Layout | |
def display_cluster_layout(): | |
st.title("Drawing: Cluster Layout") | |
G = nx.davis_southern_women_graph() # Example graph | |
communities = nx.community.greedy_modularity_communities(G) | |
# Compute positions for the node clusters as if they were themselves nodes in a supergraph using a larger scale factor | |
supergraph = nx.cycle_graph(len(communities)) | |
superpos = nx.spring_layout(G, scale=50, seed=429) | |
# Use the "supernode" positions as the center of each node cluster | |
centers = list(superpos.values()) | |
pos = {} | |
for center, comm in zip(centers, communities): | |
pos.update(nx.spring_layout(nx.subgraph(G, comm), center=center, seed=1430)) | |
# Nodes colored by cluster | |
for nodes, clr in zip(communities, ("tab:blue", "tab:orange", "tab:green")): | |
nx.draw_networkx_nodes(G, pos=pos, nodelist=nodes, node_color=clr, node_size=100) | |
nx.draw_networkx_edges(G, pos=pos) | |
plt.tight_layout() | |
st.pyplot(plt) | |
# Function to display Degree Analysis for Drawing: Degree Analysis | |
def display_degree_analysis(): | |
st.title("Drawing: Degree Analysis") | |
option = st.radio("Choose a graph type:", ("Default Example", "Create your own")) | |
if option == "Default Example": | |
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() | |
st.pyplot(fig) | |
elif option == "Create your own": | |
n_nodes = st.number_input("Number of nodes:", min_value=2, max_value=500, value=100) | |
p_edge = st.slider("Edge probability:", min_value=0.0, max_value=1.0, value=0.02) | |
if st.button("Generate"): | |
if n_nodes >= 2: | |
G_custom = nx.gnp_random_graph(n_nodes, p_edge, seed=10374196) | |
degree_sequence = sorted((d for n, d in G_custom.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_custom.subgraph(sorted(nx.connected_components(G_custom), 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() | |
st.pyplot(fig) | |
# Function to display Ego Graph for Drawing: Ego Graph | |
def display_ego_graph(): | |
st.title("Drawing: Ego Graph") | |
option = st.radio("Choose a graph type:", ("Default Example", "Create your own")) | |
if option == "Default Example": | |
# 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.tight_layout() | |
st.pyplot(plt) | |
elif option == "Create your own": | |
n_nodes = st.number_input("Number of nodes:", min_value=2, max_value=1000, value=100) | |
m_edges = st.number_input("Edges per node:", min_value=1, max_value=10, value=2) | |
if st.button("Generate"): | |
if n_nodes >= 2: | |
G_custom = nx.barabasi_albert_graph(n_nodes, m_edges, seed=20532) | |
# Find node with largest degree | |
node_and_degree = G_custom.degree() | |
(largest_hub, degree) = sorted(node_and_degree, key=itemgetter(1))[-1] | |
# Create ego graph of main hub | |
hub_ego = nx.ego_graph(G_custom, largest_hub) | |
# Draw graph | |
pos = nx.spring_layout(hub_ego, seed=20532) # 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.tight_layout() | |
st.pyplot(plt) | |
# Display Drawing: Ego Graph if selected | |
if sidebar_option == "Drawing: Ego Graph": | |
display_ego_graph() | |
# Display Basic: Properties if selected | |
elif sidebar_option == "Basic: Properties": | |
st.title("Basic: Properties") | |
option = st.radio("Choose a graph type:", ("Default Example", "Create your own")) | |
if option == "Default Example": | |
G = nx.lollipop_graph(4, 6) | |
display_graph_properties(G) | |
elif option == "Create your own": | |
num_nodes = st.number_input("Number of nodes:", min_value=2, max_value=50, value=5) | |
num_edges = st.number_input("Number of edges per group (for lollipop graph):", min_value=1, max_value=10, value=3) | |
if st.button("Generate"): | |
if num_nodes >= 2 and num_edges >= 1: | |
G_custom = nx.lollipop_graph(num_nodes, num_edges) | |
display_graph_properties(G_custom) | |
# Display Basic: Read and write graphs if selected | |
elif sidebar_option == "Basic: Read and write graphs": | |
st.title("Basic: Read and write graphs") | |
option = st.radio("Choose a graph type:", ("Default Example", "Create your own")) | |
if option == "Default Example": | |
G = nx.grid_2d_graph(5, 5) | |
display_read_write_graph(G) | |
elif option == "Create your own": | |
rows = st.number_input("Number of rows:", min_value=2, max_value=20, value=5) | |
cols = st.number_input("Number of columns:", min_value=2, max_value=20, value=5) | |
if st.button("Generate"): | |
if rows >= 2 and cols >= 2: | |
G_custom = nx.grid_2d_graph(rows, cols) | |
display_read_write_graph(G_custom) | |
# Display Basic: Simple Graph if selected | |
elif sidebar_option == "Basic: Simple graph": | |
st.title("Basic: Simple graph") | |
option = st.radio("Choose a graph type:", ("Default Example", "Create your own")) | |
if option == "Default Example": | |
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) | |
pos = {1: (0, 0), 2: (-1, 0.3), 3: (2, 0.17), 4: (4, 0.255), 5: (5, 0.03)} | |
display_simple_graph(G, pos) | |
elif option == "Create your own": | |
edges = [] | |
edge_input = st.text_area("Edges:", value="1,2\n1,3\n2,3") | |
if edge_input: | |
edge_list = edge_input.split("\n") | |
for edge in edge_list: | |
u, v = map(int, edge.split(",")) | |
edges.append((u, v)) | |
if st.button("Generate"): | |
G_custom = nx.Graph() | |
G_custom.add_edges_from(edges) | |
pos = nx.spring_layout(G_custom, seed=42) | |
display_simple_graph(G_custom, pos) | |
# Display Basic: Simple Directed Graph if selected | |
elif sidebar_option == "Basic: Simple graph Directed": | |
st.title("Basic: Simple graph Directed") | |
option = st.radio("Choose a graph type:", ("Default Example", "Create your own")) | |
if option == "Default Example": | |
G = nx.DiGraph([(0, 3), (1, 3), (2, 4), (3, 5), (3, 6), (4, 6), (5, 6)]) | |
left_nodes = [0, 1, 2] | |
middle_nodes = [3, 4] | |
right_nodes = [5, 6] | |
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)}) | |
display_simple_directed_graph(G, pos) | |
elif option == "Create your own": | |
edges = [] | |
edge_input = st.text_area("Edges:", value="1,2\n1,3\n2,3") | |
if edge_input: | |
edge_list = edge_input.split("\n") | |
for edge in edge_list: | |
u, v = map(int, edge.split(",")) | |
edges.append((u, v)) | |
if st.button("Generate"): | |
G_custom = nx.DiGraph() | |
G_custom.add_edges_from(edges) | |
pos = nx.spring_layout(G_custom, seed=42) | |
display_simple_directed_graph(G_custom, pos) | |
# Display Drawing: Custom Node Position if selected | |
elif sidebar_option == "Drawing: Custom Node Position": | |
display_custom_node_position() | |
# Display Drawing: Cluster Layout if selected | |
elif sidebar_option == "Drawing: Cluster Layout": | |
display_cluster_layout() | |
# Display Drawing: Degree Analysis if selected | |
elif sidebar_option == "Drawing: Degree Analysis": | |
display_degree_analysis() | |