Spaces:
Sleeping
Sleeping
import streamlit as st | |
import matplotlib.pyplot as plt | |
import networkx as nx | |
import numpy as np | |
# 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"]) | |
# 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 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") | |
option = st.radio("Choose a graph type:", ("Default Example", "Create your own")) | |
if option == "Default Example": | |
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) | |
elif option == "Create your own": | |
st.write("For custom graph creation, you can specify the number of nodes and edges.") | |
# Here you can add functionality for custom graph creation if required | |
# Display Basic: Properties if selected | |
if 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() | |