Menezes commited on
Commit
06110b4
·
verified ·
1 Parent(s): 173a283

Upload 2 files

Browse files
Files changed (2) hide show
  1. app.py +214 -0
  2. requirements.txt +5 -0
app.py ADDED
@@ -0,0 +1,214 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import re
3
+ import gradio as gr
4
+ from geopy.geocoders import Nominatim
5
+ import osmnx as ox
6
+ import folium
7
+ import branca
8
+ import shutil
9
+
10
+ # --- Initial settings ---
11
+ geolocator = Nominatim(user_agent="gradio_osm_app")
12
+ ox.settings.log_console = False
13
+
14
+ # Download directory
15
+ DOWNLOAD_DIR = os.path.join(os.getcwd(), "download")
16
+ os.makedirs(DOWNLOAD_DIR, exist_ok=True)
17
+
18
+ def slugify(name):
19
+ return re.sub(r"[^0-9A-Za-z]+", "_", name).strip("_")
20
+
21
+ def ensure_saved(gdf, slug, layer):
22
+ if gdf.empty:
23
+ return
24
+ filename = f"{slug}_{layer}.gpkg"
25
+ path = os.path.join(DOWNLOAD_DIR, filename)
26
+ if os.path.exists(path):
27
+ os.remove(path)
28
+ gdf.to_file(path, driver="GPKG")
29
+
30
+ def make_legend(selected_layers):
31
+ color_map = {
32
+ "Highways": "yellow",
33
+ "Buildings": "#ff802a",
34
+ "School": "blue",
35
+ "Fire Station": "red",
36
+ "Hospital": "green",
37
+ "Police Station": "lightblue",
38
+ "Restaurants": "orange",
39
+ "Hotels": "purple",
40
+ "Monuments": "lightgreen"
41
+ }
42
+ html = '''
43
+ <div style="
44
+ position: fixed; bottom: 50px; left: 10px;
45
+ background-color: rgba(0,0,0,0.7); color: white;
46
+ padding: 10px; font-size:14px; border-radius:5px; z-index:9999;
47
+ ">
48
+ <b>Legend</b><br>
49
+ '''
50
+ for layer in selected_layers:
51
+ color = color_map.get(layer, "gray")
52
+ html += f'''
53
+ <i style="background: {color}; width:10px;height:10px;display:inline-block;margin-right:5px;"></i>{layer}<br>
54
+ '''
55
+ html += '</div>'
56
+ return branca.element.Element(html)
57
+
58
+ style_funcs = {
59
+ "Highways": lambda f: {"color": "yellow", "weight": 0.5},
60
+ "Buildings": lambda f: {"fill": True, "fillColor": "#ff802a", "color": "#ff802a", "weight": 0.5, "fillOpacity": 0.6},
61
+ "School": lambda f: {"fill": True, "fillColor": "blue", "color": "blue", "weight": 0.5, "fillOpacity": 0.6},
62
+ "Fire Station": lambda f: {"fill": True, "fillColor": "red", "color": "red", "weight": 0.5, "fillOpacity": 0.6},
63
+ "Hospital": lambda f: {"fill": True, "fillColor": "green", "color": "green", "weight": 0.5, "fillOpacity": 0.6},
64
+ "Police Station": lambda f: {"fill": True, "fillColor": "lightblue", "color": "lightblue", "weight": 0.5, "fillOpacity": 0.6},
65
+ "Restaurants": lambda f: {"fill": True, "fillColor": "orange", "color": "orange", "weight": 0.5, "fillOpacity": 0.6},
66
+ "Hotels": lambda f: {"fill": True, "fillColor": "purple", "color": "purple", "weight": 0.5, "fillOpacity": 0.6},
67
+ "Monuments": lambda f: {"fill": True, "fillColor": "lightgreen", "color": "lightgreen", "weight": 0.5, "fillOpacity": 0.6},
68
+ }
69
+
70
+ def map_with_layers(place_name, cb_highways, cb_buildings, cb_school,
71
+ cb_fire, cb_hospital, cb_police, cb_rest, cb_hotels, cb_monuments):
72
+ if not place_name.strip():
73
+ yield None, "❌ Please enter a valid place name."
74
+ return
75
+ slug = slugify(place_name)
76
+
77
+ yield None, "🔄 Geocoding..."
78
+ try:
79
+ gdf_place = ox.geocode_to_gdf(place_name)
80
+ poly = gdf_place.geometry.iloc[0]
81
+ lat, lon = poly.centroid.y, poly.centroid.x
82
+ except Exception as e:
83
+ yield None, f"❌ Geocoding error: {e}"
84
+ return
85
+
86
+ layers = {}
87
+ if cb_highways:
88
+ yield None, "🔄 Downloading Highways..."
89
+ G = ox.graph_from_polygon(poly, network_type="all", simplify=True)
90
+ gdf = ox.graph_to_gdfs(G, nodes=False, edges=True)
91
+ layers['Highways'] = gdf
92
+ ensure_saved(gdf, slug, 'highways')
93
+
94
+ tag_map = {
95
+ 'Buildings': {'building': True}, 'School': {'amenity': 'school'},
96
+ 'Fire Station': {'amenity': 'fire_station'}, 'Hospital': {'amenity': 'hospital'},
97
+ 'Police Station': {'amenity': 'police'}, 'Restaurants': {'amenity': 'restaurant'},
98
+ 'Hotels': {'tourism': 'hotel'}, 'Monuments': {'historic': 'monument'}
99
+ }
100
+ flags = [cb_buildings, cb_school, cb_fire, cb_hospital,
101
+ cb_police, cb_rest, cb_hotels, cb_monuments]
102
+ for (name, tags), flag in zip(tag_map.items(), flags):
103
+ if flag:
104
+ yield None, f"🔄 Downloading {name}..."
105
+ gdf2 = ox.features_from_polygon(poly, tags)
106
+ gdf2 = gdf2[gdf2.geometry.type.isin(['Polygon', 'MultiPolygon'])]
107
+ layers[name] = gdf2
108
+ ensure_saved(gdf2, slug, name.replace(' ', '').lower())
109
+
110
+ yield None, "🔄 Rendering map..."
111
+ m = folium.Map([lat, lon], zoom_start=13, tiles='CartoDB Dark_Matter')
112
+ for name, gdf in layers.items():
113
+ if gdf.empty:
114
+ continue
115
+ has_name = 'name' in gdf.columns and gdf['name'].notna().any()
116
+ cols = ['geometry', 'name'] if has_name else ['geometry']
117
+ gj = folium.GeoJson(gdf[cols], name=name, style_function=style_funcs[name])
118
+ if has_name:
119
+ gj.add_child(folium.GeoJsonPopup(fields=['name'], labels=False))
120
+ gj.add_to(m)
121
+
122
+ folium.LayerControl(collapsed=False).add_to(m)
123
+ m.get_root().html.add_child(make_legend(list(layers.keys())))
124
+
125
+ html_path = os.path.join(DOWNLOAD_DIR, f"{slug}_map.html")
126
+ m.save(html_path)
127
+ yield m._repr_html_(), '✅ Map ready!'
128
+
129
+ def download_data(place_name, cb_highways, cb_buildings, cb_school,
130
+ cb_fire, cb_hospital, cb_police, cb_rest, cb_hotels, cb_monuments):
131
+ slug = slugify(place_name)
132
+ files = []
133
+ for layer, flag in zip(
134
+ ['highways', 'buildings', 'school', 'fire_station', 'hospital',
135
+ 'police_station', 'restaurants', 'hotels', 'monuments'],
136
+ [cb_highways, cb_buildings, cb_school, cb_fire, cb_hospital,
137
+ cb_police, cb_rest, cb_hotels, cb_monuments]
138
+ ):
139
+ if flag:
140
+ path = os.path.join(DOWNLOAD_DIR, f"{slug}_{layer}.gpkg")
141
+ if os.path.exists(path):
142
+ files.append(path)
143
+ html_path = os.path.join(DOWNLOAD_DIR, f"{slug}_map.html")
144
+ if os.path.exists(html_path):
145
+ files.append(html_path)
146
+ if not files:
147
+ raise gr.Error('No layer to download.')
148
+
149
+ # Limpa a pasta após retorno
150
+ result = list(files) # cópia da lista
151
+ shutil.rmtree(DOWNLOAD_DIR)
152
+ os.makedirs(DOWNLOAD_DIR, exist_ok=True)
153
+ return result
154
+
155
+ # --- Layout com abas ---
156
+ with gr.Blocks(title="Geoeasy View") as demo:
157
+ gr.HTML("""
158
+ <style>
159
+ #logo { float: left; }
160
+ #app-title { display: inline-block; vertical-align: middle; margin: 0 0 0 1em; }
161
+ .header-wrapper { overflow: auto; margin-bottom: 1em; }
162
+ </style>
163
+ """)
164
+ with gr.Tabs():
165
+ with gr.TabItem('Map'):
166
+ gr.HTML("""
167
+ <div class="header-wrapper">
168
+ <h1 id="app-title">OSM View</h1>
169
+ </div>
170
+ """)
171
+ inp = gr.Textbox(label='Place', placeholder='e.g.: Porto, Portugal')
172
+ with gr.Row():
173
+ cb_highways = gr.Checkbox(label='Highways', value=True)
174
+ cb_buildings = gr.Checkbox(label='Buildings', value=True)
175
+ cb_school = gr.Checkbox(label='School')
176
+ cb_fire = gr.Checkbox(label='Fire Station')
177
+ cb_hospital = gr.Checkbox(label='Hospital')
178
+ with gr.Row():
179
+ cb_police = gr.Checkbox(label='Police Station')
180
+ cb_rest = gr.Checkbox(label='Restaurants')
181
+ cb_hotels = gr.Checkbox(label='Hotels')
182
+ cb_monuments = gr.Checkbox(label='Monuments')
183
+ btn_map = gr.Button('Show Map')
184
+ btn_dl = gr.Button('Download Files')
185
+ out_map, out_status = gr.HTML(), gr.Textbox(interactive=False)
186
+ out_files = gr.File(file_count='multiple')
187
+
188
+ inputs = [inp, cb_highways, cb_buildings, cb_school, cb_fire,
189
+ cb_hospital, cb_police, cb_rest, cb_hotels, cb_monuments]
190
+ btn_map.click(map_with_layers, inputs=inputs, outputs=[out_map, out_status])
191
+ btn_dl.click(download_data, inputs=inputs, outputs=out_files)
192
+
193
+ with gr.TabItem('Taginfo'):
194
+ gr.Markdown('''
195
+ **Most used keys (Taginfo)**
196
+
197
+ | Position | Key | Approximate usage¹ |
198
+ |----------|------------|----------------------------|
199
+ | 1 | `highway` | ~58 million geometries |
200
+ | 2 | `name` | ~55 million geometries |
201
+ | 3 | `source` | ~52 million geometries |
202
+ | 4 | `building` | ~48 million geometries |
203
+ | 5 | `landuse` | ~34 million geometries |
204
+ | 6 | `natural` | ~20 million geometries |
205
+ | 7 | `waterway` | ~18 million geometries |
206
+ | 8 | `amenity` | ~16 million geometries |
207
+ | 9 | `place` | ~12 million geometries |
208
+ | 10 | `power` | ~14 million geometries |
209
+
210
+ ¹ Approximate values from daily Taginfo reports.
211
+ ''')
212
+
213
+ if __name__ == '__main__':
214
+ demo.launch()
requirements.txt ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ gradio
2
+ osmnx
3
+ geopy
4
+ folium
5
+ branca