143 lines
4.3 KiB
Python
Executable File
143 lines
4.3 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
"""
|
|
Process worldcities.json to filter cities based on:
|
|
- Population >= 1 million OR capital city
|
|
- If country has < 5 cities with 1M+ population, keep largest cities + capitals
|
|
- For city-states (only 1 city), mark for auto-selection
|
|
"""
|
|
|
|
import json
|
|
import sys
|
|
import os
|
|
from collections import defaultdict
|
|
|
|
# Prompt for input file path
|
|
input_path = input("Enter the path to worldcities.json (using Simple Maps data): ").strip()
|
|
|
|
# Expand user home directory if present
|
|
input_path = os.path.expanduser(input_path)
|
|
|
|
# Check if file exists
|
|
if not os.path.isfile(input_path):
|
|
print(f"Error: File not found: {input_path}")
|
|
sys.exit(1)
|
|
|
|
# Prompt for output directory
|
|
output_dir = input("Enter the directory to save filtered_world_cities.json: ").strip()
|
|
|
|
# Expand user home directory if present
|
|
output_dir = os.path.expanduser(output_dir)
|
|
|
|
# Create output directory if it doesn't exist
|
|
if not os.path.exists(output_dir):
|
|
os.makedirs(output_dir)
|
|
|
|
# Construct output file path
|
|
output_path = os.path.join(output_dir, 'filtered_world_cities.json')
|
|
|
|
# Read the input JSON
|
|
print(f"\nReading from: {input_path}")
|
|
with open(input_path, 'r') as f:
|
|
cities = json.load(f)
|
|
|
|
# Group cities by country
|
|
cities_by_country = defaultdict(list)
|
|
for city in cities:
|
|
cities_by_country[city['country']].append(city)
|
|
|
|
# Process each country
|
|
filtered_cities = []
|
|
countries_with_single_city = {}
|
|
|
|
for country, country_cities in cities_by_country.items():
|
|
# Get cities with population >= 1 million
|
|
million_plus = []
|
|
capitals = []
|
|
|
|
for city in country_cities:
|
|
pop = city.get('population')
|
|
is_capital = bool(city.get('capital') and city.get('capital') not in ("", None))
|
|
|
|
# Parse population
|
|
try:
|
|
pop_int = int(pop) if pop else 0
|
|
except (ValueError, TypeError):
|
|
pop_int = 0
|
|
|
|
city['population_int'] = pop_int
|
|
|
|
if is_capital:
|
|
capitals.append(city)
|
|
|
|
if pop_int >= 1000000:
|
|
million_plus.append(city)
|
|
|
|
# Apply filtering rules
|
|
if len(million_plus) >= 5:
|
|
# Keep cities with 1M+ population and capitals
|
|
selected = million_plus + [c for c in capitals if c not in million_plus]
|
|
else:
|
|
# Keep largest cities + capitals
|
|
# Sort by population
|
|
sorted_cities = sorted(country_cities, key=lambda x: x['population_int'], reverse=True)
|
|
|
|
# Take top cities and ensure capitals are included
|
|
num_to_keep = max(5, len(million_plus))
|
|
selected = sorted_cities[:num_to_keep]
|
|
|
|
# Add any capitals not already included
|
|
for capital in capitals:
|
|
if capital not in selected:
|
|
selected.append(capital)
|
|
|
|
# Remove duplicates
|
|
selected_unique = []
|
|
seen_ids = set()
|
|
for city in selected:
|
|
if city['id'] not in seen_ids:
|
|
selected_unique.append(city)
|
|
seen_ids.add(city['id'])
|
|
|
|
# Track city-states (countries with only 1 city in final selection)
|
|
is_city_state = len(selected_unique) == 1
|
|
countries_with_single_city[country] = is_city_state
|
|
|
|
filtered_cities.extend(selected_unique)
|
|
|
|
# Keep only required fields and sort
|
|
output_cities = []
|
|
for city in filtered_cities:
|
|
output_cities.append({
|
|
'city': city['city'],
|
|
'city_ascii': city['city_ascii'],
|
|
'lat': city['lat'],
|
|
'lng': city['lng'],
|
|
'country': city['country'],
|
|
'admin_name': city['admin_name'],
|
|
'population': city['population'],
|
|
'id': city['id'],
|
|
'isCityCountry': countries_with_single_city.get(city['country'], False)
|
|
})
|
|
|
|
# Sort by country, then by population
|
|
def safe_pop_int(pop_str):
|
|
try:
|
|
return -int(float(pop_str)) if pop_str else 0
|
|
except (ValueError, TypeError):
|
|
return 0
|
|
|
|
output_cities.sort(key=lambda x: (x['country'], safe_pop_int(x['population'])))
|
|
|
|
# Write output
|
|
print(f"Writing to: {output_path}")
|
|
with open(output_path, 'w') as f:
|
|
json.dump(output_cities, f, indent=2, ensure_ascii=False)
|
|
|
|
city_states_count = sum(1 for v in countries_with_single_city.values() if v)
|
|
|
|
print(f"\nProcessed {len(cities)} cities")
|
|
print(f"Filtered to {len(output_cities)} cities")
|
|
print(f"Countries: {len(cities_by_country)}")
|
|
print(f"City-states (auto-select): {city_states_count}")
|
|
print(f"\nOutput successfully written to: {output_path}")
|