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

update tab 2

Browse files
Files changed (1) hide show
  1. app.py +66 -226
app.py CHANGED
@@ -3,21 +3,9 @@ import pandas as pd
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
@@ -80,40 +68,22 @@ 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
- height=600,
84
  labels={'count': 'Number of Incidents', 'Violation': 'Violation Type'},
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
- # )
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=150,r=0), # Increase bottom margin to avoid pruning
107
- xaxis=dict(automargin=True)
108
  )
109
 
110
- # return fig
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(),
@@ -145,70 +115,19 @@ def get_top_violations(df, age_group):
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]
152
-
153
- # Create a pie chart for severity distribution of the selected violation type
154
- fig = px.pie(
155
- filtered_data,
156
- names='Severity',
157
- values='count',
158
- # title=f'Severity Level Distribution for Violation: {selected_violation}',
159
- title=f'Severity Level Distribution for Violation: {selected_violation} - {selected_age}', # dynamically update pie chart's title
160
- height=600,
161
- color_discrete_map=severity_colors
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,11 +135,9 @@ def create_map(df, selected_year, selected_severity=None):
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):
@@ -391,7 +308,7 @@ def create_category_distribution_chart(df, selected_category, selected_year):
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
@@ -428,16 +345,16 @@ def main():
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.
@@ -450,21 +367,14 @@ def main():
450
 
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:
@@ -482,8 +392,6 @@ def main():
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("""
@@ -500,7 +408,6 @@ def main():
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.
@@ -512,24 +419,12 @@ def main():
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':
@@ -540,46 +435,37 @@ def main():
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:
@@ -614,7 +500,7 @@ def main():
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.
@@ -676,83 +562,37 @@ def main():
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__":
 
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
 
68
  y='count',
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(),
 
115
 
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
  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
  barmode='stack',
309
  xaxis_tickangle=-45,
310
  legend_title='Injury Severity',
311
+ margin=dict(t=50, b=100),
312
  )
313
 
314
  return fig
 
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
 
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
  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
  * **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
  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
  (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
  ## 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
  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__":