namdini commited on
Commit
791e8a0
·
verified ·
1 Parent(s): 77650cc

Update app.py

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