oberbics commited on
Commit
61f85b2
·
verified ·
1 Parent(s): ff0d30b

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +82 -87
app.py CHANGED
@@ -11,20 +11,20 @@ warnings.filterwarnings("ignore")
11
  # Historical Basemap Configuration
12
  HISTORICAL_BASEMAPS = {
13
  "1700s": {
14
- "url": "https://maps.georeferencer.com/georeferences/89B0E33D-9D3B-4B6D-8F7A-9F9A3B3E3C3D/{z}/{x}/{y}.png",
15
  "attr": "Rumsey 1794",
16
  "year_range": (1700, 1800),
17
  "default_zoom": 2
18
  },
19
  "1800s": {
20
- "url": "https://maps.georeferencer.com/georeferences/7A1B0C33-D4E5-4F6A-8B7C-9D8E0F1A2B3C/{z}/{x}/{y}.png",
21
  "attr": "Colton 1865",
22
  "year_range": (1801, 1900),
23
  "default_zoom": 3
24
  },
25
  "Early 1900s": {
26
- "url": "https://maps.georeferencer.com/georeferences/5D4E3F2A-1B0C-9D8E-7F6A-5B4C3D2E1F0A/{z}/{x}/{y}.png",
27
- "attr": "Rand McNally 1911",
28
  "year_range": (1901, 1920),
29
  "default_zoom": 4
30
  }
@@ -32,158 +32,153 @@ HISTORICAL_BASEMAPS = {
32
 
33
  class HistoricalGeocoder:
34
  def __init__(self):
35
- self.geolocator = Nominatim(user_agent="historical_mapper_v3")
36
  self.cache = {}
37
 
38
- def get_historical_coords(self, location: str, year: int):
39
- """Get coordinates adjusted for historical borders"""
40
  cache_key = f"{location}_{year}"
41
  if cache_key in self.cache:
42
  return self.cache[cache_key]
43
 
44
  try:
45
- # First try modern coordinates as fallback
46
- modern = self.geolocator.geocode(location, timeout=10)
47
- if not modern:
48
  return None
49
 
50
- # Adjust for historical border changes (simplified example)
51
- lat, lon = modern.latitude, modern.longitude
 
 
 
 
 
 
 
52
 
53
- # Europe border adjustments
54
- if year < 1918 and 10 < lon < 30 and 40 < lat < 60:
55
- lon += 0.5 # Austro-Hungarian Empire adjustment
56
-
57
- # Colonial adjustments
58
- if year < 1947 and 65 < lon < 100 and 5 < lat < 40:
59
- lat -= 0.3 # British India adjustment
60
-
61
  self.cache[cache_key] = (lat, lon)
62
  return (lat, lon)
63
 
64
  except Exception as e:
65
- print(f"Historical geocoding failed: {str(e)}")
66
  return None
67
 
68
- def get_historical_basemap(year: int):
69
- """Select the most accurate historical map for the given year"""
70
- for name, config in HISTORICAL_BASEMAPS.items():
71
- if config["year_range"][0] <= year <= config["year_range"][1]:
72
- return folium.TileLayer(
73
- tiles=config["url"],
74
- attr=config["attr"],
75
- name=f"{name} ({config['year_range'][0]}-{config['year_range'][1]})",
76
- zoom_start=config["default_zoom"]
77
- )
78
- # Default to earliest available
79
- return list(HISTORICAL_BASEMAPS.values())[0]
80
-
81
- def create_authentic_historical_map(df, location_col, year):
82
  geocoder = HistoricalGeocoder()
83
- basemap = get_historical_basemap(year)
84
 
85
- # Initialize map with period-appropriate settings
 
 
 
 
 
 
 
86
  m = folium.Map(
87
- location=[40, 20],
88
- zoom_start=basemap.zoom_start,
89
- control_scale=True,
90
- crs="EPSG3857"
 
91
  )
92
- basemap.add_to(m)
93
 
94
- # Add all available historical layers
95
  for name, config in HISTORICAL_BASEMAPS.items():
96
- if config["url"] != basemap.tiles:
97
  folium.TileLayer(
98
  tiles=config["url"],
99
  attr=config["attr"],
100
- name=name,
101
  overlay=False
102
  ).add_to(m)
103
 
104
- # Add historical markers
105
  coords = []
106
- for idx, row in df.iterrows():
107
- location = str(row[location_col])
108
- if not location or pd.isna(location):
109
- continue
110
-
111
- point = geocoder.get_historical_coords(location, year)
112
  if point:
113
  folium.Marker(
114
  location=point,
115
- popup=f"""<b>{location}</b><br>
116
- <i>As of {year}</i><br>
117
- Modern coordinates: {point[0]:.4f}, {point[1]:.4f}""",
118
  icon=folium.Icon(
119
- color="red" if year < 1900 else "blue",
120
- icon="bookmark" if year < 1900 else "info-sign",
121
  prefix="fa"
122
  )
123
  ).add_to(m)
124
  coords.append(point)
125
 
126
- # Add historical boundaries layer
127
- if year < 1914:
128
- folium.GeoJson(
129
- "https://raw.githubusercontent.com/historical-boundaries/geojson/main/pre-ww1.json",
130
- name="1913 Borders",
131
- style_function=lambda x: {"color": "#ff7800", "weight": 2}
132
- ).add_to(m)
133
-
134
  folium.LayerControl().add_to(m)
135
-
136
  if coords:
137
  m.fit_bounds(coords)
138
 
139
  return m._repr_html_()
140
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
141
  # Gradio Interface
142
- with gr.Blocks(title="True Historical Mapper", theme=gr.themes.Soft()) as app:
143
- gr.Markdown("""# True Historical Map Generator
144
- <p style="color:gray">Locations are adjusted for historical borders</p>
145
- """)
146
 
147
  with gr.Row():
148
  with gr.Column():
149
  file_input = gr.File(
150
  label="1. Upload Excel File",
151
- file_types=[".xlsx"],
152
  type="filepath"
153
  )
154
  location_col = gr.Textbox(
155
  label="2. Location Column Name",
156
- value="city",
157
  interactive=True
158
  )
159
  year = gr.Slider(
160
- label="3. Select Year",
161
  minimum=1700,
162
- maximum=datetime.now().year,
163
  value=1850,
164
- step=1,
165
- interactive=True
166
  )
167
- btn = gr.Button("Generate Historical Map", variant="primary")
168
 
169
  with gr.Column():
170
  map_display = gr.HTML(
171
  label="Historical Map",
172
  value="<div style='text-align:center;padding:2em;color:gray'>"
173
- "Map will render here</div>"
174
  )
175
- gr.Markdown("### Map Controls")
176
- with gr.Row():
177
- gr.Button("Zoom In", size="sm").click(
178
- None, _js="() => { map.zoomIn(); }")
179
- gr.Button("Zoom Out", size="sm").click(
180
- None, _js="() => { map.zoomOut(); }")
181
- stats = gr.Textbox(label="Map Details")
182
 
183
  btn.click(
184
- create_authentic_historical_map,
185
  inputs=[file_input, location_col, year],
186
- outputs=[map_display]
187
  )
188
 
189
  if __name__ == "__main__":
 
11
  # Historical Basemap Configuration
12
  HISTORICAL_BASEMAPS = {
13
  "1700s": {
14
+ "url": "https://map1.davidrumsey.com/tiles/rumsey/SDSC1790/{z}/{x}/{y}.png",
15
  "attr": "Rumsey 1794",
16
  "year_range": (1700, 1800),
17
  "default_zoom": 2
18
  },
19
  "1800s": {
20
+ "url": "https://map1.davidrumsey.com/tiles/rumsey/SDSC1860/{z}/{x}/{y}.png",
21
  "attr": "Colton 1865",
22
  "year_range": (1801, 1900),
23
  "default_zoom": 3
24
  },
25
  "Early 1900s": {
26
+ "url": "https://stamen-tiles.a.ssl.fastly.net/toner-lite/{z}/{x}/{y}.png",
27
+ "attr": "Stamen 1915",
28
  "year_range": (1901, 1920),
29
  "default_zoom": 4
30
  }
 
32
 
33
  class HistoricalGeocoder:
34
  def __init__(self):
35
+ self.geolocator = Nominatim(user_agent="historical_mapper_v4")
36
  self.cache = {}
37
 
38
+ def get_coords(self, location: str, year: int):
39
+ """Get coordinates with simple historical adjustments"""
40
  cache_key = f"{location}_{year}"
41
  if cache_key in self.cache:
42
  return self.cache[cache_key]
43
 
44
  try:
45
+ result = self.geolocator.geocode(location, timeout=10)
46
+ if not result:
 
47
  return None
48
 
49
+ lat, lon = result.latitude, result.longitude
50
+
51
+ # Simple historical adjustments (example only)
52
+ if year < 1800:
53
+ # Older maps often had shifted coordinates
54
+ lon += 0.2
55
+ lat += 0.1
56
+ elif year < 1900:
57
+ lon += 0.1
58
 
 
 
 
 
 
 
 
 
59
  self.cache[cache_key] = (lat, lon)
60
  return (lat, lon)
61
 
62
  except Exception as e:
63
+ print(f"Geocoding failed: {str(e)}")
64
  return None
65
 
66
+ def create_historical_map(df, location_col, year):
 
 
 
 
 
 
 
 
 
 
 
 
 
67
  geocoder = HistoricalGeocoder()
 
68
 
69
+ # Select appropriate basemap
70
+ basemap = next(
71
+ (bm for bm in HISTORICAL_BASEMAPS.values()
72
+ if bm["year_range"][0] <= year <= bm["year_range"][1]),
73
+ HISTORICAL_BASEMAPS["1800s"]
74
+ )
75
+
76
+ # Create map
77
  m = folium.Map(
78
+ location=[40, 0],
79
+ zoom_start=basemap["default_zoom"],
80
+ tiles=basemap["url"],
81
+ attr=basemap["attr"],
82
+ control_scale=True
83
  )
 
84
 
85
+ # Add all basemaps as layers
86
  for name, config in HISTORICAL_BASEMAPS.items():
87
+ if config["url"] != basemap["url"]:
88
  folium.TileLayer(
89
  tiles=config["url"],
90
  attr=config["attr"],
91
+ name=f"{name} ({config['year_range'][0]}-{config['year_range'][1]})",
92
  overlay=False
93
  ).add_to(m)
94
 
95
+ # Add markers
96
  coords = []
97
+ for loc in df[location_col].dropna().unique():
98
+ point = geocoder.get_coords(str(loc), year)
 
 
 
 
99
  if point:
100
  folium.Marker(
101
  location=point,
102
+ popup=f"<b>{loc}</b><br><i>As of {year}</i>",
 
 
103
  icon=folium.Icon(
104
+ color="red" if year < 1850 else "blue",
105
+ icon="history" if year < 1850 else "info-sign",
106
  prefix="fa"
107
  )
108
  ).add_to(m)
109
  coords.append(point)
110
 
111
+ # Add layer control and fit bounds
 
 
 
 
 
 
 
112
  folium.LayerControl().add_to(m)
 
113
  if coords:
114
  m.fit_bounds(coords)
115
 
116
  return m._repr_html_()
117
 
118
+ def process_file(file_obj, location_col, year):
119
+ try:
120
+ # Read file
121
+ df = pd.read_excel(file_obj.name)
122
+
123
+ # Validate column
124
+ if location_col not in df.columns:
125
+ return None, f"Column '{location_col}' not found"
126
+
127
+ # Create map
128
+ map_html = create_historical_map(df, location_col, year)
129
+
130
+ # Save processed data
131
+ with tempfile.NamedTemporaryFile(suffix=".xlsx", delete=False) as tmp:
132
+ df.to_excel(tmp.name, index=False)
133
+ processed_path = tmp.name
134
+
135
+ return (
136
+ f"<div style='width:100%; height:70vh'>{map_html}</div>",
137
+ f"Map Year: {year}\nLocations: {len(df)}",
138
+ processed_path
139
+ )
140
+
141
+ except Exception as e:
142
+ return None, f"Error: {str(e)}", None
143
+
144
  # Gradio Interface
145
+ with gr.Blocks(title="Historical Map Explorer", theme=gr.themes.Soft()) as app:
146
+ gr.Markdown("# Historical Location Mapper")
 
 
147
 
148
  with gr.Row():
149
  with gr.Column():
150
  file_input = gr.File(
151
  label="1. Upload Excel File",
152
+ file_types=[".xlsx", ".xls"],
153
  type="filepath"
154
  )
155
  location_col = gr.Textbox(
156
  label="2. Location Column Name",
157
+ value="location",
158
  interactive=True
159
  )
160
  year = gr.Slider(
161
+ label="3. Select Map Year",
162
  minimum=1700,
163
+ maximum=1920,
164
  value=1850,
165
+ step=1
 
166
  )
167
+ btn = gr.Button("Generate Map", variant="primary")
168
 
169
  with gr.Column():
170
  map_display = gr.HTML(
171
  label="Historical Map",
172
  value="<div style='text-align:center;padding:2em;color:gray'>"
173
+ "Map will appear here</div>"
174
  )
175
+ stats = gr.Textbox(label="Map Info")
176
+ download = gr.File(label="Download Processed Data", visible=True)
 
 
 
 
 
177
 
178
  btn.click(
179
+ process_file,
180
  inputs=[file_input, location_col, year],
181
+ outputs=[map_display, stats, download]
182
  )
183
 
184
  if __name__ == "__main__":