Spaces:
Sleeping
Sleeping
import gradio as gr | |
import pandas as pd | |
import folium | |
from geopy.geocoders import Nominatim | |
import tempfile | |
import warnings | |
from datetime import datetime | |
warnings.filterwarnings("ignore") | |
# Historical Basemap Configuration | |
HISTORICAL_BASEMAPS = { | |
"1700s": { | |
"url": "https://map1.davidrumsey.com/tiles/rumsey/SDSC1790/{z}/{x}/{y}.png", | |
"attr": "Rumsey 1794", | |
"year_range": (1700, 1800), | |
"default_zoom": 2 | |
}, | |
"1800s": { | |
"url": "https://map1.davidrumsey.com/tiles/rumsey/SDSC1860/{z}/{x}/{y}.png", | |
"attr": "Colton 1865", | |
"year_range": (1801, 1900), | |
"default_zoom": 3 | |
}, | |
"Early 1900s": { | |
"url": "https://stamen-tiles.a.ssl.fastly.net/toner-lite/{z}/{x}/{y}.png", | |
"attr": "Stamen 1915", | |
"year_range": (1901, 1920), | |
"default_zoom": 4 | |
} | |
} | |
class HistoricalGeocoder: | |
def __init__(self): | |
self.geolocator = Nominatim(user_agent="historical_mapper_v4") | |
self.cache = {} | |
def get_coords(self, location: str, year: int): | |
"""Get coordinates with simple historical adjustments""" | |
cache_key = f"{location}_{year}" | |
if cache_key in self.cache: | |
return self.cache[cache_key] | |
try: | |
result = self.geolocator.geocode(location, timeout=10) | |
if not result: | |
return None | |
lat, lon = result.latitude, result.longitude | |
# Simple historical adjustments (example only) | |
if year < 1800: | |
# Older maps often had shifted coordinates | |
lon += 0.2 | |
lat += 0.1 | |
elif year < 1900: | |
lon += 0.1 | |
self.cache[cache_key] = (lat, lon) | |
return (lat, lon) | |
except Exception as e: | |
print(f"Geocoding failed: {str(e)}") | |
return None | |
def create_historical_map(df, location_col, year): | |
geocoder = HistoricalGeocoder() | |
# Select appropriate basemap | |
basemap = next( | |
(bm for bm in HISTORICAL_BASEMAPS.values() | |
if bm["year_range"][0] <= year <= bm["year_range"][1]), | |
HISTORICAL_BASEMAPS["1800s"] | |
) | |
# Create map | |
m = folium.Map( | |
location=[40, 0], | |
zoom_start=basemap["default_zoom"], | |
tiles=basemap["url"], | |
attr=basemap["attr"], | |
control_scale=True | |
) | |
# Add all basemaps as layers | |
for name, config in HISTORICAL_BASEMAPS.items(): | |
if config["url"] != basemap["url"]: | |
folium.TileLayer( | |
tiles=config["url"], | |
attr=config["attr"], | |
name=f"{name} ({config['year_range'][0]}-{config['year_range'][1]})", | |
overlay=False | |
).add_to(m) | |
# Add markers | |
coords = [] | |
for loc in df[location_col].dropna().unique(): | |
point = geocoder.get_coords(str(loc), year) | |
if point: | |
folium.Marker( | |
location=point, | |
popup=f"<b>{loc}</b><br><i>As of {year}</i>", | |
icon=folium.Icon( | |
color="red" if year < 1850 else "blue", | |
icon="history" if year < 1850 else "info-sign", | |
prefix="fa" | |
) | |
).add_to(m) | |
coords.append(point) | |
# Add layer control and fit bounds | |
folium.LayerControl().add_to(m) | |
if coords: | |
m.fit_bounds(coords) | |
return m._repr_html_() | |
def process_file(file_obj, location_col, year): | |
try: | |
# Read file | |
df = pd.read_excel(file_obj.name) | |
# Validate column | |
if location_col not in df.columns: | |
return None, f"Column '{location_col}' not found" | |
# Create map | |
map_html = create_historical_map(df, location_col, year) | |
# Save processed data | |
with tempfile.NamedTemporaryFile(suffix=".xlsx", delete=False) as tmp: | |
df.to_excel(tmp.name, index=False) | |
processed_path = tmp.name | |
return ( | |
f"<div style='width:100%; height:70vh'>{map_html}</div>", | |
f"Map Year: {year}\nLocations: {len(df)}", | |
processed_path | |
) | |
except Exception as e: | |
return None, f"Error: {str(e)}", None | |
# Gradio Interface | |
with gr.Blocks(title="Historical Map Explorer", theme=gr.themes.Soft()) as app: | |
gr.Markdown("# Historical Location Mapper") | |
with gr.Row(): | |
with gr.Column(): | |
file_input = gr.File( | |
label="1. Upload Excel File", | |
file_types=[".xlsx", ".xls"], | |
type="filepath" | |
) | |
location_col = gr.Textbox( | |
label="2. Location Column Name", | |
value="location", | |
interactive=True | |
) | |
year = gr.Slider( | |
label="3. Select Map Year", | |
minimum=1700, | |
maximum=1920, | |
value=1850, | |
step=1 | |
) | |
btn = gr.Button("Generate Map", variant="primary") | |
with gr.Column(): | |
map_display = gr.HTML( | |
label="Historical Map", | |
value="<div style='text-align:center;padding:2em;color:gray'>" | |
"Map will appear here</div>" | |
) | |
stats = gr.Textbox(label="Map Info") | |
download = gr.File(label="Download Processed Data", visible=True) | |
btn.click( | |
process_file, | |
inputs=[file_input, location_col, year], | |
outputs=[map_display, stats, download] | |
) | |
if __name__ == "__main__": | |
app.launch() |