Spaces:
Build error
Build error
File size: 9,932 Bytes
888ccff f87674b b4dbd8b f87674b 458cf78 f87674b 458cf78 79e740d 6e8e627 b4dbd8b dfb606a b4dbd8b 458cf78 dfb606a 458cf78 f87674b 458cf78 f87674b 458cf78 f87674b dfb606a f87674b dfb606a f87674b dfb606a f87674b 79e740d dfb606a f87674b dfb606a f87674b 458cf78 dfb606a 458cf78 dfb606a f87674b 458cf78 f87674b 458cf78 f87674b b4dbd8b f87674b 6e8e627 f87674b dfb606a f87674b dfb606a f87674b dfb606a f87674b dfb606a f87674b dfb606a b4dbd8b 888ccff dfb606a f87674b dfb606a | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 | import streamlit as st
import osmnx as ox
import networkx as nx
import pandas as pd
import plotly.graph_objects as go
import heapq
from math import asin, radians, cos, sin, sqrt
# Plotting
DEFAULT_WEIGHT_KG = 70
ELEVATION_SCALE = 5
# --- Location list ---
locations = [
{'name': 'Grha Sabha Pramana', 'lat': -7.770071488953822, 'lon': 110.3783984379329, 'elevation': 142},
{'name': 'Boulevard UGM', 'lat': -7.775446818599403, 'lon': 110.37643708634688, 'elevation': 133},
{'name': 'Fakultas Ilmu Sosial dan Ilmu Politik', 'lat': -7.769082851574989, 'lon': 110.38088752769059, 'elevation': 145},
{'name': 'Fakultas Teknik', 'lat': -7.765067267048453, 'lon': 110.37252242878728, 'elevation': 139},
{'name': 'Perpustakaan Pusat', 'lat': -7.769132738499928, 'lon': 110.37819025762326, 'elevation': 142},
{'name': 'Fakultas Farmasi', 'lat': -7.768920115853235, 'lon': 110.37629125348137, 'elevation': 143},
{'name': 'Fakultas Kedokteran', 'lat': -7.769241968897335, 'lon': 110.37410241529511, 'elevation': 138},
{'name': 'Fakultas Hukum', 'lat': -7.770083777982755, 'lon': 110.38117766903606, 'elevation': 143},
{'name': 'Fakultas Ekonomika dan Bisnis', 'lat': -7.770126237227525, 'lon': 110.37903152864811, 'elevation': 142},
{'name': 'Fakultas Ilmu Budaya', 'lat': -7.771190276512944, 'lon': 110.37876576685031, 'elevation': 139},
{'name': 'Fakultas Biologi', 'lat': -7.76442822947009, 'lon': 110.37698323450962, 'elevation': 148},
{'name': 'Fakultas Kehutanan', 'lat': -7.766739271152903, 'lon': 110.38109875565928, 'elevation': 149},
{'name': 'Fakultas Peternakan', 'lat': -7.766930486720981, 'lon': 110.38542241877909, 'elevation': 144},
{'name': 'Fakultas Pertanian', 'lat': -7.767908235085672, 'lon': 110.38100213548348, 'elevation': 148},
{'name': 'Fakultas Geografi', 'lat': -7.765983577235556, 'lon': 110.37794577655771, 'elevation': 150},
{'name': 'Fakultas MIPA', 'lat': -7.766770213071046, 'lon': 110.37617551844697, 'elevation': 142},
{'name': 'Fakultas Psikologi', 'lat': -7.7721010490703355, 'lon': 110.38076316079525, 'elevation': 138},
{'name': 'Fakultas Filsafat', 'lat': -7.771194580135096, 'lon': 110.38124107602673, 'elevation': 140},
{'name': 'Rektorat UGM', 'lat': -7.767550457927047, 'lon': 110.37912599375315, 'elevation': 155},
{'name': 'Masjid Kampus UGM', 'lat': -7.773202436052038, 'lon': 110.38040009798743, 'elevation': 140},
{'name': 'RSUP Dr. Sardjito', 'lat': -7.76857375077125, 'lon': 110.37380676773756, 'elevation': 138}
]
# Dynamically generate key_locations for quick lookup
key_locations = {loc["name"]: (loc["lat"], loc["lon"], loc["elevation"]) for loc in locations}
def haversine(lat1, lon1, lat2, lon2):
dlon = radians(lon2 - lon1)
dlat = radians(lat2 - lat1)
a = sin(dlat/2)**2 + cos(radians(lat1)) * cos(radians(lat2)) * sin(dlon/2)**2
c = 2 * asin(sqrt(a))
return 6371 * c # km
def elevation_difference(u, v):
# Get the nearest locations for nodes u and v
u_coords = (G.nodes[u]['y'], G.nodes[u]['x']) # lat, lon
v_coords = (G.nodes[v]['y'], G.nodes[v]['x']) # lat, lon
# Find the nearest locations from the locations list
u_location = min(locations, key=lambda loc: haversine(u_coords[0], u_coords[1], loc['lat'], loc['lon']))
v_location = min(locations, key=lambda loc: haversine(v_coords[0], v_coords[1], loc['lat'], loc['lon']))
# Get the elevation values from the nearest locations
elev_u = u_location['elevation']
elev_v = v_location['elevation']
# Return the absolute elevation difference
return abs(elev_v - elev_u)
def heuristic(u, v):
u_lat, u_lon = G.nodes[u]['y'], G.nodes[u]['x']
v_lat, v_lon = G.nodes[v]['y'], G.nodes[v]['x']
return haversine(u_lat, u_lon, v_lat, v_lon) + (ELEVATION_SCALE * elevation_difference(u, v))
def astar(graph, start, goal):
open_set = []
heapq.heappush(open_set, (0, start))
came_from = {}
g_score = {node: float('inf') for node in graph.nodes}
g_score[start] = 0
f_score = {node: float('inf') for node in graph.nodes}
f_score[start] = heuristic(start, goal)
while open_set:
_, current = heapq.heappop(open_set)
if current == goal:
path = []
while current in came_from:
path.append(current)
current = came_from[current]
path.append(start)
return path[::-1]
for neighbor in graph.neighbors(current):
tentative_g = g_score[current] + graph[current][neighbor][0]['length']
if tentative_g < g_score[neighbor]:
came_from[neighbor] = current
g_score[neighbor] = tentative_g
f_score[neighbor] = tentative_g + heuristic(neighbor, goal)
heapq.heappush(open_set, (f_score[neighbor], neighbor))
raise nx.NetworkXNoPath("No path found")
def get_coordinates(locations, target_name):
for loc in locations:
if loc["name"].lower() == target_name.lower():
return (loc["lon"], loc["lat"]) # Return in (lon, lat) format
return None
def adjust_map_zoom_and_center(lats, lons, real_distance, total_distance):
# Calculate the center of the route for better zoom
center_lat = sum(lats) / len(lats)
center_lon = sum(lons) / len(lons)
# Adjust zoom level based on the route length
route_length_km = real_distance / 1000 if real_distance else total_distance
zoom_level = max(10, min(16, 16 - int(route_length_km / 2)))
return center_lat, center_lon, zoom_level
# Streamlit App
st.set_page_config(page_title="UGM Running Route", layout="wide")
st.title("๐ถโโ๏ธ Running Route Through UGM")
st.markdown("---")
# Layout: Input, Map, and Output
col1, col2, col3 = st.columns([1, 2, 1])
# Input Section
with col1:
st.header("๐ Input")
st.markdown("Select your starting and ending points for the route.")
with st.form("route_form"):
st.write("### Route Options")
location_names = [loc["name"] for loc in locations]
start_point = st.selectbox("Start Point", location_names)
end_point = st.selectbox("End Point", location_names)
submitted = st.form_submit_button('๐ Submit Route')
start_loc = next(loc for loc in locations if loc['name'] == start_point)
end_loc = next(loc for loc in locations if loc['name'] == end_point)
center_lat = (start_loc['lat'] + end_loc['lat']) / 2
center_lon = (start_loc['lon'] + end_loc['lon']) / 2
G = ox.graph_from_point((center_lat, center_lon), dist=1000, network_type='walk')
start_node = ox.distance.nearest_nodes(G, start_loc['lon'], start_loc['lat'])
end_node = ox.distance.nearest_nodes(G, end_loc['lon'], end_loc['lat'])
#calculations
route = astar(G, start_node, end_node)
route_coords = [(G.nodes[n]['y'], G.nodes[n]['x']) for n in route] # lat, lon
real_distance = sum(G[u][v][0]['length'] for u, v in zip(route[:-1], route[1:]))
elevation_gain = sum(elevation_difference(u, v) for u, v in zip(route[:-1], route[1:]))
if elevation_gain < 5:
difficulty = "Easy"
elif elevation_gain < 15:
difficulty = "Moderate"
else:
difficulty = "Difficult"
calories_burned = {}
for speed in [4, 6, 8]:
time_h = real_distance / 1000 / speed
met = 3.5 if speed == 4 else 7 if speed == 6 else 10
cal = met * DEFAULT_WEIGHT_KG * time_h
calories_burned[f"{speed} km/h"] = round(cal, 2)
lats, lons = zip(*route_coords)
fig = go.Figure()
for loc in locations:
fig.add_scattermapbox(
lat=[loc['lat']],
lon=[loc['lon']],
mode='markers+text',
marker=dict(size=8, color='red'),
text=[loc['name']],
textposition="top center",
name=loc['name'],
showlegend=False,
hoverinfo='text'
)
# Route line
fig.add_trace(go.Scattermapbox(
lat=lats,
lon=lons,
mode='lines+markers',
line=dict(width=4, color='blue'),
marker=dict(size=6, color='red'),
name='A* Route'
))
# Start point
fig.add_trace(go.Scattermapbox(
lat=[start_loc['lat']],
lon=[start_loc['lon']],
mode='markers+text',
marker=dict(size=12, color='green'),
text=[start_point],
textposition="top center",
name='Start'
))
# End point
fig.add_trace(go.Scattermapbox(
lat=[end_loc['lat']],
lon=[end_loc['lon']],
mode='markers+text',
marker=dict(size=12, color='green'),
text=[end_point],
textposition="top center",
name='End'
))
# Map layout
fig.update_layout(
mapbox_style="open-street-map",
mapbox_zoom=16,
mapbox_center={"lat": center_lat, "lon": center_lon},
margin={"r":0,"t":0,"l":0,"b":0},
title="A* Route Between UGM Locations"
)
# Use the new method to adjust map zoom and center
# center_lat, center_lon, zoom_level = adjust_map_zoom_and_center(lats, lons, real_distance, total_distance)
fig.update_layout(
mapbox=dict(
center=dict(lat=center_lat, lon=center_lon),
zoom=14
)
)
fig.update_layout(
mapbox_style="open-street-map",
margin={"r":0, "t":0, "l":0, "b":0}
)
# Map Section
with col2:
st.header("๐บ๏ธ Map")
if submitted:
st.plotly_chart(fig, use_container_width=True)
else:
st.info("Submit the form to see the map.")
# Output Section
with col3:
st.header("๐ Output")
if submitted:
st.success("### Route Summary")
st.metric(label="Real Distance (km)", value="{:.2f}".format(real_distance/1000) if real_distance else "N/A")
st.metric(label="Elevation Gain (m)", value=round(elevation_gain, 2))
st.metric(label="Difficulty", value=difficulty)
st.write("### Calories Burned")
for speed, calories in calories_burned.items():
st.write(f"- **{speed}:** {calories} kcal")
else:
st.info("Submit the form to see the output.")
st.markdown("---")
st.caption("Developed with โค๏ธ for UGM runners.") |