hyzhang00 commited on
Commit
fdb4d25
·
verified ·
1 Parent(s): cdca6fa

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +231 -66
app.py CHANGED
@@ -3,9 +3,21 @@ import pandas as pd
3
  import plotly.express as px
4
  import altair as alt
5
  import folium
 
6
  from folium.plugins import HeatMap, MarkerCluster
7
  from streamlit_folium import st_folium
8
 
 
 
 
 
 
 
 
 
 
 
 
9
  @st.cache_data
10
  def load_and_preprocess_data(file_path):
11
  # Read the data
@@ -69,21 +81,44 @@ def create_severity_violation_chart(df, age_group=None):
69
  color='Severity',
70
  title=f'Crash Severity Distribution by Violation Type - {age_group}',
71
  labels={'count': 'Number of Incidents', 'Violation': 'Violation Type'},
72
- height=600
 
73
  )
74
 
 
 
 
 
 
 
 
75
  fig.update_layout(
76
  xaxis_tickangle=-45,
77
- legend_title='Severity Level',
78
- barmode='stack'
 
 
 
 
 
 
 
 
 
 
 
 
79
  )
80
 
81
- return fig
 
 
 
82
 
83
  def get_top_violations(df, age_group):
84
  # Calculate total incidents for the age group
85
  if age_group == 'All Ages':
86
- total_incidents = len(df) # 总样本数
87
  # Get violations for all ages
88
  violations = pd.concat([
89
  df['Violation1_Drv1'].value_counts(),
@@ -116,18 +151,69 @@ def get_top_violations(df, age_group):
116
  return violations_df.head()
117
 
118
  @st.cache_data
119
- def create_map(df, selected_year):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
120
  filtered_df = df[df['Year'] == selected_year]
121
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
122
  m = folium.Map(
123
- location=[33.4255, -111.9400],
124
  zoom_start=12,
125
  control_scale=True,
126
  tiles='CartoDB positron'
127
  )
128
 
129
- marker_cluster = MarkerCluster().add_to(m)
130
-
 
 
131
  for _, row in filtered_df.iterrows():
132
  folium.Marker(
133
  location=[row['Latitude'], row['Longitude']],
@@ -135,9 +221,11 @@ def create_map(df, selected_year):
135
  icon=folium.Icon(color='red')
136
  ).add_to(marker_cluster)
137
 
 
138
  heat_data = filtered_df[['Latitude', 'Longitude']].values.tolist()
139
- HeatMap(heat_data, radius=15, max_zoom=13, min_opacity=0.3).add_to(m)
140
 
 
141
  return m
142
 
143
  def create_injuries_fatalities_chart(crash_data, unit_type):
@@ -308,7 +396,7 @@ def create_category_distribution_chart(df, selected_category, selected_year):
308
  barmode='stack',
309
  xaxis_tickangle=-45,
310
  legend_title='Injury Severity',
311
- margin=dict(t=50, b=100),
312
  )
313
 
314
  return fig
@@ -345,16 +433,16 @@ def main():
345
 
346
  st.markdown("""
347
  **Team Members:**
348
- - Janhavi Tushar Zarapkar [email protected]
349
  - Hangyue Zhang ([email protected])
350
  - Andrew Nam ([email protected])
351
  - Nirmal Attarde ([email protected])
352
- - Maanas Sandeep Agrawa ([email protected])
353
  """)
354
 
355
 
356
  st.markdown("""
357
- ### Introduction to the Traffic Accident Dataset
358
  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.
359
 
360
  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.
@@ -367,14 +455,21 @@ def main():
367
 
368
  if 'Weather' not in df.columns:
369
  df['Weather'] = 'Unknown'
 
 
 
370
 
 
 
 
 
371
  # Create tabs for different visualizations
372
  tab1, tab2, tab3, tab4, tab5 = st.tabs([
373
  "Crash Trend",
374
- "Crash Statistics",
375
  "Distribution by Category",
376
  "Crash Injuries/Fatalities",
377
- "Crash Map"
378
  ])
379
 
380
  with tab1:
@@ -392,6 +487,8 @@ def main():
392
  margin=dict(l=50, r=50, t=50, b=50)
393
  )
394
  st.plotly_chart(trend_fig, use_container_width=True)
 
 
395
 
396
  with desc_col:
397
  st.markdown("""
@@ -408,6 +505,7 @@ def main():
408
  * **Dynamic Title**: The chart updates its title to reflect the selected weather condition or "All Conditions" for the overall trend.
409
 
410
  **Insights:**
 
411
  This chart helps uncover:
412
  * Annual fluctuations in crash incidents.
413
  * Correlations between weather conditions and crash frequencies.
@@ -419,12 +517,24 @@ def main():
419
  age_groups = ['All Ages', '16-25', '26-35', '36-45', '46-55', '56-65', '65+']
420
  selected_age = st.selectbox('Select Age Group:', age_groups)
421
 
422
- chart_col, desc_col = st.columns([7, 3])
423
 
424
  with chart_col:
425
  # Create and display chart
426
- fig = create_severity_violation_chart(df, selected_age)
427
- st.plotly_chart(fig, use_container_width=True)
 
 
 
 
 
 
 
 
 
 
 
 
428
 
429
  # Display statistics
430
  if selected_age == 'All Ages':
@@ -435,37 +545,46 @@ def main():
435
  (df['Age_Group_Drv2'] == selected_age)
436
  ])
437
 
438
- # Create two columns for statistics
439
- col1, col2 = st.columns(2)
440
-
441
- with col1:
442
- st.markdown(f"### Total Incidents")
443
- st.markdown(f"**{total_incidents:,}** incidents for {selected_age}")
444
-
445
- with col2:
446
- st.markdown("### Top Violations")
447
- top_violations = get_top_violations(df, selected_age)
448
- st.table(top_violations)
449
 
450
  with desc_col:
451
  st.markdown("""
452
- ## Severity of Violations Across Age Groups
453
-
454
- 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.
455
 
456
- **Key Features:**
457
- 1. **Age Group Analysis**:
458
- * Select specific age groups (e.g., "16-25", "65+") or analyze all ages to explore correlations between age, violation type, and crash severity.
459
- * Understand how different age groups are involved in various types of violations.
460
 
461
- 2. **Violation Breakdown**:
462
- * Examine the most frequent violations contributing to traffic accidents for each age group.
463
- * View detailed statistics showing the distribution of violation types.
464
 
465
- **Insights:**
466
- * Identifies high-risk behaviors within specific age groups, such as reckless driving in younger drivers or impaired driving in older groups.
467
- * Highlights which violations are associated with more severe outcomes, aiding targeted safety interventions and public awareness campaigns.
468
- * Supports data-driven decision making for age-specific traffic safety programs.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
469
  """)
470
 
471
  with tab3:
@@ -500,7 +619,7 @@ def main():
500
  ## Distribution of Incidents by {selected_category}
501
  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).
502
 
503
- **Key features include:**
504
  * Interactive Filters: Select a category and filter by year to analyze trends over time.
505
  * Insightful Tooltips: Hover over each segment to view the exact count and percentage of incidents for a given severity level.
506
  * Comparative Analysis: Quickly identify how different conditions or behaviors correlate with injury severity.
@@ -562,37 +681,83 @@ def main():
562
  years = sorted(df['Year'].unique())
563
  selected_year = st.selectbox('Select Year:', years)
564
 
565
- map_col, desc_col = st.columns([7, 3])
 
566
 
567
- with map_col:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
568
  map_placeholder = st.empty()
569
  with map_placeholder:
570
- m = create_map(df, selected_year)
571
  map_data = st_folium(
572
  m,
573
  width=None,
574
- height=800,
575
- key=f"map_{selected_year}",
576
  returned_objects=["null_drawing"]
577
  )
578
-
579
  with desc_col:
580
  st.markdown("""
581
- ### Traffic Crash Location Map
582
- This interactive map visualizes traffic accidents in Tempe for the selected year. It combines **marker clustering** and a **heatmap** to show:
583
- 1. **Accident Markers**: Red markers indicate individual accidents, with popups displaying the coordinates, date/time, and severity of each incident.
584
- 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.
585
-
586
- **Key Features:**
587
- * **Interactive Year Selection**: Users can select a year to view accidents for that specific time.
588
- * **Accident Patterns**: The map reveals accident-prone areas and severity patterns, helping identify dangerous locations.
589
-
590
- **Color Scheme:**
591
- * **Red**: Individual accident markers.
592
- * **Blue to Red**: Heatmap colors indicate accident frequency, from low (blue) to high (red).
593
-
594
- This map provides insights into accident trends and can help guide safety improvements in the city.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
595
  """)
 
 
 
 
 
 
 
 
 
596
 
597
 
598
  if __name__ == "__main__":
 
3
  import plotly.express as px
4
  import altair as alt
5
  import folium
6
+ from streamlit_plotly_events import plotly_events # added for part3 interactivity
7
  from folium.plugins import HeatMap, MarkerCluster
8
  from streamlit_folium import st_folium
9
 
10
+ # To fix the color scheme in crash stats plot (asked ChatGPT for appropriate colors)
11
+ severity_colors = {
12
+ "No Injury": "#1f77b4",
13
+ "Possible Injury": "#aec7e8",
14
+ "Non Incapacitating Injury": "#ff7f0e",
15
+ "Incapacitating Injury": "#ffbb78",
16
+ "Suspected Minor Injury": "#2ca02c",
17
+ "Suspected Serious Injury": "#98df8a",
18
+ "Fatal": "#d62728",
19
+ }
20
+
21
  @st.cache_data
22
  def load_and_preprocess_data(file_path):
23
  # Read the data
 
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(),
 
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]
157
+
158
+ # Create a pie chart for severity distribution of the selected violation type
159
+ fig = px.pie(
160
+ filtered_data,
161
+ names='Severity',
162
+ values='count',
163
+ # title=f'Severity Level Distribution for Violation: {selected_violation}',
164
+ title=f'Severity Level Distribution for Violation: {selected_violation} - {selected_age}', # dynamically update pie chart's title
165
+ height=600,
166
+ color_discrete_map=severity_colors
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):
 
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
 
433
 
434
  st.markdown("""
435
  **Team Members:**
436
+ - Janhavi Tushar Zarapkar ([email protected])
437
  - Hangyue Zhang ([email protected])
438
  - Andrew Nam ([email protected])
439
  - Nirmal Attarde ([email protected])
440
+ - Maanas Sandeep Agrawal ([email protected])
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.
 
455
 
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:
 
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("""
 
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.
 
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':
 
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
 
553
+ 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.
 
 
 
554
 
555
+ ---
 
 
556
 
557
+ ## **Key Features**
558
+
559
+ ### 1. **Age Group Analysis**
560
+ - Select specific age groups (e.g., "16-25", "65+") or analyze all ages to explore correlations between:
561
+ - Age
562
+ - Violation type
563
+ - Crash severity
564
+ - Understand how different age groups are involved in various types of violations.
565
+
566
+ ### 2. **Violation Breakdown**
567
+ - Examine the most frequent violations contributing to traffic accidents for each age group.
568
+ - View detailed statistics showing the distribution of violation types.
569
+
570
+ ### 3. **Understanding Severity Level**
571
+ - Identify the proportion of severity levels for a specific violation type based on different age groups.
572
+ - Investigate detailed severity patterns for each violation type across age groups.
573
+
574
+ ---
575
+
576
+ ## **Insights**
577
+
578
+ - **Identifies High-Risk Behaviors:**
579
+ - Highlights risky behaviors such as reckless driving in younger drivers or impaired driving in older groups.
580
+
581
+ - **Highlights Severity Associations:**
582
+ - Shows which violations are associated with more severe outcomes, aiding targeted safety interventions and public awareness campaigns.
583
+
584
+ - **Supports Data-Driven Decision Making:**
585
+ - Provides insights for designing **age-specific traffic safety programs**.
586
+
587
+ ---
588
  """)
589
 
590
  with tab3:
 
619
  ## Distribution of Incidents by {selected_category}
620
  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).
621
 
622
+ **Key Features:**
623
  * Interactive Filters: Select a category and filter by year to analyze trends over time.
624
  * Insightful Tooltips: Hover over each segment to view the exact count and percentage of incidents for a given severity level.
625
  * Comparative Analysis: Quickly identify how different conditions or behaviors correlate with injury severity.
 
681
  years = sorted(df['Year'].unique())
682
  selected_year = st.selectbox('Select Year:', years)
683
 
684
+ # Create two columns for visualization and description
685
+ viz_col, desc_col = st.columns([6, 4])
686
 
687
+ with viz_col:
688
+ # First add bar chart
689
+ st.subheader("Severity-Location Analysis")
690
+ bar_fig = create_map_bar_chart(df, selected_year)
691
+
692
+ # Capture click events with bar chart
693
+ clicked_points = plotly_events(
694
+ bar_fig,
695
+ click_event=True,
696
+ override_height=300,
697
+ override_width="100%"
698
+ )
699
+
700
+ if clicked_points:
701
+ selected_severity = clicked_points[0]['x']
702
+ st.session_state["selected_severity"] = selected_severity
703
+
704
+ # Show currently selected severity
705
+ st.write(f"Selected Severity: {st.session_state['selected_severity'] if st.session_state['selected_severity'] else 'All'}")
706
+
707
+ # Add map below bar chart
708
+ st.subheader("Accident Locations")
709
  map_placeholder = st.empty()
710
  with map_placeholder:
711
+ m = create_map(df, selected_year, st.session_state["selected_severity"])
712
  map_data = st_folium(
713
  m,
714
  width=None,
715
+ height=600, # Reduced height since it's now below bar chart
716
+ key=f"map_{selected_year}_{st.session_state['selected_severity']}",
717
  returned_objects=["null_drawing"]
718
  )
719
+
720
  with desc_col:
721
  st.markdown("""
722
+ # Exploring Traffic Accident Severity and Location
723
+ The two linked graphs show an interactive platform for exploring traffic accident data, featuring a **bar chart** and a **dynamic map**.
724
+ - The **bar chart** displays the distribution of accidents by severity.
725
+ - The **map** combines marker clustering and heatmaps to highlight accident locations.
726
+ - Users can filter data by year and severity to explore patterns.
727
+ ---
728
+ ## **Key Features**
729
+ - **Interactive Bar Chart:**
730
+ Displays accident counts by severity, updating the map based on selected severity.
731
+ - **Map with Dual Layers:**
732
+ Includes marker clustering for individual accidents and a heatmap to visualize accident density.
733
+ - **Year-Based Filtering:**
734
+ Allows users to filter data by year and severity for focused analysis.
735
+ - **Seamless Integration:**
736
+ Combines Streamlit and Folium, with Plotly events linking the visualizations.
737
+ ---
738
+ ## **Design**
739
+ - **Bar Chart:**
740
+ - Uses a calm blue color for clarity.
741
+ - **Map:**
742
+ - Uses **CartoDB tiles** with red markers and heatmaps for visibility.
743
+ ---
744
+ ## **Insights**
745
+ - **Severity Patterns:**
746
+ The bar chart reveals accident trends across severity levels.
747
+ - **Spatial Trends:**
748
+ The map identifies high-risk accident hotspots.
749
+ - **Yearly and Severity Insights:**
750
+ Filters help uncover temporal and severity-related patterns, aiding traffic safety analysis.
751
  """)
752
+ st.markdown("---")
753
+
754
+ # Add conclusion section
755
+ st.markdown("# FP3 Conclusion")
756
+
757
+ st.markdown("""
758
+ TODO
759
+ """)
760
+
761
 
762
 
763
  if __name__ == "__main__":