hyzhang00 commited on
Commit
1e5c28a
·
verified ·
1 Parent(s): 4243537

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +295 -181
app.py CHANGED
@@ -80,8 +80,8 @@ def create_severity_violation_chart(df, age_group=None):
80
  y='count',
81
  color='Severity',
82
  title=f'Crash Severity Distribution by Violation Type - {age_group}',
83
- labels={'count': 'Number of Incidents', 'Violation': 'Violation Type'},
84
  height=600,
 
85
  color_discrete_map=severity_colors, # --> for part 3
86
  )
87
 
@@ -94,9 +94,16 @@ def create_severity_violation_chart(df, age_group=None):
94
  # modified the above code because x-axis labels were partially pruned
95
  fig.update_layout(
96
  xaxis_tickangle=-45,
97
- legend_title='Severity Level',
 
 
 
 
 
 
 
98
  barmode='stack',
99
- margin=dict(t=50, b=150), # Increase bottom margin to avoid pruning
100
  xaxis=dict(automargin=True)
101
  )
102
 
@@ -104,16 +111,22 @@ def create_severity_violation_chart(df, age_group=None):
104
  return fig, violations
105
 
106
  def get_top_violations(df, age_group):
 
107
  if age_group == 'All Ages':
 
 
108
  violations = pd.concat([
109
  df['Violation1_Drv1'].value_counts(),
110
  df['Violation1_Drv2'].value_counts()
111
  ]).groupby(level=0).sum()
112
  else:
 
113
  filtered_df = df[
114
  (df['Age_Group_Drv1'] == age_group) |
115
  (df['Age_Group_Drv2'] == age_group)
116
  ]
 
 
117
  violations = pd.concat([
118
  filtered_df['Violation1_Drv1'].value_counts(),
119
  filtered_df['Violation1_Drv2'].value_counts()
@@ -122,13 +135,17 @@ def get_top_violations(df, age_group):
122
  # Convert to DataFrame and format
123
  violations_df = violations.reset_index()
124
  violations_df.columns = ['Violation Type', 'Count']
125
- violations_df['Percentage'] = (violations_df['Count'] / violations_df['Count'].sum() * 100).round(2)
 
 
 
 
 
126
  violations_df['Percentage'] = violations_df['Percentage'].map('{:.2f}%'.format)
127
 
128
  return violations_df.head()
129
 
130
- # added interactivity pie plot for part3 (linked with crash stats visualization)
131
- # def create_interactive_pie_chart(violations, selected_violation):
132
  def create_interactive_pie_chart(violations, selected_violation, selected_age):
133
  # Filter data based on selected violation
134
  filtered_data = violations[violations['Violation'] == selected_violation]
@@ -145,20 +162,53 @@ def create_interactive_pie_chart(violations, selected_violation, selected_age):
145
  )
146
 
147
  return fig
 
 
 
 
 
 
148
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
149
  @st.cache_data
150
- def create_map(df, selected_year):
 
151
  filtered_df = df[df['Year'] == selected_year]
152
-
 
 
 
 
 
 
 
 
153
  m = folium.Map(
154
- location=[33.4255, -111.9400],
155
  zoom_start=12,
156
  control_scale=True,
157
  tiles='CartoDB positron'
158
  )
159
 
160
- marker_cluster = MarkerCluster().add_to(m)
161
-
 
 
162
  for _, row in filtered_df.iterrows():
163
  folium.Marker(
164
  location=[row['Latitude'], row['Longitude']],
@@ -166,15 +216,17 @@ def create_map(df, selected_year):
166
  icon=folium.Icon(color='red')
167
  ).add_to(marker_cluster)
168
 
 
169
  heat_data = filtered_df[['Latitude', 'Longitude']].values.tolist()
170
- HeatMap(heat_data, radius=15, max_zoom=13, min_opacity=0.3).add_to(m)
171
 
 
172
  return m
173
 
174
  def create_injuries_fatalities_chart(crash_data, unit_type):
175
 
176
  # 5th visualization title
177
- st.header("Total Injuries and Fatalities by Month")
178
 
179
  # Filter rows where we have valid data for all necessary columns
180
  crash_data = crash_data[['DateTime', 'Totalinjuries', 'Totalfatalities', 'Unittype_One', 'Unittype_Two']].dropna()
@@ -213,10 +265,10 @@ def create_injuries_fatalities_chart(crash_data, unit_type):
213
 
214
  # Reshape the data for easier plotting
215
  injuries = monthly_sum[['Month', 'Totalinjuries']].rename(columns={'Totalinjuries': 'Value'})
216
- injuries['Type'] = 'Total Injuries'
217
 
218
  fatalities = monthly_sum[['Month', 'Totalfatalities']].rename(columns={'Totalfatalities': 'Value'})
219
- fatalities['Type'] = 'Total Fatalities'
220
 
221
  combined_data = pd.concat([injuries, fatalities])
222
 
@@ -263,8 +315,8 @@ def create_injuries_fatalities_chart(crash_data, unit_type):
263
  line_chart = alt.Chart(combined_data).mark_line(point=True).encode(
264
  x=alt.X('Month:N', sort=month_order, title='Month'),
265
  y=alt.Y('Value:Q', title='Total Injuries & Fatalities'),
266
- color=alt.Color('Type:N', title='', scale=alt.Scale(domain=['Total Injuries', 'Total Fatalities'], range=['blue', 'red'])),
267
- tooltip=['Month', 'Type:N', 'Value:Q']
268
  ).properties(
269
  title=f'Total Injuries and Fatalities by Month for Unit Type Pair: {unit_type}',
270
  width=600,
@@ -339,7 +391,7 @@ def create_category_distribution_chart(df, selected_category, selected_year):
339
  barmode='stack',
340
  xaxis_tickangle=-45,
341
  legend_title='Injury Severity',
342
- margin=dict(t=50, b=100),
343
  )
344
 
345
  return fig
@@ -371,21 +423,21 @@ def main():
371
  </style>
372
  """, unsafe_allow_html=True)
373
 
374
- st.markdown("<div class='title'><h1> Accident Analysis for City of Tempe, Arizona </h1></div>", unsafe_allow_html=True)
375
 
376
 
377
  st.markdown("""
378
  **Team Members:**
379
- - Janhavi Tushar Zarapkar [email protected]
380
  - Hangyue Zhang ([email protected])
381
  - Andrew Nam ([email protected])
382
  - Nirmal Attarde ([email protected])
383
- - Maanas Sandeep Agrawa ([email protected])
384
  """)
385
 
386
 
387
  st.markdown("""
388
- ### Introduction to the Traffic Accident Dataset
389
  This dataset contains detailed information about traffic accidents in the city of **Tempe**. It includes various attributes of the accidents, such as the severity of injuries, the demographics of the drivers involved, the locations of the incidents, and the conditions at the time of the accidents. The dataset covers accidents that occurred over several years, with data on factors like **weather conditions**, **road surface conditions**, the **time of day**, and the type of **violations** (e.g., alcohol or drug use) that may have contributed to the accident.
390
 
391
  The data was sourced from **Tempe City's traffic incident reports** and provides a comprehensive view of the factors influencing road safety and accident severity in the city. By analyzing this dataset, we can gain insights into the key contributors to traffic incidents and uncover trends that could help improve traffic safety measures, urban planning, and law enforcement policies in the city.
@@ -399,137 +451,176 @@ def main():
399
  if 'Weather' not in df.columns:
400
  df['Weather'] = 'Unknown'
401
 
402
- # Initialize session state to store selected violation --> added for part3 (interactive pie chart)
403
  if 'selected_violation' not in st.session_state:
404
  st.session_state['selected_violation'] = None
405
 
 
 
 
 
406
  # Create tabs for different visualizations
407
- tab1, tab2, tab3, tab4, tab5 = st.tabs(["Crash Statistics", "Crash Map", "Crash Trend", "Crash Injuries/Fatalities","Distribution by Category"])
 
 
 
 
 
 
408
 
409
  with tab1:
410
- # Age group selection
411
- age_groups = ['All Ages', '16-25', '26-35', '36-45', '46-55', '56-65', '65+']
412
- selected_age = st.selectbox('Select Age Group:', age_groups)
413
-
414
- # Create and display chart
415
- # fig = create_severity_violation_chart(df, selected_age)
416
- fig, violations = create_severity_violation_chart(df, selected_age) # --> for part3 (interactive pie chart)
417
- # st.plotly_chart(fig, use_container_width=True)
418
-
419
- # Display the first bar chart and capture click events using plotly_events
420
- clicked_points = plotly_events(fig, click_event=True, override_height=600, override_width="100%") # added for part3 (interactive pie chart)
421
-
422
- # If a bar is clicked, update the selected_violation in session_state --> added for part3 (interactive pie chart)
423
- if clicked_points:
424
- selected_violation = clicked_points[0]['x']
425
- if selected_violation != st.session_state['selected_violation']:
426
- st.session_state['selected_violation'] = selected_violation
427
-
428
- # If a violation is selected, display the pie chart --> added for part3 (interactive pie chart)
429
- if st.session_state['selected_violation']:
430
- # pie_chart = create_interactive_pie_chart(violations, st.session_state['selected_violation'])
431
- pie_chart = create_interactive_pie_chart(violations, st.session_state['selected_violation'], selected_age) # dynamically update pie chart's title
432
- st.plotly_chart(pie_chart, use_container_width=True)
433
-
434
- # Display statistics
435
- if selected_age == 'All Ages':
436
- total_incidents = len(df)
437
- else:
438
- total_incidents = len(df[
439
- (df['Age_Group_Drv1'] == selected_age) |
440
- (df['Age_Group_Drv2'] == selected_age)
441
- ])
442
-
443
- # Create two columns for statistics
444
- col1, col2 = st.columns(2)
445
-
446
- with col1:
447
- st.markdown(f"### Total Incidents")
448
- st.markdown(f"**{total_incidents:,}** incidents for {selected_age}")
449
 
450
- with col2:
451
- st.markdown("### Top Violations")
452
- top_violations = get_top_violations(df, selected_age)
453
- st.table(top_violations)
454
-
455
- with tab2:
456
- # Year selection for map
457
- years = sorted(df['Year'].unique())
458
- selected_year = st.selectbox('Select Year:', years)
459
 
460
- map_col, desc_col = st.columns([7, 3])
 
 
 
 
 
 
 
 
461
 
462
- with map_col:
463
- # Create and display map
464
- st.markdown("### Crash Location Map")
465
- map_placeholder = st.empty()
466
- with map_placeholder:
467
- m = create_map(df, selected_year)
468
- map_data = st_folium(
469
- m,
470
- width=None,
471
- height=800,
472
- key=f"map_{selected_year}",
473
- returned_objects=["null_drawing"]
474
- )
475
 
476
  with desc_col:
477
  st.markdown("""
478
- ### Traffic Crash Location Map
479
- This interactive map visualizes traffic accidents in Tempe for the selected year. It combines **marker clustering** and a **heatmap** to show:
480
- 1. **Accident Markers**: Red markers indicate individual accidents, with popups displaying the coordinates, date/time, and severity of each incident.
481
- 2. **Heatmap**: The heatmap highlights accident hotspots with colors ranging from blue (low frequency) to yellow (moderate) and red (high frequency), showing areas with more frequent accidents.
482
 
483
  **Key Features:**
484
- * **Interactive Year Selection**: Users can select a year to view accidents for that specific time.
485
- * **Accident Patterns**: The map reveals accident-prone areas and severity patterns, helping identify dangerous locations.
 
 
 
 
 
486
 
487
- **Color Scheme:**
488
- * **Red**: Individual accident markers.
489
- * **Blue to Red**: Heatmap colors indicate accident frequency, from low (blue) to high (red).
490
 
491
- This map provides insights into accident trends and can help guide safety improvements in the city.
 
 
 
492
  """)
 
 
 
 
 
493
 
494
-
495
- with tab3:
496
- # Weather condition filter
497
- weather = ['All Conditions'] + sorted(df['Weather'].unique())
498
- selected_weather = st.selectbox('Select Weather Condition:', weather)
499
 
500
- # Create and display line graph
 
 
501
 
502
- trend_col, desc_col = st.columns([7, 3])
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
503
 
504
- with trend_col:
505
- st.markdown("### Crash Trend Over Time")
506
- trend_fig = create_crash_trend_chart(df, selected_weather)
507
- # Update the figure layout for larger size
508
- trend_fig.update_layout(
509
- height=800, # Increased height
510
- width=None, # Let width be responsive
511
  margin=dict(l=50, r=50, t=50, b=50)
512
  )
513
- st.plotly_chart(trend_fig, use_container_width=True)
514
 
515
  with desc_col:
516
- st.markdown("""
517
- ## **Crash Trend Over Time**
518
- This interactive line chart visualizes the trend of unique traffic crashes over the years, optionally filtered by weather conditions. It highlights how crash frequency changes over time, helping identify trends and potential contributing factors.
519
- **Key Features:**
520
- * **Time Trend Analysis**: Displays the total number of unique crashes for each year, showing long-term patterns.
521
- * **Weather Filter**: Users can filter the data by weather conditions (e.g., "Rainy", "Sunny") to analyze how weather impacts crash trends.
522
- * **Interactive Tooltips**: Hovering over data points reveals the exact crash count for each year, providing detailed insights.
523
- **Color Scheme and Design:**
524
- * **Line and Markers**: A smooth line connects data points, with prominent markers for each year to highlight trends clearly.
525
- * **Dynamic Title**: The chart updates its title to reflect the selected weather condition or "All Conditions" for the overall trend.
526
- **Insights:**
527
- This chart helps uncover:
528
- * Annual fluctuations in crash incidents.
529
- * Correlations between weather conditions and crash frequencies.
530
- * Historical patterns that can guide future safety measures and urban planning decisions
531
- """)
532
-
533
 
534
  with tab4:
535
  # Dropdown for Unit Type selection
@@ -541,27 +632,12 @@ def main():
541
  unit_type_pairs = sorted(list(unit_type_pairs))
542
  unit_type = st.selectbox("Select Unit Type Pair", options=['Total'] + unit_type_pairs)
543
 
544
- # # Create 5th Visualization: Injuries and fatalities chart
545
- # injuries_fatalities_chart = create_injuries_fatalities_chart(df, unit_type)
546
- # st.altair_chart(injuries_fatalities_chart, use_container_width=True)
547
-
548
- # st.markdown("""
549
- # This line chart shows the **total number of injuries and fatalities by month for the selected unit type pair**. The blue line represents total injuries, while the red line represents total fatalities. Observing the trends over the months can help identify any seasonal patterns or peaks in traffic incidents involving specific unit types.
550
-
551
- # - **Total Injuries**: The blue line indicates how injuries vary over different months, highlighting any particular spikes or declines.
552
- # - **Total Fatalities**: The red line shows the trend for fatalities, which is generally much lower compared to injuries.
553
- # - **Unit Types**: The dropdown selection allows users to filter the data by specific unit type pairs (e.g., Driver vs Pedestrian) or view the overall trend across all types.
554
-
555
- # This visualization aims to provide an intuitive understanding of how injuries and fatalities are distributed across the year, helping stakeholders develop targeted safety measures.
556
- # """)
557
-
558
  chart_col, desc_col = st.columns([7, 3])
559
 
560
  with chart_col:
561
- # Create 5th Visualization: Injuries and fatalities chart
562
  injuries_fatalities_chart = create_injuries_fatalities_chart(df, unit_type)
563
  injuries_fatalities_chart = injuries_fatalities_chart.properties(
564
- height=800 # Make the chart taller to match the description column
565
  )
566
  st.altair_chart(injuries_fatalities_chart, use_container_width=True)
567
 
@@ -595,50 +671,88 @@ def main():
595
 
596
  This visualization aids stakeholders in developing effective safety measures and resource allocation strategies throughout the year.
597
  """)
598
-
599
-
600
-
601
  with tab5:
602
- # Dropdown for category selection
603
- categories = [
604
- 'Collisionmanner',
605
- 'Lightcondition',
606
- 'Weather',
607
- 'SurfaceCondition',
608
- 'AlcoholUse_Drv1',
609
- 'Gender_Drv1',
610
- ]
611
- selected_category = st.selectbox("Select Category:", categories)
612
-
613
- # Dropdown for year selection
614
- years = ['All Years'] + sorted(df['Year'].dropna().unique().astype(int).tolist())
615
- selected_year = st.selectbox("Select Year:", years)
616
-
617
- chart_col, desc_col = st.columns([7, 3])
618
 
619
- with chart_col:
620
- st.markdown(f"### Distribution of Incidents by {selected_category}")
621
- distribution_chart = create_category_distribution_chart(df, selected_category, selected_year)
622
- # Update the figure layout for larger size
623
- distribution_chart.update_layout(
624
- height=800, # Increased height
625
- width=None, # Let width be responsive
626
- margin=dict(l=50, r=50, t=50, b=50)
 
 
 
 
 
 
627
  )
628
- st.plotly_chart(distribution_chart, use_container_width=True)
629
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
630
  with desc_col:
631
  st.markdown("""
632
- ## Distribution by Category
633
- This visualization explores the distribution of traffic incidents across various categories, such as Collision Manner, Weather, Surface Condition, Alcohol Use, and Driver Gender. Each bar represents a specific category value (e.g., "Male" or "Female" for Gender), and the bars are divided into segments based on Injury Severity (e.g., Minor, Moderate, Serious, Fatal).
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
634
 
635
- **Key features include:**
636
- * Interactive Filters: Select a category and filter by year to analyze trends over time.
637
- * Insightful Tooltips: Hover over each segment to view the exact count and percentage of incidents for a given severity level.
638
- * Comparative Analysis: Quickly identify how different conditions or behaviors correlate with injury severity.
639
 
640
- This chart provides actionable insights into factors contributing to traffic incidents and their outcomes, helping stakeholders target interventions and improve road safety.
641
- """)
 
 
642
 
643
 
644
  if __name__ == "__main__":
 
80
  y='count',
81
  color='Severity',
82
  title=f'Crash Severity Distribution by Violation Type - {age_group}',
 
83
  height=600,
84
+ labels={'count': 'Number of Incidents', 'Violation': 'Violation Type'},
85
  color_discrete_map=severity_colors, # --> for part 3
86
  )
87
 
 
94
  # modified the above code because x-axis labels were partially pruned
95
  fig.update_layout(
96
  xaxis_tickangle=-45,
97
+ legend=dict(
98
+ orientation='v',
99
+ x=1,
100
+ y=1,
101
+ yanchor='top',
102
+ xanchor='left',
103
+ title="Severity Level"
104
+ ),
105
  barmode='stack',
106
+ margin=dict(t=50, b=150,r=0), # Increase bottom margin to avoid pruning
107
  xaxis=dict(automargin=True)
108
  )
109
 
 
111
  return fig, violations
112
 
113
  def get_top_violations(df, age_group):
114
+ # Calculate total incidents for the age group
115
  if age_group == 'All Ages':
116
+ total_incidents = len(df)
117
+ # Get violations for all ages
118
  violations = pd.concat([
119
  df['Violation1_Drv1'].value_counts(),
120
  df['Violation1_Drv2'].value_counts()
121
  ]).groupby(level=0).sum()
122
  else:
123
+ # Filter for specific age group
124
  filtered_df = df[
125
  (df['Age_Group_Drv1'] == age_group) |
126
  (df['Age_Group_Drv2'] == age_group)
127
  ]
128
+ total_incidents = len(filtered_df)
129
+ # Get violations for specific age group
130
  violations = pd.concat([
131
  filtered_df['Violation1_Drv1'].value_counts(),
132
  filtered_df['Violation1_Drv2'].value_counts()
 
135
  # Convert to DataFrame and format
136
  violations_df = violations.reset_index()
137
  violations_df.columns = ['Violation Type', 'Count']
138
+
139
+ # Sort by Count in descending order
140
+ violations_df = violations_df.sort_values('Count', ascending=False)
141
+
142
+ # Calculate percentage of total incidents
143
+ violations_df['Percentage'] = (violations_df['Count'] / total_incidents * 100).round(2)
144
  violations_df['Percentage'] = violations_df['Percentage'].map('{:.2f}%'.format)
145
 
146
  return violations_df.head()
147
 
148
+
 
149
  def create_interactive_pie_chart(violations, selected_violation, selected_age):
150
  # Filter data based on selected violation
151
  filtered_data = violations[violations['Violation'] == selected_violation]
 
162
  )
163
 
164
  return fig
165
+
166
+ def create_map_bar_chart(df, selected_year):
167
+ # Create severity count bar chart
168
+ filtered_df = df[df['Year'] == selected_year]
169
+ severity_count = filtered_df['Injuryseverity'].value_counts().reset_index()
170
+ severity_count.columns = ['Injuryseverity', 'Count']
171
 
172
+ fig = px.bar(
173
+ severity_count,
174
+ x='Injuryseverity',
175
+ y='Count',
176
+ title="Accidents by Severity",
177
+ labels={'Injuryseverity': 'Severity', 'Count': 'Number of Accidents'} # Adjust height as needed
178
+ )
179
+ fig.update_traces(marker_color='blue')
180
+ fig.update_layout(
181
+ clickmode='event+select', # Enable interactivity
182
+ xaxis_tickangle=45, # Rotate x-axis labels 45 degrees
183
+ margin=dict(t=50, b=150, r=20), # Add bottom margin to prevent label cutoff
184
+ )
185
+ return fig
186
+
187
+
188
  @st.cache_data
189
+ def create_map(df, selected_year, selected_severity=None):
190
+ # Filter data by selected year
191
  filtered_df = df[df['Year'] == selected_year]
192
+
193
+ # Filter further by selected severity if provided
194
+ if selected_severity:
195
+ filtered_df = filtered_df[filtered_df['Injuryseverity'] == selected_severity]
196
+
197
+ # Remove rows with missing latitude or longitude
198
+ filtered_df = filtered_df.dropna(subset=['Latitude', 'Longitude'])
199
+
200
+ # Create the map
201
  m = folium.Map(
202
+ location=[33.4255, -111.9400], # Default location (can be customized)
203
  zoom_start=12,
204
  control_scale=True,
205
  tiles='CartoDB positron'
206
  )
207
 
208
+ # Add marker cluster
209
+ marker_cluster = MarkerCluster(name="Accident Locations").add_to(m)
210
+
211
+ # Add accident markers
212
  for _, row in filtered_df.iterrows():
213
  folium.Marker(
214
  location=[row['Latitude'], row['Longitude']],
 
216
  icon=folium.Icon(color='red')
217
  ).add_to(marker_cluster)
218
 
219
+ # Add heatmap
220
  heat_data = filtered_df[['Latitude', 'Longitude']].values.tolist()
221
+ HeatMap(heat_data, radius=15, max_zoom=13, min_opacity=0.3, name="Heat Map").add_to(m)
222
 
223
+ folium.LayerControl().add_to(m)
224
  return m
225
 
226
  def create_injuries_fatalities_chart(crash_data, unit_type):
227
 
228
  # 5th visualization title
229
+ # st.header("5. Total Injuries and Fatalities by Month")
230
 
231
  # Filter rows where we have valid data for all necessary columns
232
  crash_data = crash_data[['DateTime', 'Totalinjuries', 'Totalfatalities', 'Unittype_One', 'Unittype_Two']].dropna()
 
265
 
266
  # Reshape the data for easier plotting
267
  injuries = monthly_sum[['Month', 'Totalinjuries']].rename(columns={'Totalinjuries': 'Value'})
268
+ injuries['Measure'] = 'Total Injuries'
269
 
270
  fatalities = monthly_sum[['Month', 'Totalfatalities']].rename(columns={'Totalfatalities': 'Value'})
271
+ fatalities['Measure'] = 'Total Fatalities'
272
 
273
  combined_data = pd.concat([injuries, fatalities])
274
 
 
315
  line_chart = alt.Chart(combined_data).mark_line(point=True).encode(
316
  x=alt.X('Month:N', sort=month_order, title='Month'),
317
  y=alt.Y('Value:Q', title='Total Injuries & Fatalities'),
318
+ color=alt.Color('Measure:N', title='', scale=alt.Scale(domain=['Total Injuries', 'Total Fatalities'], range=['blue', 'red'])),
319
+ tooltip=['Month', 'Measure:N', 'Value:Q']
320
  ).properties(
321
  title=f'Total Injuries and Fatalities by Month for Unit Type Pair: {unit_type}',
322
  width=600,
 
391
  barmode='stack',
392
  xaxis_tickangle=-45,
393
  legend_title='Injury Severity',
394
+ margin=dict(t=50, b=150, l=50, r=50),
395
  )
396
 
397
  return fig
 
423
  </style>
424
  """, unsafe_allow_html=True)
425
 
426
+ st.markdown("<div class='title'><h1> Accident Analysis for City of Tempe,Arizona </h1></div>", unsafe_allow_html=True)
427
 
428
 
429
  st.markdown("""
430
  **Team Members:**
431
+ - Janhavi Tushar Zarapkar ([email protected])
432
  - Hangyue Zhang ([email protected])
433
  - Andrew Nam ([email protected])
434
  - Nirmal Attarde ([email protected])
435
+ - Maanas Sandeep Agrawal ([email protected])
436
  """)
437
 
438
 
439
  st.markdown("""
440
+ # Introduction to the Traffic Accident Dataset
441
  This dataset contains detailed information about traffic accidents in the city of **Tempe**. It includes various attributes of the accidents, such as the severity of injuries, the demographics of the drivers involved, the locations of the incidents, and the conditions at the time of the accidents. The dataset covers accidents that occurred over several years, with data on factors like **weather conditions**, **road surface conditions**, the **time of day**, and the type of **violations** (e.g., alcohol or drug use) that may have contributed to the accident.
442
 
443
  The data was sourced from **Tempe City's traffic incident reports** and provides a comprehensive view of the factors influencing road safety and accident severity in the city. By analyzing this dataset, we can gain insights into the key contributors to traffic incidents and uncover trends that could help improve traffic safety measures, urban planning, and law enforcement policies in the city.
 
451
  if 'Weather' not in df.columns:
452
  df['Weather'] = 'Unknown'
453
 
 
454
  if 'selected_violation' not in st.session_state:
455
  st.session_state['selected_violation'] = None
456
 
457
+ if "selected_severity" not in st.session_state:
458
+ st.session_state["selected_severity"] = None
459
+
460
+
461
  # Create tabs for different visualizations
462
+ tab1, tab2, tab3, tab4, tab5 = st.tabs([
463
+ "Crash Trend",
464
+ "Violation-Severity Analysis",
465
+ "Distribution by Category",
466
+ "Crash Injuries/Fatalities",
467
+ "Severity-Location Analysis"
468
+ ])
469
 
470
  with tab1:
471
+ # Weather condition filter
472
+ weather = ['All Conditions'] + sorted(df['Weather'].unique())
473
+ selected_weather = st.selectbox('Select Weather Condition:', weather)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
474
 
475
+ trend_col, desc_col = st.columns([7, 3])
 
 
 
 
 
 
 
 
476
 
477
+ with trend_col:
478
+ trend_fig = create_crash_trend_chart(df, selected_weather)
479
+ trend_fig.update_layout(
480
+ height=800,
481
+ width=None,
482
+ margin=dict(l=50, r=50, t=50, b=50)
483
+ )
484
+ st.plotly_chart(trend_fig, use_container_width=True)
485
+
486
 
 
 
 
 
 
 
 
 
 
 
 
 
 
487
 
488
  with desc_col:
489
  st.markdown("""
490
+ ## **Crash Trend Over Time**
491
+ This interactive line chart visualizes the trend of unique traffic crashes over the years, optionally filtered by weather conditions. It highlights how crash frequency changes over time, helping identify trends and potential contributing factors.
 
 
492
 
493
  **Key Features:**
494
+ * **Time Trend Analysis**: Displays the total number of unique crashes for each year, showing long-term patterns.
495
+ * **Weather Filter**: Users can filter the data by weather conditions (e.g., "Rainy", "Sunny") to analyze how weather impacts crash trends.
496
+ * **Interactive Tooltips**: Hovering over data points reveals the exact crash count for each year, providing detailed insights.
497
+
498
+ **Color Scheme and Design:**
499
+ * **Line and Markers**: A smooth line connects data points, with prominent markers for each year to highlight trends clearly.
500
+ * **Dynamic Title**: The chart updates its title to reflect the selected weather condition or "All Conditions" for the overall trend.
501
 
502
+ **Insights:**
 
 
503
 
504
+ This chart helps uncover:
505
+ * Annual fluctuations in crash incidents.
506
+ * Correlations between weather conditions and crash frequencies.
507
+ * Historical patterns that can guide future safety measures and urban planning decisions
508
  """)
509
+
510
+ with tab2:
511
+ # Age group selection
512
+ age_groups = ['All Ages', '16-25', '26-35', '36-45', '46-55', '56-65', '65+']
513
+ selected_age = st.selectbox('Select Age Group:', age_groups)
514
 
515
+ chart_col, desc_col = st.columns([6, 4])
 
 
 
 
516
 
517
+ with chart_col:
518
+ # Create and display chart
519
+ fig, violations = create_severity_violation_chart(df, selected_age)
520
 
521
+ clicked_points = plotly_events(fig, click_event=True, override_height=600, override_width="100%")
522
+
523
+ if clicked_points:
524
+ selected_violation = clicked_points[0]['x']
525
+ if selected_violation != st.session_state['selected_violation']:
526
+ st.session_state['selected_violation'] = selected_violation
527
+
528
+ # If a violation is selected, display the pie chart --> added for part3 (interactive pie chart)
529
+ if st.session_state['selected_violation']:
530
+ # pie_chart = create_interactive_pie_chart(violations, st.session_state['selected_violation'])
531
+ pie_chart = create_interactive_pie_chart(violations, st.session_state['selected_violation'], selected_age) # dynamically update pie chart's title
532
+ st.plotly_chart(pie_chart, use_container_width=True)
533
+
534
+ # Display statistics
535
+ if selected_age == 'All Ages':
536
+ total_incidents = len(df)
537
+ else:
538
+ total_incidents = len(df[
539
+ (df['Age_Group_Drv1'] == selected_age) |
540
+ (df['Age_Group_Drv2'] == selected_age)
541
+ ])
542
+
543
+
544
+ with desc_col:
545
+ st.markdown("""
546
+ # Severity of Violations Across Age Groups
547
+
548
+ This section provides an interactive visualization of **crash severities** linked to specific violation types, segmented by driver age groups. It enables a comprehensive analysis of how **age influences crash severity and violation trends**. The visualization is linked to an **interactive pie chart** that updates when a specific bar is selected, displaying the detailed distribution of the selected violation type based on the selected age group.
549
+
550
+ ---
551
+
552
+ ## **Key Features**
553
+
554
+ ### 1. **Age Group Analysis**
555
+ - Select specific age groups (e.g., "16-25", "65+") or analyze all ages to explore correlations between:
556
+ - Age
557
+ - Violation type
558
+ - Crash severity
559
+ - Understand how different age groups are involved in various types of violations.
560
+
561
+ ### 2. **Violation Breakdown**
562
+ - Examine the most frequent violations contributing to traffic accidents for each age group.
563
+ - View detailed statistics showing the distribution of violation types.
564
+
565
+ ### 3. **Understanding Severity Level**
566
+ - Identify the proportion of severity levels for a specific violation type based on different age groups.
567
+ - Investigate detailed severity patterns for each violation type across age groups.
568
+
569
+ ---
570
+
571
+ ## **Insights**
572
+
573
+ - **Identifies High-Risk Behaviors:**
574
+ - Highlights risky behaviors such as reckless driving in younger drivers or impaired driving in older groups.
575
+
576
+ - **Highlights Severity Associations:**
577
+ - Shows which violations are associated with more severe outcomes, aiding targeted safety interventions and public awareness campaigns.
578
+
579
+ - **Supports Data-Driven Decision Making:**
580
+ - Provides insights for designing **age-specific traffic safety programs**.
581
+
582
+ ---
583
+ """)
584
+
585
+ with tab3:
586
+ # Dropdown for category selection
587
+ categories = [
588
+ 'Collisionmanner',
589
+ 'Lightcondition',
590
+ 'Weather',
591
+ 'SurfaceCondition',
592
+ 'AlcoholUse_Drv1',
593
+ 'Gender_Drv1',
594
+ ]
595
+ selected_category = st.selectbox("Select Category:", categories)
596
+
597
+ # Dropdown for year selection
598
+ years = ['All Years'] + sorted(df['Year'].dropna().unique().astype(int).tolist())
599
+ selected_year = st.selectbox("Select Year:", years)
600
+
601
+ chart_col, desc_col = st.columns([7, 3])
602
 
603
+ with chart_col:
604
+ distribution_chart = create_category_distribution_chart(df, selected_category, selected_year)
605
+ distribution_chart.update_layout(
606
+ height=800,
607
+ width=None,
 
 
608
  margin=dict(l=50, r=50, t=50, b=50)
609
  )
610
+ st.plotly_chart(distribution_chart, use_container_width=True)
611
 
612
  with desc_col:
613
+ st.markdown(f"""
614
+ ## Distribution of Incidents by {selected_category}
615
+ This visualization explores the distribution of traffic incidents across various categories, such as Collision Manner, Weather, Surface Condition, Alcohol Use, and Driver Gender. Each bar represents a specific category value (e.g., "Male" or "Female" for Gender), and the bars are divided into segments based on Injury Severity (e.g., Minor, Moderate, Serious, Fatal).
616
+
617
+ **Key Features:**
618
+ * Interactive Filters: Select a category and filter by year to analyze trends over time.
619
+ * Insightful Tooltips: Hover over each segment to view the exact count and percentage of incidents for a given severity level.
620
+ * Comparative Analysis: Quickly identify how different conditions or behaviors correlate with injury severity.
621
+
622
+ This chart provides actionable insights into factors contributing to traffic incidents and their outcomes, helping stakeholders target interventions and improve road safety.
623
+ """)
 
 
 
 
 
 
624
 
625
  with tab4:
626
  # Dropdown for Unit Type selection
 
632
  unit_type_pairs = sorted(list(unit_type_pairs))
633
  unit_type = st.selectbox("Select Unit Type Pair", options=['Total'] + unit_type_pairs)
634
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
635
  chart_col, desc_col = st.columns([7, 3])
636
 
637
  with chart_col:
 
638
  injuries_fatalities_chart = create_injuries_fatalities_chart(df, unit_type)
639
  injuries_fatalities_chart = injuries_fatalities_chart.properties(
640
+ height=800
641
  )
642
  st.altair_chart(injuries_fatalities_chart, use_container_width=True)
643
 
 
671
 
672
  This visualization aids stakeholders in developing effective safety measures and resource allocation strategies throughout the year.
673
  """)
674
+
 
 
675
  with tab5:
676
+ years = sorted(df['Year'].unique())
677
+ selected_year = st.selectbox('Select Year:', years)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
678
 
679
+ # Create two columns for visualization and description
680
+ viz_col, desc_col = st.columns([6, 4])
681
+
682
+ with viz_col:
683
+ # First add bar chart
684
+ st.subheader("Severity-Location Analysis")
685
+ bar_fig = create_map_bar_chart(df, selected_year)
686
+
687
+ # Capture click events with bar chart
688
+ clicked_points = plotly_events(
689
+ bar_fig,
690
+ click_event=True,
691
+ override_height=300,
692
+ override_width="100%"
693
  )
694
+
695
+ if clicked_points:
696
+ selected_severity = clicked_points[0]['x']
697
+ st.session_state["selected_severity"] = selected_severity
698
+
699
+ # Show currently selected severity
700
+ st.write(f"Selected Severity: {st.session_state['selected_severity'] if st.session_state['selected_severity'] else 'All'}")
701
+
702
+ # Add map below bar chart
703
+ st.subheader("Accident Locations")
704
+ map_placeholder = st.empty()
705
+ with map_placeholder:
706
+ m = create_map(df, selected_year, st.session_state["selected_severity"])
707
+ map_data = st_folium(
708
+ m,
709
+ width=None,
710
+ height=600, # Reduced height since it's now below bar chart
711
+ key=f"map_{selected_year}_{st.session_state['selected_severity']}",
712
+ returned_objects=["null_drawing"]
713
+ )
714
+
715
  with desc_col:
716
  st.markdown("""
717
+ # Exploring Traffic Accident Severity and Location
718
+ The two linked graphs show an interactive platform for exploring traffic accident data, featuring a **bar chart** and a **dynamic map**.
719
+ - The **bar chart** displays the distribution of accidents by severity.
720
+ - The **map** combines marker clustering and heatmaps to highlight accident locations.
721
+ - Users can filter data by year and severity to explore patterns.
722
+ ---
723
+ ## **Key Features**
724
+ - **Interactive Bar Chart:**
725
+ Displays accident counts by severity, updating the map based on selected severity.
726
+ - **Map with Dual Layers:**
727
+ Includes marker clustering for individual accidents and a heatmap to visualize accident density.
728
+ - **Year-Based Filtering:**
729
+ Allows users to filter data by year and severity for focused analysis.
730
+ - **Seamless Integration:**
731
+ Combines Streamlit and Folium, with Plotly events linking the visualizations.
732
+ ---
733
+ ## **Design**
734
+ - **Bar Chart:**
735
+ - Uses a calm blue color for clarity.
736
+ - **Map:**
737
+ - Uses **CartoDB tiles** with red markers and heatmaps for visibility.
738
+ ---
739
+ ## **Insights**
740
+ - **Severity Patterns:**
741
+ The bar chart reveals accident trends across severity levels.
742
+ - **Spatial Trends:**
743
+ The map identifies high-risk accident hotspots.
744
+ - **Yearly and Severity Insights:**
745
+ Filters help uncover temporal and severity-related patterns, aiding traffic safety analysis.
746
+ """)
747
+ st.markdown("---")
748
 
749
+ # Add conclusion section
750
+ st.markdown("# FP3 Conclusion")
 
 
751
 
752
+ st.markdown("""
753
+ TODO
754
+ """)
755
+
756
 
757
 
758
  if __name__ == "__main__":