GeoAnalytics / app.py
baiganinn's picture
in
86b6abc
import gradio as gr
import pandas as pd
import json
import matplotlib.pyplot as plt
import plotly.express as px
import plotly.graph_objects as go
from plotly.subplots import make_subplots
import numpy as np
from datetime import datetime
import warnings
warnings.filterwarnings('ignore')
# Import our predictor functions
from predictor import predict_traffic_patterns_with_plots
def validate_csv_file(file):
"""Validate the uploaded CSV file"""
try:
df = pd.read_csv(file.name)
required_columns = ['randomized_id', 'lat', 'lng']
optional_columns = ['azm', 'alt', 'spd']
missing_required = [col for col in required_columns if col not in df.columns]
available_optional = [col for col in optional_columns if col in df.columns]
if missing_required:
return False, f"❌ Missing required columns: {missing_required}", None, None
# Check data quality
if df.empty:
return False, "❌ The CSV file is empty", None, None
if df['lat'].isna().all() or df['lng'].isna().all():
return False, "❌ Latitude and longitude columns contain no valid data", None, None
# Basic statistics
stats = {
'total_records': len(df),
'unique_vehicles': df['randomized_id'].nunique(),
'date_range': f"{len(df):,} GPS points",
'required_columns': required_columns,
'optional_columns_found': available_optional,
'lat_range': (df['lat'].min(), df['lat'].max()),
'lng_range': (df['lng'].min(), df['lng'].max())
}
return True, "βœ… CSV file validated successfully!", df, stats
except Exception as e:
return False, f"❌ Error reading CSV file: {str(e)}", None, None
def create_summary_text(predictions, stats):
"""Create a beautiful summary text"""
if predictions['status'] != 'success':
return f"❌ **Analysis Failed**: {predictions.get('error_message', 'Unknown error')}"
summary = predictions['analysis_summary']
metadata = predictions['metadata']
text = f"""
# πŸš— Traffic Analysis Report
**Generated on:** {datetime.now().strftime("%Y-%m-%d %H:%M:%S")}
## πŸ“Š Dataset Overview
- **Total GPS Records:** {metadata['sample_size_used']:,}
- **Unique Vehicles:** {metadata['unique_vehicles']:,}
- **Geographic Coverage:** {stats['lat_range'][0]:.4f}Β° to {stats['lat_range'][1]:.4f}Β° (Lat), {stats['lng_range'][0]:.4f}Β° to {stats['lng_range'][1]:.4f}Β° (Lng)
## πŸ›£οΈ Popular Routes Analysis
- **Route Clusters Identified:** {summary['popular_routes']['total_route_clusters']}
### Top 5 Popular Routes:
"""
if summary['popular_routes']['top_5_routes']:
for i, route in enumerate(summary['popular_routes']['top_5_routes'], 1):
text += f"""
**Route {i}:** `{route['route_id']}`
- πŸš™ **Trips:** {route['trip_count']} ({route['popularity_percentage']:.1f}% of all routes)
- πŸ“ **Average Length:** {route['avg_length_km']:.2f} km
- πŸ“ **Start:** ({route['start_location']['lat']:.4f}, {route['start_location']['lng']:.4f})
- 🏁 **End:** ({route['end_location']['lat']:.4f}, {route['end_location']['lng']:.4f})
"""
else:
text += "\n*No popular routes identified in the dataset.*"
text += f"""
## 🚦 Congestion Analysis
- **Congestion Areas Found:** {summary['tight_places']['total_congestion_areas']}
- **Severity Breakdown:**
- πŸ”΄ High: {summary['tight_places']['severity_breakdown'].get('High', 0)}
- 🟑 Medium: {summary['tight_places']['severity_breakdown'].get('Medium', 0)}
- 🟒 Low: {summary['tight_places']['severity_breakdown'].get('Low', 0)}
### Top 5 Congestion Areas:
"""
if summary['tight_places']['top_5_congestion_areas']:
for i, area in enumerate(summary['tight_places']['top_5_congestion_areas'], 1):
severity_emoji = {'High': 'πŸ”΄', 'Medium': '🟑', 'Low': '🟒'}
text += f"""
**Area {i}:** `{area['area_id']}`
- {severity_emoji.get(area['severity'], 'βšͺ')} **Severity:** {area['severity']}
- πŸš— **Vehicles Affected:** {area['unique_vehicles']}
- ⚑ **Average Speed:** {area['avg_speed_kmh']:.1f} km/h
- πŸ“ **Location:** ({area['location']['lat']:.4f}, {area['location']['lng']:.4f})
- πŸ“ˆ **Congestion Score:** {area['congestion_score']:.2f}
"""
else:
text += "\n*No significant congestion areas detected.*"
return text
def analyze_traffic_data(file, sample_size, progress=gr.Progress()):
"""Main analysis function"""
if file is None:
return (
"❌ Please upload a CSV file first!",
"No analysis performed.",
None, None, None, None,
None, None
)
progress(0.1, desc="Validating CSV file...")
# Validate file
is_valid, message, df, stats = validate_csv_file(file)
if not is_valid:
return (
message,
"Please check your CSV file format and try again.",
None, None, None, None,
None, None
)
progress(0.2, desc="Starting traffic analysis...")
try:
# Run the analysis
progress(0.3, desc="Processing GPS data...")
predictions, figures = predict_traffic_patterns_with_plots(df, sample_size=sample_size)
if predictions['status'] != 'success':
return (
f"❌ Analysis failed: {predictions['error_message']}",
"Please check your data and try again.",
None, None, None, None,
None, None
)
progress(0.8, desc="Generating visualizations...")
# Create summary text
summary_text = create_summary_text(predictions, stats)
# Convert predictions to pretty JSON
json_output = json.dumps(predictions, indent=2, default=str)
progress(1.0, desc="Analysis complete!")
return (
"βœ… Analysis completed successfully!",
summary_text,
figures.get('popular_routes'),
figures.get('tight_places'),
figures.get('combined_analysis'),
figures.get('statistics_dashboard'),
json_output,
gr.update(visible=True)
)
except Exception as e:
return (
f"❌ Error during analysis: {str(e)}",
"An unexpected error occurred. Please check your data format.",
None, None, None, None,
None, None
)
def create_sample_data():
"""Create sample data for demonstration"""
np.random.seed(42)
n_points = 1000
n_vehicles = 50
# Create sample data around Astana coordinates
base_lat, base_lng = 51.1694, 71.4491
data = []
for vehicle_id in range(n_vehicles):
n_points_vehicle = np.random.randint(10, 30)
# Random walk for each vehicle
start_lat = base_lat + np.random.normal(0, 0.02)
start_lng = base_lng + np.random.normal(0, 0.02)
lat, lng = start_lat, start_lng
for i in range(n_points_vehicle):
# Random walk
lat += np.random.normal(0, 0.001)
lng += np.random.normal(0, 0.001)
data.append({
'randomized_id': f'vehicle_{vehicle_id}',
'lat': lat,
'lng': lng,
'azm': np.random.randint(0, 360),
'alt': np.random.randint(200, 400),
'spd': max(0, np.random.normal(30, 15))
})
df = pd.DataFrame(data)
sample_file = "sample_traffic_data.csv"
df.to_csv(sample_file, index=False)
return sample_file
# Custom CSS for beautiful styling
custom_css = """
.gradio-container {
max-width: 1200px !important;
margin: auto !important;
}
.header-text {
text-align: center;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
font-size: 2.5em;
font-weight: bold;
margin-bottom: 20px;
}
.description-text {
text-align: center;
font-size: 1.2em;
color: #666;
margin-bottom: 30px;
}
.status-success {
background-color: #d4edda;
border: 1px solid #c3e6cb;
color: #155724;
padding: 15px;
border-radius: 5px;
margin: 10px 0;
}
.status-error {
background-color: #f8d7da;
border: 1px solid #f5c6cb;
color: #721c24;
padding: 15px;
border-radius: 5px;
margin: 10px 0;
}
.plot-container {
border: 2px solid #e9ecef;
border-radius: 10px;
padding: 10px;
margin: 10px 0;
}
"""
# Create the Gradio interface
with gr.Blocks(css=custom_css, title="πŸš— Advanced Traffic Analytics", theme=gr.themes.Soft()) as app:
gr.HTML("""
<div class="header-text">
πŸš— Advanced Traffic Analytics Dashboard
</div>
<div class="description-text">
Upload your GPS tracking data and get comprehensive traffic analysis with route optimization and congestion detection
</div>
""")
with gr.Row():
with gr.Column(scale=1):
gr.Markdown("## πŸ“ Data Upload & Configuration")
file_input = gr.File(
label="πŸ“„ Upload CSV File",
file_types=[".csv"]
)
gr.Markdown("*Upload a CSV file with columns: randomized_id, lat, lng, azm (optional), alt (optional), spd (optional)*")
sample_size = gr.Slider(
minimum=1000,
maximum=1000000,
value=500000,
step=10000,
label="πŸ“Š Sample Size for Analysis"
)
gr.Markdown("*Number of GPS points to analyze (larger = more accurate but slower)*")
with gr.Row():
analyze_btn = gr.Button("πŸš€ Analyze Traffic Data", variant="primary", size="lg")
sample_btn = gr.Button("πŸ“‹ Generate Sample Data", variant="secondary")
gr.Markdown("### πŸ“‹ Required CSV Format:")
gr.Markdown("""
- **randomized_id**: Vehicle identifier
- **lat**: Latitude (required)
- **lng**: Longitude (required)
- **azm**: Azimuth/bearing (optional)
- **alt**: Altitude (optional)
- **spd**: Speed (optional)
""")
with gr.Column(scale=2):
gr.Markdown("## πŸ“ˆ Analysis Status")
status_output = gr.Textbox(
label="Status",
value="Ready to analyze. Please upload a CSV file.",
interactive=False
)
# Results section
with gr.Row(visible=False) as results_section:
gr.Markdown("## πŸ“Š Analysis Results")
with gr.Row():
with gr.Column():
summary_output = gr.Markdown("## Analysis Summary")
with gr.Row():
with gr.Column():
gr.Markdown("### πŸ›£οΈ Popular Routes Visualization")
plot1 = gr.Plot(label="Popular Routes Map")
with gr.Column():
gr.Markdown("### 🚦 Congestion Areas")
plot2 = gr.Plot(label="Traffic Congestion Heatmap")
with gr.Row():
with gr.Column():
gr.Markdown("### πŸ—ΊοΈ Combined Analysis")
plot3 = gr.Plot(label="Routes & Congestion Combined")
with gr.Column():
gr.Markdown("### πŸ“ˆ Statistical Dashboard")
plot4 = gr.Plot(label="Traffic Statistics")
with gr.Row():
with gr.Column():
gr.Markdown("### πŸ“„ Raw JSON Output")
json_output = gr.Code(
label="Analysis Results (JSON)",
language="json",
lines=20
)
# Event handlers
analyze_btn.click(
fn=analyze_traffic_data,
inputs=[file_input, sample_size],
outputs=[
status_output,
summary_output,
plot1,
plot2,
plot3,
plot4,
json_output,
results_section
]
)
sample_btn.click(
fn=create_sample_data,
outputs=file_input
)
# Footer
gr.HTML("""
<div style="text-align: center; margin-top: 50px; padding: 20px; background-color: #f8f9fa; border-radius: 10px; color: black;">
<h3 style="color: black;">πŸš— Advanced Traffic Analytics</h3>
<p style="color: black;">Powered by Machine Learning β€’ Built with Gradio β€’ GPS Data Analysis</p>
<p style="color: black;"><em>Upload your traffic data and discover insights about popular routes and congestion patterns!</em></p>
</div>
""")
if __name__ == "__main__":
print("πŸš€ Starting Advanced Traffic Analytics Dashboard...")
print("πŸ“Š Features:")
print(" β€’ Popular Routes Detection")
print(" β€’ Congestion Area Analysis")
print(" β€’ Statistical Dashboards")
print(" β€’ Interactive Visualizations")
print("\n🌐 Opening in browser...")
app.launch(
share=True,
show_error=True,
debug=True,
server_name="0.0.0.0",
server_port=7860
)