Spaces:
Build error
Build error
Update src/streamlit_app.py
Browse files- src/streamlit_app.py +49 -47
src/streamlit_app.py
CHANGED
|
@@ -230,7 +230,7 @@ criminal threats and minor burglary. Violent acts such as simple assault and rob
|
|
| 230 |
relying on specific numbers. By pairing each slice with its label, the chart provides an immediate intuitive understanding of which crime types contribute most to overall
|
| 231 |
volume and which are comparatively rare, helping stakeholders focus on the offenses that matter most.</div>""",unsafe_allow_html=True)
|
| 232 |
|
| 233 |
-
# -------------------------------- Plot
|
| 234 |
# st.markdown("<div class='sectionheader'>Crime Hotspots by Region</div>", unsafe_allow_html=True)
|
| 235 |
|
| 236 |
# # 1. Aggregate counts and centroids
|
|
@@ -270,46 +270,7 @@ volume and which are comparatively rare, helping stakeholders focus on the offen
|
|
| 270 |
# # 4. Render
|
| 271 |
# st.plotly_chart(fig, use_container_width=True)
|
| 272 |
|
| 273 |
-
# -------------------------------- Plot
|
| 274 |
-
st.markdown("<div class='sectionheader'>Incidents Trends over Time </div>", unsafe_allow_html=True)
|
| 275 |
-
# 1. Aggregate total incidents by year
|
| 276 |
-
yearly_region = (
|
| 277 |
-
df
|
| 278 |
-
.groupby(["year", "RegionName"])
|
| 279 |
-
.size()
|
| 280 |
-
.reset_index(name="Count")
|
| 281 |
-
)
|
| 282 |
-
|
| 283 |
-
# 2. Let the user pick one region to highlight
|
| 284 |
-
regions = sorted(yearly_region["RegionName"].unique())
|
| 285 |
-
sel_region = st.selectbox("Select Region", ["All"] + regions, index=0)
|
| 286 |
-
|
| 287 |
-
if sel_region != "All":
|
| 288 |
-
yearly_region = yearly_region[yearly_region["RegionName"] == sel_region]
|
| 289 |
-
|
| 290 |
-
# 3. Plot a smooth line per region (or just the one selected)
|
| 291 |
-
fig = px.line(
|
| 292 |
-
yearly_region,
|
| 293 |
-
x="year",
|
| 294 |
-
y="Count",
|
| 295 |
-
color="RegionName",
|
| 296 |
-
title=(" "),
|
| 297 |
-
labels={"year":"Year", "Count":"Incident Count"}
|
| 298 |
-
)
|
| 299 |
-
|
| 300 |
-
# 4. Add LOWESS smoothing (optional)
|
| 301 |
-
for trace in fig.data:
|
| 302 |
-
trace.update(mode="lines") # remove markers
|
| 303 |
-
|
| 304 |
-
st.plotly_chart(fig, use_container_width=True)
|
| 305 |
-
# Description.
|
| 306 |
-
st.markdown("""<div class="description"> This multi‐line chart tracks how total crime incidents have evolved across LAPD regions from 2020
|
| 307 |
-
through 2025. Each colored line represents a different precinct, letting you compare their trajectories side by side. You’ll notice that most
|
| 308 |
-
areas rose to a peak around 2022 before tapering off, while a handful of regions bucked the trend—either holding steady or dipping earlier. The
|
| 309 |
-
clear visual of converging and diverging lines makes it easy to spot which precincts saw the sharpest upticks, which managed to keep incidents
|
| 310 |
-
relatively flat, and how the overall pattern shifted over the five‐year span.</div>""",unsafe_allow_html=True)
|
| 311 |
-
|
| 312 |
-
# -------------------------------- Plot 8: Stacked Bar Charts for Regions --------------------------------
|
| 313 |
st.markdown("<div class='sectionheader'>Crime Composition by Region: Top 5 Offenses </div>", unsafe_allow_html=True)
|
| 314 |
# 1. Compute counts per region and crime
|
| 315 |
counts = (
|
|
@@ -357,7 +318,48 @@ violent or specialty offenses. By grouping all five slices together, the visuali
|
|
| 357 |
for example, precincts where assault plays a disproportionately large role versus those driven mainly by theft. This makes it straightforward to compare how
|
| 358 |
offense patterns differ from one region to the next.</div>""",unsafe_allow_html=True)
|
| 359 |
|
| 360 |
-
# -------------------------------- Plot
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 361 |
# st.markdown("<div class='sectionheader'>Crime Hotspots by Region NO MAP</div>", unsafe_allow_html=True)
|
| 362 |
|
| 363 |
# # 1. Aggregate total incidents by region and pick top 10
|
|
@@ -392,7 +394,7 @@ offense patterns differ from one region to the next.</div>""",unsafe_allow_html=
|
|
| 392 |
# # 4. Render in Streamlit
|
| 393 |
# st.plotly_chart(fig, use_container_width=True)
|
| 394 |
|
| 395 |
-
# -------------------------------- Plot
|
| 396 |
st.markdown("<div class='sectionheader'> HeatMap </div>", unsafe_allow_html=True)
|
| 397 |
# Count the crime type and list out the top 10 crime type that have the most cases.
|
| 398 |
top_crimes = df['crm_cd_desc'].value_counts().nlargest(10).index
|
|
@@ -436,7 +438,7 @@ This heatmap shows the frequency of the top 10 crimes from 2020 to 2025. The x a
|
|
| 436 |
</div>""",unsafe_allow_html=True)
|
| 437 |
|
| 438 |
|
| 439 |
-
# -------------------------------- Plot
|
| 440 |
st.markdown("<div class='sectionheader'> Line Chart </div>", unsafe_allow_html=True)
|
| 441 |
# Filter out the year 2025 since it is not the end, so that the trend can't be see.
|
| 442 |
df = df[df['year'] != 2025]
|
|
@@ -476,7 +478,7 @@ crime type: Battery - Simple Assault, Burglary From Vehicle, Theft of Identity,
|
|
| 476 |
the fluctuations and overall trajectories of these major crime categories across the years.</div>""",unsafe_allow_html=True)
|
| 477 |
|
| 478 |
|
| 479 |
-
# -------------------------------- Plot
|
| 480 |
st.markdown("<div class='sectionheader'> Explore LA Crime Patterns: An Interactive Folium Map </div>", unsafe_allow_html=True)
|
| 481 |
# Load the data.
|
| 482 |
with open(GEOJSON_PATH, "r", encoding="utf-8") as f:
|
|
@@ -543,7 +545,7 @@ st.markdown("""<div class="description">
|
|
| 543 |
This visualization uses Folium to build an interactive map of crime distribution in Los Angeles, highlighting the geospatial clustering characteristics of different years and crime types, and emphasizing the user's experience of freely exploring the map. The base map uses real streets and geographic backgrounds to enhance the spatial visualization of the image. The map shows the administrative boundaries of Los Angeles County in blue polygons, which are loaded with GeoJSON data and overlaid on the map to specify the geographic boundaries of crime locations. The red dots on the map represent the location of individual crimes, and the system samples no more than 300 data items from this category for visualization, with each dot pinpointed by latitude and longitude coordinates. The map supports full Leaflet.js functionality, including zooming, dragging, layer control, and other operations, which greatly enhances the flexibility of data exploration. A drop-down menu in the upper left corner of the page allows users to customize filters for specific years and crime types, enabling instant updates to the map content.
|
| 544 |
</div>""",unsafe_allow_html=True)
|
| 545 |
|
| 546 |
-
# -------------------------------- Plot
|
| 547 |
st.markdown("<div class='sectionheader'>Trends in Top 10 Crime Types (2020–2024)</div>", unsafe_allow_html=True)
|
| 548 |
# Group by crime type and year.
|
| 549 |
stacked_year_df = df_top.groupby(['year', 'crm_cd_desc']).size().reset_index(name='count')
|
|
@@ -570,7 +572,7 @@ Description: Our stacked bar chart shows the number of reported crimes for the t
|
|
| 570 |
By observing the plot, we can find out that 2022 had the most crimes, the year had the second most crimes is 2023, and etc. Besides that, we can also find out that some crimes, like vehicle theft, petty theft, and burglary from vehicles, happened a lot every year and make up a big part of the total.
|
| 571 |
</div>""",unsafe_allow_html=True)
|
| 572 |
|
| 573 |
-
# -------------------------------- Plot
|
| 574 |
st.markdown("<div class='sectionheader'>Crime Rankings for Selected Year</div>", unsafe_allow_html=True)
|
| 575 |
# Group by crime type and year.
|
| 576 |
heatmap1_df = df_top.groupby(['crm_cd_desc', 'year']).size().reset_index(name='count')
|
|
|
|
| 230 |
relying on specific numbers. By pairing each slice with its label, the chart provides an immediate intuitive understanding of which crime types contribute most to overall
|
| 231 |
volume and which are comparatively rare, helping stakeholders focus on the offenses that matter most.</div>""",unsafe_allow_html=True)
|
| 232 |
|
| 233 |
+
# -------------------------------- Plot : Bubble Map of Incident Counts by Region --------------------------------
|
| 234 |
# st.markdown("<div class='sectionheader'>Crime Hotspots by Region</div>", unsafe_allow_html=True)
|
| 235 |
|
| 236 |
# # 1. Aggregate counts and centroids
|
|
|
|
| 270 |
# # 4. Render
|
| 271 |
# st.plotly_chart(fig, use_container_width=True)
|
| 272 |
|
| 273 |
+
# -------------------------------- Plot 2: Stacked Bar Charts for Regions --------------------------------
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 274 |
st.markdown("<div class='sectionheader'>Crime Composition by Region: Top 5 Offenses </div>", unsafe_allow_html=True)
|
| 275 |
# 1. Compute counts per region and crime
|
| 276 |
counts = (
|
|
|
|
| 318 |
for example, precincts where assault plays a disproportionately large role versus those driven mainly by theft. This makes it straightforward to compare how
|
| 319 |
offense patterns differ from one region to the next.</div>""",unsafe_allow_html=True)
|
| 320 |
|
| 321 |
+
# -------------------------------- Plot 3: Line Chart for Incident Counts by Region --------------------------------
|
| 322 |
+
st.markdown("<div class='sectionheader'>Incidents Trends over Time </div>", unsafe_allow_html=True)
|
| 323 |
+
# 1. Aggregate total incidents by year
|
| 324 |
+
yearly_region = (
|
| 325 |
+
df
|
| 326 |
+
.groupby(["year", "RegionName"])
|
| 327 |
+
.size()
|
| 328 |
+
.reset_index(name="Count")
|
| 329 |
+
)
|
| 330 |
+
|
| 331 |
+
# 2. Let the user pick one region to highlight
|
| 332 |
+
regions = sorted(yearly_region["RegionName"].unique())
|
| 333 |
+
sel_region = st.selectbox("Select Region", ["All"] + regions, index=0)
|
| 334 |
+
|
| 335 |
+
if sel_region != "All":
|
| 336 |
+
yearly_region = yearly_region[yearly_region["RegionName"] == sel_region]
|
| 337 |
+
|
| 338 |
+
# 3. Plot a smooth line per region (or just the one selected)
|
| 339 |
+
fig = px.line(
|
| 340 |
+
yearly_region,
|
| 341 |
+
x="year",
|
| 342 |
+
y="Count",
|
| 343 |
+
color="RegionName",
|
| 344 |
+
title=(" "),
|
| 345 |
+
labels={"year":"Year", "Count":"Incident Count"}
|
| 346 |
+
)
|
| 347 |
+
|
| 348 |
+
# 4. Add LOWESS smoothing (optional)
|
| 349 |
+
for trace in fig.data:
|
| 350 |
+
trace.update(mode="lines") # remove markers
|
| 351 |
+
|
| 352 |
+
st.plotly_chart(fig, use_container_width=True)
|
| 353 |
+
# Description.
|
| 354 |
+
st.markdown("""<div class="description"> This multi‐line chart tracks how total crime incidents have evolved across LAPD regions from 2020
|
| 355 |
+
through 2025. Each colored line represents a different precinct, letting you compare their trajectories side by side. You’ll notice that most
|
| 356 |
+
areas rose to a peak around 2022 before tapering off, while a handful of regions bucked the trend—either holding steady or dipping earlier. The
|
| 357 |
+
clear visual of converging and diverging lines makes it easy to spot which precincts saw the sharpest upticks, which managed to keep incidents
|
| 358 |
+
relatively flat, and how the overall pattern shifted over the five‐year span.</div>""",unsafe_allow_html=True)
|
| 359 |
+
|
| 360 |
+
|
| 361 |
+
|
| 362 |
+
# -------------------------------- Plot : Bubble Map of Incident Counts by Region NO MAP --------------------------------
|
| 363 |
# st.markdown("<div class='sectionheader'>Crime Hotspots by Region NO MAP</div>", unsafe_allow_html=True)
|
| 364 |
|
| 365 |
# # 1. Aggregate total incidents by region and pick top 10
|
|
|
|
| 394 |
# # 4. Render in Streamlit
|
| 395 |
# st.plotly_chart(fig, use_container_width=True)
|
| 396 |
|
| 397 |
+
# -------------------------------- Plot 4: Heat Map --------------------------------
|
| 398 |
st.markdown("<div class='sectionheader'> HeatMap </div>", unsafe_allow_html=True)
|
| 399 |
# Count the crime type and list out the top 10 crime type that have the most cases.
|
| 400 |
top_crimes = df['crm_cd_desc'].value_counts().nlargest(10).index
|
|
|
|
| 438 |
</div>""",unsafe_allow_html=True)
|
| 439 |
|
| 440 |
|
| 441 |
+
# -------------------------------- Plot 5: Line Chart --------------------------------
|
| 442 |
st.markdown("<div class='sectionheader'> Line Chart </div>", unsafe_allow_html=True)
|
| 443 |
# Filter out the year 2025 since it is not the end, so that the trend can't be see.
|
| 444 |
df = df[df['year'] != 2025]
|
|
|
|
| 478 |
the fluctuations and overall trajectories of these major crime categories across the years.</div>""",unsafe_allow_html=True)
|
| 479 |
|
| 480 |
|
| 481 |
+
# -------------------------------- Plot 6: Map --------------------------------
|
| 482 |
st.markdown("<div class='sectionheader'> Explore LA Crime Patterns: An Interactive Folium Map </div>", unsafe_allow_html=True)
|
| 483 |
# Load the data.
|
| 484 |
with open(GEOJSON_PATH, "r", encoding="utf-8") as f:
|
|
|
|
| 545 |
This visualization uses Folium to build an interactive map of crime distribution in Los Angeles, highlighting the geospatial clustering characteristics of different years and crime types, and emphasizing the user's experience of freely exploring the map. The base map uses real streets and geographic backgrounds to enhance the spatial visualization of the image. The map shows the administrative boundaries of Los Angeles County in blue polygons, which are loaded with GeoJSON data and overlaid on the map to specify the geographic boundaries of crime locations. The red dots on the map represent the location of individual crimes, and the system samples no more than 300 data items from this category for visualization, with each dot pinpointed by latitude and longitude coordinates. The map supports full Leaflet.js functionality, including zooming, dragging, layer control, and other operations, which greatly enhances the flexibility of data exploration. A drop-down menu in the upper left corner of the page allows users to customize filters for specific years and crime types, enabling instant updates to the map content.
|
| 546 |
</div>""",unsafe_allow_html=True)
|
| 547 |
|
| 548 |
+
# -------------------------------- Plot 7: Stacked Bar Chart --------------------------------
|
| 549 |
st.markdown("<div class='sectionheader'>Trends in Top 10 Crime Types (2020–2024)</div>", unsafe_allow_html=True)
|
| 550 |
# Group by crime type and year.
|
| 551 |
stacked_year_df = df_top.groupby(['year', 'crm_cd_desc']).size().reset_index(name='count')
|
|
|
|
| 572 |
By observing the plot, we can find out that 2022 had the most crimes, the year had the second most crimes is 2023, and etc. Besides that, we can also find out that some crimes, like vehicle theft, petty theft, and burglary from vehicles, happened a lot every year and make up a big part of the total.
|
| 573 |
</div>""",unsafe_allow_html=True)
|
| 574 |
|
| 575 |
+
# -------------------------------- Plot 8: Bar Chart --------------------------------
|
| 576 |
st.markdown("<div class='sectionheader'>Crime Rankings for Selected Year</div>", unsafe_allow_html=True)
|
| 577 |
# Group by crime type and year.
|
| 578 |
heatmap1_df = df_top.groupby(['crm_cd_desc', 'year']).size().reset_index(name='count')
|