-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathvoter_roll_map.py
95 lines (78 loc) · 3.22 KB
/
voter_roll_map.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
# Dependencies
import pandas as pd
import folium
from geopy.geocoders import Nominatim
from geopy.distance import geodesic
import csv
from tkinter import filedialog, Tk
import webbrowser
import os
# 1. Load the Voter Roll CSV
def load_voter_roll():
Tk().withdraw() # Hides the root window
file_path = filedialog.askopenfilename(filetypes=[("CSV files", "*.csv")])
if not file_path:
raise ValueError("No file selected.")
return pd.read_csv(file_path)
# 2. Check for Duplicates and Concatenate Addresses
def clean_voter_roll(df):
df['Address'] = df['Address'].str.strip() # Remove leading/trailing whitespaces
df_grouped = df.groupby('Address', as_index=False).agg(lambda x: ', '.join(set(x)))
return df_grouped
# 3. Geolocate and Plot the Addresses
def plot_addresses(df):
geolocator = Nominatim(user_agent="voter_roll_mapping")
map_center = [37.7749, -122.4194] # Default to San Francisco, update later
voter_map = folium.Map(location=map_center, zoom_start=12)
for index, row in df.iterrows():
address = row['Address']
try:
location = geolocator.geocode(address)
if location:
folium.Marker(
location=[location.latitude, location.longitude],
popup=address,
icon=folium.Icon(color="green", icon="ok-sign")
).add_to(voter_map)
except Exception as e:
print(f"Error geolocating {address}: {e}")
return voter_map
# 4. Geo-locate or Input Address
def geolocate_and_zoom(voter_map, user_address=None):
geolocator = Nominatim(user_agent="voter_roll_user_location")
if not user_address:
user_location = geolocator.geocode("Your IP-based location")
if user_location:
user_coords = [user_location.latitude, user_location.longitude]
else:
raise ValueError("Unable to determine geolocation.")
else:
location = geolocator.geocode(user_address)
if location:
user_coords = [location.latitude, location.longitude]
else:
raise ValueError("Address not found.")
# Zoom to .5 mile (approx. 0.8 km) radius
voter_map.fit_bounds([[user_coords[0] - 0.005, user_coords[1] - 0.005],
[user_coords[0] + 0.005, user_coords[1] + 0.005]])
return voter_map
# 5. Save and Display the Map
def save_and_open_map(voter_map):
voter_map.save("voter_roll_map.html")
webbrowser.open(f"file://{os.path.realpath('voter_roll_map.html')}")
# Main workflow
if __name__ == "__main__":
try:
# Load voter roll
voter_roll_df = load_voter_roll()
# Clean and concatenate addresses
cleaned_voter_roll_df = clean_voter_roll(voter_roll_df)
# Plot voter addresses on map
voter_map = plot_addresses(cleaned_voter_roll_df)
# Geolocate or use input address
user_input_address = input("Enter your address or press Enter to use geolocation: ")
voter_map = geolocate_and_zoom(voter_map, user_address=user_input_address if user_input_address else None)
# Save and open the map in a browser
save_and_open_map(voter_map)
except Exception as e:
print(f"An error occurred: {e}")