TRAFFIC / app.py
VIATEUR-AI's picture
Update app.py
66291ac verified
import gradio as gr
import folium
import networkx as nx
from folium import Map, Marker, PolyLine, Popup, IFrame
from math import radians, cos, sin, sqrt, atan2
from branca.element import MacroElement
from jinja2 import Template
# 1. Districts and Coordinates (Harimo Kigali)
places = {
"Kigali": (-1.9441, 30.0619),
"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)
}
# 2. Place images URLs
place_images = {
"Kigali": "https://upload.wikimedia.org/wikipedia/commons/8/89/Kigali_city_view.jpg",
"Nyarugenge": "https://upload.wikimedia.org/wikipedia/commons/f/f8/Nyarugenge_district.jpg",
"Gasabo": "https://upload.wikimedia.org/wikipedia/commons/a/a5/Gasabo_district.jpg",
"Kicukiro": "https://upload.wikimedia.org/wikipedia/commons/1/10/Kicukiro_District_-_Rwanda.jpg",
"Burera": "https://upload.wikimedia.org/wikipedia/commons/3/33/Burera_Lake_Muhazi.jpg",
"Gakenke": "https://upload.wikimedia.org/wikipedia/commons/c/c4/Gakenke_landscape.jpg",
"Rulindo": "https://upload.wikimedia.org/wikipedia/commons/0/01/Rulindo_landscape.jpg",
"Musanze": "https://upload.wikimedia.org/wikipedia/commons/6/6c/Musanze_scenery.jpg",
"Gicumbi": "https://upload.wikimedia.org/wikipedia/commons/7/7e/Gicumbi_landscape.jpg",
"Nyagatare": "https://upload.wikimedia.org/wikipedia/commons/9/98/Nyagatare_landscape.jpg",
"Gatsibo": "https://upload.wikimedia.org/wikipedia/commons/f/f0/Gatsibo_landscape.jpg",
"Kayonza": "https://upload.wikimedia.org/wikipedia/commons/b/b6/Kayonza_landscape.jpg",
"Kirehe": "https://upload.wikimedia.org/wikipedia/commons/3/3f/Kirehe_landscape.jpg",
"Ngoma": "https://upload.wikimedia.org/wikipedia/commons/4/49/Ngoma_landscape.jpg",
"Rwamagana": "https://upload.wikimedia.org/wikipedia/commons/0/00/Rwamagana_landscape.jpg",
"Bugesera": "https://upload.wikimedia.org/wikipedia/commons/1/12/Bugesera_landscape.jpg",
"Kamonyi": "https://upload.wikimedia.org/wikipedia/commons/d/d4/Kamonyi_landscape.jpg",
"Muhanga": "https://upload.wikimedia.org/wikipedia/commons/2/2a/Muhanga_landscape.jpg",
"Ruhango": "https://upload.wikimedia.org/wikipedia/commons/9/96/Ruhango_landscape.jpg",
"Nyamagabe": "https://upload.wikimedia.org/wikipedia/commons/8/80/Nyamagabe_landscape.jpg",
"Nyaruguru": "https://upload.wikimedia.org/wikipedia/commons/6/63/Nyaruguru_landscape.jpg",
"Huye": "https://upload.wikimedia.org/wikipedia/commons/7/7a/Huye_landscape.jpg",
"Gisagara": "https://upload.wikimedia.org/wikipedia/commons/8/8c/Gisagara_landscape.jpg",
"Nyanza": "https://upload.wikimedia.org/wikipedia/commons/3/3a/Nyanza_landscape.jpg",
"Rutsiro": "https://upload.wikimedia.org/wikipedia/commons/5/5f/Rutsiro_landscape.jpg",
"Karongi": "https://upload.wikimedia.org/wikipedia/commons/f/f5/Karongi_landscape.jpg",
"Rubavu": "https://upload.wikimedia.org/wikipedia/commons/6/68/Rubavu_landscape.jpg",
"Rusizi": "https://upload.wikimedia.org/wikipedia/commons/3/30/Rusizi_landscape.jpg",
"Nyamasheke": "https://upload.wikimedia.org/wikipedia/commons/1/17/Nyamasheke_landscape.jpg",
"Ngororero": "https://upload.wikimedia.org/wikipedia/commons/7/7d/Ngororero_landscape.jpg"
}
# 3. Distance calculator (Haversine Formula)
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
# 4. Edges (connect Kigali and other districts)
edges = [
("Nyarugenge", "Gasabo"), ("Gasabo", "Kicukiro"), ("Kicukiro", "Bugesera"), ("Bugesera", "Rwamagana"),
("Rwamagana", "Kayonza"), ("Kayonza", "Kirehe"), ("Kirehe", "Ngoma"), ("Ngoma", "Gatsibo"),
("Gatsibo", "Nyagatare"), ("Gatsibo", "Gicumbi"), ("Gicumbi", "Rulindo"), ("Rulindo", "Gakenke"),
("Gakenke", "Burera"), ("Burera", "Musanze"), ("Musanze", "Rubavu"), ("Rubavu", "Rutsiro"),
("Rutsiro", "Karongi"), ("Karongi", "Nyamasheke"), ("Nyamasheke", "Rusizi"), ("Rutsiro", "Ngororero"),
("Ngororero", "Muhanga"), ("Muhanga", "Kamonyi"), ("Kamonyi", "Nyarugenge"), ("Muhanga", "Ruhango"),
("Ruhango", "Nyanza"), ("Nyanza", "Huye"), ("Huye", "Gisagara"), ("Gisagara", "Nyaruguru"),
("Nyaruguru", "Nyamagabe"), ("Nyamagabe", "Karongi"), ("Ngororero", "Ruhango"),
("Gicumbi", "Gasabo"), ("Bugesera", "Ngoma"),
("Kigali", "Nyarugenge"), ("Kigali", "Gasabo"), ("Kigali", "Kicukiro")
]
# 5. Create Graph
G = nx.Graph()
for u, v in edges:
G.add_edge(u, v, weight=haversine(places[u], places[v]))
# 6. Animation class 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
# 7. Routing function with popup images on map markers
def generate_map(start, end):
if start == end:
return "Hitamo aho utangiriye n’aho ugiye bitandukanye.", "", ""
if not nx.has_path(G, start, end):
return f"Nta nzira ibaho hagati ya {start} na {end}.", "", ""
try:
path = nx.astar_path(G, start, end, heuristic=lambda u, v: haversine(places[u], places[v]), weight='weight')
coords = [places[p] for p in path]
m = Map(location=[-1.9441, 30.0619], zoom_start=9)
# Add markers for all places (normal popup with name)
for name, coord in places.items():
if name == start or name == end:
# For start and end: popup with image + name
img_url = place_images.get(name, "https://via.placeholder.com/300?text=No+Image")
html = f"""
<h4>{name}</h4>
<img src="{img_url}" width="300" style="border-radius:8px;"/>
"""
iframe = IFrame(html, width=320, height=320)
popup = Popup(iframe, max_width=320)
Marker(location=coord, popup=popup, icon=folium.Icon(color='green' if name == start else 'red')).add_to(m)
else:
Marker(location=coord, popup=name).add_to(m)
# Draw the route line
PolyLine(coords, color="blue", weight=5).add_to(m)
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)}", "", ""
# 8. Gradio interface
with gr.Blocks() as demo:
gr.Markdown("## Shaka inzira ngufi hagati y’uturere twa Rwanda")
start = gr.Dropdown(list(places.keys()), label="Aho utangirira")
end = gr.Dropdown(list(places.keys()), label="Aho ugiye")
btn = gr.Button("Shaka inzira")
output_text = gr.Textbox(label="Inzira", interactive=False)
output_map = gr.HTML()
btn.click(fn=generate_map, inputs=[start, end], outputs=[output_text, output_map, gr.Textbox(visible=False)])
demo.launch()