Spaces:
Runtime error
Runtime error
| """ | |
| Component 8 β Interactive Folium Map. | |
| Draws: | |
| β’ Full route polyline (color-coded by country) | |
| β’ Source / destination markers with custom icons | |
| β’ Toll plaza markers (green/orange/red by cost) with rich popups | |
| showing plaza name, highway, vehicle rate, electronic vs cash split, | |
| and data source. | |
| """ | |
| from typing import Dict, Any, List | |
| import folium | |
| from folium.plugins import Fullscreen | |
| # Country theme colors | |
| _THEMES = { | |
| "India": {"route": "#FF9933", "accent": "#138808", "bg": "#FFFFFF"}, | |
| "United States": {"route": "#B22234", "accent": "#3C3B6E", "bg": "#FFFFFF"}, | |
| } | |
| # Plaza cost thresholds for color coding (in currency units) | |
| _LOW_THRESHOLD = { | |
| "India": 50, | |
| "United States": 3, | |
| } | |
| _MID_THRESHOLD = { | |
| "India": 150, | |
| "United States": 10, | |
| } | |
| def build_map(result: Dict[str, Any]) -> folium.Map: | |
| """ | |
| Build and return a Folium map from a calculator result dict. | |
| """ | |
| country = result["country"] | |
| route = result["route"] | |
| plazas: List[Dict] = result["plazas"] | |
| theme = _THEMES.get(country, _THEMES["United States"]) | |
| currency_symbol = "βΉ" if country == "India" else "$" | |
| electronic_label = "FASTag" if country == "India" else "E-ZPass" | |
| coords = route["coords"] | |
| mid_idx = len(coords) // 2 | |
| center = coords[mid_idx] | |
| m = folium.Map( | |
| location=list(center), | |
| zoom_start=7, | |
| tiles="CartoDB positron", | |
| prefer_canvas=True, | |
| ) | |
| Fullscreen(position="topright").add_to(m) | |
| # ββ Route polyline ββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| folium.PolyLine( | |
| locations=[[lat, lon] for lat, lon in coords], | |
| color=theme["route"], | |
| weight=5, | |
| opacity=0.85, | |
| tooltip=f"{route['source']} β {route['destination']}", | |
| ).add_to(m) | |
| # ββ Source marker ββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| src = route["source_coords"] | |
| folium.Marker( | |
| location=[src[0], src[1]], | |
| popup=folium.Popup( | |
| f"<b>Start:</b> {route['source']}<br>" | |
| f"<b>Distance:</b> {route['distance_display']}<br>" | |
| f"<b>Travel time:</b> {route['duration_display']}", | |
| max_width=220, | |
| ), | |
| icon=folium.Icon( | |
| color="green", | |
| icon="play", | |
| prefix="fa", | |
| ), | |
| tooltip=f"Start: {route['source']}", | |
| ).add_to(m) | |
| # ββ Destination marker ββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| dst = route["destination_coords"] | |
| folium.Marker( | |
| location=[dst[0], dst[1]], | |
| popup=folium.Popup( | |
| f"<b>End:</b> {route['destination']}<br>" | |
| f"<b>Total toll:</b> {currency_symbol}{result['total_toll']:.2f}", | |
| max_width=220, | |
| ), | |
| icon=folium.Icon( | |
| color="red", | |
| icon="flag-checkered", | |
| prefix="fa", | |
| ), | |
| tooltip=f"End: {route['destination']}", | |
| ).add_to(m) | |
| # ββ Toll plaza markers ββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| low_t = _LOW_THRESHOLD.get(country, 5) | |
| mid_t = _MID_THRESHOLD.get(country, 10) | |
| for plaza in plazas: | |
| lat, lon = plaza["latitude"], plaza["longitude"] | |
| if lat == 0 and lon == 0: | |
| continue | |
| rate = plaza["rate"] | |
| e_rate = plaza["electronic_rate"] | |
| c_rate = plaza["cash_rate"] | |
| unavailable = plaza.get("rate_unavailable", False) | |
| if unavailable: | |
| marker_color = "gray" | |
| elif rate <= low_t: | |
| marker_color = "green" | |
| elif rate <= mid_t: | |
| marker_color = "orange" | |
| else: | |
| marker_color = "red" | |
| icon_char = "βΉ" if country == "India" else "$" | |
| if unavailable: | |
| rate_html = "<i>Rate unavailable</i>" | |
| elif e_rate != c_rate: | |
| rate_html = ( | |
| f"<b>{electronic_label}:</b> {icon_char}{e_rate:.2f}<br>" | |
| f"<b>Cash:</b> {icon_char}{c_rate:.2f}" | |
| ) | |
| else: | |
| rate_html = f"<b>Toll:</b> {icon_char}{rate:.2f}" | |
| highway_html = f"<b>Highway:</b> {plaza['highway_number']}<br>" if plaza["highway_number"] else "" | |
| source_html = f"<br><small style='color:#888'>Source: {plaza['source']}</small>" | |
| popup_html = f""" | |
| <div style="font-family:sans-serif;font-size:13px;min-width:180px"> | |
| <b style="font-size:14px">{plaza['plaza_name']}</b><br> | |
| {highway_html} | |
| {rate_html} | |
| {source_html} | |
| </div>""" | |
| folium.Marker( | |
| location=[lat, lon], | |
| popup=folium.Popup(popup_html, max_width=260), | |
| icon=folium.DivIcon( | |
| html=_plaza_icon_html(icon_char, marker_color), | |
| icon_size=(32, 32), | |
| icon_anchor=(16, 16), | |
| ), | |
| tooltip=f"{plaza['plaza_name']} β {icon_char}{rate:.2f}", | |
| ).add_to(m) | |
| # ββ Fit map to route bounds ββββββββββββββββββββββββββββββββββββββββββββββββ | |
| if coords: | |
| lats = [c[0] for c in coords] | |
| lons = [c[1] for c in coords] | |
| m.fit_bounds([[min(lats), min(lons)], [max(lats), max(lons)]]) | |
| return m | |
| def _plaza_icon_html(symbol: str, color: str) -> str: | |
| color_map = { | |
| "green": "#27ae60", | |
| "orange": "#e67e22", | |
| "red": "#e74c3c", | |
| "gray": "#95a5a6", | |
| } | |
| bg = color_map.get(color, "#95a5a6") | |
| return ( | |
| f'<div style="' | |
| f'background:{bg};' | |
| f'color:white;' | |
| f'border-radius:50%;' | |
| f'width:28px;height:28px;' | |
| f'display:flex;align-items:center;justify-content:center;' | |
| f'font-size:14px;font-weight:bold;' | |
| f'border:2px solid white;' | |
| f'box-shadow:0 2px 4px rgba(0,0,0,0.4);' | |
| f'">{symbol}</div>' | |
| ) | |