LeonceNsh commited on
Commit
80ac61f
Β·
verified Β·
1 Parent(s): 92fb37e

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +143 -112
app.py CHANGED
@@ -1,37 +1,26 @@
1
- # Standard library imports
2
  import logging
3
- import os
4
- import math
5
-
6
- # Third-party imports
7
  import pandas as pd
 
 
8
  import numpy as np
9
  import geopandas as gpd
10
- import folium
11
- import plotly.express as px
12
  from folium.plugins import MarkerCluster
13
  from sklearn.neighbors import BallTree
14
  from geopy.geocoders import Nominatim
15
  from geopy.extra.rate_limiter import RateLimiter
16
-
17
- # Gradio imports
18
- import gradio as gr
19
- from gradio.components import Map # Import Map component
20
 
21
  # Logger setup
22
  logging.basicConfig(level=logging.INFO)
23
  logger = logging.getLogger(__name__)
24
 
25
  # Load datasets
26
- try:
27
- df_md_final1 = pd.read_csv("data/location-of-auto-businesses.csv")
28
- cbg_geographic_data = pd.read_csv("data/cbg_geographic_data.csv")
29
- except FileNotFoundError as e:
30
- logger.error(f"Error loading data files: {e}")
31
- raise
32
 
33
  # Create DataFrames for the 2020 and 2010 populations
34
- # For demonstration, we are using hardcoded data
35
  population_2020_data = {
36
  'County': ['Shelby', 'Davidson', 'Knox', 'Hamilton', 'Rutherford', 'Williamson', 'Montgomery', 'Sumner', 'Blount', 'Washington',
37
  'Madison', 'Sevier', 'Maury', 'Wilson', 'Bradley'],
@@ -47,105 +36,94 @@ df_population_2010.rename(columns={'cntyname': 'County', 'pop10': 'Population_20
47
  df_population_comparison = pd.merge(df_population_2010, df_population_2020, on='County')
48
 
49
  # Define Business Types
50
- def assign_business_type(name):
51
- if pd.isna(name):
52
- return "Other Auto Repair Shops"
53
- name = name.lower()
54
- if "autozone" in name:
55
- return "Autozone"
56
- elif "napa auto parts" in name:
57
- return "Napa Auto"
58
- elif "firestone complete auto care" in name:
59
- return "Firestone"
60
- elif "o'reilly auto parts" in name:
61
- return "O'Reilly Auto"
62
- elif "advance auto parts" in name:
63
- return "Advance Auto"
64
- elif any(dealer in name for dealer in ["toyota", "honda", "kia", "nissan", "chevy", "ford", "carmax", "gmc"]):
65
- return "Car Dealership"
66
- else:
67
- return "Other Auto Repair Shops"
68
-
69
- df_md_final1['business_type'] = df_md_final1['name'].apply(assign_business_type)
70
-
71
- # Load shapefiles
72
- def load_shapefile(shapefile_path, state_fips='47', state_abbr='TN'):
73
- if not os.path.exists(shapefile_path):
74
- raise FileNotFoundError(f"Shapefile not found at {shapefile_path}. Please ensure the file exists.")
75
- geo_df = gpd.read_file(shapefile_path)
76
- if 'statefp' in geo_df.columns:
77
- geo_df = geo_df[geo_df['statefp'] == state_fips]
78
- elif 'hsastate' in geo_df.columns:
79
- geo_df = geo_df[geo_df['hsastate'] == state_abbr]
80
- elif 'hrrstate' in geo_df.columns:
81
- geo_df = geo_df[geo_df['hrrstate'] == state_abbr]
82
- elif 'STATEFP' in geo_df.columns:
83
- geo_df = geo_df[geo_df['STATEFP'] == state_fips]
84
- else:
85
- raise KeyError("Column to filter state in shapefile not found.")
86
- return geo_df
87
 
88
  # Load the County shapefile
89
  county_shapefile_path = "data/county/01_county-shape-file.shp"
90
- counties_geo = load_shapefile(county_shapefile_path, state_fips='47')
 
 
 
 
91
 
92
  # Load the HSA shapefile
93
  hsa_shapefile_path = "data/hsa/01_hsa-shape-file.shp"
94
- hsa_geo = load_shapefile(hsa_shapefile_path, state_abbr='TN')
 
 
 
 
 
 
 
 
 
95
 
96
  # Load the HRR shapefile
97
  hrr_shapefile_path = "data/hrr/01_hrr-shape-file.shp"
98
- hrr_geo = load_shapefile(hrr_shapefile_path, state_abbr='TN')
99
-
100
- # Business type colors
101
- business_colors = {
102
- "Autozone": "red",
103
- "Napa Auto": "blue",
104
- "Firestone": "green",
105
- "O'Reilly Auto": "purple",
106
- "Advance Auto": "orange",
107
- "Car Dealership": "darkred",
108
- "Other Auto Repair Shops": "gray"
109
- }
110
 
111
  # Function to create a Folium map with selected geographical boundaries and markers
112
- def create_map(geo_layer="Counties", business_filters=None):
113
- if business_filters is None:
114
- business_filters = ["All"]
115
  logger.info(f"Creating map with geo_layer: {geo_layer} and business_filters: {business_filters}")
116
 
117
  m = folium.Map(location=[35.8601, -86.6602], zoom_start=7)
118
 
119
- # Select the appropriate GeoDataFrame based on geo_layer
120
- geo_data_dict = {"Counties": counties_geo, "HSAs": hsa_geo, "HRRs": hrr_geo}
121
- geo_data = geo_data_dict.get(geo_layer, counties_geo) # Default to counties
122
- logger.info(f"Geo layer {geo_layer} selected.")
123
-
124
- # Add selected geographical boundaries
125
- folium.GeoJson(geo_data, name=geo_layer).add_to(m)
 
 
 
 
 
 
 
 
 
126
 
127
  # Initialize Marker Cluster
128
  marker_cluster = MarkerCluster().add_to(m)
129
 
130
- # Filter based on Business
131
  if "All" not in business_filters:
132
  filtered_df = df_md_final1[df_md_final1['business_type'].isin(business_filters)]
133
  else:
134
  filtered_df = df_md_final1.copy()
135
 
136
  logger.info(f"Filtered {len(filtered_df)} businesses based on filters: {business_filters}")
137
-
138
  # Add markers to the map
139
  for _, row in filtered_df.iterrows():
140
- business_type = row['business_type']
141
- marker_color = business_colors.get(business_type, 'blue')
142
  folium.Marker(
143
  location=[row['md_y'], row['md_x']],
144
- popup=folium.Popup(
145
- f"<b>{row['name']}</b><br>{row.get('address', 'N/A')}, "
146
- f"{row.get('city', 'N/A')}, TN {row.get('postal_code', 'N/A')}",
147
- max_width=300),
148
- icon=folium.Icon(color=marker_color, icon='info-sign')
149
  ).add_to(marker_cluster)
150
 
151
  folium.LayerControl().add_to(m)
@@ -170,7 +148,6 @@ def plot_2020_population_top15():
170
  def plot_population_comparison():
171
  df_melted = df_population_comparison.melt(id_vars='County', value_vars=['Population_2010', 'Population_2020'],
172
  var_name='Year', value_name='Population')
173
- df_melted['Year'] = df_melted['Year'].str.replace('Population_', '')
174
  fig = px.bar(df_melted,
175
  x='County',
176
  y='Population',
@@ -178,12 +155,13 @@ def plot_population_comparison():
178
  barmode='group',
179
  title="Tennessee Population Comparison: 2010 vs 2020",
180
  labels={'County': 'County', 'Population': 'Population'},
181
- color_discrete_map={'2010': 'purple', '2020': 'blue'})
182
 
183
  fig.update_layout(xaxis={'categoryorder': 'total descending'}, template='plotly_white')
184
  return fig
185
 
186
  # Nearest Neighbor Search Setup
 
187
  def prepare_nearest_neighbor():
188
  # Convert coordinates to radians for BallTree
189
  coords = df_md_final1[['md_y', 'md_x']].to_numpy()
@@ -229,11 +207,7 @@ def find_nearest_shop(address=None, latitude=None, longitude=None):
229
  # Add nearest shop marker
230
  folium.Marker(
231
  location=[nearest_shop['md_y'], nearest_shop['md_x']],
232
- popup=folium.Popup(
233
- f"Nearest Shop: {nearest_shop['name']}<br>{nearest_shop.get('address', 'N/A')}, "
234
- f"{nearest_shop.get('city', 'N/A')}, TN {nearest_shop.get('postal_code', 'N/A')}<br>"
235
- f"Distance: {distance_km:.2f} km",
236
- max_width=300),
237
  icon=folium.Icon(color='green', icon='shopping-cart')
238
  ).add_to(m)
239
 
@@ -248,9 +222,78 @@ with gr.Blocks(theme=gr.themes.Default()) as app:
248
 
249
  with gr.Tab("Overview"):
250
  gr.Markdown("## πŸ“Š Tennessee Population Statistics")
251
- gr.Markdown("### 2010 vs 2020 Population Comparison")
252
- pop_comp = gr.Plot(plot_population_comparison)
 
 
 
 
 
253
  gr.Markdown("### πŸ› οΈ Auto Businesses in Tennessee")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
254
  map_output_overview = gr.HTML(create_map(geo_layer="Counties", business_filters=["All"]))
255
 
256
  with gr.Tab("πŸ“ Shops in TN Counties"):
@@ -318,8 +361,7 @@ with gr.Blocks(theme=gr.themes.Default()) as app:
318
  address_input = gr.Textbox(label="Enter Address", placeholder="e.g., 123 Main St, Nashville, TN")
319
  address_suggestions = gr.Dropdown(label="Suggestions", choices=[])
320
  gr.Markdown("**OR**")
321
- gr.Markdown("### Click on the Map to Select Your Location")
322
- location_input = Map(label="Select Location") # Use Map component
323
  with gr.Column(scale=4):
324
  nearest_map = gr.HTML()
325
  message_output = gr.Textbox(label="Message", interactive=False)
@@ -360,22 +402,12 @@ with gr.Blocks(theme=gr.themes.Default()) as app:
360
  message, updated_map = find_nearest_shop(address=selected_address)
361
  return message, updated_map
362
 
363
- # Function to update the map based on map click
364
- def update_nearest_map_from_click(map_data):
365
- if not map_data:
366
- return "Please select a location on the map.", None
367
- latitude, longitude = map_data['latitude'], map_data['longitude']
368
- message, updated_map = find_nearest_shop(latitude=latitude, longitude=longitude)
369
- return message, updated_map
370
-
371
  # When the user types in the address_input, update suggestions
372
  address_input.input(fn=get_address_suggestions, inputs=address_input, outputs=address_suggestions, every=1.0)
373
  # When the user presses Enter in address_input, update map
374
  address_input.submit(fn=update_nearest_map_from_input, inputs=address_input, outputs=[message_output, nearest_map])
375
  # When the user selects an address from suggestions, update the map
376
  address_suggestions.change(fn=update_nearest_map_from_suggestion, inputs=address_suggestions, outputs=[message_output, nearest_map])
377
- # When the user clicks on the map
378
- location_input.change(fn=update_nearest_map_from_click, inputs=location_input, outputs=[message_output, nearest_map])
379
 
380
  with gr.Tab("πŸ” Help"):
381
  gr.Markdown("""
@@ -387,15 +419,14 @@ with gr.Blocks(theme=gr.themes.Default()) as app:
387
  - **Filter by Business Type:** Use the checkboxes to select one or multiple business types to display on the map.
388
  - **Filter by Geographical Area:** Depending on the tab, you can filter businesses based on Counties, HSAs, or HRRs.
389
  - **Reset Filters:** Click the reset button to clear all selected filters and view all businesses.
390
- - **Interactive Map:** Zoom in/out, click on markers to view business details.
391
 
392
  - **Nearest Shop Finder Tab:**
393
  - **Enter Address:** Type your address in the textbox. As you type, address suggestions will appear. Select one or press Enter to find the nearest auto shop.
394
- - **Click on Map:** Alternatively, click on the map to select your location.
395
  - **View Results:** The map will display your location and the nearest auto shop with a line connecting them.
396
 
397
  """)
398
 
399
  gr.Markdown("### πŸ“„ Source: Yellow Pages")
400
 
401
- app.launch(server_name="0.0.0.0", server_port=7860, share=True)
 
 
1
  import logging
2
+ import gradio as gr
 
 
 
3
  import pandas as pd
4
+ import plotly.express as px
5
+ import folium
6
  import numpy as np
7
  import geopandas as gpd
 
 
8
  from folium.plugins import MarkerCluster
9
  from sklearn.neighbors import BallTree
10
  from geopy.geocoders import Nominatim
11
  from geopy.extra.rate_limiter import RateLimiter
12
+ import math
13
+ import os
 
 
14
 
15
  # Logger setup
16
  logging.basicConfig(level=logging.INFO)
17
  logger = logging.getLogger(__name__)
18
 
19
  # Load datasets
20
+ df_md_final1 = pd.read_csv("data/location-of-auto-businesses.csv")
21
+ cbg_geographic_data = pd.read_csv("data/cbg_geographic_data.csv")
 
 
 
 
22
 
23
  # Create DataFrames for the 2020 and 2010 populations
 
24
  population_2020_data = {
25
  'County': ['Shelby', 'Davidson', 'Knox', 'Hamilton', 'Rutherford', 'Williamson', 'Montgomery', 'Sumner', 'Blount', 'Washington',
26
  'Madison', 'Sevier', 'Maury', 'Wilson', 'Bradley'],
 
36
  df_population_comparison = pd.merge(df_population_2010, df_population_2020, on='County')
37
 
38
  # Define Business Types
39
+ df_md_final1['business_type'] = np.where(df_md_final1['name'].str.contains("Autozone", case=False, na=False), "Autozone",
40
+ np.where(df_md_final1['name'].str.contains("Napa Auto Parts", case=False, na=False), "Napa Auto",
41
+ np.where(df_md_final1['name'].str.contains("Firestone Complete Auto Care", case=False, na=False), "Firestone",
42
+ np.where(df_md_final1['name'].str.contains("O'Reilly Auto Parts", case=False, na=False), "O'Reilly Auto",
43
+ np.where(df_md_final1['name'].str.contains("Advance Auto Parts", case=False, na=False), "Advance Auto",
44
+ np.where(df_md_final1['name'].str.contains("Toyota|Honda|Kia|Nissan|Chevy|Ford|Carmax|GMC", case=False, na=False),
45
+ "Car Dealership",
46
+ "Other Auto Repair Shops")
47
+ )
48
+ )
49
+ )
50
+ )
51
+ )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
52
 
53
  # Load the County shapefile
54
  county_shapefile_path = "data/county/01_county-shape-file.shp"
55
+ if not os.path.exists(county_shapefile_path):
56
+ raise FileNotFoundError(f"County shapefile not found at {county_shapefile_path}. Please ensure the file exists.")
57
+
58
+ counties_geo = gpd.read_file(county_shapefile_path)
59
+ counties_geo = counties_geo[counties_geo['statefp'] == '47'] # Tennessee FIPS code
60
 
61
  # Load the HSA shapefile
62
  hsa_shapefile_path = "data/hsa/01_hsa-shape-file.shp"
63
+ if not os.path.exists(hsa_shapefile_path):
64
+ raise FileNotFoundError(f"HSA shapefile not found at {hsa_shapefile_path}. Please ensure the file exists.")
65
+
66
+ hsa_geo = gpd.read_file(hsa_shapefile_path)
67
+ if 'hsastate' in hsa_geo.columns:
68
+ hsa_geo = hsa_geo[hsa_geo['hsastate'].isin(['TN'])]
69
+ elif 'STATEFP' in hsa_geo.columns:
70
+ hsa_geo = hsa_geo[hsa_geo['STATEFP'].isin(['47'])]
71
+ else:
72
+ raise KeyError("Column to filter state in HSA shapefile not found.")
73
 
74
  # Load the HRR shapefile
75
  hrr_shapefile_path = "data/hrr/01_hrr-shape-file.shp"
76
+ if not os.path.exists(hrr_shapefile_path):
77
+ raise FileNotFoundError(f"HRR shapefile not found at {hrr_shapefile_path}. Please ensure the file exists.")
78
+
79
+ hrr_geo = gpd.read_file(hrr_shapefile_path)
80
+ if 'hrrstate' in hrr_geo.columns:
81
+ hrr_geo = hrr_geo[hrr_geo['hrrstate'].isin(['TN'])]
82
+ elif 'STATEFP' in hrr_geo.columns:
83
+ hrr_geo = hrr_geo[hrr_geo['STATEFP'].isin(['47'])]
84
+ else:
85
+ raise KeyError("Column to filter state in HRR shapefile not found.")
 
 
86
 
87
  # Function to create a Folium map with selected geographical boundaries and markers
88
+ def create_map(geo_layer="Counties", business_filters=["All"]):
 
 
89
  logger.info(f"Creating map with geo_layer: {geo_layer} and business_filters: {business_filters}")
90
 
91
  m = folium.Map(location=[35.8601, -86.6602], zoom_start=7)
92
 
93
+ try:
94
+ # Select the appropriate GeoDataFrame based on geo_layer
95
+ if geo_layer == "Counties":
96
+ geo_data = counties_geo
97
+ elif geo_layer == "HSAs":
98
+ geo_data = hsa_geo
99
+ elif geo_layer == "HRRs":
100
+ geo_data = hrr_geo
101
+ else:
102
+ geo_data = counties_geo # Default to counties
103
+ logger.info(f"Geo layer {geo_layer} selected.")
104
+
105
+ # Add selected geographical boundaries
106
+ folium.GeoJson(geo_data, name=geo_layer).add_to(m)
107
+ except Exception as e:
108
+ logger.error(f"Error loading GeoData for {geo_layer}: {e}")
109
 
110
  # Initialize Marker Cluster
111
  marker_cluster = MarkerCluster().add_to(m)
112
 
113
+ # Filter based on Business
114
  if "All" not in business_filters:
115
  filtered_df = df_md_final1[df_md_final1['business_type'].isin(business_filters)]
116
  else:
117
  filtered_df = df_md_final1.copy()
118
 
119
  logger.info(f"Filtered {len(filtered_df)} businesses based on filters: {business_filters}")
120
+
121
  # Add markers to the map
122
  for _, row in filtered_df.iterrows():
 
 
123
  folium.Marker(
124
  location=[row['md_y'], row['md_x']],
125
+ popup=f"<b>{row['name']}</b><br>{row.get('address', 'N/A')}, {row.get('city', 'N/A')}, TN {row.get('postal_code', 'N/A')}",
126
+ icon=folium.Icon(color='blue', icon='info-sign')
 
 
 
127
  ).add_to(marker_cluster)
128
 
129
  folium.LayerControl().add_to(m)
 
148
  def plot_population_comparison():
149
  df_melted = df_population_comparison.melt(id_vars='County', value_vars=['Population_2010', 'Population_2020'],
150
  var_name='Year', value_name='Population')
 
151
  fig = px.bar(df_melted,
152
  x='County',
153
  y='Population',
 
155
  barmode='group',
156
  title="Tennessee Population Comparison: 2010 vs 2020",
157
  labels={'County': 'County', 'Population': 'Population'},
158
+ color_discrete_map={'Population_2010': 'purple', 'Population_2020': 'blue'})
159
 
160
  fig.update_layout(xaxis={'categoryorder': 'total descending'}, template='plotly_white')
161
  return fig
162
 
163
  # Nearest Neighbor Search Setup
164
+ # Prepare the data for nearest neighbor search
165
  def prepare_nearest_neighbor():
166
  # Convert coordinates to radians for BallTree
167
  coords = df_md_final1[['md_y', 'md_x']].to_numpy()
 
207
  # Add nearest shop marker
208
  folium.Marker(
209
  location=[nearest_shop['md_y'], nearest_shop['md_x']],
210
+ popup=f"Nearest Shop: {nearest_shop['name']}<br>{nearest_shop.get('address', 'N/A')}, {nearest_shop.get('city', 'N/A')}, TN {nearest_shop.get('postal_code', 'N/A')}<br>Distance: {distance_km:.2f} km",
 
 
 
 
211
  icon=folium.Icon(color='green', icon='shopping-cart')
212
  ).add_to(m)
213
 
 
222
 
223
  with gr.Tab("Overview"):
224
  gr.Markdown("## πŸ“Š Tennessee Population Statistics")
225
+
226
+ with gr.Row():
227
+
228
+ with gr.Column():
229
+ gr.Markdown("### 2010 vs 2020 Population Comparison")
230
+ pop_comp = gr.Plot(plot_population_comparison)
231
+
232
  gr.Markdown("### πŸ› οΈ Auto Businesses in Tennessee")
233
+
234
+ manual_table = gr.Dataframe(
235
+ headers=["Location Name", "Street Address", "City", "State", "Postal Code"],
236
+ datatype=["str", "str", "str", "str", "str"],
237
+ value=[
238
+ ["AutoZone Auto Parts - Nashville #2080", "100 Donelson Pike", "Nashville", "Tennessee", "37214"],
239
+ ["AutoZone Auto Parts - Nashville #3597", "1007 Murfreesboro Pike", "Nashville", "Tennessee", "37217"],
240
+ ["AutoZone Auto Parts - Nashville #2095", "2340 Murfreesboro Pike", "Nashville", "Tennessee", "37217"],
241
+ ["AutoZone Auto Parts - Nashville #69", "2800 Gallatin Pike", "Nashville", "Tennessee", "37216"],
242
+ ["AutoZone Auto Parts - Nashville #67", "2917 Nolensville Pike", "Nashville", "Tennessee", "37211"],
243
+ ["AutoZone Auto Parts - Nashville #66", "3041 Dickerson", "Nashville", "Tennessee", "37207"],
244
+ ["AutoZone Auto Parts - Nashville #346", "3712 Clarksville Pike", "Nashville", "Tennessee", "37218"],
245
+ ["AutoZone Auto Parts - Nashville #68", "3913 Charlotte Ave", "Nashville", "Tennessee", "37209"],
246
+ ["AutoZone Auto Parts - Nashville #146", "4815 Nolensville Rd", "Nashville", "Tennessee", "37211"],
247
+ ["AutoZone Auto Parts - Nashville #5963", "5731 Nolensville Pike", "Nashville", "Tennessee", "37211"],
248
+ ["AutoZone Auto Parts - Nashville #2302", "6217 Charlotte Pike", "Nashville", "Tennessee", "37209"],
249
+ ["AutoZone Auto Parts - Nashville #6320", "7621 Hwy 70 S # 3", "Nashville", "Tennessee", "37221"],
250
+ ["AutoZone Auto Parts - Knoxville #4549", "10650 Kingston Pike", "Knoxville", "Tennessee", "37922"],
251
+ ["AutoZone Auto Parts - Knoxville #3884", "110 Holston Ferry Rd", "Knoxville", "Tennessee", "37924"],
252
+ ["AutoZone Auto Parts - Knoxville #700", "2800 North Broadway", "Knoxville", "Tennessee", "37917"],
253
+ ["AutoZone Auto Parts - Knoxville #167", "3100 Magnolia Ave", "Knoxville", "Tennessee", "37914"],
254
+ ["AutoZone Auto Parts - Knoxville #228", "3315 S Chapman Hwy", "Knoxville", "Tennessee", "37920"],
255
+ ["AutoZone Auto Parts - Knoxville #3603", "4768 Centerline Dr", "Knoxville", "Tennessee", "37917"],
256
+ ["AutoZone Auto Parts - Knoxville #154", "4910 N Broadway", "Knoxville", "Tennessee", "37918"],
257
+ ["AutoZone Auto Parts - Knoxville #308", "5715 Western Ave", "Knoxville", "Tennessee", "37921"],
258
+ ["AutoZone Auto Parts - Knoxville #356", "5723 Clinton Hwy", "Knoxville", "Tennessee", "37912"],
259
+ ["AutoZone Auto Parts - Knoxville #2075", "7421 Maynardville", "Knoxville", "Tennessee", "37938"],
260
+ ["AutoZone Auto Parts - Knoxville #118", "8309 Kingston Pike", "Knoxville", "Tennessee", "37919"],
261
+ ["AutoZone Auto Parts - Knoxville #126", "9305 Kingston Pike", "Knoxville", "Tennessee", "37922"],
262
+ ["AutoZone Auto Parts - Memphis #5625", "1203 E Shelby Dr", "Memphis", "Tennessee", "38116"],
263
+ ["AutoZone Auto Parts - Memphis", "1209 E Raines Rd", "Memphis", "Tennessee", "38116"],
264
+ ["AutoZone Auto Parts - Memphis #4395", "1290 Lamar Ave", "Memphis", "Tennessee", "38104"],
265
+ ["AutoZone Auto Parts - Memphis #8", "1363 Getwell Rd", "Memphis", "Tennessee", "38111"],
266
+ ["AutoZone Auto Parts - Memphis #2", "1510 Elvis Presley Blvd", "Memphis", "Tennessee", "38106"],
267
+ ["AutoZone Auto Parts - Memphis #2098", "1770 Sycamore View Rd", "Memphis", "Tennessee", "38134"],
268
+ ["AutoZone Auto Parts - Memphis #27", "1850 S Third St", "Memphis", "Tennessee", "38109"],
269
+ ["AutoZone Auto Parts - Memphis #5421", "2010 Whitten Rd", "Memphis", "Tennessee", "38134"],
270
+ ["AutoZone Auto Parts - Memphis #30", "2076 Frayser Blvd", "Memphis", "Tennessee", "38127"],
271
+ ["AutoZone Auto Parts - Memphis #46", "2323 Lamar Ave", "Memphis", "Tennessee", "38114"],
272
+ ["AutoZone Auto Parts - Memphis #5756", "2449 Jackson Ave", "Memphis", "Tennessee", "38108"],
273
+ ["AutoZone Auto Parts - Memphis #6000", "2761 Kirby Rd", "Memphis", "Tennessee", "38119"],
274
+ ["AutoZone Auto Parts - Memphis #45", "2900 Covington Pk", "Memphis", "Tennessee", "38128"],
275
+ ["AutoZone Auto Parts - Memphis #598", "3166 N Thomas", "Memphis", "Tennessee", "38127"],
276
+ ["AutoZone Auto Parts - Memphis #324", "3171 Summer Ave", "Memphis", "Tennessee", "38112"],
277
+ ["AutoZone Auto Parts - Chattanooga #180", "2021 E 3rd St", "Chattanooga", "Tennessee", "37404"],
278
+ ["AutoZone Auto Parts - Chattanooga #5517", "2114 Gunbarrel Rd", "Chattanooga", "Tennessee", "37421"],
279
+ ["AutoZone Auto Parts - Chattanooga #149", "3201 Dayton Blvd", "Chattanooga", "Tennessee", "37415"],
280
+ ["AutoZone Auto Parts - Chattanooga #116", "3536 Brainerd Rd", "Chattanooga", "Tennessee", "37411"],
281
+ ["AutoZone Auto Parts - Chattanooga #123", "4307 Rossville Blvd", "Chattanooga", "Tennessee", "37407"],
282
+ ["AutoZone Auto Parts - Chattanooga #76", "4818 Hwy 58", "Chattanooga", "Tennessee", "37416"],
283
+ ["AutoZone Auto Parts - Chattanooga #151", "5317 Ringgold Rd", "Chattanooga", "Tennessee", "37412"],
284
+ ["AutoZone Auto Parts - Chattanooga #2072", "7630 E Brainerd Rd", "Chattanooga", "Tennessee", "37421"],
285
+ ["AutoZone Auto Parts - Clarksville #6301", "101 Merchants Blvd", "Clarksville", "Tennessee", "37040"],
286
+ ["AutoZone Auto Parts - Clarksville #64", "1105 Riverwood Pl", "Clarksville", "Tennessee", "37040"],
287
+ ["AutoZone Auto Parts - Clarksville #70", "1444 Fort Campbell Blvd", "Clarksville", "Tennessee", "37042"],
288
+ ["AutoZone Auto Parts - Clarksville #3890", "1832 Tiny Town Rd", "Clarksville", "Tennessee", "37042"],
289
+ ["AutoZone Auto Parts - Clarksville #586", "1959 Madison St", "Clarksville", "Tennessee", "37043"],
290
+ ["AutoZone Auto Parts - Clarksville #3880", "2653 Ft Campbell Blvd", "Clarksville", "Tennessee", "37042"]
291
+ ],
292
+ row_count=52, # Updated for the total number of rows
293
+ interactive=False
294
+ )
295
+
296
+ gr.Markdown("### πŸ“ Interactive Map")
297
  map_output_overview = gr.HTML(create_map(geo_layer="Counties", business_filters=["All"]))
298
 
299
  with gr.Tab("πŸ“ Shops in TN Counties"):
 
361
  address_input = gr.Textbox(label="Enter Address", placeholder="e.g., 123 Main St, Nashville, TN")
362
  address_suggestions = gr.Dropdown(label="Suggestions", choices=[])
363
  gr.Markdown("**OR**")
364
+ # Note: Interactive map clicks are not implemented in this version
 
365
  with gr.Column(scale=4):
366
  nearest_map = gr.HTML()
367
  message_output = gr.Textbox(label="Message", interactive=False)
 
402
  message, updated_map = find_nearest_shop(address=selected_address)
403
  return message, updated_map
404
 
 
 
 
 
 
 
 
 
405
  # When the user types in the address_input, update suggestions
406
  address_input.input(fn=get_address_suggestions, inputs=address_input, outputs=address_suggestions, every=1.0)
407
  # When the user presses Enter in address_input, update map
408
  address_input.submit(fn=update_nearest_map_from_input, inputs=address_input, outputs=[message_output, nearest_map])
409
  # When the user selects an address from suggestions, update the map
410
  address_suggestions.change(fn=update_nearest_map_from_suggestion, inputs=address_suggestions, outputs=[message_output, nearest_map])
 
 
411
 
412
  with gr.Tab("πŸ” Help"):
413
  gr.Markdown("""
 
419
  - **Filter by Business Type:** Use the checkboxes to select one or multiple business types to display on the map.
420
  - **Filter by Geographical Area:** Depending on the tab, you can filter businesses based on Counties, HSAs, or HRRs.
421
  - **Reset Filters:** Click the reset button to clear all selected filters and view all businesses.
422
+ - **Interactive Map:** Zoom in/out, click on markers to view business details, and use the search bar to find specific businesses.
423
 
424
  - **Nearest Shop Finder Tab:**
425
  - **Enter Address:** Type your address in the textbox. As you type, address suggestions will appear. Select one or press Enter to find the nearest auto shop.
 
426
  - **View Results:** The map will display your location and the nearest auto shop with a line connecting them.
427
 
428
  """)
429
 
430
  gr.Markdown("### πŸ“„ Source: Yellow Pages")
431
 
432
+ app.launch(server_name="0.0.0.0", server_port=7860, share=True)