Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
@@ -3,98 +3,58 @@ import folium
|
|
3 |
import networkx as nx
|
4 |
from folium import Map, Marker, PolyLine
|
5 |
from math import radians, cos, sin, sqrt, atan2
|
6 |
-
import time
|
7 |
from branca.element import MacroElement
|
8 |
from jinja2 import Template
|
9 |
|
10 |
-
#
|
11 |
places = {
|
12 |
-
"Nyarugenge": (-1.9577, 30.0619),
|
13 |
-
"
|
14 |
-
"
|
15 |
-
"
|
16 |
-
"
|
17 |
-
"
|
18 |
-
"
|
19 |
-
"
|
20 |
-
"
|
21 |
-
"
|
22 |
-
"Kayonza": (-2.0000, 30.5667),
|
23 |
-
"Kirehe": (-2.3553, 30.7767),
|
24 |
-
"Ngoma": (-2.1600, 30.4700),
|
25 |
-
"Rwamagana": (-1.9491, 30.4349),
|
26 |
-
"Bugesera": (-2.2083, 30.2576),
|
27 |
-
"Kamonyi": (-2.0833, 29.9000),
|
28 |
-
"Muhanga": (-2.1200, 29.7561),
|
29 |
-
"Ruhango": (-2.2136, 29.7628),
|
30 |
-
"Nyamagabe": (-2.4978, 29.4897),
|
31 |
-
"Nyaruguru": (-2.5806, 29.4306),
|
32 |
-
"Huye": (-2.5921, 29.7408),
|
33 |
-
"Gisagara": (-2.6283, 29.6820),
|
34 |
-
"Nyanza": (-2.3566, 29.7507),
|
35 |
-
"Rutsiro": (-2.0986, 29.3269),
|
36 |
-
"Karongi": (-2.0667, 29.4677),
|
37 |
-
"Rubavu": (-1.7481, 29.2730),
|
38 |
-
"Rusizi": (-2.5406, 29.3737),
|
39 |
-
"Nyamasheke": (-2.4700, 29.3222),
|
40 |
-
"Ngororero": (-1.8733, 29.5811)
|
41 |
}
|
42 |
|
43 |
-
# Haversine function (
|
44 |
def haversine(coord1, coord2):
|
45 |
-
R = 6371
|
46 |
lat1, lon1 = coord1
|
47 |
lat2, lon2 = coord2
|
48 |
dlat = radians(lat2 - lat1)
|
49 |
dlon = radians(lon2 - lon1)
|
50 |
-
a = sin(dlat/2)**2 + cos(radians(lat1))*cos(radians(lat2))*sin(dlon/2)**2
|
51 |
-
c = 2 * atan2(sqrt(a), sqrt(1-a))
|
52 |
return R * c
|
53 |
|
54 |
-
#
|
55 |
-
G = nx.Graph()
|
56 |
edges = [
|
57 |
-
("Nyarugenge", "Gasabo"),
|
58 |
-
("
|
59 |
-
("
|
60 |
-
("Gakenke", "
|
61 |
-
("
|
62 |
-
("
|
63 |
-
("
|
64 |
-
("
|
65 |
-
("Bugesera", "
|
66 |
-
("Muhanga", "Ruhango"),
|
67 |
-
("Nyamagabe", "Nyaruguru"),
|
68 |
-
("Huye", "Gisagara"),
|
69 |
-
("Nyanza", "Ruhango"),
|
70 |
-
("Rutsiro", "Karongi"),
|
71 |
-
("Rubavu", "Rusizi"),
|
72 |
-
("Nyamasheke", "Ngororero"),
|
73 |
-
("Rulindo", "Gasabo"),
|
74 |
-
("Gicumbi", "Nyagatare"),
|
75 |
-
("Kicukiro", "Kamonyi"),
|
76 |
-
("Kamonyi", "Muhanga"),
|
77 |
-
("Ruhango", "Nyamagabe"),
|
78 |
-
("Karongi", "Rubavu"),
|
79 |
-
("Rusizi", "Nyamasheke"),
|
80 |
-
("Ngororero", "Rutsiro")
|
81 |
]
|
82 |
-
for edge in edges:
|
83 |
-
c1 = places[edge[0]]
|
84 |
-
c2 = places[edge[1]]
|
85 |
-
dist = haversine(c1, c2)
|
86 |
-
G.add_edge(edge[0], edge[1], weight=dist)
|
87 |
|
88 |
-
#
|
89 |
-
|
90 |
-
|
91 |
-
|
|
|
92 |
|
93 |
-
#
|
94 |
def heuristic(u, v):
|
95 |
return haversine(places[u], places[v])
|
96 |
|
97 |
-
# Folium animation
|
98 |
class AnimateMarker(MacroElement):
|
99 |
_template = Template("""
|
100 |
{% macro script(this, kwargs) %}
|
@@ -117,46 +77,41 @@ class AnimateMarker(MacroElement):
|
|
117 |
self._name = "AnimateMarker"
|
118 |
self.locations = locations
|
119 |
|
|
|
120 |
def generate_map(start, end):
|
121 |
-
if start is None or end is None:
|
122 |
-
return "Hitamo aho utangiriye n’aho ugiye neza.", ""
|
123 |
-
if start not in G.nodes or end not in G.nodes:
|
124 |
-
return "Hitamo aho utangiriye n’aho ugiye neza (ntiboneka mu rutonde).", ""
|
125 |
-
|
126 |
-
m = Map(location=[-2.0, 30.0], zoom_start=8)
|
127 |
-
for name, coord in places.items():
|
128 |
-
Marker(location=coord, popup=name).add_to(m)
|
129 |
-
|
130 |
if start == end:
|
131 |
-
return "Hitamo aho utangiriye n’aho ugiye bitandukanye.",
|
132 |
|
133 |
if not nx.has_path(G, start, end):
|
134 |
-
return f"Nta nzira ibaho hagati ya {start} na {end}.",
|
135 |
|
136 |
try:
|
137 |
path = nx.astar_path(G, start, end, heuristic=heuristic, weight='weight')
|
138 |
coords = [places[p] for p in path]
|
139 |
-
PolyLine(coords, color="blue", weight=5).add_to(m)
|
140 |
|
141 |
-
|
|
|
|
|
|
|
|
|
142 |
m.add_child(AnimateMarker(coords))
|
143 |
|
144 |
return "Inzira ngufi ni: " + " ➔ ".join(path), m._repr_html_()
|
145 |
except Exception as e:
|
146 |
-
return f"Ntibishoboka kubona inzira: {str(e)}",
|
147 |
|
|
|
148 |
iface = gr.Interface(
|
149 |
fn=generate_map,
|
150 |
inputs=[
|
151 |
-
gr.Dropdown(list(places.keys()), label="Hitamo aho uri"
|
152 |
-
gr.Dropdown(list(places.keys()), label="Hitamo aho ugiye"
|
153 |
],
|
154 |
outputs=[
|
155 |
gr.Textbox(label="Ubutumwa"),
|
156 |
gr.HTML(label="Ikarita")
|
157 |
],
|
158 |
-
title="🗺️ Rwanda Smart Route Planner
|
159 |
)
|
160 |
|
161 |
iface.launch()
|
162 |
-
|
|
|
3 |
import networkx as nx
|
4 |
from folium import Map, Marker, PolyLine
|
5 |
from math import radians, cos, sin, sqrt, atan2
|
|
|
6 |
from branca.element import MacroElement
|
7 |
from jinja2 import Template
|
8 |
|
9 |
+
# 1. Districts of Rwanda with coordinates
|
10 |
places = {
|
11 |
+
"Nyarugenge": (-1.9577, 30.0619), "Gasabo": (-1.9400, 30.0861), "Kicukiro": (-1.9781, 30.0597),
|
12 |
+
"Burera": (-1.4800, 29.7300), "Gakenke": (-1.5700, 29.7561), "Rulindo": (-1.8333, 30.0833),
|
13 |
+
"Musanze": (-1.5014, 29.6344), "Gicumbi": (-1.5794, 30.0542), "Nyagatare": (-1.3100, 30.3000),
|
14 |
+
"Gatsibo": (-1.6800, 30.3900), "Kayonza": (-2.0000, 30.5667), "Kirehe": (-2.3553, 30.7767),
|
15 |
+
"Ngoma": (-2.1600, 30.4700), "Rwamagana": (-1.9491, 30.4349), "Bugesera": (-2.2083, 30.2576),
|
16 |
+
"Kamonyi": (-2.0833, 29.9000), "Muhanga": (-2.1200, 29.7561), "Ruhango": (-2.2136, 29.7628),
|
17 |
+
"Nyamagabe": (-2.4978, 29.4897), "Nyaruguru": (-2.5806, 29.4306), "Huye": (-2.5921, 29.7408),
|
18 |
+
"Gisagara": (-2.6283, 29.6820), "Nyanza": (-2.3566, 29.7507), "Rutsiro": (-2.0986, 29.3269),
|
19 |
+
"Karongi": (-2.0667, 29.4677), "Rubavu": (-1.7481, 29.2730), "Rusizi": (-2.5406, 29.3737),
|
20 |
+
"Nyamasheke": (-2.4700, 29.3222), "Ngororero": (-1.8733, 29.5811)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
21 |
}
|
22 |
|
23 |
+
# 2. Haversine function for distance (used in graph and heuristic)
|
24 |
def haversine(coord1, coord2):
|
25 |
+
R = 6371
|
26 |
lat1, lon1 = coord1
|
27 |
lat2, lon2 = coord2
|
28 |
dlat = radians(lat2 - lat1)
|
29 |
dlon = radians(lon2 - lon1)
|
30 |
+
a = sin(dlat / 2)**2 + cos(radians(lat1)) * cos(radians(lat2)) * sin(dlon / 2)**2
|
31 |
+
c = 2 * atan2(sqrt(a), sqrt(1 - a))
|
32 |
return R * c
|
33 |
|
34 |
+
# 3. Graph structure with real connections between neighboring districts
|
|
|
35 |
edges = [
|
36 |
+
("Nyarugenge", "Gasabo"), ("Gasabo", "Kicukiro"), ("Kicukiro", "Bugesera"), ("Bugesera", "Rwamagana"),
|
37 |
+
("Rwamagana", "Kayonza"), ("Kayonza", "Kirehe"), ("Kirehe", "Ngoma"), ("Ngoma", "Gatsibo"),
|
38 |
+
("Gatsibo", "Nyagatare"), ("Gatsibo", "Gicumbi"), ("Gicumbi", "Rulindo"), ("Rulindo", "Gakenke"),
|
39 |
+
("Gakenke", "Burera"), ("Burera", "Musanze"), ("Musanze", "Rubavu"), ("Rubavu", "Rutsiro"),
|
40 |
+
("Rutsiro", "Karongi"), ("Karongi", "Nyamasheke"), ("Nyamasheke", "Rusizi"), ("Rutsiro", "Ngororero"),
|
41 |
+
("Ngororero", "Muhanga"), ("Muhanga", "Kamonyi"), ("Kamonyi", "Nyarugenge"), ("Muhanga", "Ruhango"),
|
42 |
+
("Ruhango", "Nyanza"), ("Nyanza", "Huye"), ("Huye", "Gisagara"), ("Gisagara", "Nyaruguru"),
|
43 |
+
("Nyaruguru", "Nyamagabe"), ("Nyamagabe", "Karongi"), ("Ngororero", "Ruhango"),
|
44 |
+
("Gicumbi", "Gasabo"), ("Bugesera", "Ngoma")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
45 |
]
|
|
|
|
|
|
|
|
|
|
|
46 |
|
47 |
+
# 4. Build the weighted graph
|
48 |
+
G = nx.Graph()
|
49 |
+
for u, v in edges:
|
50 |
+
dist = haversine(places[u], places[v])
|
51 |
+
G.add_edge(u, v, weight=dist)
|
52 |
|
53 |
+
# 5. A* heuristic function
|
54 |
def heuristic(u, v):
|
55 |
return haversine(places[u], places[v])
|
56 |
|
57 |
+
# 6. Folium animation class
|
58 |
class AnimateMarker(MacroElement):
|
59 |
_template = Template("""
|
60 |
{% macro script(this, kwargs) %}
|
|
|
77 |
self._name = "AnimateMarker"
|
78 |
self.locations = locations
|
79 |
|
80 |
+
# 7. Core route generation function
|
81 |
def generate_map(start, end):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
82 |
if start == end:
|
83 |
+
return "Hitamo aho utangiriye n’aho ugiye bitandukanye.", ""
|
84 |
|
85 |
if not nx.has_path(G, start, end):
|
86 |
+
return f"Nta nzira ibaho hagati ya {start} na {end}.", ""
|
87 |
|
88 |
try:
|
89 |
path = nx.astar_path(G, start, end, heuristic=heuristic, weight='weight')
|
90 |
coords = [places[p] for p in path]
|
|
|
91 |
|
92 |
+
m = Map(location=[-2.0, 30.0], zoom_start=8)
|
93 |
+
for name, coord in places.items():
|
94 |
+
Marker(location=coord, popup=name).add_to(m)
|
95 |
+
|
96 |
+
PolyLine(coords, color="blue", weight=5).add_to(m)
|
97 |
m.add_child(AnimateMarker(coords))
|
98 |
|
99 |
return "Inzira ngufi ni: " + " ➔ ".join(path), m._repr_html_()
|
100 |
except Exception as e:
|
101 |
+
return f"Ntibishoboka kubona inzira: {str(e)}", ""
|
102 |
|
103 |
+
# 8. Gradio Interface
|
104 |
iface = gr.Interface(
|
105 |
fn=generate_map,
|
106 |
inputs=[
|
107 |
+
gr.Dropdown(list(places.keys()), label="Hitamo aho uri"),
|
108 |
+
gr.Dropdown(list(places.keys()), label="Hitamo aho ugiye")
|
109 |
],
|
110 |
outputs=[
|
111 |
gr.Textbox(label="Ubutumwa"),
|
112 |
gr.HTML(label="Ikarita")
|
113 |
],
|
114 |
+
title="🗺️ VIATEUR AI Rwanda Smart Route Planner "
|
115 |
)
|
116 |
|
117 |
iface.launch()
|
|