An app which lets users login and upload gpx tracks. Those gpx tracks will be replayed
Drop files here
or click to upload
import streamlit as st
import gpxpy
import folium
from streamlit_folium import folium_static
from sqlalchemy import create_engine, Column, Integer, String, LargeBinary, Float
from sqlalchemy.orm import DeclarativeBase, Session
import time
import json
import numpy as np
# Database setup
class Base(DeclarativeBase):
pass
class Track(Base):
__tablename__ = 'tracks'
id = Column(Integer, primary_key=True)
user_id = Column(String)
name = Column(String)
gpx_data = Column(LargeBinary)
duration = Column(Float) # Duration in seconds
engine = create_engine('sqlite:///tracks.db')
Base.metadata.create_all(engine)
# Authentication
def check_password():
"""Returns `True` if the user had the correct password."""
def password_entered():
if st.session_state["password"] == st.secrets.get("password", "admin"):
st.session_state["password_correct"] = True
del st.session_state["password"]
else:
st.session_state["password_correct"] = False
if "password_correct" not in st.session_state:
st.text_input(
"Password", type="password", on_change=password_entered, key="password"
)
return False
elif not st.session_state["password_correct"]:
st.text_input(
"Password", type="password", on_change=password_entered, key="password"
)
st.error("😕 Password incorrect")
return False
else:
return True
if not check_password():
st.stop()
# Main app
st.title("GPX Track Viewer")
# File upload
uploaded_file = st.file_uploader("Upload GPX file", type=['gpx'])
if uploaded_file:
# Parse GPX file
gpx = gpxpy.parse(uploaded_file)
# Save to database
with Session(engine) as session:
track = Track(
user_id=st.session_state["password_correct"],
name=uploaded_file.name,
gpx_data=uploaded_file.getvalue(),
duration=gpx.get_duration()
)
session.add(track)
session.commit()
# Display tracks
with Session(engine) as session:
tracks = session.query(Track).all()
if tracks:
selected_track = st.selectbox(
"Select track to view",
options=tracks,
format_func=lambda x: x.name
)
if selected_track:
gpx = gpxpy.parse(selected_track.gpx_data.decode())
# Create map centered on the first point
points = []
for track in gpx.tracks:
for segment in track.segments:
for point in segment.points:
points.append([point.latitude, point.longitude])
points = np.array(points)
center_lat = np.mean(points[:, 0])
center_lon = np.mean(points[:, 1])
m = folium.Map(location=[center_lat, center_lon], zoom_start=12)
# Add the track
folium.PolyLine(
points,
weight=3,
color='red',
opacity=0.8
).add_to(m)
# Add start and end markers
folium.Marker(
points[0],
popup='Start',
icon=folium.Icon(color='green')
).add_to(m)
folium.Marker(
points[-1],
popup='End',
icon=folium.Icon(color='red')
).add_to(m)
# Display map
folium_static(m)
# Display track info
st.write(f"Duration: {selected_track.duration/3600:.2f} hours")
st.write(f"Distance: {gpx.tracks[0].length_3d()/1000:.2f} km")
# Replay controls
if st.button("Replay track"):
progress_bar = st.progress(0)
status_text = st.empty()
# Calculate total points for progress
total_points = len(points)
for i, point in enumerate(points):
# Update map center and marker
m = folium.Map(location=point, zoom_start=14)
# Add full track
folium.PolyLine(
points,
weight=3,
color='red',
opacity=0.8
).add_to(m)
# Add current position marker
folium.Marker(
point,
popup='Current Position',
icon=folium.Icon(color='blue')
).add_to(m)
# Update progress
progress = int((i + 1) * 100 / total_points)
progress_bar.progress(progress)
status_text.text(f'Progress: {progress}%')
# Display updated map
folium_static(m)
time.sleep(0.1) # Control replay speed
status_text.text('Replay complete!')
Hi! I can help you with any questions about Streamlit and Python. What would you like to know?