Roberta2024 commited on
Commit
71a36bf
1 Parent(s): c7734b6

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +102 -125
app.py CHANGED
@@ -1,5 +1,3 @@
1
- import requests
2
- from bs4 import BeautifulSoup
3
  import pandas as pd
4
  import folium
5
  from folium.plugins import MarkerCluster, HeatMap
@@ -12,15 +10,17 @@ import streamlit as st
12
  import time
13
 
14
  # Streamlit title and description
15
- st.title("米其林餐廳指南爬蟲與分析")
16
- st.write("提取餐廳數據,可視化區域分佈,並在地圖上顯示位置和推薦度熱力圖。")
17
 
18
  # Read data from Google Sheets
19
  sheet_id = "1xUfnD1WCF5ldqECI8YXIko1gCpaDDCwTztL17kjI42U"
20
  df = pd.read_csv(f"https://docs.google.com/spreadsheets/d/{sheet_id}/export?format=csv")
21
 
22
- # Print column names
23
  st.write("資料框的列名:", df.columns.tolist())
 
 
24
 
25
  # Initialize Nominatim geocoder
26
  geolocator = Nominatim(user_agent="my_unique_app/3.0")
@@ -40,130 +40,107 @@ def get_lat_lon(district):
40
  location = geolocator.geocode(f"台南市{district}")
41
  if location:
42
  time.sleep(1) # Delay to avoid rate limiting
43
- return location.latitude, location.longitude
44
  except GeocoderInsufficientPrivileges:
45
  st.error("地理編碼器遇到權限問題,請稍後再試。")
46
  return None, None
47
 
48
- # Check if required columns exist
49
- required_columns = ['Address', 'Store Name', '推薦度']
50
- missing_columns = [col for col in required_columns if col not in df.columns]
51
-
52
- if missing_columns:
53
- st.error(f"資料中缺少以下列:{', '.join(missing_columns)}")
54
- st.stop()
55
-
56
- # Apply geocoding to the dataframe
57
- df['Region'] = df['Address'].apply(extract_region)
58
- df['Latitude'], df['Longitude'] = zip(*df['Region'].apply(get_lat_lon))
59
-
60
- # Display the DataFrame as a table at the top
61
- st.subheader("餐廳數據")
62
- st.dataframe(df)
63
-
64
- # Group the data by region and sum the number of restaurants
65
- region_group = df.groupby("Region").agg({'Store Name': 'count', '推薦度': 'mean'}).reset_index()
66
- region_group.columns = ['Region', 'Count', 'Avg_Recommendation']
67
-
68
- # Create hierarchical data for the Sunburst chart
69
- region_group['Total'] = 'All Regions' # Add a root level
70
- hierarchical_data = region_group[['Total', 'Region', 'Count']]
71
-
72
- # Plot interactive Sunburst chart
73
- sunburst = go.Figure(go.Sunburst(
74
- labels=hierarchical_data['Region'].tolist() + hierarchical_data['Total'].tolist(),
75
- parents=hierarchical_data['Total'].tolist() + [''],
76
- values=hierarchical_data['Count'].tolist() + [hierarchical_data['Count'].sum()],
77
- branchvalues="total",
78
- hovertemplate='<b>%{label}</b><br>餐廳數量: %{value}<extra></extra>',
79
- maxdepth=2,
80
- ))
81
-
82
- sunburst.update_layout(
83
- title="餐廳分佈(點擊可放大查看)",
84
- title_x=0.5,
85
- title_font=dict(size=24, family="Arial"),
86
- height=600,
87
- margin=dict(t=50, b=50, l=0, r=0)
88
- )
89
-
90
- # Add custom JavaScript for click events
91
- sunburst.update_layout(
92
- updatemenus=[{
93
- 'type': 'buttons',
94
- 'showactive': False,
95
- 'buttons': [{
96
- 'label': '重置視圖',
97
- 'method': 'update',
98
- 'args': [{'visible': [True] * len(sunburst.data)},
99
- {'title': '餐廳分佈(點擊可放大查看)'}]
100
- }]
101
- }]
102
- )
103
-
104
- st.subheader("餐廳分佈(Sunburst 圖)")
105
- st.plotly_chart(sunburst, use_container_width=True)
106
-
107
- # Plot bar chart with custom colors and labels
108
- bar_chart = go.Figure(go.Bar(
109
- x=region_group["Region"],
110
- y=region_group["Count"],
111
- text=region_group["Count"],
112
- textposition='auto',
113
- marker=dict(color=px.colors.qualitative.Set2)
114
- ))
115
-
116
- bar_chart.update_layout(
117
- title="各區域餐廳數量",
118
- title_x=0.5,
119
- title_font=dict(size=24, family="Arial"),
120
- height=400,
121
- margin=dict(t=50, b=50, l=50, r=50),
122
- xaxis_title="區域",
123
- yaxis_title="餐廳數量",
124
- xaxis=dict(tickangle=-45)
125
- )
126
- st.subheader("各區域餐廳數量(條形圖)")
127
- st.plotly_chart(bar_chart)
128
-
129
- # 推薦度與地理位置的關聯性
130
- st.header("推薦度與地理位置的關聯性")
131
-
132
- # 區域性推薦度分析
133
- fig_bar = px.bar(region_group, x="Region", y="Avg_Recommendation",
134
- title="不同區域的平均推薦度比較",
135
- color_discrete_sequence=['#66CDAA'])
136
- st.plotly_chart(fig_bar)
137
-
138
- # Display a map using Folium
139
- st.subheader("餐廳位置地圖(含推薦度熱力圖)")
140
-
141
- # Create map centered around Tainan
142
- m = folium.Map(location=[23.0, 120.2], zoom_start=12)
143
-
144
- # Add marker cluster to the map
145
- marker_cluster = MarkerCluster().add_to(m)
146
-
147
- # Prepare data for heatmap
148
- heat_data = []
149
-
150
- for index, row in df.iterrows():
151
- if pd.notnull(row["Latitude"]) and pd.notnull(row["Longitude"]):
152
- folium.Marker(
153
- location=[row["Latitude"], row["Longitude"]],
154
- popup=f"{row['Store Name']} (推薦度: {row['推薦度']})",
155
- tooltip=row["Address"]
156
- ).add_to(marker_cluster)
157
- heat_data.append([row["Latitude"], row["Longitude"], row["推薦度"]])
158
-
159
- # Add heatmap layer
160
- HeatMap(heat_data, radius=15, blur=10, max_zoom=1, name="推薦度熱力圖").add_to(m)
161
-
162
- # Add layer control
163
- folium.LayerControl().add_to(m)
164
-
165
- # Display the map in Streamlit
166
- st.components.v1.html(m._repr_html_(), height=600)
167
 
168
  # Save the DataFrame to CSV with UTF-8 encoding
169
  csv_file = "restaurants_data.csv"
 
 
 
1
  import pandas as pd
2
  import folium
3
  from folium.plugins import MarkerCluster, HeatMap
 
10
  import time
11
 
12
  # Streamlit title and description
13
+ st.title("米其林餐廳指南分析")
14
+ st.write("分析餐廳數據,可視化區域分佈,並在地圖上顯示位置和餐廳數量熱力圖。")
15
 
16
  # Read data from Google Sheets
17
  sheet_id = "1xUfnD1WCF5ldqECI8YXIko1gCpaDDCwTztL17kjI42U"
18
  df = pd.read_csv(f"https://docs.google.com/spreadsheets/d/{sheet_id}/export?format=csv")
19
 
20
+ # Print column names and first few rows
21
  st.write("資料框的列名:", df.columns.tolist())
22
+ st.write("資料預覽:")
23
+ st.dataframe(df.head())
24
 
25
  # Initialize Nominatim geocoder
26
  geolocator = Nominatim(user_agent="my_unique_app/3.0")
 
40
  location = geolocator.geocode(f"台南市{district}")
41
  if location:
42
  time.sleep(1) # Delay to avoid rate limiting
43
+ return location.latitude, longitude
44
  except GeocoderInsufficientPrivileges:
45
  st.error("地理編碼器遇到權限問題,請稍後再試。")
46
  return None, None
47
 
48
+ # Assuming we have a column that represents the region or can be used to derive it
49
+ # If we don't have such a column, we'll need to skip this part
50
+ if '區域' in df.columns:
51
+ region_column = '區域'
52
+ elif '地址' in df.columns:
53
+ df['區域'] = df['地址'].apply(extract_region)
54
+ region_column = '區域'
55
+ else:
56
+ st.error("無法找到區域資訊,某些分析將無法進行。")
57
+ region_column = None
58
+
59
+ # Group the data by region and count the number of restaurants
60
+ if region_column:
61
+ region_group = df.groupby(region_column).size().reset_index(name='Count')
62
+
63
+ # Create hierarchical data for the Sunburst chart
64
+ region_group['Total'] = 'All Regions' # Add a root level
65
+ hierarchical_data = region_group[['Total', region_column, 'Count']]
66
+
67
+ # Plot interactive Sunburst chart
68
+ sunburst = go.Figure(go.Sunburst(
69
+ labels=hierarchical_data[region_column].tolist() + hierarchical_data['Total'].tolist(),
70
+ parents=hierarchical_data['Total'].tolist() + [''],
71
+ values=hierarchical_data['Count'].tolist() + [hierarchical_data['Count'].sum()],
72
+ branchvalues="total",
73
+ hovertemplate='<b>%{label}</b><br>餐廳數量: %{value}<extra></extra>',
74
+ maxdepth=2,
75
+ ))
76
+
77
+ sunburst.update_layout(
78
+ title="餐廳分佈(點擊可放大查看)",
79
+ title_x=0.5,
80
+ title_font=dict(size=24, family="Arial"),
81
+ height=600,
82
+ margin=dict(t=50, b=50, l=0, r=0)
83
+ )
84
+
85
+ st.subheader("餐廳分佈(Sunburst 圖)")
86
+ st.plotly_chart(sunburst, use_container_width=True)
87
+
88
+ # Plot bar chart with custom colors and labels
89
+ bar_chart = go.Figure(go.Bar(
90
+ x=region_group[region_column],
91
+ y=region_group["Count"],
92
+ text=region_group["Count"],
93
+ textposition='auto',
94
+ marker=dict(color=px.colors.qualitative.Set2)
95
+ ))
96
+
97
+ bar_chart.update_layout(
98
+ title="各區域餐廳數量",
99
+ title_x=0.5,
100
+ title_font=dict(size=24, family="Arial"),
101
+ height=400,
102
+ margin=dict(t=50, b=50, l=50, r=50),
103
+ xaxis_title="區域",
104
+ yaxis_title="餐廳數量",
105
+ xaxis=dict(tickangle=-45)
106
+ )
107
+ st.subheader("各區域餐廳數量(條形圖)")
108
+ st.plotly_chart(bar_chart)
109
+
110
+ # Display a map using Folium if we have latitude and longitude
111
+ if '緯度' in df.columns and '經度' in df.columns:
112
+ st.subheader("餐廳位置地圖(含數量熱力圖)")
113
+
114
+ # Create map centered around the mean latitude and longitude
115
+ center_lat = df['緯度'].mean()
116
+ center_lon = df['經度'].mean()
117
+ m = folium.Map(location=[center_lat, center_lon], zoom_start=12)
118
+
119
+ # Add marker cluster to the map
120
+ marker_cluster = MarkerCluster().add_to(m)
121
+
122
+ # Prepare data for heatmap
123
+ heat_data = []
124
+
125
+ for index, row in df.iterrows():
126
+ if pd.notnull(row["緯度"]) and pd.notnull(row["經度"]):
127
+ folium.Marker(
128
+ location=[row["緯度"], row["經度"]],
129
+ popup=f"{row.get('店名', 'Unknown')}",
130
+ tooltip=row.get('地址', 'Unknown')
131
+ ).add_to(marker_cluster)
132
+ heat_data.append([row["緯度"], row["經度"], 1]) # Weight of 1 for each restaurant
133
+
134
+ # Add heatmap layer
135
+ HeatMap(heat_data, radius=15, blur=10, max_zoom=1, name="餐廳數量熱力圖").add_to(m)
136
+
137
+ # Add layer control
138
+ folium.LayerControl().add_to(m)
139
+
140
+ # Display the map in Streamlit
141
+ st.components.v1.html(m._repr_html_(), height=600)
142
+ else:
143
+ st.error("無法顯示地圖,因為缺少緯度和經度資訊。")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
144
 
145
  # Save the DataFrame to CSV with UTF-8 encoding
146
  csv_file = "restaurants_data.csv"