Spaces:
Sleeping
Sleeping
| 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 | |
| ) | |