shukdevdatta123's picture
Update app.py
dea80b0 verified
raw
history blame
17.5 kB
import streamlit as st
import matplotlib.pyplot as plt
import networkx as nx
import numpy as np
from operator import itemgetter
# 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"])
# 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)
# 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()