Spaces:
Running
Running
Hannah
commited on
Commit
Β·
dc030d6
1
Parent(s):
3c02b8d
remove comments
Browse files
app.py
CHANGED
@@ -3,35 +3,25 @@ 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)
|
8 |
|
9 |
-
# Create styling functions
|
10 |
def style_quality_of_life(val):
|
11 |
"""Style the Quality of Life column with color gradient from red to green"""
|
12 |
if pd.isna(val):
|
13 |
-
# Special styling for null/missing values
|
14 |
return 'background-color: rgba(200, 200, 200, 0.2); color: #999; font-style: italic;'
|
15 |
|
16 |
-
|
17 |
-
|
18 |
-
max_val = 9.0 # Anything above this will be bright green
|
19 |
|
20 |
-
# Normalize value between 0 and 1
|
21 |
normalized = (val - min_val) / (max_val - min_val)
|
22 |
-
# Clamp between 0 and 1
|
23 |
normalized = max(0, min(normalized, 1))
|
24 |
|
25 |
-
# Calculate percentage fill for gradient
|
26 |
percentage = int(normalized * 100)
|
27 |
|
28 |
-
# Create a linear gradient based on the normalized value
|
29 |
if normalized < 0.5:
|
30 |
-
# Red to yellow gradient
|
31 |
start_color = f"rgba(255, {int(255 * (normalized * 2))}, 0, 0.3)"
|
32 |
end_color = "rgba(255, 255, 255, 0)"
|
33 |
else:
|
34 |
-
# Yellow to green gradient
|
35 |
start_color = f"rgba({int(255 * (1 - (normalized - 0.5) * 2))}, 255, 0, 0.3)"
|
36 |
end_color = "rgba(255, 255, 255, 0)"
|
37 |
|
@@ -40,28 +30,20 @@ def style_quality_of_life(val):
|
|
40 |
def style_internet_speed(val):
|
41 |
"""Style the Internet Speed column from red (slow) to green (fast)"""
|
42 |
if pd.isna(val):
|
43 |
-
# Special styling for null/missing values
|
44 |
return 'background-color: rgba(200, 200, 200, 0.2); color: #999; font-style: italic;'
|
45 |
|
46 |
-
# Define min and max values
|
47 |
min_val = 20 # Slow internet
|
48 |
max_val = 300 # Fast internet
|
49 |
|
50 |
-
# Normalize value between 0 and 1
|
51 |
normalized = (val - min_val) / (max_val - min_val)
|
52 |
-
# Clamp between 0 and 1
|
53 |
normalized = max(0, min(normalized, 1))
|
54 |
|
55 |
-
# Calculate percentage fill for gradient
|
56 |
percentage = int(normalized * 100)
|
57 |
|
58 |
-
# Create a linear gradient based on the normalized value
|
59 |
if normalized < 0.5:
|
60 |
-
# Red to yellow gradient
|
61 |
start_color = f"rgba(255, {int(255 * (normalized * 2))}, 0, 0.3)"
|
62 |
end_color = "rgba(255, 255, 255, 0)"
|
63 |
else:
|
64 |
-
# Yellow to green gradient
|
65 |
start_color = f"rgba({int(255 * (1 - (normalized - 0.5) * 2))}, 255, 0, 0.3)"
|
66 |
end_color = "rgba(255, 255, 255, 0)"
|
67 |
|
@@ -69,23 +51,17 @@ def style_internet_speed(val):
|
|
69 |
|
70 |
def style_dataframe(df):
|
71 |
"""Apply styling to the entire dataframe"""
|
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 |
|
81 |
-
# Apply styles to specific columns
|
82 |
styler = styler.applymap(style_quality_of_life, subset=['Quality of Life'])
|
83 |
styler = styler.applymap(style_internet_speed, subset=['Internet Speed (Mbps)'])
|
84 |
|
85 |
-
# Highlight null values in all columns
|
86 |
styler = styler.highlight_null(props='color: #999; font-style: italic; background-color: rgba(200, 200, 200, 0.2)')
|
87 |
|
88 |
-
# Format numeric columns
|
89 |
styler = styler.format({
|
90 |
'Quality of Life': lambda x: f'{x:.1f}' if pd.notna(x) else 'Data Not Available',
|
91 |
'Internet Speed (Mbps)': lambda x: f'{x:.1f}' if pd.notna(x) else 'Data Not Available',
|
@@ -104,20 +80,16 @@ def filter_data(country, max_cost):
|
|
104 |
if country and country != "All":
|
105 |
filtered_df = filtered_df[filtered_df["Country"] == country]
|
106 |
|
107 |
-
# Filter by maximum cost of living (and handle null values)
|
108 |
if max_cost < df["Monthly Cost Living (USD)"].max():
|
109 |
-
# Include rows where cost is less than max_cost OR cost is null
|
110 |
cost_mask = (filtered_df["Monthly Cost Living (USD)"] <= max_cost) | (filtered_df["Monthly Cost Living (USD)"].isna())
|
111 |
filtered_df = filtered_df[cost_mask]
|
112 |
|
113 |
return style_dataframe(filtered_df)
|
114 |
|
115 |
-
# Function to get unique values for dropdowns with "All" option
|
116 |
def get_unique_values(column):
|
117 |
unique_values = ["All"] + sorted(df[column].unique().tolist())
|
118 |
return unique_values
|
119 |
|
120 |
-
# Add country emojis for the dropdown
|
121 |
def get_country_with_emoji(column):
|
122 |
choices_with_emoji = ["βοΈ All"]
|
123 |
for c in df[column].unique():
|
@@ -127,7 +99,6 @@ def get_country_with_emoji(column):
|
|
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()):
|
@@ -135,7 +106,6 @@ def get_terrain_with_emoji():
|
|
135 |
terrains.append(terrain_emoji_map[terrain])
|
136 |
return terrains
|
137 |
|
138 |
-
# Initial styled dataframe
|
139 |
styled_df = style_dataframe(df)
|
140 |
|
141 |
with gr.Blocks(css="""
|
@@ -168,16 +138,13 @@ with gr.Blocks(css="""
|
|
168 |
}
|
169 |
|
170 |
""") as demo:
|
171 |
-
# Remove header container and directly show title and subtitle with regular markdown
|
172 |
gr.HTML(elem_classes="title", value="π")
|
173 |
gr.HTML("<img src='https://see.fontimg.com/api/rf5/JpZqa/MWMyNzc2ODk3OTFlNDk2OWJkY2VjYTIzNzFlY2E4MWIudHRm/bm9tYWQgZGVzdGluYXRpb25z/super-feel.png?r=fs&h=130&w=2000&fg=e2e2e2&bg=FFFFFF&tb=1&s=65' alt='Graffiti fonts'></a>")
|
174 |
|
175 |
gr.Markdown("Discover the best places for digital nomads around the globe")
|
176 |
|
177 |
-
# Remove the separate row for basic filters and integrate all filters into one section
|
178 |
with gr.Row():
|
179 |
with gr.Column(scale=1):
|
180 |
-
# Group all sliders together
|
181 |
cost_slider = gr.Slider(
|
182 |
minimum=500,
|
183 |
maximum=4000,
|
@@ -203,21 +170,18 @@ with gr.Blocks(css="""
|
|
203 |
)
|
204 |
|
205 |
with gr.Column(scale=1):
|
206 |
-
# Put country dropdown with the checkboxes
|
207 |
country_dropdown = gr.Dropdown(
|
208 |
choices=get_country_with_emoji("Country"),
|
209 |
value="βοΈ All",
|
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"],
|
223 |
label="π Visa Requirements"
|
@@ -240,9 +204,7 @@ with gr.Blocks(css="""
|
|
240 |
pinned_columns=3
|
241 |
)
|
242 |
|
243 |
-
# Update data when filters change
|
244 |
def process_country_filter(country, cost):
|
245 |
-
# Remove emoji from country name if present
|
246 |
if country and country.startswith("βοΈ All"):
|
247 |
country = "All"
|
248 |
else:
|
@@ -253,11 +215,9 @@ with gr.Blocks(css="""
|
|
253 |
|
254 |
filtered_df = df.copy()
|
255 |
|
256 |
-
# Filter by country
|
257 |
if country and country != "All":
|
258 |
filtered_df = filtered_df[filtered_df["Country"] == country]
|
259 |
|
260 |
-
# Filter by cost with special handling for nulls
|
261 |
if cost < df["Monthly Cost Living (USD)"].max():
|
262 |
cost_mask = (filtered_df["Monthly Cost Living (USD)"] <= cost) & (filtered_df["Monthly Cost Living (USD)"].notna())
|
263 |
|
@@ -265,9 +225,7 @@ with gr.Blocks(css="""
|
|
265 |
|
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"
|
273 |
else:
|
@@ -276,7 +234,6 @@ with gr.Blocks(css="""
|
|
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:
|
@@ -287,7 +244,6 @@ with gr.Blocks(css="""
|
|
287 |
|
288 |
filtered_df = df.copy()
|
289 |
|
290 |
-
# Basic filters (country and cost)
|
291 |
if country and country != "All":
|
292 |
filtered_df = filtered_df[filtered_df["Country"] == country]
|
293 |
|
@@ -295,27 +251,21 @@ with gr.Blocks(css="""
|
|
295 |
cost_mask = (filtered_df["Monthly Cost Living (USD)"] <= cost) & (filtered_df["Monthly Cost Living (USD)"].notna())
|
296 |
filtered_df = filtered_df[cost_mask]
|
297 |
|
298 |
-
# Advanced filters
|
299 |
-
# Internet speed filter
|
300 |
if min_internet_speed > 0:
|
301 |
filtered_df = filtered_df[filtered_df["Internet Speed (Mbps)"] >= min_internet_speed]
|
302 |
-
|
303 |
-
# Quality of life filter
|
304 |
if min_qol > 5:
|
305 |
filtered_df = filtered_df[filtered_df["Quality of Life"] >= min_qol]
|
306 |
|
307 |
-
# Visa filters
|
308 |
if "Has Digital Nomad Visa" in visa_reqs:
|
309 |
filtered_df = filtered_df[filtered_df["Digital Nomad Visa"] == "Yes"]
|
310 |
|
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"]
|
321 |
mask = filtered_df["Key Feature"].str.contains("|".join(coastal_keywords), case=False, na=False)
|
@@ -331,7 +281,6 @@ with gr.Blocks(css="""
|
|
331 |
|
332 |
return style_dataframe(filtered_df)
|
333 |
|
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],
|
@@ -394,10 +343,8 @@ with gr.Blocks(css="""
|
|
394 |
if not priorities:
|
395 |
return "Please select at least one priority to get a recommendation."
|
396 |
|
397 |
-
# Filter by budget first
|
398 |
budget_filtered_df = df[df["Monthly Cost Living (USD)"] <= max_budget]
|
399 |
|
400 |
-
# If no cities match the budget, use the full dataset but mention it
|
401 |
budget_warning = ""
|
402 |
if len(budget_filtered_df) == 0:
|
403 |
budget_filtered_df = df
|
@@ -430,9 +377,7 @@ with gr.Blocks(css="""
|
|
430 |
recommendations.append(message)
|
431 |
|
432 |
if "Balance of All Factors" in priorities:
|
433 |
-
# Create a composite score
|
434 |
df_temp = budget_filtered_df.copy()
|
435 |
-
# Normalize and weight each factor
|
436 |
df_temp['quality_norm'] = df_temp['Quality of Life'] / 10
|
437 |
df_temp['internet_norm'] = df_temp['Internet Speed (Mbps)'] / 400
|
438 |
df_temp['cost_norm'] = 1 - (df_temp['Monthly Cost Living (USD)'] / 4000)
|
@@ -450,7 +395,6 @@ with gr.Blocks(css="""
|
|
450 |
|
451 |
find_btn.click(recommend_location, inputs=[priority, cost_slider], outputs=recommendation)
|
452 |
|
453 |
-
# Also update when budget slider changes
|
454 |
cost_slider.change(recommend_location, inputs=[priority, cost_slider], outputs=recommendation)
|
455 |
|
456 |
demo.launch()
|
|
|
3 |
|
4 |
from nomad_data import country_emoji_map, data, terrain_emoji_map
|
5 |
|
|
|
6 |
df = pd.DataFrame(data)
|
7 |
|
|
|
8 |
def style_quality_of_life(val):
|
9 |
"""Style the Quality of Life column with color gradient from red to green"""
|
10 |
if pd.isna(val):
|
|
|
11 |
return 'background-color: rgba(200, 200, 200, 0.2); color: #999; font-style: italic;'
|
12 |
|
13 |
+
min_val = 5.0
|
14 |
+
max_val = 9.0
|
|
|
15 |
|
|
|
16 |
normalized = (val - min_val) / (max_val - min_val)
|
|
|
17 |
normalized = max(0, min(normalized, 1))
|
18 |
|
|
|
19 |
percentage = int(normalized * 100)
|
20 |
|
|
|
21 |
if normalized < 0.5:
|
|
|
22 |
start_color = f"rgba(255, {int(255 * (normalized * 2))}, 0, 0.3)"
|
23 |
end_color = "rgba(255, 255, 255, 0)"
|
24 |
else:
|
|
|
25 |
start_color = f"rgba({int(255 * (1 - (normalized - 0.5) * 2))}, 255, 0, 0.3)"
|
26 |
end_color = "rgba(255, 255, 255, 0)"
|
27 |
|
|
|
30 |
def style_internet_speed(val):
|
31 |
"""Style the Internet Speed column from red (slow) to green (fast)"""
|
32 |
if pd.isna(val):
|
|
|
33 |
return 'background-color: rgba(200, 200, 200, 0.2); color: #999; font-style: italic;'
|
34 |
|
|
|
35 |
min_val = 20 # Slow internet
|
36 |
max_val = 300 # Fast internet
|
37 |
|
|
|
38 |
normalized = (val - min_val) / (max_val - min_val)
|
|
|
39 |
normalized = max(0, min(normalized, 1))
|
40 |
|
|
|
41 |
percentage = int(normalized * 100)
|
42 |
|
|
|
43 |
if normalized < 0.5:
|
|
|
44 |
start_color = f"rgba(255, {int(255 * (normalized * 2))}, 0, 0.3)"
|
45 |
end_color = "rgba(255, 255, 255, 0)"
|
46 |
else:
|
|
|
47 |
start_color = f"rgba({int(255 * (1 - (normalized - 0.5) * 2))}, 255, 0, 0.3)"
|
48 |
end_color = "rgba(255, 255, 255, 0)"
|
49 |
|
|
|
51 |
|
52 |
def style_dataframe(df):
|
53 |
"""Apply styling to the entire dataframe"""
|
|
|
54 |
styled_df = df.copy()
|
55 |
|
|
|
56 |
styled_df['Terrain'] = styled_df['Terrain'].apply(lambda x: terrain_emoji_map.get(x, x) if pd.notna(x) else x)
|
57 |
|
|
|
58 |
styler = styled_df.style
|
59 |
|
|
|
60 |
styler = styler.applymap(style_quality_of_life, subset=['Quality of Life'])
|
61 |
styler = styler.applymap(style_internet_speed, subset=['Internet Speed (Mbps)'])
|
62 |
|
|
|
63 |
styler = styler.highlight_null(props='color: #999; font-style: italic; background-color: rgba(200, 200, 200, 0.2)')
|
64 |
|
|
|
65 |
styler = styler.format({
|
66 |
'Quality of Life': lambda x: f'{x:.1f}' if pd.notna(x) else 'Data Not Available',
|
67 |
'Internet Speed (Mbps)': lambda x: f'{x:.1f}' if pd.notna(x) else 'Data Not Available',
|
|
|
80 |
if country and country != "All":
|
81 |
filtered_df = filtered_df[filtered_df["Country"] == country]
|
82 |
|
|
|
83 |
if max_cost < df["Monthly Cost Living (USD)"].max():
|
|
|
84 |
cost_mask = (filtered_df["Monthly Cost Living (USD)"] <= max_cost) | (filtered_df["Monthly Cost Living (USD)"].isna())
|
85 |
filtered_df = filtered_df[cost_mask]
|
86 |
|
87 |
return style_dataframe(filtered_df)
|
88 |
|
|
|
89 |
def get_unique_values(column):
|
90 |
unique_values = ["All"] + sorted(df[column].unique().tolist())
|
91 |
return unique_values
|
92 |
|
|
|
93 |
def get_country_with_emoji(column):
|
94 |
choices_with_emoji = ["βοΈ All"]
|
95 |
for c in df[column].unique():
|
|
|
99 |
choices_with_emoji.append(c)
|
100 |
return sorted(choices_with_emoji)
|
101 |
|
|
|
102 |
def get_terrain_with_emoji():
|
103 |
terrains = ["β¨ All"]
|
104 |
for terrain in sorted(df["Terrain"].unique()):
|
|
|
106 |
terrains.append(terrain_emoji_map[terrain])
|
107 |
return terrains
|
108 |
|
|
|
109 |
styled_df = style_dataframe(df)
|
110 |
|
111 |
with gr.Blocks(css="""
|
|
|
138 |
}
|
139 |
|
140 |
""") as demo:
|
|
|
141 |
gr.HTML(elem_classes="title", value="π")
|
142 |
gr.HTML("<img src='https://see.fontimg.com/api/rf5/JpZqa/MWMyNzc2ODk3OTFlNDk2OWJkY2VjYTIzNzFlY2E4MWIudHRm/bm9tYWQgZGVzdGluYXRpb25z/super-feel.png?r=fs&h=130&w=2000&fg=e2e2e2&bg=FFFFFF&tb=1&s=65' alt='Graffiti fonts'></a>")
|
143 |
|
144 |
gr.Markdown("Discover the best places for digital nomads around the globe")
|
145 |
|
|
|
146 |
with gr.Row():
|
147 |
with gr.Column(scale=1):
|
|
|
148 |
cost_slider = gr.Slider(
|
149 |
minimum=500,
|
150 |
maximum=4000,
|
|
|
170 |
)
|
171 |
|
172 |
with gr.Column(scale=1):
|
|
|
173 |
country_dropdown = gr.Dropdown(
|
174 |
choices=get_country_with_emoji("Country"),
|
175 |
value="βοΈ All",
|
176 |
label="π Filter by Country"
|
177 |
)
|
178 |
|
|
|
179 |
terrain_dropdown = gr.Dropdown(
|
180 |
choices=get_terrain_with_emoji(),
|
181 |
value="β¨ All",
|
182 |
label="ποΈ Filter by Terrain"
|
183 |
)
|
184 |
|
|
|
185 |
visa_filter = gr.CheckboxGroup(
|
186 |
choices=["Has Digital Nomad Visa", "Visa Length β₯ 12 Months"],
|
187 |
label="π Visa Requirements"
|
|
|
204 |
pinned_columns=3
|
205 |
)
|
206 |
|
|
|
207 |
def process_country_filter(country, cost):
|
|
|
208 |
if country and country.startswith("βοΈ All"):
|
209 |
country = "All"
|
210 |
else:
|
|
|
215 |
|
216 |
filtered_df = df.copy()
|
217 |
|
|
|
218 |
if country and country != "All":
|
219 |
filtered_df = filtered_df[filtered_df["Country"] == country]
|
220 |
|
|
|
221 |
if cost < df["Monthly Cost Living (USD)"].max():
|
222 |
cost_mask = (filtered_df["Monthly Cost Living (USD)"] <= cost) & (filtered_df["Monthly Cost Living (USD)"].notna())
|
223 |
|
|
|
225 |
|
226 |
return style_dataframe(filtered_df)
|
227 |
|
|
|
228 |
def apply_advanced_filters(country, cost, min_internet_speed, min_qol, visa_reqs, features, terrain):
|
|
|
229 |
if country and country.startswith("βοΈ All"):
|
230 |
country = "All"
|
231 |
else:
|
|
|
234 |
country = country.split(" ", 1)[1]
|
235 |
break
|
236 |
|
|
|
237 |
if terrain and terrain.startswith("β¨ All"):
|
238 |
terrain = "All"
|
239 |
else:
|
|
|
244 |
|
245 |
filtered_df = df.copy()
|
246 |
|
|
|
247 |
if country and country != "All":
|
248 |
filtered_df = filtered_df[filtered_df["Country"] == country]
|
249 |
|
|
|
251 |
cost_mask = (filtered_df["Monthly Cost Living (USD)"] <= cost) & (filtered_df["Monthly Cost Living (USD)"].notna())
|
252 |
filtered_df = filtered_df[cost_mask]
|
253 |
|
|
|
|
|
254 |
if min_internet_speed > 0:
|
255 |
filtered_df = filtered_df[filtered_df["Internet Speed (Mbps)"] >= min_internet_speed]
|
256 |
+
|
|
|
257 |
if min_qol > 5:
|
258 |
filtered_df = filtered_df[filtered_df["Quality of Life"] >= min_qol]
|
259 |
|
|
|
260 |
if "Has Digital Nomad Visa" in visa_reqs:
|
261 |
filtered_df = filtered_df[filtered_df["Digital Nomad Visa"] == "Yes"]
|
262 |
|
263 |
if "Visa Length β₯ 12 Months" in visa_reqs:
|
264 |
filtered_df = filtered_df[filtered_df["Visa Length (Months)"] >= 12]
|
265 |
|
|
|
266 |
if terrain and terrain != "All":
|
267 |
filtered_df = filtered_df[filtered_df["Terrain"] == terrain]
|
268 |
|
|
|
269 |
if "Coastal Cities" in features:
|
270 |
coastal_keywords = ["coast", "beach", "sea", "ocean"]
|
271 |
mask = filtered_df["Key Feature"].str.contains("|".join(coastal_keywords), case=False, na=False)
|
|
|
281 |
|
282 |
return style_dataframe(filtered_df)
|
283 |
|
|
|
284 |
country_dropdown.change(
|
285 |
apply_advanced_filters,
|
286 |
[country_dropdown, cost_slider, min_internet, min_quality, visa_filter, special_features, terrain_dropdown],
|
|
|
343 |
if not priorities:
|
344 |
return "Please select at least one priority to get a recommendation."
|
345 |
|
|
|
346 |
budget_filtered_df = df[df["Monthly Cost Living (USD)"] <= max_budget]
|
347 |
|
|
|
348 |
budget_warning = ""
|
349 |
if len(budget_filtered_df) == 0:
|
350 |
budget_filtered_df = df
|
|
|
377 |
recommendations.append(message)
|
378 |
|
379 |
if "Balance of All Factors" in priorities:
|
|
|
380 |
df_temp = budget_filtered_df.copy()
|
|
|
381 |
df_temp['quality_norm'] = df_temp['Quality of Life'] / 10
|
382 |
df_temp['internet_norm'] = df_temp['Internet Speed (Mbps)'] / 400
|
383 |
df_temp['cost_norm'] = 1 - (df_temp['Monthly Cost Living (USD)'] / 4000)
|
|
|
395 |
|
396 |
find_btn.click(recommend_location, inputs=[priority, cost_slider], outputs=recommendation)
|
397 |
|
|
|
398 |
cost_slider.change(recommend_location, inputs=[priority, cost_slider], outputs=recommendation)
|
399 |
|
400 |
demo.launch()
|