hussain2010 commited on
Commit
48ceb28
Β·
verified Β·
1 Parent(s): 620c262

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +162 -200
app.py CHANGED
@@ -8,60 +8,21 @@ import warnings
8
  import io
9
  from shapely.geometry import Polygon, MultiPolygon
10
 
11
- # Suppress warnings
12
- warnings.filterwarnings("ignore", category=RuntimeWarning)
13
- warnings.filterwarnings("ignore", category=UserWarning)
14
-
15
- # Set Streamlit Page Configuration
16
- st.set_page_config(page_title="World Administrative Map Customizer", layout="wide")
17
-
18
- # Hugging Face Credentials
19
- hf_api_key = st.secrets["World_Map_Huggingface_API"]
20
- repo_id = "hussain2010/World_Map_Files"
21
- filename = "gadm_410.gpkg"
22
-
23
- # Streamlit App Title
24
- st.title("πŸ—ΊοΈ World Administrative Map Customizer")
25
-
26
- # Step 1: Download File from Hugging Face
27
- st.subheader("πŸ“₯ Loading Dataset")
28
- try:
29
- dataset_path = hf_hub_download(repo_id=repo_id, filename=filename, token=hf_api_key, repo_type="dataset")
30
- st.success("βœ… Dataset loaded successfully!")
31
- except Exception as e:
32
- st.error(f"⚠️ Error loading dataset: {e}")
33
- st.stop()
34
-
35
- # Step 2: Country Selection
36
- st.subheader("🌍 Select Country")
37
- try:
38
- # Load list of countries first (optimization)
39
- countries_df = gpd.read_file(dataset_path, layer=0)[["NAME_0"]].drop_duplicates()
40
- countries = sorted(countries_df["NAME_0"].tolist())
41
-
42
- selected_country = st.selectbox("Choose a country", countries)
43
-
44
- # Load data for selected country and world data
45
- gdf = gpd.read_file(dataset_path, layer=0, where=f"NAME_0 = '{selected_country}'")
46
- gdf = gdf[gdf.is_valid].to_crs("EPSG:4326")
47
-
48
- # Load world data for the third visualization
49
- world_gdf = gpd.read_file(dataset_path, layer=0)
50
- world_gdf = world_gdf[world_gdf.is_valid].to_crs("EPSG:4326")
51
 
52
  # Special handling for Pakistan
53
  if selected_country == "Pakistan":
54
  # Define administrative levels for Pakistan
55
- admin_levels = {
56
- "Provinces and Territories": "NAME_1",
57
- }
58
- # Add other administrative levels if available
59
- for i in range(2, 6):
60
  col_name = f"NAME_{i}"
61
  if col_name in gdf.columns and not gdf[col_name].isna().all():
62
  level_name = f"Administrative Level {i}"
63
  admin_levels[level_name] = col_name
64
 
 
 
 
65
  # Define Pakistan-specific regions
66
  pakistan_regions = {
67
  "Provinces": ["Punjab", "Sindh", "Khyber Pakhtunkhwa", "Balochistan"],
@@ -75,7 +36,7 @@ try:
75
  default=["Provinces and Territories"]
76
  )
77
 
78
- # Initialize selected_gdf and selected_areas
79
  selected_gdf = gpd.GeoDataFrame(columns=gdf.columns, geometry='geometry', crs=gdf.crs)
80
  selected_areas = []
81
 
@@ -97,10 +58,14 @@ try:
97
  default=pakistan_regions["Territories"]
98
  )
99
 
100
- # Combine provinces and territories selections
101
  selected = selected_provinces + selected_territories
102
  if selected:
103
- level_gdf = gdf[gdf["NAME_1"].isin(selected)]
 
 
 
 
104
  selected_gdf = pd.concat([selected_gdf, level_gdf], ignore_index=True)
105
  selected_areas.extend(selected)
106
 
@@ -116,173 +81,170 @@ try:
116
  )
117
 
118
  if selected:
119
- level_gdf = gdf[gdf[name_column].isin(selected)]
 
120
  selected_gdf = pd.concat([selected_gdf, level_gdf], ignore_index=True)
121
  selected_areas.extend(selected)
122
 
123
- else:
124
- # Handle other countries
125
- admin_levels = {}
126
- for i in range(1, 6):
127
- col_name = f"NAME_{i}"
128
- if col_name in gdf.columns and not gdf[col_name].isna().all():
129
- level_name = f"Administrative Level {i}"
130
- admin_levels[level_name] = col_name
131
-
132
- # Select administrative levels to display
133
- selected_admin_levels = st.multiselect(
134
- "Select Administrative Levels to Display",
135
- list(admin_levels.keys()),
136
- default=[list(admin_levels.keys())[0]] if admin_levels else []
137
- )
138
-
139
- # Initialize selected_gdf and selected_areas
140
- selected_gdf = gpd.GeoDataFrame(columns=gdf.columns, geometry='geometry', crs=gdf.crs)
141
- selected_areas = []
142
-
143
- # Handle selection for each administrative level
144
- for level in selected_admin_levels:
145
- name_column = admin_levels[level]
146
- available_areas = sorted(gdf[name_column].dropna().unique())
147
- selected = st.multiselect(
148
- f"Select {level} regions",
149
- available_areas,
150
- key=f"select_{level}"
151
- )
152
-
153
- if selected:
154
- level_gdf = gdf[gdf[name_column].isin(selected)]
155
- selected_gdf = pd.concat([selected_gdf, level_gdf], ignore_index=True)
156
- selected_areas.extend(selected)
157
 
158
- if not selected_gdf.empty and selected_areas:
159
- # Area Customization
160
- st.subheader("🎨 Area Customization")
161
 
162
- # Create columns for color pickers
163
- num_cols = 3
164
- cols = st.columns(num_cols)
165
- border_colors = {}
166
- fill_colors = {}
167
-
168
- # Create color pickers for each area
169
- for idx, area in enumerate(selected_areas):
170
- with cols[idx % num_cols]:
171
- st.markdown(f"### {area}")
172
- border_colors[area] = st.color_picker(
173
- f"Border color for {area}",
174
- "#000000",
175
- key=f"border_{area}"
176
- )
177
- fill_colors[area] = st.color_picker(
178
- f"Fill color for {area}",
179
- f"#{hash(area) % 0xFFFFFF:06x}",
180
- key=f"fill_{area}"
181
- )
182
-
183
- # Legend Customization
184
- st.subheader("πŸ“Œ Legend Customization")
185
- col1, col2 = st.columns(2)
186
- with col1:
187
- legend_font_size = st.slider("Font Size:", 8, 20, 12)
188
- legend_font_weight = st.selectbox("Font Weight:", ["Normal", "Bold"], index=0)
189
- legend_bg_color = st.color_picker("Background Color:", "#FFFFFF")
190
- with col2:
191
- legend_border_color = st.color_picker("Border Color:", "#000000")
192
- legend_border_width = st.slider("Border Width:", 0.5, 2.0, 1.0)
193
- legend_transparency = st.slider("Transparency:", 0.0, 1.0, 0.5)
194
-
195
- legend_title = st.text_input("Legend Title:", value=f"{selected_country} Administrative Divisions")
196
- legend_location = st.selectbox("Legend Location:",
197
- ["upper right", "upper left", "lower right", "lower left"],
198
- index=0)
199
- legend_columns = st.selectbox("Legend Columns:", [1, 2, 3], index=1)
200
-
201
- # 2D Map Visualization
202
- st.subheader("πŸ—ΊοΈ 2D Map Visualization")
203
-
204
- def create_2d_map():
205
- fig, ax = plt.subplots(figsize=(15, 10))
206
-
207
- # Plot all regions first with a light gray color
208
- for _, row in gdf.iterrows():
209
  if isinstance(row.geometry, MultiPolygon):
210
  for poly in row.geometry.geoms:
211
  x, y = poly.exterior.xy
212
- ax.fill(x, y, color='#EEEEEE', alpha=0.3)
213
- ax.plot(x, y, color='#CCCCCC', linewidth=0.5)
214
  else:
215
  x, y = row.geometry.exterior.xy
216
- ax.fill(x, y, color='#EEEEEE', alpha=0.3)
217
- ax.plot(x, y, color='#CCCCCC', linewidth=0.5)
218
-
219
- patches = []
220
- legend_labels = []
 
 
 
 
 
 
 
 
 
221
 
222
- # Plot selected areas with their chosen colors
223
- for _, row in selected_gdf.iterrows():
224
- area_name = None
225
- for level in selected_admin_levels:
226
- col_name = admin_levels[level]
227
- if row[col_name] in selected_areas:
228
- area_name = row[col_name]
229
- break
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
230
 
231
- if area_name and area_name in border_colors:
232
- if isinstance(row.geometry, MultiPolygon):
233
- for poly in row.geometry.geoms:
234
- x, y = poly.exterior.xy
235
- ax.fill(x, y, color=fill_colors[area_name], alpha=0.5)
236
- ax.plot(x, y, color=border_colors[area_name], linewidth=1)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
237
  else:
238
- x, y = row.geometry.exterior.xy
239
- ax.fill(x, y, color=fill_colors[area_name], alpha=0.5)
240
- ax.plot(x, y, color=border_colors[area_name], linewidth=1)
 
 
 
 
 
241
 
242
- if area_name not in legend_labels:
243
- patch = plt.Rectangle((0, 0), 1, 1,
244
- fc=fill_colors[area_name],
245
- ec=border_colors[area_name],
246
- alpha=0.5)
247
- patches.append(patch)
248
- legend_labels.append(area_name)
249
 
250
- if patches:
251
- ax.legend(patches, legend_labels,
252
- title=legend_title,
253
- loc=legend_location,
254
- fontsize=legend_font_size,
255
- title_fontsize=legend_font_size + 2,
256
- frameon=True,
257
- facecolor=legend_bg_color,
258
- edgecolor=legend_border_color,
259
- framealpha=1-legend_transparency,
260
- ncol=legend_columns)
261
-
262
- ax.set_xticks([])
263
- ax.set_yticks([])
264
- ax.set_frame_on(False)
265
- return fig
266
-
267
- fig_2d = create_2d_map()
268
- st.pyplot(fig_2d)
269
-
270
- # 2D Map Download
271
- col1, col2 = st.columns(2)
272
- with col1:
273
- dpi = st.selectbox("Select DPI", [100, 200, 300, 600])
274
- with col2:
275
- format_option = st.selectbox("Select Format", ["PNG", "PDF", "SVG"])
276
-
277
- buf = io.BytesIO()
278
- fig_2d.savefig(buf, format=format_option.lower(), dpi=dpi, bbox_inches='tight')
279
- buf.seek(0)
280
- st.download_button(
281
- f"Download 2D Map ({format_option})",
282
- buf,
283
- f"{selected_country.lower()}_map_2d.{format_option.lower()}",
284
- f"image/{format_option.lower()}"
285
- )
286
 
287
  # 3D Map Visualization (Current Version)
288
  st.subheader("🌐 3D Map Visualization (Current Version)")
 
8
  import io
9
  from shapely.geometry import Polygon, MultiPolygon
10
 
11
+ # [Previous code remains the same until the Pakistan-specific handling]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
12
 
13
  # Special handling for Pakistan
14
  if selected_country == "Pakistan":
15
  # Define administrative levels for Pakistan
16
+ admin_levels = {}
17
+ for i in range(6): # Include level 0 now
 
 
 
18
  col_name = f"NAME_{i}"
19
  if col_name in gdf.columns and not gdf[col_name].isna().all():
20
  level_name = f"Administrative Level {i}"
21
  admin_levels[level_name] = col_name
22
 
23
+ # Add special entry for Provinces and Territories
24
+ admin_levels["Provinces and Territories"] = "NAME_1"
25
+
26
  # Define Pakistan-specific regions
27
  pakistan_regions = {
28
  "Provinces": ["Punjab", "Sindh", "Khyber Pakhtunkhwa", "Balochistan"],
 
36
  default=["Provinces and Territories"]
37
  )
38
 
39
+ # Initialize selected_gdf and selected_areas with proper structure
40
  selected_gdf = gpd.GeoDataFrame(columns=gdf.columns, geometry='geometry', crs=gdf.crs)
41
  selected_areas = []
42
 
 
58
  default=pakistan_regions["Territories"]
59
  )
60
 
61
+ # Process both provinces and territories
62
  selected = selected_provinces + selected_territories
63
  if selected:
64
+ level_gdf = gdf[gdf["NAME_1"].isin(selected)].copy()
65
+ # Store the region type (province or territory) in the GeoDataFrame
66
+ level_gdf['region_type'] = level_gdf['NAME_1'].map(
67
+ lambda x: 'Province' if x in pakistan_regions["Provinces"] else 'Territory'
68
+ )
69
  selected_gdf = pd.concat([selected_gdf, level_gdf], ignore_index=True)
70
  selected_areas.extend(selected)
71
 
 
81
  )
82
 
83
  if selected:
84
+ level_gdf = gdf[gdf[name_column].isin(selected)].copy()
85
+ level_gdf['region_type'] = level # Store the admin level type
86
  selected_gdf = pd.concat([selected_gdf, level_gdf], ignore_index=True)
87
  selected_areas.extend(selected)
88
 
89
+ # [Rest of the code remains the same until the visualization functions]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
90
 
91
+ def create_2d_map():
92
+ fig, ax = plt.subplots(figsize=(15, 10))
 
93
 
94
+ # Plot base map (all regions in light gray)
95
+ for _, row in gdf.iterrows():
96
+ if isinstance(row.geometry, MultiPolygon):
97
+ for poly in row.geometry.geoms:
98
+ x, y = poly.exterior.xy
99
+ ax.fill(x, y, color='#EEEEEE', alpha=0.3)
100
+ ax.plot(x, y, color='#CCCCCC', linewidth=0.5)
101
+ else:
102
+ x, y = row.geometry.exterior.xy
103
+ ax.fill(x, y, color='#EEEEEE', alpha=0.3)
104
+ ax.plot(x, y, color='#CCCCCC', linewidth=0.5)
105
+
106
+ patches = []
107
+ legend_labels = []
108
+
109
+ # Plot selected areas with their colors
110
+ for _, row in selected_gdf.iterrows():
111
+ area_name = None
112
+ # Check all possible name columns for the area name
113
+ for level in selected_admin_levels:
114
+ col_name = admin_levels[level]
115
+ if row[col_name] in selected_areas:
116
+ area_name = row[col_name]
117
+ break
118
+
119
+ if area_name and area_name in fill_colors:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
120
  if isinstance(row.geometry, MultiPolygon):
121
  for poly in row.geometry.geoms:
122
  x, y = poly.exterior.xy
123
+ ax.fill(x, y, color=fill_colors[area_name], alpha=0.5)
124
+ ax.plot(x, y, color=border_colors[area_name], linewidth=1)
125
  else:
126
  x, y = row.geometry.exterior.xy
127
+ ax.fill(x, y, color=fill_colors[area_name], alpha=0.5)
128
+ ax.plot(x, y, color=border_colors[area_name], linewidth=1)
129
+
130
+ if area_name not in legend_labels:
131
+ patch = plt.Rectangle((0, 0), 1, 1,
132
+ fc=fill_colors[area_name],
133
+ ec=border_colors[area_name],
134
+ alpha=0.5)
135
+ patches.append(patch)
136
+ # Add region type to legend if it's a territory
137
+ if 'region_type' in row and row['region_type'] == 'Territory':
138
+ legend_labels.append(f"{area_name} (Territory)")
139
+ else:
140
+ legend_labels.append(area_name)
141
 
142
+ if patches:
143
+ ax.legend(patches, legend_labels,
144
+ title=legend_title,
145
+ loc=legend_location,
146
+ fontsize=legend_font_size,
147
+ title_fontsize=legend_font_size + 2,
148
+ frameon=True,
149
+ facecolor=legend_bg_color,
150
+ edgecolor=legend_border_color,
151
+ framealpha=1-legend_transparency,
152
+ ncol=legend_columns)
153
+
154
+ ax.set_xticks([])
155
+ ax.set_yticks([])
156
+ ax.set_frame_on(False)
157
+ return fig
158
+
159
+ def create_3d_map():
160
+ fig_3d = go.Figure()
161
+ added_to_legend = set()
162
+
163
+ # Plot base map
164
+ for _, row in gdf.iterrows():
165
+ if isinstance(row.geometry, MultiPolygon):
166
+ for poly in row.geometry.geoms:
167
+ x, y = poly.exterior.xy
168
+ fig_3d.add_trace(go.Scatter3d(
169
+ x=list(x), y=list(y), z=[0]*len(x),
170
+ mode='lines',
171
+ line=dict(color='#CCCCCC', width=1),
172
+ showlegend=False
173
+ ))
174
+ else:
175
+ x, y = row.geometry.exterior.xy
176
+ fig_3d.add_trace(go.Scatter3d(
177
+ x=list(x), y=list(y), z=[0]*len(x),
178
+ mode='lines',
179
+ line=dict(color='#CCCCCC', width=1),
180
+ showlegend=False
181
+ ))
182
+
183
+ # Plot selected areas
184
+ for _, row in selected_gdf.iterrows():
185
+ area_name = None
186
+ for level in selected_admin_levels:
187
+ col_name = admin_levels[level]
188
+ if row[col_name] in selected_areas:
189
+ area_name = row[col_name]
190
+ break
191
+
192
+ if area_name and area_name in fill_colors:
193
+ display_name = area_name
194
+ if 'region_type' in row and row['region_type'] == 'Territory':
195
+ display_name = f"{area_name} (Territory)"
196
 
197
+ if isinstance(row.geometry, MultiPolygon):
198
+ for poly in row.geometry.geoms:
199
+ x, y = poly.exterior.xy
200
+ if display_name not in added_to_legend:
201
+ fig_3d.add_trace(go.Scatter3d(
202
+ x=list(x), y=list(y), z=[0]*len(x),
203
+ mode='lines+markers',
204
+ line=dict(color=border_colors[area_name], width=2),
205
+ marker=dict(size=1, color=fill_colors[area_name], opacity=0.5),
206
+ name=display_name,
207
+ showlegend=True
208
+ ))
209
+ added_to_legend.add(display_name)
210
+ else:
211
+ fig_3d.add_trace(go.Scatter3d(
212
+ x=list(x), y=list(y), z=[0]*len(x),
213
+ mode='lines+markers',
214
+ line=dict(color=border_colors[area_name], width=2),
215
+ marker=dict(size=1, color=fill_colors[area_name], opacity=0.5),
216
+ name=display_name,
217
+ showlegend=False
218
+ ))
219
+ else:
220
+ x, y = row.geometry.exterior.xy
221
+ if display_name not in added_to_legend:
222
+ fig_3d.add_trace(go.Scatter3d(
223
+ x=list(x), y=list(y), z=[0]*len(x),
224
+ mode='lines+markers',
225
+ line=dict(color=border_colors[area_name], width=2),
226
+ marker=dict(size=1, color=fill_colors[area_name], opacity=0.5),
227
+ name=display_name,
228
+ showlegend=True
229
+ ))
230
+ added_to_legend.add(display_name)
231
  else:
232
+ fig_3d.add_trace(go.Scatter3d(
233
+ x=list(x), y=list(y), z=[0]*len(x),
234
+ mode='lines+markers',
235
+ line=dict(color=border_colors[area_name], width=2),
236
+ marker=dict(size=1, color=fill_colors[area_name], opacity=0.5),
237
+ name=display_name,
238
+ showlegend=False
239
+ ))
240
 
241
+ # [Rest of the create_3d_map function remains the same]
 
 
 
 
 
 
242
 
243
+ def create_3d_world_map():
244
+ # [Similar modifications as create_3d_map but with world_gdf as base]
245
+ # [Implementation follows the same pattern as create_3d_map]
246
+
247
+ # [Rest of the code remains the same]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
248
 
249
  # 3D Map Visualization (Current Version)
250
  st.subheader("🌐 3D Map Visualization (Current Version)")