Skip to content

Commit

Permalink
Dijkstra visualizer added (#562)
Browse files Browse the repository at this point in the history
## Pull Request for PyVerse 💡

### Requesting to submit a pull request to the PyVerse repository.

---

#### Issue Title
**Please enter the title of the issue related to your pull request.**  
[Code Addition Request]: Dijkstra Algorithm Visualizer 

- [x] I have provided the issue title.

---

#### Info about the Related Issue
**What's the goal of the project?**  
This Python project provides a visual representation of Dijkstra's
algorithm on a graph. It allows users to input the number of nodes,
specify the nodes, input the edges with weights, and choose a starting
node. The script then visualizes the shortest distances and paths from
the chosen starting node using networkx and matplotlib.

- [x] I have described the aim of the project.

---

#### Name
**Please mention your name.**  
Anantesh G

- [x] I have provided my name.

---

#### GitHub ID
**Please mention your GitHub ID.**  
https://github.com/AnanteshG

- [x] I have provided my GitHub ID.

---

#### Email ID
**Please mention your email ID for further communication.**  
[email protected]

- [x] I have provided my email ID.

---

#### Identify Yourself
**Mention in which program you are contributing (e.g., WoB, GSSOC, SSOC,
SWOC).**
GSSoC, Hacktoberfest 

- [x] I have mentioned my participant role.

---

#### Closes
**Enter the issue number that will be closed through this PR.**  
*Closes: #531 

- [x] I have provided the issue number.

---

#### Describe the Add-ons or Changes You've Made
**Give a clear description of what you have added or modified.**  
Added Dijkstra Visualizer

- [x] I have described my changes.

---

#### Type of Change
**Select the type of change:**  
- [ ] Bug fix (non-breaking change which fixes an issue)
- [ ] New feature (non-breaking change which adds functionality)
- [ ] Code style update (formatting, local variables)
- [ ] Breaking change (fix or feature that would cause existing
functionality to not work as expected)
- [ ] This change requires a documentation update

---

#### How Has This Been Tested?
**Describe how your changes have been tested.**  
*Describe your testing process here.*

- [ ] I have described my testing process.

---

#### Checklist
**Please confirm the following:**  
- [x] My code follows the guidelines of this project.
- [x] I have performed a self-review of my own code.
- [x] I have commented my code, particularly wherever it was hard to
understand.
- [x] I have made corresponding changes to the documentation.
- [x] My changes generate no new warnings.
- [x] I have added things that prove my fix is effective or that my
feature works.
- [x] Any dependent changes have been merged and published in downstream
modules.
  • Loading branch information
UTSAVS26 authored Oct 16, 2024
2 parents e1e2d1e + d44fba1 commit b7ab872
Show file tree
Hide file tree
Showing 2 changed files with 116 additions and 0 deletions.
75 changes: 75 additions & 0 deletions Algorithms_and_Data_Structures/Dijkstra/main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import networkx as nx
import matplotlib.pyplot as plt

# function to create graph
def graph_create():
G = nx.Graph()
nodes_num = int(input("Enter the number of nodes: "))
for i in range(nodes_num):
nodes_name = input(f"Enter the name of node {i+1} : ")

edges = int(input("Enter the number of edges: "))
for i in range(edges):
edge_name = input(f"Enter edge {i+1} : (format: source, destination, value): ")
source, destination, weight = edge_name.split()
G.add_edge(source, destination, weight = int(weight))

return G

# dijkstra algorithm implementation
def dijkstra(graph, start):
distances = {node: float("inf") for node in graph.nodes} #dictionary to store shortest distances
distances[start] = 0
paths = {node: [] for node in graph.nodes} #dictionary to store shortest paths
visited = set()

while len(visited) < len(graph.nodes): #loop till all nodes are visited
not_visited = {node: distances[node] for node in graph.nodes if node not in visited} #dictionary contains distances of unvisited nodes
min_node = min(not_visited, key=not_visited.get) # to get node with minimum distance from start node
visited.add(min_node)

for neighbor, weight in graph[min_node].items():
# If the distance to the neighbor through the current node is less than the previously known shortest distance to the neighbor
if distances[min_node] + weight["weight"] < distances[neighbor]:
# Update the shortest distance and path to the neighbor
distances[neighbor] = distances[min_node] + weight["weight"]
paths[neighbor] = paths[min_node] + [min_node]

# After visiting all nodes, finalize the shortest paths by adding the destination node to each path

paths = {node: path + [node] for node, path in paths.items() if path}

return distances, paths

def visualise_dijkstra(graph, start):
if start not in graph.nodes:
print("Start node not found in graph")
return

distances, paths = dijkstra(graph, start)
pos = nx.spring_layout(graph)
plt.get_current_fig_manager().window.title("Dijkstra Algorithm Visualiser")
nx.draw(graph, pos, with_labels = True, node_color = "lightblue", edgecolors="black", node_size = 500, font_size = 15, font_weight = "bold")
labels = nx.get_edge_attributes(graph, "weight")
nx.draw_networkx_edge_labels(graph, pos, edge_labels = labels, font_size = 8)

plt.title("Dijkstra's Algorithm Visualisation")
print("Shortest distances from the start node:")
for node, distance in distances.items():
print(f"{node}: {distance}")

print("Shortest paths from the start node:")
for node, path in paths.items():
print(f"{node}: {' -> '.join(path)}")

plt.show()

if __name__ == "__main__":
user_graph = graph_create()
start_node = input("Enter the start node: ")
visualise_dijkstra(user_graph, start_node)





41 changes: 41 additions & 0 deletions Algorithms_and_Data_Structures/Dijkstra/test_main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import unittest
from main import dijkstra

class DijkstraTestCase(unittest.TestCase):
def test_shortest_path(self):
graph = {
'A': {'B': {'weight': 5}, 'C': {'weight': 3}},
'B': {'A': {'weight': 5}, 'C': {'weight': 2}, 'D': {'weight': 1}},
'C': {'A': {'weight': 3}, 'B': {'weight': 2}, 'D': {'weight': 4}, 'E': {'weight': 6}},
'D': {'B': {'weight': 1}, 'C': {'weight': 4}, 'E': {'weight': 2}},
'E': {'C': {'weight': 6}, 'D': {'weight': 2}}
}
start_node = 'A'
expected_distances = {'A': 0, 'B': 3, 'C': 3, 'D': 4, 'E': 6}
expected_paths = {'A': ['A'], 'B': ['A', 'B'], 'C': ['A', 'C'], 'D': ['A', 'B', 'D'], 'E': ['A', 'B', 'D', 'E']}

distances, paths = dijkstra(graph, start_node)

self.assertEqual(distances, expected_distances)
self.assertEqual(paths, expected_paths)

def test_disconnected_graph(self):
graph = {
'A': {'B': {'weight': 5}, 'C': {'weight': 3}},
'B': {'A': {'weight': 5}, 'C': {'weight': 2}, 'D': {'weight': 1}},
'C': {'A': {'weight': 3}, 'B': {'weight': 2}, 'D': {'weight': 4}, 'E': {'weight': 6}},
'D': {'B': {'weight': 1}, 'C': {'weight': 4}, 'E': {'weight': 2}},
'E': {'C': {'weight': 6}, 'D': {'weight': 2}},
'F': {} # Disconnected node
}
start_node = 'A'
expected_distances = {'A': 0, 'B': 3, 'C': 3, 'D': 4, 'E': 6}
expected_paths = {'A': ['A'], 'B': ['A', 'B'], 'C': ['A', 'C'], 'D': ['A', 'B', 'D'], 'E': ['A', 'B', 'D', 'E']}

distances, paths = dijkstra(graph, start_node)

self.assertEqual(distances, expected_distances)
self.assertEqual(paths, expected_paths)

if __name__ == '__main__':
unittest.main()

0 comments on commit b7ab872

Please sign in to comment.