Spaces:
Sleeping
Sleeping
import gradio as gr import folium import networkx as nx from folium import Map, Marker, PolyLine from math import radians, cos, sin, sqrt, atan2 import time from branca.element import MacroElement from jinja2 import Template # Uturere two mu Rwanda hamwe na coordinates (latitude, longitude) places = { "Nyarugenge": (-1.9577, 30.0619), "Gasabo": (-1.9400, 30.0861), "Kicukiro": (-1.9781, 30.0597), "Burera": (-1.4800, 29.7300), "Gakenke": (-1.5700, 29.7561), "Rulindo": (-1.8333, 30.0833), "Musanze": (-1.5014, 29.6344), "Gicumbi": (-1.5794, 30.0542), "Nyagatare": (-1.3100, 30.3000), "Gatsibo": (-1.6800, 30.3900), "Kayonza": (-2.0000, 30.5667), "Kirehe": (-2.3553, 30.7767), "Ngoma": (-2.1600, 30.4700), "Rwamagana": (-1.9491, 30.4349), "Bugesera": (-2.2083, 30.2576), "Kamonyi": (-2.0833, 29.9000), "Muhanga": (-2.1200, 29.7561), "Ruhango": (-2.2136, 29.7628), "Nyamagabe": (-2.4978, 29.4897), "Nyaruguru": (-2.5806, 29.4306), "Huye": (-2.5921, 29.7408), "Gisagara": (-2.6283, 29.6820), "Nyanza": (-2.3566, 29.7507), "Rutsiro": (-2.0986, 29.3269), "Karongi": (-2.0667, 29.4677), "Rubavu": (-1.7481, 29.2730), "Rusizi": (-2.5406, 29.3737), "Nyamasheke": (-2.4700, 29.3222), "Ngororero": (-1.8733, 29.5811) } # Haversine function (heuristic for A*) def haversine(coord1, coord2): R = 6371 # Earth radius in km lat1, lon1 = coord1 lat2, lon2 = coord2 dlat = radians(lat2 - lat1) dlon = radians(lon2 - lon1) a = sin(dlat/2)**2 + cos(radians(lat1))*cos(radians(lat2))*sin(dlon/2)**2 c = 2 * atan2(sqrt(a), sqrt(1-a)) return R * c # Build graph with edges and weights G = nx.Graph() edges = [ ("Nyarugenge", "Gasabo"), ("Gasabo", "Kicukiro"), ("Burera", "Gakenke"), ("Gakenke", "Rulindo"), ("Musanze", "Gicumbi"), ("Nyagatare", "Gatsibo"), ("Kayonza", "Kirehe"), ("Ngoma", "Rwamagana"), ("Bugesera", "Kamonyi"), ("Muhanga", "Ruhango"), ("Nyamagabe", "Nyaruguru"), ("Huye", "Gisagara"), ("Nyanza", "Ruhango"), ("Rutsiro", "Karongi"), ("Rubavu", "Rusizi"), ("Nyamasheke", "Ngororero"), ("Rulindo", "Gasabo"), ("Gicumbi", "Nyagatare"), ("Kicukiro", "Kamonyi"), ("Kamonyi", "Muhanga"), ("Ruhango", "Nyamagabe"), ("Karongi", "Rubavu"), ("Rusizi", "Nyamasheke"), ("Ngororero", "Rutsiro") ] for edge in edges: c1 = places[edge[0]] c2 = places[edge[1]] dist = haversine(c1, c2) G.add_edge(edge[0], edge[1], weight=dist) # Add nodes that might be missing for place in places.keys(): if place not in G: G.add_node(place) # Heuristic function for A* def heuristic(u, v): return haversine(places[u], places[v]) # Folium animation plugin for marker movement class AnimateMarker(MacroElement): _template = Template(""" {% macro script(this, kwargs) %} var marker = L.marker({{this.locations[0]}}).addTo({{this._parent.get_name()}}); var latlngs = {{this.locations}}; var index = 0; function moveMarker(){ index++; if(index >= latlngs.length){ return; } marker.setLatLng(latlngs[index]); setTimeout(moveMarker, 700); } moveMarker(); {% endmacro %} """) def __init__(self, locations): super().__init__() self._name = "AnimateMarker" self.locations = locations def generate_map(start, end): if start is None or end is None: return "Hitamo aho utangiriye n’aho ugiye neza.", "" if start not in G.nodes or end not in G.nodes: return "Hitamo aho utangiriye n’aho ugiye neza (ntiboneka mu rutonde).", "" m = Map(location=[-2.0, 30.0], zoom_start=8) for name, coord in places.items(): Marker(location=coord, popup=name).add_to(m) if start == end: return "Hitamo aho utangiriye n’aho ugiye bitandukanye.", m._repr_html_() if not nx.has_path(G, start, end): return f"Nta nzira ibaho hagati ya {start} na {end}.", m._repr_html_() try: path = nx.astar_path(G, start, end, heuristic=heuristic, weight='weight') coords = [places[p] for p in path] PolyLine(coords, color="blue", weight=5).add_to(m) # Add animated marker along the path m.add_child(AnimateMarker(coords)) return "Inzira ngufi ni: " + " ➔ ".join(path), m._repr_html_() except Exception as e: return f"Ntibishoboka kubona inzira: {str(e)}", m._repr_html_() iface = gr.Interface( fn=generate_map, inputs=[ gr.Dropdown(list(places.keys()), label="Hitamo aho uri", value=list(places.keys())[0]), gr.Dropdown(list(places.keys()), label="Hitamo aho ugiye", value=list(places.keys())[1]) ], outputs=[ gr.Textbox(label="Ubutumwa"), gr.HTML(label="Ikarita") ], title="🗺️ Rwanda Smart Route Planner with Animation" ) iface.launch()
Browse files
app.py
CHANGED
@@ -1,11 +1,13 @@
|
|
1 |
import gradio as gr
|
2 |
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
|
7 |
-
from
|
|
|
8 |
|
|
|
9 |
places = {
|
10 |
"Nyarugenge": (-1.9577, 30.0619),
|
11 |
"Gasabo": (-1.9400, 30.0861),
|
@@ -38,16 +40,18 @@ places = {
|
|
38 |
"Ngororero": (-1.8733, 29.5811)
|
39 |
}
|
40 |
|
|
|
41 |
def haversine(coord1, coord2):
|
42 |
-
R = 6371
|
43 |
lat1, lon1 = coord1
|
44 |
lat2, lon2 = coord2
|
45 |
dlat = radians(lat2 - lat1)
|
46 |
dlon = radians(lon2 - lon1)
|
47 |
-
a = sin(dlat/2)**2 + cos(radians(lat1))
|
48 |
-
c = 2 * atan2(sqrt(a), sqrt(1
|
49 |
return R * c
|
50 |
|
|
|
51 |
G = nx.Graph()
|
52 |
edges = [
|
53 |
("Nyarugenge", "Gasabo"),
|
@@ -75,20 +79,53 @@ edges = [
|
|
75 |
("Rusizi", "Nyamasheke"),
|
76 |
("Ngororero", "Rutsiro")
|
77 |
]
|
78 |
-
|
79 |
for edge in edges:
|
80 |
-
|
81 |
-
|
82 |
-
|
83 |
-
G.add_edge(edge[0], edge[1], weight=
|
|
|
|
|
|
|
|
|
|
|
84 |
|
|
|
85 |
def heuristic(u, v):
|
86 |
return haversine(places[u], places[v])
|
87 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
88 |
def generate_map(start, end):
|
|
|
|
|
|
|
|
|
|
|
89 |
m = Map(location=[-2.0, 30.0], zoom_start=8)
|
90 |
-
for name,
|
91 |
-
Marker(location=
|
92 |
|
93 |
if start == end:
|
94 |
return "Hitamo aho utangiriye n’aho ugiye bitandukanye.", m._repr_html_()
|
@@ -98,64 +135,21 @@ def generate_map(start, end):
|
|
98 |
|
99 |
try:
|
100 |
path = nx.astar_path(G, start, end, heuristic=heuristic, weight='weight')
|
101 |
-
|
102 |
-
# Coordinates for polyline and for animation points
|
103 |
coords = [places[p] for p in path]
|
104 |
PolyLine(coords, color="blue", weight=5).add_to(m)
|
105 |
|
106 |
-
#
|
107 |
-
|
108 |
-
start_time = datetime.now()
|
109 |
-
time_increment = timedelta(seconds=2) # 2 seconds between points
|
110 |
-
|
111 |
-
for i, coord in enumerate(coords):
|
112 |
-
feature = {
|
113 |
-
"type": "Feature",
|
114 |
-
"geometry": {
|
115 |
-
"type": "Point",
|
116 |
-
"coordinates": [coord[1], coord[0]] # GeoJSON uses [lon, lat]
|
117 |
-
},
|
118 |
-
"properties": {
|
119 |
-
"time": (start_time + i * time_increment).isoformat(),
|
120 |
-
"style": {"color": "red"},
|
121 |
-
"icon": "circle",
|
122 |
-
"iconstyle": {
|
123 |
-
"fillColor": "red",
|
124 |
-
"fillOpacity": 0.8,
|
125 |
-
"stroke": "true",
|
126 |
-
"radius": 7
|
127 |
-
}
|
128 |
-
}
|
129 |
-
}
|
130 |
-
features.append(feature)
|
131 |
-
|
132 |
-
timestamped_geojson = {
|
133 |
-
"type": "FeatureCollection",
|
134 |
-
"features": features
|
135 |
-
}
|
136 |
-
|
137 |
-
plugins.TimestampedGeoJson(
|
138 |
-
timestamped_geojson,
|
139 |
-
period='PT2S',
|
140 |
-
add_last_point=True,
|
141 |
-
auto_play=True,
|
142 |
-
loop=False,
|
143 |
-
max_speed=1,
|
144 |
-
loop_button=True,
|
145 |
-
date_options='YYYY/MM/DD HH:mm:ss',
|
146 |
-
time_slider_drag_update=True
|
147 |
-
).add_to(m)
|
148 |
|
149 |
return "Inzira ngufi ni: " + " ➔ ".join(path), m._repr_html_()
|
150 |
-
|
151 |
except Exception as e:
|
152 |
return f"Ntibishoboka kubona inzira: {str(e)}", m._repr_html_()
|
153 |
|
154 |
iface = gr.Interface(
|
155 |
fn=generate_map,
|
156 |
inputs=[
|
157 |
-
gr.Dropdown(list(places.keys()), label="Hitamo aho uri"),
|
158 |
-
gr.Dropdown(list(places.keys()), label="Hitamo aho ugiye")
|
159 |
],
|
160 |
outputs=[
|
161 |
gr.Textbox(label="Ubutumwa"),
|
@@ -166,4 +160,3 @@ iface = gr.Interface(
|
|
166 |
|
167 |
iface.launch()
|
168 |
|
169 |
-
|
|
|
1 |
import gradio as gr
|
2 |
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 |
+
# Uturere two mu Rwanda hamwe na coordinates (latitude, longitude)
|
11 |
places = {
|
12 |
"Nyarugenge": (-1.9577, 30.0619),
|
13 |
"Gasabo": (-1.9400, 30.0861),
|
|
|
40 |
"Ngororero": (-1.8733, 29.5811)
|
41 |
}
|
42 |
|
43 |
+
# Haversine function (heuristic for A*)
|
44 |
def haversine(coord1, coord2):
|
45 |
+
R = 6371 # Earth radius in km
|
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 |
+
# Build graph with edges and weights
|
55 |
G = nx.Graph()
|
56 |
edges = [
|
57 |
("Nyarugenge", "Gasabo"),
|
|
|
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 |
+
# Add nodes that might be missing
|
89 |
+
for place in places.keys():
|
90 |
+
if place not in G:
|
91 |
+
G.add_node(place)
|
92 |
|
93 |
+
# Heuristic function for A*
|
94 |
def heuristic(u, v):
|
95 |
return haversine(places[u], places[v])
|
96 |
|
97 |
+
# Folium animation plugin for marker movement
|
98 |
+
class AnimateMarker(MacroElement):
|
99 |
+
_template = Template("""
|
100 |
+
{% macro script(this, kwargs) %}
|
101 |
+
var marker = L.marker({{this.locations[0]}}).addTo({{this._parent.get_name()}});
|
102 |
+
var latlngs = {{this.locations}};
|
103 |
+
var index = 0;
|
104 |
+
function moveMarker(){
|
105 |
+
index++;
|
106 |
+
if(index >= latlngs.length){
|
107 |
+
return;
|
108 |
+
}
|
109 |
+
marker.setLatLng(latlngs[index]);
|
110 |
+
setTimeout(moveMarker, 700);
|
111 |
+
}
|
112 |
+
moveMarker();
|
113 |
+
{% endmacro %}
|
114 |
+
""")
|
115 |
+
def __init__(self, locations):
|
116 |
+
super().__init__()
|
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.", m._repr_html_()
|
|
|
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 |
+
# Add animated marker along the path
|
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)}", m._repr_html_()
|
147 |
|
148 |
iface = gr.Interface(
|
149 |
fn=generate_map,
|
150 |
inputs=[
|
151 |
+
gr.Dropdown(list(places.keys()), label="Hitamo aho uri", value=list(places.keys())[0]),
|
152 |
+
gr.Dropdown(list(places.keys()), label="Hitamo aho ugiye", value=list(places.keys())[1])
|
153 |
],
|
154 |
outputs=[
|
155 |
gr.Textbox(label="Ubutumwa"),
|
|
|
160 |
|
161 |
iface.launch()
|
162 |
|
|