Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4,693 changes: 4,693 additions & 0 deletions bg_centroids.csv

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's not put actual data in this repo. Just the tools.

Large diffs are not rendered by default.

1,184 changes: 1,184 additions & 0 deletions milwaukee_multiservice_yelp.csv

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions tl_2024_55_bg.cpg
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
UTF-8
Binary file added tl_2024_55_bg.dbf
Binary file not shown.
1 change: 1 addition & 0 deletions tl_2024_55_bg.prj
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
GEOGCS["GCS_North_American_1983",DATUM["D_North_American_1983",SPHEROID["GRS_1980",6378137,298.257222101]],PRIMEM["Greenwich",0],UNIT["Degree",0.017453292519943295]]
Binary file added tl_2024_55_bg.shp
Binary file not shown.
428 changes: 428 additions & 0 deletions tl_2024_55_bg.shp.ea.iso.xml

Large diffs are not rendered by default.

851 changes: 851 additions & 0 deletions tl_2024_55_bg.shp.iso.xml

Large diffs are not rendered by default.

Binary file added tl_2024_55_bg.shx
Binary file not shown.
83 changes: 83 additions & 0 deletions tool0&1.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import geopandas as gpd

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's have a different file for each program. Let's use short, descriptive names for the programs, without special characters.

import requests
import pandas as pd
import time
import os

# Load shapefile

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's have a main() function for this.

block_groups = gpd.read_file("tl_2024_55_bg/tl_2024_55_bg.shp").to_crs(epsg=4326)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No hardcoding paths.


# Reproject to a local projected CRS
block_groups_proj = block_groups.to_crs(epsg=3071)

# Compute centroids
block_groups_proj['centroid'] = block_groups_proj.geometry.centroid

# transform centroids back to WGS84 for yelp
centroids_wgs84 = block_groups_proj.set_geometry('centroid').to_crs(epsg=4326)
block_groups['lat'] = centroids_wgs84.geometry.y
block_groups['lon'] = centroids_wgs84.geometry.x

# Yelp API
YELP_API_KEY = "bDAon8ZKyViqMGdQp07QOu9X9trtnPOcJGpUxX02u1proTwYqM6DmJqOCzIrHac1e2A-WhrYHfuMQJ3fX7tNpY4icycxFX_VJEYqvCuZm4ptZdhGlYaPpKlXXLH8Z3Yx"
headers = {"Authorization": f"Bearer {YELP_API_KEY}"}
yelp_url = "https://api.yelp.com/v3/businesses/search"

yelp_categories = [
"grocery",
"restaurant",
"pharmacy",
"clinic",
"hospital",
"school",
"gasstation",
"bank",
"hair",
"gym",
"coffee",
"daycare",
"laundry"
]
# Tool 1 (get services per block centroid)
services = []

N = 50 # Number of block groups sampled

for idx, row in block_groups.iterrows():

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

itertuples is much faster that iterrows.

for category in yelp_categories:
print(f"🔍 GEOID {row['GEOID']} — {category}")

params = {
"term": category,
"latitude": row["lat"],
"longitude": row["lon"],
"radius": 1000,
"limit": 5
}
try:
response = requests.get(yelp_url, headers=headers, params=params)
if response.status_code == 200:
businesses = response.json().get("businesses", [])
for b in businesses:
services.append({
"GEOID": row["GEOID"],
"category": category,
"name": b["name"],
"rating": b["rating"],
"lat": b["coordinates"]["latitude"],
"lon": b["coordinates"]["longitude"]
})
else:
print(f"Yelp error {response.status_code} for GEOID {row['GEOID']}")
except Exception as e:
print(f"Request failed for GEOID {row['GEOID']}: {e}")

time.sleep(0.5)

if idx >= N - 1:
break

# Save to csv
services_df = pd.DataFrame(services)
services_df.to_csv("milwaukee_multiservice_yelp.csv", index=False)
print(f"Done. Saved {len(services_df)} results to milwaukee_multiservice_yelp.csv.")
33 changes: 33 additions & 0 deletions tool0&1plots.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns

services_df = pd.read_csv("milwaukee_multiservice_yelp.csv")

#Plot 1: Top 10 Most Common Service Categories

category_counts = services_df['category'].value_counts().reset_index()
category_counts.columns = ['category', 'count']

plt.figure(figsize=(10, 6))
sns.barplot(x='count', y='category', data=category_counts.head(10), palette="viridis")
plt.title("Top 10 Most Common Service Categories in Milwaukee")
plt.xlabel("Number of Services")
plt.ylabel("Service Category")
plt.tight_layout()
plt.show()


# Plot 2: Distribution of Services per Block Group (GEOID)

geo_counts = services_df['GEOID'].value_counts().reset_index()
geo_counts.columns = ['GEOID', 'service_count']

plt.figure(figsize=(10, 6))
sns.histplot(geo_counts['service_count'], bins=20, kde=True, color="skyblue")
plt.title("Distribution of Services Across Block Groups")
plt.xlabel("Number of Services per Block Group")
plt.ylabel("Number of Block Groups")
plt.tight_layout()
plt.show()