Spaces:
Runtime error
Runtime error
Update app.py
Browse files
app.py
CHANGED
|
@@ -8,60 +8,21 @@ import warnings
|
|
| 8 |
import io
|
| 9 |
from shapely.geometry import Polygon, MultiPolygon
|
| 10 |
|
| 11 |
-
#
|
| 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 |
-
|
| 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 |
-
#
|
| 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 |
-
|
| 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 |
-
|
| 159 |
-
|
| 160 |
-
st.subheader("π¨ Area Customization")
|
| 161 |
|
| 162 |
-
#
|
| 163 |
-
|
| 164 |
-
|
| 165 |
-
|
| 166 |
-
|
| 167 |
-
|
| 168 |
-
|
| 169 |
-
|
| 170 |
-
|
| 171 |
-
|
| 172 |
-
|
| 173 |
-
|
| 174 |
-
|
| 175 |
-
|
| 176 |
-
|
| 177 |
-
|
| 178 |
-
|
| 179 |
-
|
| 180 |
-
|
| 181 |
-
|
| 182 |
-
|
| 183 |
-
|
| 184 |
-
|
| 185 |
-
|
| 186 |
-
|
| 187 |
-
|
| 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=
|
| 213 |
-
ax.plot(x, y, color=
|
| 214 |
else:
|
| 215 |
x, y = row.geometry.exterior.xy
|
| 216 |
-
ax.fill(x, y, color=
|
| 217 |
-
ax.plot(x, y, color=
|
| 218 |
-
|
| 219 |
-
|
| 220 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 221 |
|
| 222 |
-
|
| 223 |
-
|
| 224 |
-
|
| 225 |
-
|
| 226 |
-
|
| 227 |
-
|
| 228 |
-
|
| 229 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 230 |
|
| 231 |
-
if
|
| 232 |
-
|
| 233 |
-
|
| 234 |
-
|
| 235 |
-
|
| 236 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 237 |
else:
|
| 238 |
-
|
| 239 |
-
|
| 240 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 241 |
|
| 242 |
-
|
| 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 |
-
|
| 251 |
-
|
| 252 |
-
|
| 253 |
-
|
| 254 |
-
|
| 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)")
|