yousefmazhar's picture
added PERSON_SEX
216e88d verified
import gradio as gr
import plotly.express as px
import plotly.graph_objects as go
import pandas as pd
import warnings
import re
warnings.filterwarnings('ignore', category=DeprecationWarning)
# Load data
print("Loading data...")
df = pd.read_parquet('nyc_crashes_integrated_clean.parquet')
df['CRASH DATE'] = pd.to_datetime(df['CRASH DATE'])
print(f"Data loaded: {len(df):,} records")
# Clean vehicle types
VALID_VEHICLE_TYPES = [
'SEDAN', 'STATION WAGON/SPORT UTILITY VEHICLE', 'TAXI', 'PICK-UP TRUCK',
'BOX TRUCK', 'VAN', 'MOTORCYCLE', 'SCOOTER', 'MOPED', 'E-SCOOTER', 'E-BIKE',
'BICYCLE', 'BUS', 'AMBULANCE', 'FIRE TRUCK', 'TRACTOR TRUCK DIESEL',
'TRACTOR TRUCK GASOLINE', 'DUMP', 'FLAT BED', 'GARBAGE OR REFUSE',
'CONCRETE MIXER', 'REFRIGERATED VAN', 'TRUCK', 'LIVERY VEHICLE',
'PASSENGER VEHICLE', '2 DR SEDAN', '4 DR SEDAN', 'CONVERTIBLE',
'SPORT UTILITY / STATION WAGON', 'LIMOUSINE', 'UNKNOWN'
]
df['VEHICLE TYPE CODE 1'] = df['VEHICLE TYPE CODE 1'].apply(
lambda x: x if x in VALID_VEHICLE_TYPES else 'OTHER'
)
df['VEHICLE TYPE CODE 2'] = df['VEHICLE TYPE CODE 2'].apply(
lambda x: x if x in VALID_VEHICLE_TYPES or x == 'NO SECOND VEHICLE' else 'OTHER'
)
print(f"Cleaned vehicle types. Valid categories: {len(df['VEHICLE TYPE CODE 1'].unique())}")
# Define column groups
TEMPORAL_COLS = ['CRASH_YEAR', 'CRASH_MONTH', 'CRASH_DAYOFWEEK', 'CRASH_HOUR']
CATEGORICAL_COLS = ['BOROUGH', 'PERSON_TYPE', 'PERSON_INJURY',
'CONTRIBUTING FACTOR VEHICLE 1', 'VEHICLE TYPE CODE 1',
'PERSON_SEX', 'SAFETY_EQUIPMENT', 'POSITION_IN_VEHICLE',
'EJECTION', 'EMOTIONAL_STATUS']
NUMERIC_COLS = ['NUMBER OF PERSONS INJURED', 'NUMBER OF PERSONS KILLED',
'NUMBER OF PEDESTRIANS INJURED', 'NUMBER OF PEDESTRIANS KILLED',
'NUMBER OF CYCLIST INJURED', 'NUMBER OF CYCLIST KILLED',
'NUMBER OF MOTORIST INJURED', 'NUMBER OF MOTORIST KILLED']
# Prepare dropdown options
boroughs = ['All'] + sorted([b for b in df['BOROUGH'].dropna().unique() if str(b) != 'nan'])
years = ['All'] + sorted([int(y) for y in df['CRASH_YEAR'].unique()])
months = ['All'] + list(range(1, 13))
vehicles = ['All'] + sorted(VALID_VEHICLE_TYPES + ['OTHER'])
person_types = ['All'] + sorted([p for p in df['PERSON_TYPE'].dropna().unique() if str(p) != 'nan'])
injury_types = ['All'] + sorted([i for i in df['PERSON_INJURY'].dropna().unique() if str(i) != 'nan'])
genders = ['All', 'M', 'F', 'U']
safety_equip = ['All'] + sorted([s for s in df['SAFETY_EQUIPMENT'].dropna().unique()
if str(s) not in ['nan', 'NOT APPLICABLE', 'NOT REPORTED', 'DOES NOT APPLY']][:15])
def smart_search_parser(search_text):
"""Parse natural language search query into filters"""
if not search_text:
return None
search_lower = search_text.lower()
filters = {}
applied_filters = []
# Borough detection
boroughs_map = ['BROOKLYN', 'MANHATTAN', 'QUEENS', 'BRONX', 'STATEN ISLAND']
for b in boroughs_map:
if b.lower() in search_lower:
filters['borough'] = b
applied_filters.append(f"Borough: {b}")
break
# Year detection
years_found = re.findall(r'\b(20[1-2][0-9])\b', search_text)
if years_found:
filters['year'] = int(years_found[0])
applied_filters.append(f"Year: {years_found[0]}")
# Month detection
months_map = {'january': 1, 'february': 2, 'march': 3, 'april': 4, 'may': 5, 'june': 6,
'july': 7, 'august': 8, 'september': 9, 'october': 10, 'november': 11, 'december': 12,
'jan': 1, 'feb': 2, 'mar': 3, 'apr': 4, 'jun': 6, 'jul': 7, 'aug': 8,
'sep': 9, 'oct': 10, 'nov': 11, 'dec': 12}
for m_name, m_num in months_map.items():
if m_name in search_lower:
filters['month'] = m_num
applied_filters.append(f"Month: {m_name.capitalize()}")
break
# Day of week detection
days_map = {'monday': [0], 'tuesday': [1], 'wednesday': [2], 'thursday': [3],
'friday': [4], 'saturday': [5], 'sunday': [6],
'mon': [0], 'tue': [1], 'wed': [2], 'thu': [3], 'fri': [4], 'sat': [5], 'sun': [6],
'weekday': [0, 1, 2, 3, 4], 'weekend': [5, 6]}
for day_name, day_nums in days_map.items():
if day_name in search_lower:
filters['dow'] = day_nums
applied_filters.append(f"Day: {day_name.capitalize()}")
break
# Time of day detection
if 'morning' in search_lower:
filters['hour_range'] = (6, 10)
applied_filters.append("Time: Morning (6-10)")
elif 'afternoon' in search_lower:
filters['hour_range'] = (12, 17)
applied_filters.append("Time: Afternoon (12-17)")
elif 'evening' in search_lower:
filters['hour_range'] = (17, 20)
applied_filters.append("Time: Evening (17-20)")
elif 'night' in search_lower:
filters['hour_range'] = (20, 23)
applied_filters.append("Time: Night (20-23)")
elif 'late night' in search_lower or 'midnight' in search_lower:
filters['hour_range'] = (0, 5)
applied_filters.append("Time: Late Night (0-5)")
# Vehicle type detection
vehicle_keywords = {
'sedan': 'SEDAN', 'suv': 'STATION WAGON/SPORT UTILITY VEHICLE',
'taxi': 'TAXI', 'truck': 'PICK-UP TRUCK', 'bus': 'BUS',
'motorcycle': 'MOTORCYCLE', 'bike': 'BICYCLE', 'scooter': 'SCOOTER',
'van': 'VAN', 'ambulance': 'AMBULANCE', 'moped': 'MOPED'
}
for keyword, vehicle_type in vehicle_keywords.items():
if keyword in search_lower:
filters['vehicle'] = vehicle_type
applied_filters.append(f"Vehicle: {keyword.capitalize()}")
break
# Person type detection
if 'pedestrian' in search_lower:
filters['person_type'] = 'PEDESTRIAN'
applied_filters.append("Person: Pedestrian")
elif 'cyclist' in search_lower:
filters['person_type'] = 'CYCLIST'
applied_filters.append("Person: Cyclist")
elif 'occupant' in search_lower or 'driver' in search_lower:
filters['person_type'] = 'OCCUPANT'
applied_filters.append("Person: Occupant")
# Injury type detection
if 'fatal' in search_lower or 'death' in search_lower or 'killed' in search_lower:
filters['injury'] = 'KILLED'
applied_filters.append("Injury: Fatal")
elif 'injured' in search_lower or 'injury' in search_lower:
filters['injury'] = 'INJURED'
applied_filters.append("Injury: Injured")
# Gender detection
if 'male' in search_lower and 'female' not in search_lower:
filters['gender'] = 'M'
applied_filters.append("Gender: Male")
elif 'female' in search_lower:
filters['gender'] = 'F'
applied_filters.append("Gender: Female")
return filters, applied_filters
def generate_report(borough, year, month, dow, hour_min, hour_max, vehicle, person_type,
person_injury, gender, safety, c1_x, c1_y, c3_x, c3_y, c3_top,
c4_x, c4_y, compare_cat):
"""Generate all visualizations based on filters"""
# Filter data
filtered_df = df.copy()
if borough != 'All':
filtered_df = filtered_df[filtered_df['BOROUGH'] == borough]
if year != 'All':
filtered_df = filtered_df[filtered_df['CRASH_YEAR'] == year]
if month != 'All':
filtered_df = filtered_df[filtered_df['CRASH_MONTH'] == month]
if dow:
filtered_df = filtered_df[filtered_df['CRASH_DAYOFWEEK'].isin(dow)]
filtered_df = filtered_df[(filtered_df['CRASH_HOUR'] >= hour_min) &
(filtered_df['CRASH_HOUR'] <= hour_max)]
if vehicle != 'All':
filtered_df = filtered_df[filtered_df['VEHICLE TYPE CODE 1'] == vehicle]
if person_type != 'All':
filtered_df = filtered_df[filtered_df['PERSON_TYPE'] == person_type]
if person_injury != 'All':
filtered_df = filtered_df[filtered_df['PERSON_INJURY'] == person_injury]
if gender != 'All':
filtered_df = filtered_df[filtered_df['PERSON_SEX'] == gender]
if safety != 'All':
filtered_df = filtered_df[filtered_df['SAFETY_EQUIPMENT'] == safety]
if len(filtered_df) == 0:
empty_fig = go.Figure()
empty_fig.add_annotation(text="No data found. Adjust filters.", xref="paper", yref="paper",
x=0.5, y=0.5, showarrow=False, font=dict(size=16, color="gray"))
return ("No data found", empty_fig, "", empty_fig, "", empty_fig, "", empty_fig, "",
empty_fig, "", empty_fig, "", empty_fig, "", empty_fig, "", empty_fig, "")
# Summary Statistics
total_records = len(filtered_df)
total_injuries = int(filtered_df['NUMBER OF PERSONS INJURED'].sum())
total_fatalities = int(filtered_df['NUMBER OF PERSONS KILLED'].sum())
injury_rate = (total_injuries / total_records * 100) if total_records > 0 else 0
fatality_rate = (total_fatalities / total_records * 100) if total_records > 0 else 0
summary_text = f"""
## πŸ“Š Summary Statistics
| Metric | Value |
|--------|-------|
| **Total Records** | {total_records:,} |
| **Total Injuries** | {total_injuries:,} ({injury_rate:.2f}%) |
| **Total Fatalities** | {total_fatalities:,} ({fatality_rate:.2f}%) |
| **Pedestrian Injuries** | {int(filtered_df['NUMBER OF PEDESTRIANS INJURED'].sum()):,} |
| **Cyclist Injuries** | {int(filtered_df['NUMBER OF CYCLIST INJURED'].sum()):,} |
| **Motorist Injuries** | {int(filtered_df['NUMBER OF MOTORIST INJURED'].sum()):,} |
| **Unique Crashes** | {len(filtered_df['COLLISION_ID'].unique()):,} |
| **Avg Persons/Crash** | {(total_records / len(filtered_df['COLLISION_ID'].unique())):.1f} |
"""
# Chart 1: Trend Analysis
if c1_y == 'count':
chart1_data = filtered_df.groupby(c1_x).size().reset_index(name='count')
y_label = 'Number of Records'
else:
chart1_data = filtered_df.groupby(c1_x)[c1_y].sum().reset_index()
y_label = c1_y
fig1 = px.line(chart1_data, x=c1_x, y=chart1_data.columns[1],
labels={chart1_data.columns[1]: y_label, c1_x: c1_x},
title='Trend Analysis')
fig1.update_traces(line_color='#3498db', line_width=3)
fig1.update_layout(template='plotly_white', height=400)
# Insight 1
max_val = chart1_data[chart1_data.columns[1]].max()
min_val = chart1_data[chart1_data.columns[1]].min()
max_cat = chart1_data.loc[chart1_data[chart1_data.columns[1]].idxmax(), c1_x]
min_cat = chart1_data.loc[chart1_data[chart1_data.columns[1]].idxmin(), c1_x]
insight1 = f"πŸ“ˆ **Insight:** Peak at {max_cat} ({max_val:,.0f}), lowest at {min_cat} ({min_val:,.0f})"
# Chart 2: Person Type Distribution
person_type_data = filtered_df['PERSON_TYPE'].value_counts()
fig2 = px.pie(values=person_type_data.values, names=person_type_data.index,
title='Person Type Distribution',
color_discrete_sequence=['#2ecc71', '#f39c12', '#e74c3c', '#3498db'])
fig2.update_layout(height=400)
# Insight 2
most_common = person_type_data.idxmax()
pct = (person_type_data.max() / person_type_data.sum() * 100)
insight2 = f"πŸ₯§ **Insight:** Most common person type: {most_common} ({pct:.1f}% of records)"
# Chart 3: Categorical Analysis
if c3_y == 'count':
chart3_data = filtered_df[c3_x].value_counts().head(int(c3_top))
y_label = 'Number of Records'
else:
chart3_data = filtered_df.groupby(c3_x)[c3_y].sum().sort_values(ascending=False).head(int(c3_top))
y_label = c3_y
fig3 = px.bar(x=chart3_data.index, y=chart3_data.values,
labels={'x': c3_x, 'y': y_label},
title=f'Categorical Analysis - Top {int(c3_top)}')
fig3.update_traces(marker_color='#3498db')
fig3.update_layout(template='plotly_white', height=400)
# Insight 3
max_cat3 = chart3_data.idxmax()
min_cat3 = chart3_data.idxmin()
insight3 = f"πŸ“Š **Insight:** Highest: {max_cat3} ({chart3_data.max():,.0f}), Lowest: {min_cat3} ({chart3_data.min():,.0f})"
# Chart 4: Time Distribution
if c4_y == 'count':
chart4_data = filtered_df[c4_x].value_counts().sort_index()
y_label = 'Number of Records'
else:
chart4_data = filtered_df.groupby(c4_x)[c4_y].sum().sort_index()
y_label = c4_y
fig4 = px.bar(x=chart4_data.index, y=chart4_data.values,
labels={'x': c4_x, 'y': y_label},
title='Time Distribution')
fig4.update_traces(marker_color='#e67e22')
fig4.update_layout(template='plotly_white', height=400)
# Insight 4
max_cat4 = chart4_data.idxmax()
min_cat4 = chart4_data.idxmin()
insight4 = f"⏰ **Insight:** Peak time: {max_cat4} ({chart4_data.max():,.0f}), Quietest: {min_cat4} ({chart4_data.min():,.0f})"
# Chart 5: Contributing Factor 1
factor1_data = filtered_df['CONTRIBUTING FACTOR VEHICLE 1'].value_counts().head(15)
factor1_data = factor1_data[factor1_data.index != 'UNSPECIFIED']
fig5 = px.bar(x=factor1_data.index, y=factor1_data.values,
labels={'x': 'Contributing Factor', 'y': 'Number of Crashes'},
title='Top Contributing Factors (Vehicle 1)')
fig5.update_traces(marker_color='#e74c3c')
fig5.update_layout(template='plotly_white', height=400, xaxis={'tickangle': -45})
# Insight 5
top_factor1 = factor1_data.idxmax() if len(factor1_data) > 0 else "N/A"
top_factor1_pct = (factor1_data.max() / len(filtered_df) * 100) if len(factor1_data) > 0 else 0
insight5 = f"🚨 **Insight:** Top cause: {top_factor1} ({factor1_data.max():,} crashes, {top_factor1_pct:.1f}%)"
# Chart 6: Contributing Factor 2
factor2_data = filtered_df['CONTRIBUTING FACTOR VEHICLE 2'].value_counts().head(15)
factor2_data = factor2_data[~factor2_data.index.isin(['UNSPECIFIED', 'NO SECOND VEHICLE'])]
if len(factor2_data) > 0:
fig6 = px.bar(x=factor2_data.index, y=factor2_data.values,
labels={'x': 'Secondary Contributing Factor', 'y': 'Number of Crashes'},
title='Top Contributing Factors (Vehicle 2)')
fig6.update_traces(marker_color='#f39c12')
fig6.update_layout(template='plotly_white', height=400, xaxis={'tickangle': -45})
# Insight 6
top_factor2 = factor2_data.idxmax()
top_factor2_pct = (factor2_data.max() / len(filtered_df) * 100)
insight6 = f"🚨 **Insight:** Top secondary cause: {top_factor2} ({factor2_data.max():,} crashes, {top_factor2_pct:.1f}%)"
else:
fig6 = go.Figure()
fig6.add_annotation(text="No secondary factors", xref="paper", yref="paper",
x=0.5, y=0.5, showarrow=False)
fig6.update_layout(height=400, title='Top Contributing Factors (Vehicle 2)')
insight6 = "ℹ️ **Note:** Most crashes involve only one vehicle or have unspecified secondary factors"
# Chart 7: Injury Rate Comparison
compare_data = filtered_df.groupby(compare_cat).agg({
'COLLISION_ID': 'count',
'NUMBER OF PERSONS INJURED': 'sum',
'NUMBER OF PERSONS KILLED': 'sum'
}).reset_index()
compare_data.columns = [compare_cat, 'Total_Records', 'Total_Injuries', 'Total_Fatalities']
compare_data['Injury_Rate'] = (compare_data['Total_Injuries'] / compare_data['Total_Records'] * 100)
compare_data['Fatality_Rate'] = (compare_data['Total_Fatalities'] / compare_data['Total_Records'] * 100)
# Map day numbers to names if comparing by day of week
if compare_cat == 'CRASH_DAYOFWEEK':
day_mapping = {
0: 'Monday',
1: 'Tuesday',
2: 'Wednesday',
3: 'Thursday',
4: 'Friday',
5: 'Saturday',
6: 'Sunday'
}
compare_data[compare_cat] = compare_data[compare_cat].map(day_mapping)
# Sort by day order
day_order = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday']
compare_data[compare_cat] = pd.Categorical(compare_data[compare_cat], categories=day_order, ordered=True)
compare_data = compare_data.sort_values(compare_cat)
else:
compare_data = compare_data.sort_values('Injury_Rate', ascending=False).head(15)
fig7 = go.Figure()
fig7.add_trace(go.Bar(x=compare_data[compare_cat], y=compare_data['Injury_Rate'],
name='Injury Rate (%)', marker_color='#f39c12'))
fig7.add_trace(go.Bar(x=compare_data[compare_cat], y=compare_data['Fatality_Rate'],
name='Fatality Rate (%)', marker_color='#e74c3c'))
fig7.update_layout(barmode='group', template='plotly_white', height=400,
title='Injury Rate Comparison',
xaxis_title=compare_cat, yaxis_title='Rate (%)')
# Insight 7
highest_injury = compare_data.loc[compare_data['Injury_Rate'].idxmax()]
highest_fatal = compare_data.loc[compare_data['Fatality_Rate'].idxmax()]
insight7 = f"⚠️ **Insight:** Highest injury rate: {highest_injury[compare_cat]} ({highest_injury['Injury_Rate']:.2f}%), Highest fatality rate: {highest_fatal[compare_cat]} ({highest_fatal['Fatality_Rate']:.2f}%)"
# Chart 8: Heatmap
heatmap_data = filtered_df.groupby(['CRASH_DAYOFWEEK', 'CRASH_HOUR']).size().reset_index(name='count')
if len(heatmap_data) > 0:
heatmap_pivot = heatmap_data.pivot(index='CRASH_DAYOFWEEK', columns='CRASH_HOUR', values='count')
fig8 = go.Figure(data=go.Heatmap(
z=heatmap_pivot.values,
x=heatmap_pivot.columns,
y=['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'],
colorscale='YlOrRd'
))
fig8.update_layout(xaxis_title='Hour of Day', yaxis_title='Day of Week',
title='Day Γ— Hour Heatmap', template='plotly_white', height=500)
# Insight 8
max_day = heatmap_pivot.sum(axis=1).idxmax()
max_hour = heatmap_pivot.sum(axis=0).idxmax()
day_names = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
insight8 = f"πŸ—“οΈ **Insight:** Busiest day: {day_names[max_day]}, Busiest hour: {max_hour}:00"
else:
fig8 = go.Figure()
fig8.update_layout(height=500, title='Day Γ— Hour Heatmap')
insight8 = ""
# Chart 9: Geographic Map
map_sample = filtered_df[(filtered_df['LATITUDE'].notna()) &
(filtered_df['LATITUDE'] != 0) &
(filtered_df['LATITUDE'] > 40) &
(filtered_df['LATITUDE'] < 41)]
if len(map_sample) > 0:
# Sample for performance
map_sample = map_sample.sample(n=min(3000, len(map_sample)), random_state=42)
# Create severity category combining injury and fatality
def categorize_severity(row):
if row['NUMBER OF PERSONS KILLED'] > 0:
return 'Fatal'
elif row['NUMBER OF PERSONS INJURED'] > 0:
return 'Injury'
else:
return 'Property Damage Only'
map_sample['SEVERITY_CATEGORY'] = map_sample.apply(categorize_severity, axis=1)
# Color mapping
color_map = {
'Fatal': '#e74c3c',
'Injury': '#f39c12',
'Property Damage Only': '#9d7aff'
}
fig9 = px.scatter_map(
map_sample,
lat='LATITUDE',
lon='LONGITUDE',
color='SEVERITY_CATEGORY',
color_discrete_map=color_map,
title=f'Geographic Distribution (Sample of {len(map_sample):,} locations)',
zoom=10,
height=600,
hover_data={
'LATITUDE': False,
'LONGITUDE': False,
'SEVERITY_CATEGORY': True,
'NUMBER OF PERSONS INJURED': True,
'NUMBER OF PERSONS KILLED': True,
'BOROUGH': True,
'VEHICLE TYPE CODE 1': True
}
)
fig9.update_layout(map_style="open-street-map")
# Insight 9
severity_counts = map_sample['SEVERITY_CATEGORY'].value_counts()
top_severity = severity_counts.idxmax() if len(severity_counts) > 0 else "N/A"
insight9 = f"πŸ—ΊοΈ **Insight:** Showing {len(map_sample):,} locations, most common severity: {top_severity}"
else:
fig9 = go.Figure()
fig9.add_annotation(
text="No location data available",
xref="paper", yref="paper",
x=0.5, y=0.5, showarrow=False,
font=dict(size=20, color="gray")
)
fig9.update_layout(height=600, title='Geographic Distribution')
insight9 = ""
return (summary_text, fig1, insight1, fig2, insight2, fig3, insight3, fig4, insight4,
fig5, insight5, fig6, insight6, fig7, insight7, fig8, insight8, fig9, insight9)
def apply_smart_search(search_text):
"""Apply smart search and return filter values"""
result = smart_search_parser(search_text)
if result is None:
return ['All'] * 11 + ["⚠️ No filters detected. Try: 'Brooklyn 2022 pedestrian crashes'"]
filters, applied = result
feedback = "βœ… Filters Applied: " + ", ".join(applied) + "\n\nClick 'Generate Report' to see results."
return (
filters.get('borough', 'All'),
filters.get('year', 'All'),
filters.get('month', 'All'),
filters.get('dow', []),
filters.get('hour_range', (0, 23))[0],
filters.get('hour_range', (0, 23))[1],
filters.get('vehicle', 'All'),
filters.get('person_type', 'All'),
filters.get('injury', 'All'),
filters.get('gender', 'All'),
filters.get('safety', 'All'),
feedback
)
# Create Gradio Interface
with gr.Blocks(title="NYC Motor Vehicle Crashes Dashboard") as demo:
gr.Markdown("# πŸš— NYC Motor Vehicle Crashes Dashboard - Enhanced Analytics")
gr.Markdown("### Comprehensive analysis with 5.7M+ crash records")
with gr.Accordion("πŸ”Ž Smart Search", open=True):
gr.Markdown("**Type natural language queries** like: `Brooklyn 2022 pedestrian crashes` or `Manhattan weekend taxi injured`")
with gr.Row():
search_input = gr.Textbox(label="Search Query",
placeholder="e.g., Queens Friday night motorcycle fatalities...",
scale=3)
search_btn = gr.Button("πŸ” Apply Smart Search", variant="primary", scale=1)
clear_search_btn = gr.Button("❌ Clear", variant="stop", scale=1)
search_feedback = gr.Markdown(visible=True)
with gr.Row():
with gr.Column(scale=1):
gr.Markdown("### πŸŽ›οΈ Filters")
borough = gr.Dropdown(choices=boroughs, value='All', label="Borough")
year = gr.Dropdown(choices=years, value='All', label="Year")
month = gr.Dropdown(choices=months, value='All', label="Month")
dow = gr.CheckboxGroup(
choices=[('Mon', 0), ('Tue', 1), ('Wed', 2), ('Thu', 3),
('Fri', 4), ('Sat', 5), ('Sun', 6)],
label="Day of Week", type="value"
)
with gr.Row():
hour_min = gr.Slider(minimum=0, maximum=23, value=0, step=1, label="Hour Min")
hour_max = gr.Slider(minimum=0, maximum=23, value=23, step=1, label="Hour Max")
vehicle = gr.Dropdown(choices=vehicles, value='All', label="Vehicle Type 1")
person_type = gr.Dropdown(choices=person_types, value='All', label="Person Type")
person_injury = gr.Dropdown(choices=injury_types, value='All', label="Person Injury")
gender = gr.Dropdown(choices=genders, value='All', label="Gender")
safety = gr.Dropdown(choices=safety_equip, value='All', label="Safety Equipment")
with gr.Column(scale=1):
gr.Markdown("### βš™οΈ Chart Settings")
c1_x = gr.Dropdown(choices=TEMPORAL_COLS, value='CRASH_YEAR', label="Chart 1 X-axis (Trend)")
c1_y = gr.Dropdown(choices=['count'] + NUMERIC_COLS, value='count', label="Chart 1 Y-axis")
c3_x = gr.Dropdown(choices=CATEGORICAL_COLS, value='BOROUGH', label="Chart 3 Category")
c3_y = gr.Dropdown(choices=['count'] + NUMERIC_COLS, value='count', label="Chart 3 Y-axis")
c3_top = gr.Slider(minimum=5, maximum=20, value=10, step=1, label="Chart 3 Top N")
c4_x = gr.Dropdown(choices=TEMPORAL_COLS, value='CRASH_HOUR', label="Chart 4 X-axis (Time)")
c4_y = gr.Dropdown(choices=['count'] + NUMERIC_COLS, value='count', label="Chart 4 Y-axis")
compare_cat = gr.Dropdown(
choices=['BOROUGH', 'VEHICLE TYPE CODE 1', 'PERSON_TYPE',
'SAFETY_EQUIPMENT', 'CRASH_HOUR', 'CRASH_DAYOFWEEK','CRASH_MONTH','CRASH_YEAR','POSITION_IN_VEHICLE','PERSON_SEX'],
value='BOROUGH', label="Comparison Category"
)
with gr.Row():
generate_btn = gr.Button("πŸ” Generate Report", variant="primary", size="lg", scale=2)
reset_btn = gr.Button("πŸ”„ Reset All Filters", variant="secondary", size="lg", scale=1)
# Outputs
summary_output = gr.Markdown(label="Summary Statistics")
with gr.Row():
with gr.Column():
chart1_output = gr.Plot(label="Chart 1: Trend Analysis")
insight1_output = gr.Markdown(label="Insight")
with gr.Column():
chart2_output = gr.Plot(label="Chart 2: Person Type Distribution")
insight2_output = gr.Markdown(label="Insight")
with gr.Row():
with gr.Column():
chart3_output = gr.Plot(label="Chart 3: Categorical Analysis")
insight3_output = gr.Markdown(label="Insight")
with gr.Column():
chart4_output = gr.Plot(label="Chart 4: Time Distribution")
insight4_output = gr.Markdown(label="Insight")
with gr.Row():
with gr.Column():
chart5_output = gr.Plot(label="Chart 5: Contributing Factor 1")
insight5_output = gr.Markdown(label="Insight")
with gr.Column():
chart6_output = gr.Plot(label="Chart 6: Contributing Factor 2")
insight6_output = gr.Markdown(label="Insight")
chart7_output = gr.Plot(label="Chart 7: Injury Rate Comparison")
insight7_output = gr.Markdown(label="Insight")
chart8_output = gr.Plot(label="Chart 8: Day Γ— Hour Heatmap")
insight8_output = gr.Markdown(label="Insight")
chart9_output = gr.Plot(label="Chart 9: Geographic Distribution Map")
insight9_output = gr.Markdown(label="Insight")
# Event handlers
generate_btn.click(
fn=generate_report,
inputs=[borough, year, month, dow, hour_min, hour_max, vehicle, person_type,
person_injury, gender, safety, c1_x, c1_y, c3_x, c3_y, c3_top,
c4_x, c4_y, compare_cat],
outputs=[summary_output,
chart1_output, insight1_output,
chart2_output, insight2_output,
chart3_output, insight3_output,
chart4_output, insight4_output,
chart5_output, insight5_output,
chart6_output, insight6_output,
chart7_output, insight7_output,
chart8_output, insight8_output,
chart9_output, insight9_output]
)
def reset_all():
return ('All', 'All', 'All', [], 0, 23, 'All', 'All', 'All', 'All', 'All', '')
reset_btn.click(
fn=reset_all,
outputs=[borough, year, month, dow, hour_min, hour_max, vehicle, person_type,
person_injury, gender, safety, search_feedback]
)
search_btn.click(
fn=apply_smart_search,
inputs=[search_input],
outputs=[borough, year, month, dow, hour_min, hour_max, vehicle, person_type,
person_injury, gender, safety, search_feedback]
)
clear_search_btn.click(
fn=lambda: ('', ''),
outputs=[search_input, search_feedback]
)
if __name__ == "__main__":
demo.launch(share=False)