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("""
🚗 Advanced Traffic Analytics Dashboard
Upload your GPS tracking data and get comprehensive traffic analysis with route optimization and congestion detection
""") 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("""

🚗 Advanced Traffic Analytics

Powered by Machine Learning • Built with Gradio • GPS Data Analysis

Upload your traffic data and discover insights about popular routes and congestion patterns!

""") 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 )