| | 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 |
| | from matplotlib import animation |
| | from mpl_toolkits.mplot3d import Axes3D |
| | from streamlit.components.v1 import html |
| | import matplotlib.colors as mpl |
| | from PIL import Image |
| |
|
| | st.sidebar.markdown(""" |
| | ### Courtesy: [NetworkX](https://networkx.org/documentation/stable/index.html) |
| | """) |
| |
|
| | |
| | sidebar_option = st.sidebar.radio("Select Tutorial", |
| | ["Introductory Tutorial", "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", |
| | "Graph: DAG - Topological Layout", "Graph: Erdos Renyi", "Graph: Karate Club", "Graph: Minimum Spanning Tree", |
| | "Graph: Triads", "Algorithms: Cycle Detection", "Algorithms: Greedy Coloring"]) |
| |
|
| | |
| | st.sidebar.markdown(""" |
| | ## Contact |
| | |
| | For any questions or issues, please contact: |
| | |
| | - **Email**: [shukdevdatta@gmail.com](mailto:shukdevdatta@gmail.com) |
| | - **GitHub**: [Click here to access the Github Profile](https://github.com/shukdevtroy) |
| | - **WhatsApp**: [Click here to chat](https://wa.me/+8801719296601) |
| | - **HuggingFace Profile**: [Click here to access the HuggingFace Profile](https://huggingface.co/shukdevdatta123) |
| | """) |
| |
|
| | |
| | |
| | |
| | |
| |
|
| | |
| | if sidebar_option == "Introductory Tutorial": |
| | st.title("Graph Visualization and Analysis Options") |
| |
|
| | |
| | image = Image.open("1.png") |
| | st.image(image, width=400) |
| |
|
| | |
| | if st.button("Go to Sorting Simulator"): |
| | st.write("Redirecting to Sorting Simulator...") |
| | st.markdown(f'<a href="https://shukdevdatta123-sorting-visualization.hf.space" target="_blank">Go to Sorting Simulator</a>', unsafe_allow_html=True) |
| | |
| | |
| | descriptions = [ |
| | ("Basic: Properties", "This option provides insights into the foundational aspects of a graph. You can count nodes (individual points) and edges (connections between nodes). For example, in a graph representing a social network, the nodes could be people, and the edges could represent friendships. The degree distribution tells how many connections each node has, helping identify influential nodes."), |
| | ("Basic: Read and Write Graphs", "This feature lets you load graphs from files or save your current graph for later use. For instance, if you have a graph stored in a GML file, you can load it and analyze it in your program. Similarly, you can save graphs as adjacency lists or edge lists for portability."), |
| | ("Basic: Simple Graph", "This generates simple, undirected graphs where edges don’t have a direction. For example, a graph showing roads between cities where travel is possible in both directions. You can create specific structures like a star graph (one central hub) or a cycle graph (nodes connected in a loop)."), |
| | ("Basic: Simple Graph Directed", "Directed graphs have edges with a direction. They are useful for workflows or dependencies. For example, in a project plan, a directed graph might show tasks with arrows indicating the order in which they need to be completed."), |
| | ("Drawing: Custom Node Position", "This feature allows you to manually set where each node appears on the graph. For example, in a family tree, you might want to position nodes to reflect generational hierarchies rather than relying on an automatic layout."), |
| | ("Drawing: Cluster Layout", "Nodes are grouped into clusters based on their connections. For instance, in a network of social media users, this could highlight friend groups. Each group would appear as a tight cluster in the visualization."), |
| | ("Drawing: Degree Analysis", "This visualizes the connections (or degree) of nodes. For example, in a transportation network, hubs like airports can be highlighted because they have the highest degree, representing more connections to other nodes."), |
| | ("Drawing: Ego Graph", "Focuses on a single node and its immediate connections. For instance, if you want to see all direct friends of a specific person on a social network, this feature isolates that person and their relationships."), |
| | ("Drawing: Eigenvalues", "Eigenvalues come from the graph’s Laplacian matrix and reveal structural properties. For example, in community detection, eigenvalues can help identify clusters or measure the connectivity of a graph."), |
| | ("Drawing: House With Colors", "Displays a basic house graph, a simple structure that resembles a house. For example, you could use it for teaching graph theory basics, with color-coded nodes and edges representing different parts of the structure."), |
| | ("Drawing: Labels and Colors", "This lets you customize the appearance of nodes and edges by adding labels or colors. For example, in a roadmap, cities (nodes) can be color-coded by region, and roads (edges) can have labels for distance."), |
| | ("Drawing: Multipartite Layout", "Creates multipartite graphs where nodes are divided into layers, and edges only connect nodes from different layers. For instance, in a university, one layer could represent professors and another students, with edges indicating which professor teaches which student."), |
| | ("Drawing: Node Colormap", "Applies color gradients to nodes based on their properties, like degree or centrality. For example, nodes in a social network can be shaded to show influence, with darker colors for highly connected individuals."), |
| | ("Drawing: Rainbow Coloring", "This colorful feature assigns different colors to edges, helping differentiate them. For example, in a circular graph, this can show the relative positions of connections, making it visually appealing."), |
| | ("Drawing: Random Geometric Graph", "Generates graphs where nodes are connected if they’re within a specific distance. For example, in a wireless sensor network, nodes represent sensors, and edges show connectivity based on signal range."), |
| | ("Drawing: Self-loops", "Visualizes edges that start and end at the same node. For example, in a citation network, a self-loop could represent a researcher citing their previous work."), |
| | ("Drawing: Simple Path", "Displays simple linear graphs where nodes connect in a sequence. For example, it could represent a production line where each step depends on the previous one."), |
| | ("Drawing: Spectral Embedding", "Uses a mathematical technique to arrange nodes in a lower-dimensional space. For example, you can visualize clusters in a high-dimensional dataset in a way that preserves their relationships."), |
| | ("Drawing: Traveling Salesman Problem", "Visualizes solutions to the Traveling Salesman Problem (TSP), where the goal is to find the shortest route visiting every node once. For example, a delivery route optimization can use this to minimize travel costs."), |
| | ("Drawing: Weighted Graph", "Shows graphs with weighted edges. For example, in a flight network, edge weights can represent ticket prices or distances, with thicker edges for higher weights."), |
| | ("3D Drawing: Animations of 3D Rotation", "Generates 3D graphs with rotation animations. For example, you can visualize molecule structures or spatial relationships dynamically."), |
| | ("3D Drawing: Basic Matplotlib", "Creates 3D graph visualizations using Matplotlib, letting you explore spatial relationships. For example, you could map a city’s buildings in 3D space."), |
| | ("Graph: DAG - Topological Layout", "Displays Directed Acyclic Graphs (DAGs) in a topological order. For example, it can represent workflows or dependency graphs where tasks need to follow a sequence."), |
| | ("Graph: Erdos Renyi", "Generates random graphs where edges appear based on a probability. For example, you can model random connections in a network to study statistical properties."), |
| | ("Graph: Karate Club", "This graph is a classic benchmark in network science, showing relationships in a club. It’s often used for community detection and teaching graph analysis."), |
| | ("Graph: Minimum Spanning Tree", "Extracts a tree from the graph connecting all nodes with the minimum total edge weight. For example, this is used in network design to minimize cable or pipeline costs."), |
| | ("Graph: Triads", "Analyzes three-node structures (triads). For example, in social networks, closed triads (triangles) indicate strong relationships among three people."), |
| | ("Algorithms: Cycle Detection", "Detects cycles in graphs, useful for spotting feedback loops or circular dependencies. For example, in a dependency graph, it can help identify tasks that reference each other."), |
| | ("Algorithms: Greedy Coloring", "Colors nodes so that no two adjacent nodes share the same color. For example, in exam scheduling, this ensures no two overlapping exams are assigned the same room.") |
| | ] |
| | |
| | |
| | |
| | |
| | |
| |
|
| | |
| | for title, desc in descriptions: |
| | with st.expander(title): |
| | st.write(desc) |
| |
|
| | def plot_greedy_coloring(graph): |
| | |
| | graph_coloring = nx.greedy_color(graph) |
| | unique_colors = set(graph_coloring.values()) |
| |
|
| | |
| | graph_color_to_mpl_color = dict(zip(unique_colors, mpl.TABLEAU_COLORS)) |
| | node_colors = [graph_color_to_mpl_color[graph_coloring[n]] for n in graph.nodes()] |
| |
|
| | |
| | pos = nx.spring_layout(graph, seed=14) |
| |
|
| | |
| | nx.draw( |
| | graph, |
| | pos, |
| | with_labels=True, |
| | node_size=500, |
| | node_color=node_colors, |
| | edge_color="grey", |
| | font_size=12, |
| | font_color="#333333", |
| | width=2, |
| | ) |
| |
|
| | plt.title("Greedy Coloring of Graph") |
| | st.pyplot(plt) |
| |
|
| | def algorithms_greedy_coloring(): |
| | st.title("Algorithms: Greedy Coloring") |
| |
|
| | |
| | graph_mode = st.radio( |
| | "Choose a Mode:", |
| | ("Default Example", "Create Your Own"), |
| | help="The default example shows a predefined graph, or you can create your own." |
| | ) |
| |
|
| | if graph_mode == "Default Example": |
| | |
| | G = nx.dodecahedral_graph() |
| | st.write("Default Graph: Dodecahedral Graph with Greedy Coloring.") |
| | plot_greedy_coloring(G) |
| |
|
| | elif graph_mode == "Create Your Own": |
| | st.write("### Create Your Own Graph") |
| |
|
| | |
| | nodes_input = st.text_area("Enter nodes (e.g., 1, 2, 3, 4):") |
| | edges_input = st.text_area("Enter edges (e.g., (1, 2), (2, 3), (3, 4)):").strip() |
| |
|
| | if st.button("Generate Graph"): |
| | if nodes_input and edges_input: |
| | try: |
| | |
| | nodes = [node.strip() for node in nodes_input.split(",") if node.strip()] |
| | nodes = list(map(int, nodes)) |
| |
|
| | |
| | edges = [edge.strip() for edge in edges_input.split("),") if edge.strip()] |
| | edges = [tuple(map(int, edge.strip("()").split(","))) for edge in edges] |
| |
|
| | G = nx.Graph() |
| | G.add_nodes_from(nodes) |
| | G.add_edges_from(edges) |
| |
|
| | st.write("Custom Graph:", G.edges()) |
| | plot_greedy_coloring(G) |
| |
|
| | except Exception as e: |
| | st.error(f"Error creating the graph: {e}") |
| | else: |
| | st.error("Please enter valid nodes and edges.") |
| |
|
| | if sidebar_option == "Algorithms: Greedy Coloring": |
| | algorithms_greedy_coloring() |
| |
|
| | |
| | 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) |
| |
|
| | def plot_cycle_detection(graph): |
| | |
| | pos = nx.spring_layout(graph, seed=8020) |
| | nx.draw(graph, pos, with_labels=True, node_size=2000, node_color="lightblue") |
| |
|
| | |
| | try: |
| | cycles = list(nx.simple_cycles(graph)) |
| | if cycles: |
| | st.write("Cycles Detected:") |
| | for cycle in cycles: |
| | st.write(cycle) |
| |
|
| | |
| | for cycle in cycles: |
| | edges_in_cycle = [(cycle[i], cycle[i + 1] if i + 1 < len(cycle) else cycle[0]) for i in range(len(cycle))] |
| | nx.draw_networkx_edges(graph, pos, edgelist=edges_in_cycle, edge_color="r", width=2) |
| | else: |
| | st.write("No cycles detected") |
| |
|
| | except Exception as e: |
| | st.error(f"Error detecting cycles: {e}") |
| |
|
| | |
| | plt.title("Cycle Detection in Directed Graph") |
| | st.pyplot(plt) |
| |
|
| | def algorithms_cycle_detection(): |
| | st.title("Algorithms: Cycle Detection") |
| |
|
| | |
| | graph_mode = st.radio( |
| | "Choose a Mode:", |
| | ("Default Example", "Create Your Own"), |
| | help="The default example shows a predefined graph, or you can create your own." |
| | ) |
| |
|
| | if graph_mode == "Default Example": |
| | |
| | G = nx.DiGraph([(1, 2), (2, 3), (3, 4), (4, 2)]) |
| | st.write("Default Graph: A simple directed graph with multiple cycles.") |
| | plot_cycle_detection(G) |
| |
|
| | elif graph_mode == "Create Your Own": |
| | st.write("### Create Your Own Graph") |
| |
|
| | |
| | edges_input = st.text_area("Enter directed edges (e.g., (1, 2), (2, 3), (3, 1), (3, 4)):").strip() |
| |
|
| | if st.button("Generate Graph"): |
| | if edges_input: |
| | try: |
| | edges = [] |
| | |
| | edge_strings = edges_input.split("),") |
| | for edge_str in edge_strings: |
| | edge_str = edge_str.strip() |
| | if edge_str: |
| | |
| | if edge_str[-1] != ")": |
| | edge_str += ")" |
| | |
| | edge_tuple = edge_str.strip("()").split(",") |
| | if len(edge_tuple) == 2: |
| | try: |
| | |
| | edge_tuple = tuple(map(int, edge_tuple)) |
| | edges.append(edge_tuple) |
| | except ValueError: |
| | st.error(f"Invalid edge format: {edge_str}") |
| | return |
| |
|
| | if edges: |
| | |
| | G = nx.DiGraph(edges) |
| | st.write("Custom Graph:", G.edges()) |
| | plot_cycle_detection(G) |
| | else: |
| | st.error("No valid edges provided.") |
| | except Exception as e: |
| | st.error(f"Error creating the graph: {e}") |
| | else: |
| | st.error("Please enter valid directed edges.") |
| |
|
| | |
| | if sidebar_option == "Algorithms: Cycle Detection": |
| | algorithms_cycle_detection() |
| |
|
| | def triads_graph(): |
| | st.title("Graph: Triads") |
| |
|
| | |
| | graph_mode = st.radio( |
| | "Choose a Mode:", |
| | ("Default Example", "Create Your Own"), |
| | help="Default example shows predefined triads, or you can create your own triads." |
| | ) |
| |
|
| | if graph_mode == "Default Example": |
| | |
| | triads = { |
| | "003": [], |
| | "012": [(1, 2)], |
| | "102": [(1, 2), (2, 1)], |
| | "021D": [(3, 1), (3, 2)], |
| | "021U": [(1, 3), (2, 3)], |
| | "021C": [(1, 3), (3, 2)], |
| | "111D": [(1, 2), (2, 1), (3, 1)], |
| | "111U": [(1, 2), (2, 1), (1, 3)], |
| | "030T": [(1, 2), (3, 2), (1, 3)], |
| | "030C": [(1, 3), (3, 2), (2, 1)], |
| | "201": [(1, 2), (2, 1), (3, 1), (1, 3)], |
| | "120D": [(1, 2), (2, 1), (3, 1), (3, 2)], |
| | "120U": [(1, 2), (2, 1), (1, 3), (2, 3)], |
| | "120C": [(1, 2), (2, 1), (1, 3), (3, 2)], |
| | "210": [(1, 2), (2, 1), (1, 3), (3, 2), (2, 3)], |
| | "300": [(1, 2), (2, 1), (2, 3), (3, 2), (1, 3), (3, 1)], |
| | } |
| |
|
| | fig, axes = plt.subplots(4, 4, figsize=(10, 10)) |
| |
|
| | for (title, triad), ax in zip(triads.items(), axes.flatten()): |
| | G = nx.DiGraph() |
| | G.add_nodes_from([1, 2, 3]) |
| | G.add_edges_from(triad) |
| | nx.draw_networkx( |
| | G, |
| | ax=ax, |
| | with_labels=True, |
| | node_color=["green"], |
| | node_size=200, |
| | arrowsize=20, |
| | width=2, |
| | pos=nx.planar_layout(G), |
| | ) |
| | ax.set_xlim(val * 1.2 for val in ax.get_xlim()) |
| | ax.set_ylim(val * 1.2 for val in ax.get_ylim()) |
| | ax.text( |
| | 0, |
| | 0, |
| | title, |
| | fontsize=15, |
| | fontweight="extra bold", |
| | horizontalalignment="center", |
| | bbox={"boxstyle": "square,pad=0.3", "fc": "none"}, |
| | ) |
| | fig.tight_layout() |
| | st.pyplot(fig) |
| |
|
| | elif graph_mode == "Create Your Own": |
| | st.write("### Create Your Own Triads") |
| |
|
| | |
| | triad_input = st.text_area( |
| | "Enter your triads in the format: {'triad_name': [(edge1), (edge2), ...]}", |
| | value="{'003': [], '012': [(1, 2)]}" |
| | ) |
| |
|
| | |
| | if st.button("Generate Graph"): |
| | |
| | try: |
| | custom_triads = eval(triad_input) |
| | if isinstance(custom_triads, dict) and all(isinstance(value, list) and all(isinstance(edge, tuple) and len(edge) == 2 for edge in value) for value in custom_triads.values()): |
| | fig, axes = plt.subplots(len(custom_triads), 1, figsize=(10, len(custom_triads) * 5)) |
| | if len(custom_triads) == 1: |
| | axes = [axes] |
| |
|
| | for (title, triad), ax in zip(custom_triads.items(), axes): |
| | G = nx.DiGraph() |
| | G.add_nodes_from([1, 2, 3]) |
| | G.add_edges_from(triad) |
| |
|
| | nx.draw_networkx( |
| | G, |
| | ax=ax, |
| | with_labels=True, |
| | node_color=["green"], |
| | node_size=200, |
| | arrowsize=20, |
| | width=2, |
| | pos=nx.planar_layout(G), |
| | ) |
| | ax.set_xlim(val * 1.2 for val in ax.get_xlim()) |
| | ax.set_ylim(val * 1.2 for val in ax.get_ylim()) |
| | ax.text( |
| | 0, |
| | 0, |
| | title, |
| | fontsize=15, |
| | fontweight="extra bold", |
| | horizontalalignment="center", |
| | bbox={"boxstyle": "square,pad=0.3", "fc": "none"}, |
| | ) |
| | fig.tight_layout() |
| | st.pyplot(fig) |
| | else: |
| | st.error("Invalid format. Please enter a dictionary of triads in the format {'triad_name': [(edge1), (edge2), ...]}.") |
| | except Exception as e: |
| | st.error(f"Error parsing input: {e}") |
| |
|
| | |
| | if sidebar_option == "Graph: Triads": |
| | triads_graph() |
| |
|
| | def minimum_spanning_tree_graph(): |
| | st.title("Graph: Minimum Spanning Tree") |
| |
|
| | |
| | graph_mode = st.radio( |
| | "Choose a Mode:", |
| | ("Default Example", "Create Your Own"), |
| | help="Default example shows a graph and its minimum spanning tree, or you can create your own graph." |
| | ) |
| |
|
| | if graph_mode == "Default Example": |
| | |
| | G = nx.Graph() |
| | G.add_edges_from( |
| | [ |
| | (0, 1, {"weight": 4}), |
| | (0, 7, {"weight": 8}), |
| | (1, 7, {"weight": 11}), |
| | (1, 2, {"weight": 8}), |
| | (2, 8, {"weight": 2}), |
| | (2, 5, {"weight": 4}), |
| | (2, 3, {"weight": 7}), |
| | (3, 4, {"weight": 9}), |
| | (3, 5, {"weight": 14}), |
| | (4, 5, {"weight": 10}), |
| | (5, 6, {"weight": 2}), |
| | (6, 8, {"weight": 6}), |
| | (7, 8, {"weight": 7}), |
| | ] |
| | ) |
| |
|
| | |
| | T = nx.minimum_spanning_tree(G) |
| |
|
| | |
| | pos = nx.spring_layout(G) |
| | fig, ax = plt.subplots(figsize=(8, 8)) |
| | nx.draw_networkx_nodes(G, pos, node_color="lightblue", node_size=500, ax=ax) |
| | nx.draw_networkx_edges(G, pos, edge_color="grey", ax=ax) |
| | nx.draw_networkx_labels(G, pos, font_size=12, font_family="sans-serif", ax=ax) |
| | nx.draw_networkx_edge_labels( |
| | G, pos, edge_labels={(u, v): d["weight"] for u, v, d in G.edges(data=True)}, ax=ax |
| | ) |
| | nx.draw_networkx_edges(T, pos, edge_color="green", width=2, ax=ax) |
| | ax.set_title("Graph and Minimum Spanning Tree") |
| | plt.axis("off") |
| | st.pyplot(fig) |
| |
|
| | elif graph_mode == "Create Your Own": |
| | st.write("### Create Your Own Graph") |
| |
|
| | |
| | num_nodes = st.number_input("Number of nodes", min_value=2, value=5) |
| | num_edges = st.number_input("Number of edges", min_value=1, value=6) |
| |
|
| | |
| | G = nx.Graph() |
| |
|
| | |
| | edges = [] |
| | for i in range(num_edges): |
| | source = st.number_input(f"Source node for edge {i+1}", min_value=0, max_value=num_nodes-1, key=f"source_{i}") |
| | dest = st.number_input(f"Destination node for edge {i+1}", min_value=0, max_value=num_nodes-1, key=f"dest_{i}") |
| | weight = st.number_input(f"Weight for edge ({source}, {dest})", min_value=1, value=1, key=f"weight_{i}") |
| | edges.append((source, dest, {"weight": weight})) |
| |
|
| | |
| | G.add_edges_from(edges) |
| |
|
| | |
| | G.add_nodes_from(range(num_nodes)) |
| |
|
| | |
| | if st.button("Generate Graph"): |
| | |
| | T = nx.minimum_spanning_tree(G) |
| |
|
| | |
| | pos = nx.spring_layout(G) |
| | fig, ax = plt.subplots(figsize=(8, 8)) |
| | nx.draw_networkx_nodes(G, pos, node_color="lightblue", node_size=500, ax=ax) |
| | nx.draw_networkx_edges(G, pos, edge_color="grey", ax=ax) |
| | nx.draw_networkx_labels(G, pos, font_size=12, font_family="sans-serif", ax=ax) |
| | nx.draw_networkx_edge_labels( |
| | G, pos, edge_labels={(u, v): d["weight"] for u, v, d in G.edges(data=True)}, ax=ax |
| | ) |
| | nx.draw_networkx_edges(T, pos, edge_color="green", width=2, ax=ax) |
| | ax.set_title("Custom Graph and Minimum Spanning Tree") |
| | plt.axis("off") |
| | st.pyplot(fig) |
| |
|
| | |
| | if sidebar_option == "Graph: Minimum Spanning Tree": |
| | minimum_spanning_tree_graph() |
| |
|
| | def karate_club_graph(): |
| | st.title("Graph: Karate Club") |
| |
|
| | |
| | graph_mode = st.radio( |
| | "Choose a Mode:", |
| | ("Default Example", "Create Your Own"), |
| | help="Default example shows the Karate Club graph, or you can create your own graph." |
| | ) |
| |
|
| | if graph_mode == "Default Example": |
| | |
| | G = nx.karate_club_graph() |
| |
|
| | |
| | st.write("### Node Degree") |
| | for v in G: |
| | st.write(f"Node {v:4}: Degree = {G.degree(v)}") |
| |
|
| | |
| | st.write("### Graph Visualization") |
| | fig, ax = plt.subplots() |
| | nx.draw_circular(G, with_labels=True, ax=ax, node_color="skyblue", edge_color="gray") |
| | ax.set_title("Karate Club Graph") |
| | st.pyplot(fig) |
| |
|
| | elif graph_mode == "Create Your Own": |
| | st.write("### Create Your Own Graph") |
| |
|
| | |
| | num_nodes = st.number_input("Number of nodes", min_value=2, value=10) |
| | num_edges = st.number_input("Number of edges", min_value=1, value=15) |
| | seed = st.number_input("Seed for Random Graph (optional)", value=20160) |
| |
|
| | |
| | if st.button("Generate Graph"): |
| | |
| | G = nx.gnm_random_graph(num_nodes, num_edges, seed=seed) |
| |
|
| | |
| | st.write("### Node Degree") |
| | for v in G: |
| | st.write(f"Node {v:4}: Degree = {G.degree(v)}") |
| |
|
| | |
| | st.write("### Graph Visualization") |
| | fig, ax = plt.subplots() |
| | nx.draw_circular(G, with_labels=True, ax=ax, node_color="lightgreen", edge_color="gray") |
| | ax.set_title("Custom Graph") |
| | st.pyplot(fig) |
| |
|
| | |
| | if sidebar_option == "Graph: Karate Club": |
| | karate_club_graph() |
| |
|
| | def erdos_renyi_graph(): |
| | st.title("Graph: Erdos Renyi") |
| |
|
| | |
| | graph_mode = st.radio( |
| | "Choose a Mode:", |
| | ("Default Example", "Create Your Own"), |
| | help="Default example shows a random graph, or you can create your own Erdos-Renyi graph." |
| | ) |
| |
|
| | if graph_mode == "Default Example": |
| | |
| | n = 10 |
| | m = 20 |
| | seed = 20160 |
| |
|
| | |
| | if st.button("Generate Graph"): |
| | |
| | G = nx.gnm_random_graph(n, m, seed=seed) |
| |
|
| | |
| | st.write("### Node Degree and Clustering Coefficient") |
| | for v in nx.nodes(G): |
| | st.write(f"Node {v}: Degree = {nx.degree(G, v)}, Clustering Coefficient = {nx.clustering(G, v)}") |
| |
|
| | |
| | st.write("### Adjacency List") |
| | adj_list = "\n".join([line for line in nx.generate_adjlist(G)]) |
| | st.text(adj_list) |
| |
|
| | |
| | pos = nx.spring_layout(G, seed=seed) |
| | fig, ax = plt.subplots() |
| | nx.draw(G, pos=pos, ax=ax, with_labels=True, node_color="skyblue", edge_color="gray") |
| | ax.set_title("Erdos-Renyi Random Graph") |
| | st.pyplot(fig) |
| |
|
| | elif graph_mode == "Create Your Own": |
| | st.write("### Create Your Own Random Erdos-Renyi Graph") |
| |
|
| | |
| | n = st.number_input("Number of nodes (n)", min_value=2, value=10) |
| | m = st.number_input("Number of edges (m)", min_value=1, value=20) |
| |
|
| | seed = st.number_input("Seed", value=20160) |
| |
|
| | |
| | if st.button("Generate Graph"): |
| | |
| | G = nx.gnm_random_graph(n, m, seed=seed) |
| |
|
| | |
| | st.write("### Node Degree and Clustering Coefficient") |
| | for v in nx.nodes(G): |
| | st.write(f"Node {v}: Degree = {nx.degree(G, v)}, Clustering Coefficient = {nx.clustering(G, v)}") |
| |
|
| | |
| | st.write("### Adjacency List") |
| | adj_list = "\n".join([line for line in nx.generate_adjlist(G)]) |
| | st.text(adj_list) |
| |
|
| | |
| | pos = nx.spring_layout(G, seed=seed) |
| | fig, ax = plt.subplots() |
| | nx.draw(G, pos=pos, ax=ax, with_labels=True, node_color="skyblue", edge_color="gray") |
| | ax.set_title("Erdos-Renyi Random Graph") |
| | st.pyplot(fig) |
| |
|
| | |
| | if sidebar_option == "Graph: Erdos Renyi": |
| | erdos_renyi_graph() |
| |
|
| | def dag_topological_layout(): |
| | st.title("Graph: DAG - Topological Layout") |
| |
|
| | |
| | graph_mode = st.radio( |
| | "Choose a Mode:", |
| | ("Default Example", "Create Your Own"), |
| | help="Default example shows DAG layout in topological order, or you can create your own DAG." |
| | ) |
| |
|
| | if graph_mode == "Default Example": |
| | |
| | G = nx.DiGraph( |
| | [ |
| | ("f", "a"), |
| | ("a", "b"), |
| | ("a", "e"), |
| | ("b", "c"), |
| | ("b", "d"), |
| | ("d", "e"), |
| | ("f", "c"), |
| | ("f", "g"), |
| | ("h", "f"), |
| | ] |
| | ) |
| |
|
| | |
| | for layer, nodes in enumerate(nx.topological_generations(G)): |
| | for node in nodes: |
| | G.nodes[node]["layer"] = layer |
| |
|
| | |
| | pos = nx.multipartite_layout(G, subset_key="layer") |
| |
|
| | |
| | fig, ax = plt.subplots() |
| | nx.draw_networkx(G, pos=pos, ax=ax) |
| | ax.set_title("DAG layout in topological order") |
| | fig.tight_layout() |
| | st.pyplot(fig) |
| |
|
| | elif graph_mode == "Create Your Own": |
| | st.write("### Custom DAG Creation") |
| |
|
| | |
| | num_nodes = st.number_input("Enter the number of nodes", min_value=2, value=5) |
| |
|
| | |
| | nodes = [str(i) for i in range(num_nodes)] |
| |
|
| | st.write(f"### Nodes: {nodes}") |
| | st.write("#### Add Edges between Nodes") |
| |
|
| | |
| | edges = [] |
| | for i in range(num_nodes): |
| | for j in range(i + 1, num_nodes): |
| | edge = (nodes[i], nodes[j]) |
| | if st.checkbox(f"Add edge from {edge[0]} to {edge[1]}", value=False): |
| | edges.append(edge) |
| |
|
| | |
| | G_custom = nx.DiGraph() |
| | G_custom.add_edges_from(edges) |
| |
|
| | |
| | for layer, nodes in enumerate(nx.topological_generations(G_custom)): |
| | for node in nodes: |
| | G_custom.nodes[node]["layer"] = layer |
| |
|
| | |
| | pos_custom = nx.multipartite_layout(G_custom, subset_key="layer") |
| |
|
| | |
| | fig_custom, ax_custom = plt.subplots() |
| | nx.draw_networkx(G_custom, pos=pos_custom, ax=ax_custom) |
| | ax_custom.set_title("Custom DAG layout in topological order") |
| | fig_custom.tight_layout() |
| | st.pyplot(fig_custom) |
| |
|
| | |
| | if sidebar_option == "Graph: DAG - Topological Layout": |
| | dag_topological_layout() |
| |
|
| | if sidebar_option == "3D Drawing: Animations of 3D Rotation": |
| | st.title("3D Drawing: Animations of 3D Rotation") |
| |
|
| | |
| | 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." |
| | ) |
| |
|
| | |
| | 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 |
| |
|
| | |
| | if graph_mode == "Default Example": |
| | G = nx.dodecahedral_graph() |
| | pos = nx.spectral_layout(G, dim=3) |
| | ani = generate_animation(G, pos) |
| |
|
| | |
| | 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) |
| | |
| | |
| | G = nx.erdos_renyi_graph(num_nodes, edge_prob) |
| | pos = nx.spectral_layout(G, dim=3) |
| | ani = generate_animation(G, pos) |
| |
|
| | |
| | with st.spinner("Rendering animation..."): |
| | ani.save("animation.gif", writer="imagemagick") |
| | st.image("animation.gif", caption="3D Graph Rotation", use_container_width=True) |
| |
|
| | |
| | def default_example(): |
| | G = nx.cycle_graph(20) |
| |
|
| | |
| | pos = nx.spring_layout(G, dim=3, seed=779) |
| | |
| | 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()]) |
| |
|
| | |
| | fig = plt.figure() |
| | ax = fig.add_subplot(111, projection="3d") |
| |
|
| | |
| | ax.scatter(*node_xyz.T, s=100, ec="w") |
| |
|
| | |
| | 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) |
| |
|
| | |
| | def create_own_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) |
| | |
| | |
| | generate_button = st.button("Generate Graph") |
| |
|
| | if generate_button: |
| | |
| | G = nx.cycle_graph(nodes) |
| | pos = nx.spring_layout(G, dim=3, seed=seed) |
| | |
| | |
| | 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()]) |
| |
|
| | |
| | fig = plt.figure() |
| | ax = fig.add_subplot(111, projection="3d") |
| |
|
| | |
| | ax.scatter(*node_xyz.T, s=100, ec="w") |
| |
|
| | |
| | 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") |
| |
|
| | |
| | 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." |
| | ) |
| |
|
| | |
| | if graph_mode == "Default Example": |
| | default_example() |
| | elif graph_mode == "Create Your Own": |
| | create_own_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": |
| | |
| | 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) |
| |
|
| | |
| | nx.draw_networkx_nodes(G, pos, node_size=700) |
| |
|
| | |
| | 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" |
| | ) |
| |
|
| | |
| | nx.draw_networkx_labels(G, pos, font_size=20, font_family="sans-serif") |
| | |
| | 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": |
| | |
| | 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" |
| | ) |
| |
|
| | |
| | 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()))) |
| |
|
| | |
| | generate_button = st.button("Generate Graph") |
| |
|
| | if generate_button: |
| | G_custom = nx.Graph() |
| |
|
| | |
| | for node1, node2, weight in edge_list: |
| | G_custom.add_edge(node1, node2, weight=weight) |
| |
|
| | |
| | pos = nx.spring_layout(G_custom, seed=7) |
| |
|
| | |
| | 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] |
| |
|
| | |
| | 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) |
| |
|
| | |
| | if sidebar_option == "Drawing: Weighted Graph": |
| | display_weighted_graph() |
| |
|
| | from networkx.algorithms.approximation import christofides |
| |
|
| | |
| | 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": |
| | |
| | G = nx.random_geometric_graph(20, radius=0.4, seed=3) |
| | pos = nx.get_node_attributes(G, "pos") |
| |
|
| | |
| | pos[0] = (0.5, 0.5) |
| |
|
| | H = G.copy() |
| |
|
| | |
| | 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 = christofides(G, weight="weight") |
| | edge_list = list(nx.utils.pairwise(cycle)) |
| |
|
| | |
| | nx.draw_networkx_edges(H, pos, edge_color="blue", width=0.5) |
| |
|
| | |
| | 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": |
| | |
| | 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) |
| |
|
| | |
| | generate_button = st.button("Generate Graph") |
| |
|
| | if generate_button: |
| | |
| | G_custom = nx.random_geometric_graph(num_nodes, radius, seed=3) |
| | pos = nx.get_node_attributes(G_custom, "pos") |
| |
|
| | |
| | pos[0] = (0.5, 0.5) |
| |
|
| | H = G_custom.copy() |
| |
|
| | |
| | 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) |
| |
|
| | |
| | cycle = christofides(G_custom, weight="weight") |
| | edge_list = list(nx.utils.pairwise(cycle)) |
| |
|
| | |
| | nx.draw_networkx_edges(H, pos, edge_color="blue", width=0.5) |
| |
|
| | |
| | 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) |
| |
|
| | |
| | if sidebar_option == "Drawing: Traveling Salesman Problem": |
| | display_tsp() |
| |
|
| | |
| | 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": |
| | |
| | options = {"node_color": "C0", "node_size": 100} |
| | G = nx.grid_2d_graph(6, 6) |
| |
|
| | fig, axs = plt.subplots(3, 3, figsize=(12, 12)) |
| | axs = axs.flatten() |
| |
|
| | for i in range(7): |
| | 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]) |
| |
|
| | |
| | for j in range(7, 9): |
| | fig.delaxes(axs[j]) |
| |
|
| | st.pyplot(fig) |
| |
|
| | elif option == "Create your own": |
| | |
| | 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) |
| |
|
| | |
| | all_edges = list(G_custom.edges()) |
| |
|
| | |
| | selected_edges_per_graph = [] |
| | for i in range(7): |
| | 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) |
| |
|
| | |
| | generate_button = st.button("Generate Graph") |
| |
|
| | if generate_button: |
| | fig, axs = plt.subplots(3, 3, figsize=(12, 12)) |
| | axs = axs.flatten() |
| |
|
| | |
| | for i in range(7): |
| | edges_to_remove = [tuple(eval(edge)) for edge in selected_edges_per_graph[i]] |
| |
|
| | |
| | G_custom_copy = G_custom.copy() |
| | G_custom_copy.remove_edges_from(edges_to_remove) |
| |
|
| | |
| | nx.draw_spectral(G_custom_copy, **{"node_color": "C0", "node_size": 100}, ax=axs[i]) |
| |
|
| | |
| | for j in range(7, 9): |
| | fig.delaxes(axs[j]) |
| |
|
| | st.pyplot(fig) |
| |
|
| | |
| | if sidebar_option == "Drawing: Spectral Embedding": |
| | display_spectral_embedding() |
| |
|
| | |
| | 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": |
| | |
| | G = nx.path_graph(8) |
| | pos = nx.spring_layout(G, seed=47) |
| |
|
| | |
| | nx.draw(G, pos=pos) |
| | st.pyplot(plt) |
| |
|
| | elif option == "Create your own": |
| | |
| | num_nodes = st.number_input("Number of nodes in the path:", min_value=2, max_value=50, value=8) |
| |
|
| | if st.button("Generate Graph"): |
| | |
| | G_custom = nx.path_graph(num_nodes) |
| | pos = nx.spring_layout(G_custom, seed=47) |
| |
|
| | |
| | nx.draw(G_custom, pos=pos) |
| | st.pyplot(plt) |
| |
|
| | |
| | if sidebar_option == "Drawing: Simple Path": |
| | display_simple_path() |
| |
|
| | |
| | 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": |
| | |
| | G = nx.complete_graph(3, create_using=nx.DiGraph) |
| | G.add_edge(0, 0) |
| | pos = nx.circular_layout(G) |
| |
|
| | |
| | nx.draw(G, pos, with_labels=True) |
| |
|
| | |
| | edgelist = [(1, 1), (2, 2)] |
| | G.add_edges_from(edgelist) |
| |
|
| | |
| | nx.draw_networkx_edges(G, pos, edgelist=edgelist, arrowstyle="<|-", style="dashed") |
| | st.pyplot(plt) |
| |
|
| | elif option == "Create your own": |
| | |
| | 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"): |
| | |
| | G = nx.complete_graph(num_nodes, create_using=nx.DiGraph) |
| | |
| | |
| | if add_self_loops: |
| | for node in G.nodes(): |
| | G.add_edge(node, node) |
| |
|
| | pos = nx.circular_layout(G) |
| | |
| | |
| | nx.draw(G, pos, with_labels=True) |
| |
|
| | |
| | edgelist = [(node, node) for node in G.nodes()] |
| | nx.draw_networkx_edges(G, pos, edgelist=edgelist, arrowstyle="<|-", style="dashed") |
| | st.pyplot(plt) |
| |
|
| | |
| | if sidebar_option == "Drawing: Self-loops": |
| | display_self_loops() |
| |
|
| | |
| | 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": |
| | |
| | G = nx.random_geometric_graph(200, 0.125, seed=896803) |
| | pos = nx.get_node_attributes(G, "pos") |
| |
|
| | |
| | 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 |
| |
|
| | |
| | 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": |
| | |
| | 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"): |
| | |
| | G = nx.random_geometric_graph(num_nodes, distance, seed=896803) |
| | pos = nx.get_node_attributes(G, "pos") |
| |
|
| | |
| | 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 |
| |
|
| | |
| | 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) |
| |
|
| | |
| | if sidebar_option == "Drawing: Random Geometric Graph": |
| | display_random_geometric_graph() |
| |
|
| | |
| | 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": |
| | |
| | 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) |
| | |
| | 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) |
| | |
| | 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) |
| | |
| | |
| | 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) |
| | |
| | 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) |
| | |
| | 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) |
| |
|
| | |
| | if sidebar_option == "Drawing: Rainbow Coloring": |
| | display_rainbow_coloring() |
| |
|
| | |
| | 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"): |
| | |
| | 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) |
| |
|
| | |
| | if sidebar_option == "Drawing: Node Colormap": |
| | display_node_colormap() |
| |
|
| | |
| | def multilayered_graph(*subset_sizes): |
| | G = nx.Graph() |
| | layers = len(subset_sizes) |
| | node_id = 0 |
| |
|
| | |
| | for i, size in enumerate(subset_sizes): |
| | for j in range(size): |
| | G.add_node(node_id, layer=i) |
| | node_id += 1 |
| |
|
| | |
| | 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 |
| |
|
| | |
| | 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" |
| | ] |
| | |
| | |
| | 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": |
| | |
| | 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(',') |
| |
|
| | |
| | if len(subset_sizes) != len(subset_colors): |
| | st.error("The number of colors should match the number of subsets.") |
| | else: |
| | |
| | if st.button("Generate 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) |
| |
|
| | |
| | if sidebar_option == "Drawing: Multipartite Layout": |
| | display_multipartite_layout() |
| |
|
| | |
| | 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": |
| | |
| | G = nx.cubical_graph() |
| | pos = nx.spring_layout(G, seed=3113794652) |
| |
|
| | |
| | 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) |
| |
|
| | |
| | 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", |
| | ) |
| |
|
| | |
| | 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": |
| | |
| | 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(',')] |
| |
|
| | |
| | node_color = st.color_picker("Pick a color for nodes:", "#FF6347") |
| | edge_color = st.color_picker("Pick a color for edges:", "#4682B4") |
| |
|
| | |
| | if st.button("Generate Graph"): |
| | |
| | G_custom = nx.Graph() |
| | G_custom.add_nodes_from(node_labels) |
| | G_custom.add_edges_from(edge_list) |
| |
|
| | |
| | pos_custom = nx.spring_layout(G_custom) |
| |
|
| | |
| | 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) |
| |
|
| | |
| | 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) |
| |
|
| | |
| | if sidebar_option == "Drawing: Labels And Colors": |
| | display_labels_and_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": |
| | |
| | G = nx.house_graph() |
| | pos = {0: (0, 0), 1: (1, 0), 2: (0, 1), 3: (1, 1), 4: (0.5, 2.0)} |
| |
|
| | |
| | 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) |
| | |
| | |
| | ax = plt.gca() |
| | ax.margins(0.11) |
| | plt.tight_layout() |
| | plt.axis("off") |
| | st.pyplot(plt) |
| |
|
| | elif option == "Create your own": |
| | |
| | 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) |
| |
|
| | |
| | wall_color = st.color_picker("Wall color:", "#0000FF") |
| | roof_color = st.color_picker("Roof color:", "#FFA500") |
| |
|
| | if st.button("Generate"): |
| | |
| | G_custom = nx.house_graph() |
| |
|
| | |
| | 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) |
| |
|
| | |
| | ax = plt.gca() |
| | ax.margins(0.11) |
| | plt.tight_layout() |
| | plt.axis("off") |
| | st.pyplot(plt) |
| |
|
| | |
| | if sidebar_option == "Drawing: House With Colors": |
| | display_house_with_colors() |
| |
|
| | |
| | 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": |
| | |
| | G = nx.grid_2d_graph(4, 4) |
| | pos = nx.spring_layout(G, iterations=100, seed=39775) |
| |
|
| | |
| | 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", |
| | edge_color="tab:gray", |
| | 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, |
| | ) |
| |
|
| | |
| | for a in ax: |
| | a.margins(0.10) |
| | fig.tight_layout() |
| | st.pyplot(fig) |
| |
|
| | elif option == "Create your own": |
| | |
| | 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"): |
| | |
| | G_custom = nx.grid_2d_graph(rows, cols) |
| | pos = nx.spring_layout(G_custom, iterations=100, seed=39775) |
| |
|
| | |
| | fig, all_axes = plt.subplots(2, 2) |
| | ax = all_axes.flat |
| |
|
| | |
| | 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", |
| | edge_color="tab:gray", |
| | 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, |
| | ) |
| |
|
| | |
| | for a in ax: |
| | a.margins(0.10) |
| | fig.tight_layout() |
| | st.pyplot(fig) |
| |
|
| | |
| | if sidebar_option == "Drawing: Four Grids": |
| | display_four_grids() |
| |
|
| | |
| | def display_eigenvalue_analysis(): |
| | st.title("Drawing: Eigenvalues") |
| |
|
| | option = st.radio("Choose a graph type:", ("Default Example", "Create your own")) |
| |
|
| | if option == "Default Example": |
| | |
| | n = 1000 |
| | m = 5000 |
| | G = nx.gnm_random_graph(n, m, seed=5040) |
| |
|
| | |
| | L = nx.normalized_laplacian_matrix(G) |
| | eigenvalues = np.linalg.eigvals(L.toarray()) |
| |
|
| | |
| | st.write(f"Largest eigenvalue: {max(eigenvalues)}") |
| | st.write(f"Smallest eigenvalue: {min(eigenvalues)}") |
| |
|
| | |
| | st.write("### Eigenvalue Histogram") |
| | plt.hist(eigenvalues, bins=100) |
| | plt.xlim(0, 2) |
| | 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("Number of edges:", min_value=1, max_value=n_nodes*(n_nodes-1)//2, value=500) |
| |
|
| | if st.button("Generate"): |
| | |
| | G_custom = nx.gnm_random_graph(n_nodes, m_edges, seed=5040) |
| |
|
| | |
| | L = nx.normalized_laplacian_matrix(G_custom) |
| | eigenvalues = np.linalg.eigvals(L.toarray()) |
| |
|
| | |
| | st.write(f"Largest eigenvalue: {max(eigenvalues)}") |
| | st.write(f"Smallest eigenvalue: {min(eigenvalues)}") |
| |
|
| | |
| | st.write("### Eigenvalue Histogram") |
| | plt.hist(eigenvalues, bins=100) |
| | plt.xlim(0, 2) |
| | st.pyplot(plt) |
| |
|
| | |
| | if sidebar_option == "Drawing: Eigenvalues": |
| | display_eigenvalue_analysis() |
| |
|
| | |
| | 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)}") |
| |
|
| | |
| | st.write("### Graph Visualization") |
| | pos = nx.spring_layout(G, seed=3068) |
| | draw_graph(G, pos) |
| |
|
| | |
| | def display_read_write_graph(G): |
| | st.write("### Adjacency List:") |
| | for line in nx.generate_adjlist(G): |
| | st.write(line) |
| | |
| | |
| | st.write("### Writing Edge List to 'grid.edgelist' file:") |
| | nx.write_edgelist(G, path="grid.edgelist", delimiter=":") |
| | st.write("Edge list written to 'grid.edgelist'") |
| |
|
| | |
| | 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") |
| |
|
| | |
| | st.write("### Graph Visualization:") |
| | pos = nx.spring_layout(H, seed=200) |
| | draw_graph(H, pos) |
| |
|
| | |
| | def display_simple_graph(G, pos=None): |
| | options = { |
| | "font_size": 36, |
| | "node_size": 3000, |
| | "node_color": "white", |
| | "edgecolors": "black", |
| | "linewidths": 5, |
| | "width": 5, |
| | } |
| | |
| | |
| | nx.draw_networkx(G, pos, **options) |
| |
|
| | |
| | ax = plt.gca() |
| | ax.margins(0.20) |
| | plt.axis("off") |
| | st.pyplot(plt) |
| |
|
| | |
| | def display_simple_directed_graph(G, pos=None): |
| | options = { |
| | "node_size": 500, |
| | "node_color": "lightblue", |
| | "arrowsize": 20, |
| | "width": 2, |
| | "edge_color": "gray", |
| | } |
| | |
| | |
| | nx.draw_networkx(G, pos, **options) |
| |
|
| | |
| | ax = plt.gca() |
| | ax.margins(0.20) |
| | plt.axis("off") |
| | st.pyplot(plt) |
| |
|
| | |
| | def display_custom_node_position(): |
| | st.title("Drawing: Custom Node Position") |
| | |
| | |
| | G = nx.path_graph(20) |
| | center_node = 5 |
| | edge_nodes = set(G) - {center_node} |
| | |
| | |
| | pos = nx.circular_layout(G.subgraph(edge_nodes)) |
| | pos[center_node] = np.array([0, 0]) |
| | |
| | |
| | draw_graph(G, pos) |
| |
|
| | |
| | def display_cluster_layout(): |
| | st.title("Drawing: Cluster Layout") |
| |
|
| | G = nx.davis_southern_women_graph() |
| | communities = nx.community.greedy_modularity_communities(G) |
| |
|
| | |
| | supergraph = nx.cycle_graph(len(communities)) |
| | superpos = nx.spring_layout(G, scale=50, seed=429) |
| |
|
| | |
| | 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)) |
| |
|
| | |
| | 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) |
| |
|
| | |
| | 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)) |
| | |
| | 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)) |
| | |
| | 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) |
| |
|
| | |
| | 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": |
| | |
| | n = 1000 |
| | m = 2 |
| | seed = 20532 |
| | G = nx.barabasi_albert_graph(n, m, seed=seed) |
| |
|
| | |
| | node_and_degree = G.degree() |
| | (largest_hub, degree) = sorted(node_and_degree, key=itemgetter(1))[-1] |
| |
|
| | |
| | hub_ego = nx.ego_graph(G, largest_hub) |
| |
|
| | |
| | pos = nx.spring_layout(hub_ego, seed=seed) |
| | nx.draw(hub_ego, pos, node_color="b", node_size=50, with_labels=False) |
| |
|
| | |
| | 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) |
| |
|
| | |
| | node_and_degree = G_custom.degree() |
| | (largest_hub, degree) = sorted(node_and_degree, key=itemgetter(1))[-1] |
| |
|
| | |
| | hub_ego = nx.ego_graph(G_custom, largest_hub) |
| |
|
| | |
| | pos = nx.spring_layout(hub_ego, seed=20532) |
| | nx.draw(hub_ego, pos, node_color="b", node_size=50, with_labels=False) |
| |
|
| | |
| | options = {"node_size": 300, "node_color": "r"} |
| | nx.draw_networkx_nodes(hub_ego, pos, nodelist=[largest_hub], **options) |
| | plt.tight_layout() |
| | st.pyplot(plt) |
| |
|
| | |
| | if sidebar_option == "Drawing: Ego Graph": |
| | display_ego_graph() |
| |
|
| | |
| | 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) |
| |
|
| | |
| | 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) |
| |
|
| | |
| | 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) |
| |
|
| | |
| | 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) |
| |
|
| | |
| | elif sidebar_option == "Drawing: Custom Node Position": |
| | display_custom_node_position() |
| |
|
| | |
| | elif sidebar_option == "Drawing: Cluster Layout": |
| | display_cluster_layout() |
| |
|
| | |
| | elif sidebar_option == "Drawing: Degree Analysis": |
| | display_degree_analysis() |
| |
|