Spaces:
Running
Running
Update app.py
Browse files
app.py
CHANGED
|
@@ -1,7 +1,7 @@
|
|
| 1 |
import gradio as gr
|
| 2 |
import pandas as pd
|
| 3 |
|
| 4 |
-
from nomad_data import country_emoji_map, data
|
| 5 |
|
| 6 |
# Create dataframe from imported data
|
| 7 |
df = pd.DataFrame(data)
|
|
@@ -72,6 +72,9 @@ def style_dataframe(df):
|
|
| 72 |
# Create a copy to avoid SettingWithCopyWarning
|
| 73 |
styled_df = df.copy()
|
| 74 |
|
|
|
|
|
|
|
|
|
|
| 75 |
# Convert to Styler object
|
| 76 |
styler = styled_df.style
|
| 77 |
|
|
@@ -124,6 +127,14 @@ def get_country_with_emoji(column):
|
|
| 124 |
choices_with_emoji.append(c)
|
| 125 |
return sorted(choices_with_emoji)
|
| 126 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 127 |
# Initial styled dataframe
|
| 128 |
styled_df = style_dataframe(df)
|
| 129 |
|
|
@@ -199,6 +210,13 @@ with gr.Blocks(css="""
|
|
| 199 |
label="π Filter by Country"
|
| 200 |
)
|
| 201 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 202 |
# Group all checkboxes together
|
| 203 |
visa_filter = gr.CheckboxGroup(
|
| 204 |
choices=["Has Digital Nomad Visa", "Visa Length β₯ 12 Months"],
|
|
@@ -212,14 +230,14 @@ with gr.Blocks(css="""
|
|
| 212 |
|
| 213 |
data_table = gr.Dataframe(
|
| 214 |
value=styled_df,
|
| 215 |
-
datatype=["str", "str", "number", "number", "number", "str", "number", "number", "str", "str"],
|
| 216 |
max_height=600,
|
| 217 |
interactive=False,
|
| 218 |
show_copy_button=True,
|
| 219 |
show_row_numbers=True,
|
| 220 |
show_search=True,
|
| 221 |
show_fullscreen_button=True,
|
| 222 |
-
pinned_columns=
|
| 223 |
)
|
| 224 |
|
| 225 |
# Update data when filters change
|
|
@@ -248,7 +266,7 @@ with gr.Blocks(css="""
|
|
| 248 |
return style_dataframe(filtered_df)
|
| 249 |
|
| 250 |
# Define advanced filters function
|
| 251 |
-
def apply_advanced_filters(country, cost, min_internet_speed, min_qol, visa_reqs, features):
|
| 252 |
# Process country filter
|
| 253 |
if country and country.startswith("βοΈ All"):
|
| 254 |
country = "All"
|
|
@@ -258,6 +276,15 @@ with gr.Blocks(css="""
|
|
| 258 |
country = country.split(" ", 1)[1]
|
| 259 |
break
|
| 260 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 261 |
filtered_df = df.copy()
|
| 262 |
|
| 263 |
# Basic filters (country and cost)
|
|
@@ -284,6 +311,10 @@ with gr.Blocks(css="""
|
|
| 284 |
if "Visa Length β₯ 12 Months" in visa_reqs:
|
| 285 |
filtered_df = filtered_df[filtered_df["Visa Length (Months)"] >= 12]
|
| 286 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 287 |
# Special features filters
|
| 288 |
if "Coastal Cities" in features:
|
| 289 |
coastal_keywords = ["coast", "beach", "sea", "ocean"]
|
|
@@ -303,32 +334,37 @@ with gr.Blocks(css="""
|
|
| 303 |
# Connect all filters to use the advanced filter function
|
| 304 |
country_dropdown.change(
|
| 305 |
apply_advanced_filters,
|
| 306 |
-
[country_dropdown, cost_slider, min_internet, min_quality, visa_filter, special_features],
|
| 307 |
data_table
|
| 308 |
)
|
| 309 |
cost_slider.change(
|
| 310 |
apply_advanced_filters,
|
| 311 |
-
[country_dropdown, cost_slider, min_internet, min_quality, visa_filter, special_features],
|
| 312 |
data_table
|
| 313 |
)
|
| 314 |
min_internet.change(
|
| 315 |
apply_advanced_filters,
|
| 316 |
-
[country_dropdown, cost_slider, min_internet, min_quality, visa_filter, special_features],
|
| 317 |
data_table
|
| 318 |
)
|
| 319 |
min_quality.change(
|
| 320 |
apply_advanced_filters,
|
| 321 |
-
[country_dropdown, cost_slider, min_internet, min_quality, visa_filter, special_features],
|
| 322 |
data_table
|
| 323 |
)
|
| 324 |
visa_filter.change(
|
| 325 |
apply_advanced_filters,
|
| 326 |
-
[country_dropdown, cost_slider, min_internet, min_quality, visa_filter, special_features],
|
| 327 |
data_table
|
| 328 |
)
|
| 329 |
special_features.change(
|
| 330 |
apply_advanced_filters,
|
| 331 |
-
[country_dropdown, cost_slider, min_internet, min_quality, visa_filter, special_features],
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 332 |
data_table
|
| 333 |
)
|
| 334 |
|
|
@@ -371,21 +407,24 @@ with gr.Blocks(css="""
|
|
| 371 |
|
| 372 |
if "Best Quality of Life" in priorities:
|
| 373 |
top_city = budget_filtered_df.sort_values("Quality of Life", ascending=False).iloc[0]
|
| 374 |
-
|
|
|
|
| 375 |
message += f"Monthly Cost: ${top_city['Monthly Cost Living (USD)']}\n"
|
| 376 |
message += f"Key Feature: {top_city['Key Feature']}"
|
| 377 |
recommendations.append(message)
|
| 378 |
|
| 379 |
if "Fastest Internet" in priorities:
|
| 380 |
top_city = budget_filtered_df.sort_values("Internet Speed (Mbps)", ascending=False).iloc[0]
|
| 381 |
-
|
|
|
|
| 382 |
message += f"Monthly Cost: ${top_city['Monthly Cost Living (USD)']}\n"
|
| 383 |
message += f"Key Feature: {top_city['Key Feature']}"
|
| 384 |
recommendations.append(message)
|
| 385 |
|
| 386 |
if "Most Affordable" in priorities:
|
| 387 |
top_city = budget_filtered_df.sort_values("Monthly Cost Living (USD)", ascending=True).iloc[0]
|
| 388 |
-
|
|
|
|
| 389 |
message += f"Quality of Life: {top_city['Quality of Life']}, Internet: {top_city['Internet Speed (Mbps)']} Mbps\n"
|
| 390 |
message += f"Key Feature: {top_city['Key Feature']}"
|
| 391 |
recommendations.append(message)
|
|
@@ -401,7 +440,8 @@ with gr.Blocks(css="""
|
|
| 401 |
df_temp['composite_score'] = (df_temp['quality_norm'] + df_temp['internet_norm'] + df_temp['cost_norm']) / 3
|
| 402 |
top_city = df_temp.sort_values("composite_score", ascending=False).iloc[0]
|
| 403 |
|
| 404 |
-
|
|
|
|
| 405 |
message += f"Quality: {top_city['Quality of Life']}, Internet: {top_city['Internet Speed (Mbps)']} Mbps, Cost: ${top_city['Monthly Cost Living (USD)']}\n"
|
| 406 |
message += f"Key Feature: {top_city['Key Feature']}"
|
| 407 |
recommendations.append(message)
|
|
|
|
| 1 |
import gradio as gr
|
| 2 |
import pandas as pd
|
| 3 |
|
| 4 |
+
from nomad_data import country_emoji_map, data, terrain_emoji_map
|
| 5 |
|
| 6 |
# Create dataframe from imported data
|
| 7 |
df = pd.DataFrame(data)
|
|
|
|
| 72 |
# Create a copy to avoid SettingWithCopyWarning
|
| 73 |
styled_df = df.copy()
|
| 74 |
|
| 75 |
+
# Apply terrain emojis
|
| 76 |
+
styled_df['Terrain'] = styled_df['Terrain'].apply(lambda x: terrain_emoji_map.get(x, x) if pd.notna(x) else x)
|
| 77 |
+
|
| 78 |
# Convert to Styler object
|
| 79 |
styler = styled_df.style
|
| 80 |
|
|
|
|
| 127 |
choices_with_emoji.append(c)
|
| 128 |
return sorted(choices_with_emoji)
|
| 129 |
|
| 130 |
+
# Add terrain filter function
|
| 131 |
+
def get_terrain_with_emoji():
|
| 132 |
+
terrains = ["β¨ All"]
|
| 133 |
+
for terrain in sorted(df["Terrain"].unique()):
|
| 134 |
+
if terrain in terrain_emoji_map:
|
| 135 |
+
terrains.append(terrain_emoji_map[terrain])
|
| 136 |
+
return terrains
|
| 137 |
+
|
| 138 |
# Initial styled dataframe
|
| 139 |
styled_df = style_dataframe(df)
|
| 140 |
|
|
|
|
| 210 |
label="π Filter by Country"
|
| 211 |
)
|
| 212 |
|
| 213 |
+
# Add terrain dropdown
|
| 214 |
+
terrain_dropdown = gr.Dropdown(
|
| 215 |
+
choices=get_terrain_with_emoji(),
|
| 216 |
+
value="β¨ All",
|
| 217 |
+
label="ποΈ Filter by Terrain"
|
| 218 |
+
)
|
| 219 |
+
|
| 220 |
# Group all checkboxes together
|
| 221 |
visa_filter = gr.CheckboxGroup(
|
| 222 |
choices=["Has Digital Nomad Visa", "Visa Length β₯ 12 Months"],
|
|
|
|
| 230 |
|
| 231 |
data_table = gr.Dataframe(
|
| 232 |
value=styled_df,
|
| 233 |
+
datatype=["str", "str", "str", "number", "number", "number", "str", "number", "number", "str", "str"],
|
| 234 |
max_height=600,
|
| 235 |
interactive=False,
|
| 236 |
show_copy_button=True,
|
| 237 |
show_row_numbers=True,
|
| 238 |
show_search=True,
|
| 239 |
show_fullscreen_button=True,
|
| 240 |
+
pinned_columns=3
|
| 241 |
)
|
| 242 |
|
| 243 |
# Update data when filters change
|
|
|
|
| 266 |
return style_dataframe(filtered_df)
|
| 267 |
|
| 268 |
# Define advanced filters function
|
| 269 |
+
def apply_advanced_filters(country, cost, min_internet_speed, min_qol, visa_reqs, features, terrain):
|
| 270 |
# Process country filter
|
| 271 |
if country and country.startswith("βοΈ All"):
|
| 272 |
country = "All"
|
|
|
|
| 276 |
country = country.split(" ", 1)[1]
|
| 277 |
break
|
| 278 |
|
| 279 |
+
# Process terrain filter
|
| 280 |
+
if terrain and terrain.startswith("β¨ All"):
|
| 281 |
+
terrain = "All"
|
| 282 |
+
else:
|
| 283 |
+
for emoji in ["ποΈ", "β°οΈ", "ποΈ", "ποΈ", "π΄", "ποΈ", "π²", "πΎ"]:
|
| 284 |
+
if terrain and emoji in terrain:
|
| 285 |
+
terrain = terrain.split(" ", 1)[1]
|
| 286 |
+
break
|
| 287 |
+
|
| 288 |
filtered_df = df.copy()
|
| 289 |
|
| 290 |
# Basic filters (country and cost)
|
|
|
|
| 311 |
if "Visa Length β₯ 12 Months" in visa_reqs:
|
| 312 |
filtered_df = filtered_df[filtered_df["Visa Length (Months)"] >= 12]
|
| 313 |
|
| 314 |
+
# Terrain filter
|
| 315 |
+
if terrain and terrain != "All":
|
| 316 |
+
filtered_df = filtered_df[filtered_df["Terrain"] == terrain]
|
| 317 |
+
|
| 318 |
# Special features filters
|
| 319 |
if "Coastal Cities" in features:
|
| 320 |
coastal_keywords = ["coast", "beach", "sea", "ocean"]
|
|
|
|
| 334 |
# Connect all filters to use the advanced filter function
|
| 335 |
country_dropdown.change(
|
| 336 |
apply_advanced_filters,
|
| 337 |
+
[country_dropdown, cost_slider, min_internet, min_quality, visa_filter, special_features, terrain_dropdown],
|
| 338 |
data_table
|
| 339 |
)
|
| 340 |
cost_slider.change(
|
| 341 |
apply_advanced_filters,
|
| 342 |
+
[country_dropdown, cost_slider, min_internet, min_quality, visa_filter, special_features, terrain_dropdown],
|
| 343 |
data_table
|
| 344 |
)
|
| 345 |
min_internet.change(
|
| 346 |
apply_advanced_filters,
|
| 347 |
+
[country_dropdown, cost_slider, min_internet, min_quality, visa_filter, special_features, terrain_dropdown],
|
| 348 |
data_table
|
| 349 |
)
|
| 350 |
min_quality.change(
|
| 351 |
apply_advanced_filters,
|
| 352 |
+
[country_dropdown, cost_slider, min_internet, min_quality, visa_filter, special_features, terrain_dropdown],
|
| 353 |
data_table
|
| 354 |
)
|
| 355 |
visa_filter.change(
|
| 356 |
apply_advanced_filters,
|
| 357 |
+
[country_dropdown, cost_slider, min_internet, min_quality, visa_filter, special_features, terrain_dropdown],
|
| 358 |
data_table
|
| 359 |
)
|
| 360 |
special_features.change(
|
| 361 |
apply_advanced_filters,
|
| 362 |
+
[country_dropdown, cost_slider, min_internet, min_quality, visa_filter, special_features, terrain_dropdown],
|
| 363 |
+
data_table
|
| 364 |
+
)
|
| 365 |
+
terrain_dropdown.change(
|
| 366 |
+
apply_advanced_filters,
|
| 367 |
+
[country_dropdown, cost_slider, min_internet, min_quality, visa_filter, special_features, terrain_dropdown],
|
| 368 |
data_table
|
| 369 |
)
|
| 370 |
|
|
|
|
| 407 |
|
| 408 |
if "Best Quality of Life" in priorities:
|
| 409 |
top_city = budget_filtered_df.sort_values("Quality of Life", ascending=False).iloc[0]
|
| 410 |
+
terrain_emoji = terrain_emoji_map.get(top_city['Terrain'], top_city['Terrain']).split()[0]
|
| 411 |
+
message = f"{terrain_emoji} {top_city['City']}, {top_city['Country']} - Quality of Life: {top_city['Quality of Life']}\n"
|
| 412 |
message += f"Monthly Cost: ${top_city['Monthly Cost Living (USD)']}\n"
|
| 413 |
message += f"Key Feature: {top_city['Key Feature']}"
|
| 414 |
recommendations.append(message)
|
| 415 |
|
| 416 |
if "Fastest Internet" in priorities:
|
| 417 |
top_city = budget_filtered_df.sort_values("Internet Speed (Mbps)", ascending=False).iloc[0]
|
| 418 |
+
terrain_emoji = terrain_emoji_map.get(top_city['Terrain'], top_city['Terrain']).split()[0]
|
| 419 |
+
message = f"{terrain_emoji} {top_city['City']}, {top_city['Country']} - Internet Speed: {top_city['Internet Speed (Mbps)']} Mbps\n"
|
| 420 |
message += f"Monthly Cost: ${top_city['Monthly Cost Living (USD)']}\n"
|
| 421 |
message += f"Key Feature: {top_city['Key Feature']}"
|
| 422 |
recommendations.append(message)
|
| 423 |
|
| 424 |
if "Most Affordable" in priorities:
|
| 425 |
top_city = budget_filtered_df.sort_values("Monthly Cost Living (USD)", ascending=True).iloc[0]
|
| 426 |
+
terrain_emoji = terrain_emoji_map.get(top_city['Terrain'], top_city['Terrain']).split()[0]
|
| 427 |
+
message = f"{terrain_emoji} {top_city['City']}, {top_city['Country']} - Monthly Cost: ${top_city['Monthly Cost Living (USD)']}\n"
|
| 428 |
message += f"Quality of Life: {top_city['Quality of Life']}, Internet: {top_city['Internet Speed (Mbps)']} Mbps\n"
|
| 429 |
message += f"Key Feature: {top_city['Key Feature']}"
|
| 430 |
recommendations.append(message)
|
|
|
|
| 440 |
df_temp['composite_score'] = (df_temp['quality_norm'] + df_temp['internet_norm'] + df_temp['cost_norm']) / 3
|
| 441 |
top_city = df_temp.sort_values("composite_score", ascending=False).iloc[0]
|
| 442 |
|
| 443 |
+
terrain_emoji = terrain_emoji_map.get(top_city['Terrain'], top_city['Terrain']).split()[0]
|
| 444 |
+
message = f"{terrain_emoji} {top_city['City']}, {top_city['Country']} - Balanced Choice\n"
|
| 445 |
message += f"Quality: {top_city['Quality of Life']}, Internet: {top_city['Internet Speed (Mbps)']} Mbps, Cost: ${top_city['Monthly Cost Living (USD)']}\n"
|
| 446 |
message += f"Key Feature: {top_city['Key Feature']}"
|
| 447 |
recommendations.append(message)
|