Last active
August 28, 2024 14:34
-
-
Save airalcorn2/b10feffd6b52c387e0836e8ff8ea5dcd to your computer and use it in GitHub Desktop.
A script for plotting Foursquare/Swarm check-in data.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Adapted from: https://stackoverflow.com/a/77261943/1316276. | |
import matplotlib | |
matplotlib.use("Agg") | |
import geodatasets | |
import geopandas as gpd | |
import glob | |
import json | |
import matplotlib.pyplot as plt | |
import os | |
import pandas as pd | |
import requests | |
from datetime import datetime, timedelta | |
from json import JSONDecodeError | |
from shapely.geometry import Point | |
def get_checkins(foursquare_path): | |
api_key_path = f"{foursquare_path}/fsq_api_key.txt" | |
with open(api_key_path) as f: | |
api_key = f.read().strip() | |
headers = {"accept": "application/json", "Authorization": api_key} | |
url = "https://api.foursquare.com/v3/places/{fsq_id}?fields=geocodes" | |
rows = [] | |
checkin_jsons = glob.glob(f"{foursquare_path}/checkins*.json") | |
for checkin_json in checkin_jsons: | |
with open(checkin_json) as f: | |
checkins = json.load(f) | |
for checkin in checkins["items"]: | |
try: | |
fsq_id = checkin["venue"]["id"] | |
except KeyError: | |
continue | |
response = requests.get(url.format(fsq_id=fsq_id), headers=headers) | |
try: | |
locations = response.json() | |
rows.append( | |
{ | |
"name": checkin["venue"]["name"], | |
"fsq_id": fsq_id, | |
"date": checkin["createdAt"], | |
"lat": locations["geocodes"]["main"]["latitude"], | |
"lon": locations["geocodes"]["main"]["longitude"], | |
} | |
) | |
except JSONDecodeError: | |
continue | |
except KeyError: | |
continue | |
df = pd.DataFrame(rows) | |
df.to_csv(f"{foursquare_path}/all_checkins.csv", index=False) | |
def save_maps(foursquare_path): | |
df = pd.read_csv(f"{foursquare_path}/all_checkins.csv") | |
geometry = [Point(xy) for xy in zip(df["lon"], df["lat"])] | |
gdf = gpd.GeoDataFrame(df, geometry=geometry) | |
gdf.set_crs(epsg=4326, inplace=True) | |
world = gpd.read_file(geodatasets.get_path("naturalearth.land")) | |
output_dir = "maps" | |
os.makedirs(output_dir) | |
cur_date = datetime.strptime(df["date"].min().split()[0], "%Y-%m-%d") | |
end_date = datetime.strptime(df["date"].max().split()[0], "%Y-%m-%d") | |
days = (end_date - cur_date).days | |
for day in range(days + 1): | |
plt.close("all") | |
ax = world.plot(figsize=(10, 6), color="lightgray", edgecolor="black") | |
cur_date_start = cur_date.strftime("%Y-%m-%d 00:00:00.000000") | |
prev_checkins = gdf[gdf["date"] < cur_date_start] | |
if len(prev_checkins) > 0: | |
prev_checkins.plot(ax=ax, color="blue", markersize=20) | |
cur_date_end = cur_date.strftime("%Y-%m-%d 24:00:00.000000") | |
today_checkins = gdf[ | |
(cur_date_start < gdf["date"]) & (gdf["date"] < cur_date_end) | |
] | |
if len(today_checkins) > 0: | |
today_checkins.plot(ax=ax, color="red", markersize=40) | |
checkins = gdf[gdf["date"] < cur_date_end] | |
n_checkins = len(checkins) | |
n_places = len(checkins["fsq_id"].unique()) | |
cur_date_str = cur_date_start.split()[0] | |
ax.set_title(f"{cur_date_str} Check-ins: {n_checkins} Places: {n_places}") | |
ax.axis("off") | |
ax.set_aspect("equal") | |
plt.savefig(f"{output_dir}/{cur_date_str}.png", dpi=300, bbox_inches="tight") | |
cur_date += timedelta(days=1) | |
def main(): | |
foursquare_path = "/home/airalcorn2/Documents/Foursquare" | |
get_checkins(foursquare_path) | |
save_maps(foursquare_path) | |
# To create a video of the saved images, in the maps directory, run: | |
# ffmpeg -framerate 14 -pattern_type glob -i 'maps/*.png' -c:v libx264 out.mp4 | |
if __name__ == "__main__": | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment