import streamlit as st import networkx as nx import plotly.graph_objects as go import string import random import heapq # generate the graph def generate_graph(): alphabet = list(string.ascii_uppercase) node_labels = alphabet + ['A' + letter for letter in alphabet[:22]] G = nx.Graph() G.add_nodes_from(node_labels) for _ in range(94): node1, node2 = random.sample(node_labels, 2) weight = random.randint(1, 10) G.add_edge(node1, node2, weight=weight) pos = {node: (random.uniform(-10, 10), random.uniform(-10, 10), random.uniform(-10, 10)) for node in node_labels} return G, pos # visualise the 3D graph def visualize_3d_graph_plotly(G, pos, path=None): edge_trace = [] path_edge_trace = [] node_x, node_y, node_z = [], [], [] node_text = [] for node in G.nodes(): x, y, z = pos[node] node_x.append(x) node_y.append(y) node_z.append(z) node_text.append(node) for edge in G.edges(): x0, y0, z0 = pos[edge[0]] x1, y1, z1 = pos[edge[1]] edge_trace.append(go.Scatter3d(x=[x0, x1], y=[y0, y1], z=[z0, z1], mode='lines', line=dict(color='gray', width=2))) if path: path_edges = list(zip(path, path[1:])) for edge in path_edges: x0, y0, z0 = pos[edge[0]] x1, y1, z1 = pos[edge[1]] path_edge_trace.append(go.Scatter3d(x=[x0, x1], y=[y0, y1], z=[z0, z1], mode='lines', line=dict(color='blue', width=4))) node_trace = go.Scatter3d(x=node_x, y=node_y, z=node_z, mode='markers+text', text=node_text, textposition='top center', marker=dict(size=8, color='skyblue'), hoverinfo='text') fig = go.Figure(data=edge_trace + path_edge_trace + [node_trace], layout=go.Layout(title='Use mouse to rotate & zoom on graph', showlegend=False, width=1000, height=800, scene=dict(xaxis=dict(showbackground=False), yaxis=dict(showbackground=False), zaxis=dict(showbackground=False)))) return fig # Dijkstra's Algorithm implementation def dijkstra_3d(graph, start, goal): queue = [(0, start)] distances = {node: float('inf') for node in graph.nodes} distances[start] = 0 previous_nodes = {node: None for node in graph.nodes} while queue: current_distance, current_node = heapq.heappop(queue) if current_node == goal: break for neighbor, attributes in graph[current_node].items(): weight = attributes['weight'] distance = current_distance + weight if distance < distances[neighbor]: distances[neighbor] = distance previous_nodes[neighbor] = current_node heapq.heappush(queue, (distance, neighbor)) path = [] current_node = goal while current_node is not None: path.insert(0, current_node) current_node = previous_nodes[current_node] return path, distances[goal] # Streamlit app def main(): st.title("3D Graph Dijkstra's Algorithm Demo") st.sidebar.header("Graph Options") G, pos = generate_graph() nodes = list(G.nodes) start_node = st.sidebar.selectbox("Select Start Point:", nodes) goal_node = st.sidebar.selectbox("Select Goal Point:", nodes) if st.sidebar.button("Run Algorithm"): shortest_path, shortest_distance = dijkstra_3d(G, start_node, goal_node) st.write(f"**Shortest path from {start_node} to {goal_node}:** {shortest_path}") st.write(f"**Shortest distance:** {shortest_distance}") fig = visualize_3d_graph_plotly(G, pos, path=shortest_path) else: fig = visualize_3d_graph_plotly(G, pos) st.plotly_chart(fig) if __name__ == "__main__": main()