Herc commited on
Commit
e6e1696
·
1 Parent(s): 4e81263

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +140 -101
app.py CHANGED
@@ -12,76 +12,76 @@ import random
12
 
13
 
14
 
15
- # 1. create_schedule
16
- def create_schedule(num_teams, num_conferences, num_inter_games):
17
- full_schedule = []
18
- for i in range(num_conferences):
19
- conference_name = chr(65 + i) # 'A', 'B', 'C', 'D', ...
20
- combined_schedule = combine_schedules(conference_name, num_teams, num_inter_games)
21
- assigned_dates = assign_dates_to_matches(combined_schedule)
22
- full_schedule.extend(assigned_dates)
23
- return pd.DataFrame(full_schedule, columns=["Team 1", "Team 2", "Date"])
24
-
25
- # 2. combine_schedules
26
- def combine_schedules(conference_name, num_teams, num_inter_games):
27
- intra_conf_matches = generate_intra_conference_schedule(conference_name, num_teams)
28
- inter_conf_matches = generate_inter_conference_schedule(conference_name, num_teams, num_inter_games)
29
- return intra_conf_matches + inter_conf_matches
30
-
31
- # 3. generate_intra_conference_schedule
32
- def generate_intra_conference_schedule(conference_name, num_teams):
33
- teams = [f"{conference_name}{i}" for i in range(1, num_teams + 1)]
34
- matches = []
35
- for i in range(len(teams)):
36
- for j in range(i+1, len(teams)):
37
- matches.append((teams[i], teams[j]))
38
- matches.append((teams[j], teams[i])) # Home and away
39
- return matches
40
-
41
- # 4. generate_inter_conference_schedule
42
- def generate_inter_conference_schedule(conference_name, num_teams, num_inter_games):
43
- current_conf_teams = [f"{conference_name}{i}" for i in range(1, num_teams + 1)]
44
- other_confs = [chr(65 + i) for i in range(4) if chr(65 + i) != conference_name]
45
- other_conf_teams = [f"{conf}{i}" for conf in other_confs for i in range(1, num_teams + 1)]
46
- matches = []
47
- for team in current_conf_teams:
48
- opponents = random.sample(other_conf_teams, num_inter_games)
49
- for opp in opponents:
50
- matches.append((team, opp))
51
- return matches
52
-
53
- # 5. assign_dates_to_matches
54
- def assign_dates_to_matches(matches):
55
- start_date = date(2022, 11, 6)
56
- end_date = date(2023, 3, 1)
57
- available_dates = [start_date + timedelta(days=i) for i in range((end_date - start_date).days) if (start_date + timedelta(days=i)).weekday() in [0, 2, 3, 5]]
58
- random.shuffle(available_dates)
59
 
60
- # Ensure cyclic reuse of dates
61
- extended_dates = available_dates * (len(matches) // len(available_dates) + 1)
 
 
 
 
 
62
 
63
- return [(match[0], match[1], extended_dates[i]) for i, match in enumerate(matches)]
 
 
 
 
 
 
 
 
 
 
 
 
 
64
 
65
 
66
  # 6. generate_mock_historical_data
67
- def generate_mock_historical_data(num_teams, num_conferences, num_inter_games, start_date, end_date):
68
- full_schedule = []
69
- for i in range(num_conferences):
70
- conference_name = chr(65 + i)
71
- combined_schedule = combine_schedules(conference_name, num_teams, num_inter_games)
72
- shuffled_dates = assign_dates_to_matches(combined_schedule)
73
- random.shuffle(shuffled_dates)
74
- for match in shuffled_dates:
75
- full_schedule.append({
76
- "Team 1": match[0],
77
- "Team 2": match[1],
78
- "Date": match[2]
79
- })
80
- return pd.DataFrame(full_schedule)
81
 
 
 
 
 
 
 
 
 
82
 
83
  # Team Workload Analysis
84
- def team_workload_analysis(schedule_df):
85
  # Check if the DataFrame is None
86
  if schedule_df is None:
87
  plt.figure(figsize=(10, 6))
@@ -92,6 +92,7 @@ def team_workload_analysis(schedule_df):
92
  plt.tight_layout()
93
  plt.show()
94
  return
 
95
  """Generate a bar chart showing the number of matches each team has per week."""
96
  schedule_df['Week'] = schedule_df['Date'].dt.isocalendar().week
97
  team_counts = schedule_df.groupby(['Week', 'Team 1']).size().unstack().fillna(0)
@@ -105,8 +106,9 @@ def team_workload_analysis(schedule_df):
105
  plt.legend(title='Teams', bbox_to_anchor=(1.05, 1), loc='upper left')
106
  plt.show()
107
 
 
108
  # Match Distribution
109
- def match_distribution(schedule_df):
110
  # Check if the DataFrame is None
111
  if schedule_df is None:
112
  plt.figure(figsize=(10, 6))
@@ -117,6 +119,7 @@ def match_distribution(schedule_df):
117
  plt.tight_layout()
118
  plt.show()
119
  return
 
120
  """Generate a histogram showing match distribution across months."""
121
  schedule_df['Month'] = schedule_df['Date'].dt.month_name()
122
  month_order = ['November', 'December', 'January', 'February', 'March']
@@ -130,8 +133,9 @@ def match_distribution(schedule_df):
130
  plt.tight_layout()
131
  plt.show()
132
 
 
133
  # Inter-Conference Match Analysis
134
- def inter_conference_analysis(schedule_df):
135
  # Check if the DataFrame is None
136
  if schedule_df is None:
137
  plt.figure(figsize=(10, 6))
@@ -143,18 +147,19 @@ def inter_conference_analysis(schedule_df):
143
  plt.show()
144
  return
145
  """Generate a heatmap showing inter-conference match frequencies."""
146
- # Extract the conference from the team names
147
- schedule_df['Conference 1'] = schedule_df['Team 1'].str[0]
148
- schedule_df['Conference 2'] = schedule_df['Team 2'].str[0]
 
149
 
150
  # Filter out intra-conference matches
151
- inter_conference_df = schedule_df[schedule_df['Conference 1'] != schedule_df['Conference 2']]
152
 
153
  # Create a crosstab for the heatmap
154
  heatmap_data = pd.crosstab(inter_conference_df['Conference 1'], inter_conference_df['Conference 2'])
155
 
156
  # Ensure every conference combination has a value
157
- all_conferences = schedule_df['Conference 1'].unique()
158
  for conf in all_conferences:
159
  if conf not in heatmap_data.columns:
160
  heatmap_data[conf] = 0
@@ -172,7 +177,7 @@ def inter_conference_analysis(schedule_df):
172
  plt.show()
173
 
174
  # Commissioner Analytics
175
- def commissioner_analytics(schedule_df, commissioners):
176
  # Check if the DataFrame is None
177
  if schedule_df is None:
178
  plt.figure(figsize=(10, 6))
@@ -183,9 +188,10 @@ def commissioner_analytics(schedule_df, commissioners):
183
  plt.tight_layout()
184
  plt.show()
185
  return
 
186
  """Generate a bar chart showing matches overseen by each commissioner."""
187
  # Assuming each commissioner oversees a specific conference
188
- comm_dict = {f"Conference {chr(65+i)}": comm for i, comm in enumerate(commissioners)}
189
  schedule_df['Commissioner'] = schedule_df['Conference 1'].map(comm_dict)
190
 
191
  # Count matches overseen by each commissioner
@@ -203,16 +209,35 @@ def commissioner_analytics(schedule_df, commissioners):
203
 
204
 
205
 
 
206
  # Streamlit App
207
 
208
  st.title("Basketball Game Schedule Generator")
209
 
210
- if 'num_teams' not in st.session_state:
211
- st.session_state.num_teams = 10
212
- if 'num_conferences' not in st.session_state:
213
- st.session_state.num_conferences = 4
214
- if 'num_inter_games' not in st.session_state:
215
- st.session_state.num_inter_games = 3
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
216
 
217
  # Initialize session state for schedule_df and st.session_state.historical_data
218
  if 'schedule_df' not in st.session_state:
@@ -221,19 +246,22 @@ if 'schedule_df' not in st.session_state:
221
  if 'st.session_state.historical_data' not in st.session_state:
222
  st.session_state.historical_data = None
223
 
224
- if st.session_state.historical_data is None:
225
- st.session_state.historical_data = generate_mock_historical_data(st.session_state.num_teams, st.session_state.num_conferences, st.session_state.num_inter_games, date(2022, 11, 6), date(2023, 3, 1))
226
- st.session_state.historical_data['Date'] = pd.to_datetime(st.session_state.historical_data['Date'])
227
-
 
 
 
 
 
 
 
228
 
229
 
230
  # Configuration UI
231
  st.header("Configuration")
232
 
233
- st.session_state.num_teams = st.number_input("Number of teams per conference:", min_value=2, value=st.session_state.num_teams)
234
- st.session_state.num_conferences = st.number_input("Number of conferences:", min_value=2, value=st.session_state.num_conferences)
235
- st.session_state.num_inter_games = st.number_input("Number of inter-conference games per team:", min_value=1, value=st.session_state.num_inter_games)
236
-
237
 
238
  commissioners = st.multiselect("Add commissioners:", options=[], default=[])
239
 
@@ -241,51 +269,62 @@ add_commissioner = st.text_input("New commissioner name:")
241
  if add_commissioner:
242
  commissioners.append(add_commissioner)
243
 
244
- # Schedule Generation
245
- if st.button("Generate Schedule"):
246
- st.session_state.schedule_df = create_schedule(st.session_state.num_teams, st.session_state.num_conferences, st.session_state.num_inter_games)
247
- if st.session_state.schedule_df is not None:
248
- st.session_state.schedule_df['Date'] = pd.to_datetime(st.session_state.schedule_df['Date'])
249
 
250
 
251
  # Schedule Viewing
252
  st.header("View Schedule")
253
- conference_selector = st.selectbox("Select conference to view schedule:", options=["All"] + [f"Conference {chr(65+i)}" for i in range(st.session_state.num_conferences)])
254
  if st.session_state.schedule_df is not None:
 
 
 
 
255
  if conference_selector == "All":
256
  st.dataframe(st.session_state.schedule_df)
257
  else:
258
- filtered_schedule = st.session_state.schedule_df[(st.session_state.schedule_df["Team 1"].str.startswith(conference_selector)) | (st.session_state.schedule_df["Team 2"].str.startswith(conference_selector))]
 
259
  st.dataframe(filtered_schedule)
 
 
 
260
 
261
  # Analytics & Comparisons
262
  st.header("Analytics & Comparisons")
263
  analytics_option = st.selectbox("Choose an analysis type:", ["Team Workload Analysis", "Match Distribution", "Inter-Conference Match Analysis", "Commissioner Analytics"])
264
- st.session_state.historical_data['Date'] = pd.to_datetime(st.session_state.historical_data['Date'])
 
 
 
 
265
 
266
  if analytics_option == "Team Workload Analysis":
267
  st.subheader("Historical Data")
268
- st.pyplot(team_workload_analysis(st.session_state.historical_data))
269
  st.subheader("Current Data")
270
- st.pyplot(team_workload_analysis(st.session_state.schedule_df))
 
271
 
272
  elif analytics_option == "Match Distribution":
273
  st.subheader("Historical Data")
274
- st.pyplot(match_distribution(st.session_state.historical_data))
275
  st.subheader("Current Data")
276
- st.pyplot(match_distribution(st.session_state.schedule_df))
 
277
 
278
  elif analytics_option == "Inter-Conference Match Analysis":
279
  st.subheader("Historical Data")
280
- st.pyplot(inter_conference_analysis(st.session_state.historical_data))
281
  st.subheader("Current Data")
282
- st.pyplot(inter_conference_analysis(st.session_state.schedule_df))
 
283
 
284
  elif analytics_option == "Commissioner Analytics":
285
  st.subheader("Historical Data")
286
- st.pyplot(commissioner_analytics(st.session_state.historical_data, commissioners))
287
  st.subheader("Current Data")
288
- st.pyplot(commissioner_analytics(st.session_state.schedule_df, commissioners))
 
289
  else:
290
  st.warning("Please generate the schedule first before viewing analytics.")
291
 
 
12
 
13
 
14
 
15
+ import pandas as pd
16
+ import random
17
+ from itertools import combinations, product
18
+ from datetime import date, timedelta
19
+
20
+ def generate_schedule_from_data(conference_team_df, available_dates):
21
+ # Extract unique conferences
22
+ conferences = conference_team_df['Conference'].unique()
23
+ # Ensure 'Conference' and 'Team' columns are present
24
+ if 'Conference' not in conference_team_df or 'Team' not in conference_team_df:
25
+ raise ValueError("The CSV file must contain 'Conference' and 'Team' columns.")
26
+
27
+ # Generate intra-conference matches
28
+ intra_conference_matches = []
29
+ for conf in conferences:
30
+ teams_in_conf = conference_team_df[conference_team_df['Conference'] == conf]['Team'].tolist()
31
+ # Each team plays each other team in their conference twice
32
+ matches = list(combinations(teams_in_conf, 2))
33
+ intra_conference_matches.extend(matches)
34
+ intra_conference_matches.extend([(team2, team1) for team1, team2 in matches])
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
35
 
36
+ # Generate inter-conference matches (limit these to 1 per team)
37
+ inter_conference_matches = []
38
+ for team, conference in zip(conference_team_df['Team'], conference_team_df['Conference']):
39
+ other_conferences = [conf for conf in conferences if conf != conference]
40
+ other_teams = conference_team_df[conference_team_df['Conference'].isin(other_conferences)]['Team'].tolist()
41
+ matches = random.sample([(team, other_team) for other_team in other_teams], 1)
42
+ inter_conference_matches.extend(matches)
43
 
44
+ # Combine the matches
45
+ combined_schedule = intra_conference_matches + inter_conference_matches
46
+ scheduled_matches = assign_dates_to_matches(combined_schedule, available_dates)
47
+
48
+
49
+ # Convert to DataFrame
50
+ schedule_df = pd.DataFrame(scheduled_matches, columns=['Team 1', 'Team 2', 'Date'])
51
+ schedule_df['Conference 1'] = schedule_df['Team 1'].map(conference_team_df.set_index('Team').to_dict()['Conference'])
52
+ schedule_df['Conference 2'] = schedule_df['Team 2'].map(conference_team_df.set_index('Team').to_dict()['Conference'])
53
+ return schedule_df
54
+
55
+ # To use this function, load your data into a DataFrame and call this function:
56
+ # df = pd.read_csv('path/to/your/csv')
57
+ # schedule_df = generate_schedule_from_data(df)
58
 
59
 
60
  # 6. generate_mock_historical_data
61
+ def generate_mock_historical_data(schedule_df):
62
+ # Generate random scores for each team in each game
63
+ schedule_df['Score 1'] = [random.randint(50, 100) for _ in range(len(schedule_df))]
64
+ schedule_df['Score 2'] = [random.randint(50, 100) for _ in range(len(schedule_df))]
65
+
66
+ # Assume the historical data is from the previous year
67
+ schedule_df['Date'] = schedule_df['Date'] - pd.DateOffset(years=1)
68
+
69
+ return schedule_df
70
+
71
+ # To use this function, pass the generated schedule DataFrame:
72
+ # historical_data = generate_mock_historical_data(schedule_df)
 
 
73
 
74
+ # Assign dates to matches
75
+ def generate_available_dates(start_date, num_days=300):
76
+ available_dates = [start_date + timedelta(days=i) for i in range(num_days) if (start_date + timedelta(days=i)).weekday() in [0, 2, 3, 5]]
77
+ return available_dates
78
+
79
+ def assign_dates_to_matches(matches, available_dates):
80
+ num_dates = len(available_dates)
81
+ return [(match[0], match[1], available_dates[i % num_dates]) for i, match in enumerate(matches)]
82
 
83
  # Team Workload Analysis
84
+ def team_workload_analysis(schedule_df, conference_team_df):
85
  # Check if the DataFrame is None
86
  if schedule_df is None:
87
  plt.figure(figsize=(10, 6))
 
92
  plt.tight_layout()
93
  plt.show()
94
  return
95
+
96
  """Generate a bar chart showing the number of matches each team has per week."""
97
  schedule_df['Week'] = schedule_df['Date'].dt.isocalendar().week
98
  team_counts = schedule_df.groupby(['Week', 'Team 1']).size().unstack().fillna(0)
 
106
  plt.legend(title='Teams', bbox_to_anchor=(1.05, 1), loc='upper left')
107
  plt.show()
108
 
109
+
110
  # Match Distribution
111
+ def match_distribution(schedule_df, conference_team_df):
112
  # Check if the DataFrame is None
113
  if schedule_df is None:
114
  plt.figure(figsize=(10, 6))
 
119
  plt.tight_layout()
120
  plt.show()
121
  return
122
+
123
  """Generate a histogram showing match distribution across months."""
124
  schedule_df['Month'] = schedule_df['Date'].dt.month_name()
125
  month_order = ['November', 'December', 'January', 'February', 'March']
 
133
  plt.tight_layout()
134
  plt.show()
135
 
136
+
137
  # Inter-Conference Match Analysis
138
+ def inter_conference_analysis(schedule_df, conference_team_df):
139
  # Check if the DataFrame is None
140
  if schedule_df is None:
141
  plt.figure(figsize=(10, 6))
 
147
  plt.show()
148
  return
149
  """Generate a heatmap showing inter-conference match frequencies."""
150
+ # Map team names to their conferences
151
+ team_to_conference = dict(zip(conference_team_df['Team'], conference_team_df['Conference']))
152
+ schedule_df['Conference 1'] = schedule_df['Team 1'].map(team_to_conference)
153
+ schedule_df['Conference 2'] = schedule_df['Team 2'].map(team_to_conference)
154
 
155
  # Filter out intra-conference matches
156
+ inter_conference_df = st.session_state.schedule_df[st.session_state.schedule_df['Conference 1'] != st.session_state.schedule_df['Conference 2']]
157
 
158
  # Create a crosstab for the heatmap
159
  heatmap_data = pd.crosstab(inter_conference_df['Conference 1'], inter_conference_df['Conference 2'])
160
 
161
  # Ensure every conference combination has a value
162
+ all_conferences = st.session_state.schedule_df['Conference 1'].unique()
163
  for conf in all_conferences:
164
  if conf not in heatmap_data.columns:
165
  heatmap_data[conf] = 0
 
177
  plt.show()
178
 
179
  # Commissioner Analytics
180
+ def commissioner_analytics(schedule_df, conference_team_df, commissioners):
181
  # Check if the DataFrame is None
182
  if schedule_df is None:
183
  plt.figure(figsize=(10, 6))
 
188
  plt.tight_layout()
189
  plt.show()
190
  return
191
+
192
  """Generate a bar chart showing matches overseen by each commissioner."""
193
  # Assuming each commissioner oversees a specific conference
194
+ comm_dict = {conf: comm for conf, comm in zip(conference_team_df['Conference'].unique(), commissioners)}
195
  schedule_df['Commissioner'] = schedule_df['Conference 1'].map(comm_dict)
196
 
197
  # Count matches overseen by each commissioner
 
209
 
210
 
211
 
212
+
213
  # Streamlit App
214
 
215
  st.title("Basketball Game Schedule Generator")
216
 
217
+ st.set_option('deprecation.showPyplotGlobalUse', False)
218
+
219
+ # UI for CSV File Uploader
220
+ uploaded_file = st.file_uploader("Choose a CSV file", type=['csv'])
221
+
222
+ # Load the Uploaded CSV File
223
+ if uploaded_file is not None:
224
+ df = pd.read_csv(uploaded_file)
225
+ st.write('Uploaded CSV file:')
226
+ st.write(df)
227
+
228
+ # Generate available dates here
229
+ start_date = date(2022, 11, 6)
230
+ available_dates = generate_available_dates(start_date)
231
+
232
+ # Generate Schedule using Uploaded Data
233
+ if st.button("Generate Schedule"):
234
+ if uploaded_file is not None:
235
+ st.session_state.schedule_df = generate_schedule_from_data(df, available_dates) # pass available_dates as argument
236
+ st.write('Generated Schedule:')
237
+ st.write(st.session_state.schedule_df)
238
+ else:
239
+ st.warning("Please upload a CSV file to proceed.")
240
+
241
 
242
  # Initialize session state for schedule_df and st.session_state.historical_data
243
  if 'schedule_df' not in st.session_state:
 
246
  if 'st.session_state.historical_data' not in st.session_state:
247
  st.session_state.historical_data = None
248
 
249
+ if st.button("Generate Mock Historical Data"):
250
+ # Only generate historical data if it hasn’t been generated already
251
+ if st.session_state.historical_data is None:
252
+ # Ensure that the schedule has been generated before generating historical data
253
+ if st.session_state.schedule_df is not None:
254
+ # Generate the mock historical data based on the generated schedule
255
+ st.session_state.historical_data = generate_mock_historical_data(st.session_state.schedule_df)
256
+ st.write('Generated Mock Historical Data:')
257
+ st.write(st.session_state.historical_data)
258
+ else:
259
+ st.warning("Please generate the schedule first before generating mock historical data.")
260
 
261
 
262
  # Configuration UI
263
  st.header("Configuration")
264
 
 
 
 
 
265
 
266
  commissioners = st.multiselect("Add commissioners:", options=[], default=[])
267
 
 
269
  if add_commissioner:
270
  commissioners.append(add_commissioner)
271
 
 
 
 
 
 
272
 
273
 
274
  # Schedule Viewing
275
  st.header("View Schedule")
276
+
277
  if st.session_state.schedule_df is not None:
278
+ # Fetching the unique conferences from the schedule DataFrame
279
+ conferences = st.session_state.schedule_df['Conference 1'].unique()
280
+ conference_selector = st.selectbox("Select conference to view schedule:", options=["All"] + list(conferences))
281
+
282
  if conference_selector == "All":
283
  st.dataframe(st.session_state.schedule_df)
284
  else:
285
+ # Filtering the schedule based on the selected conference
286
+ filtered_schedule = st.session_state.schedule_df[(st.session_state.schedule_df["Conference 1"] == conference_selector) | (st.session_state.schedule_df["Conference 2"] == conference_selector)]
287
  st.dataframe(filtered_schedule)
288
+ else:
289
+ st.warning("Schedule has not been generated yet.")
290
+
291
 
292
  # Analytics & Comparisons
293
  st.header("Analytics & Comparisons")
294
  analytics_option = st.selectbox("Choose an analysis type:", ["Team Workload Analysis", "Match Distribution", "Inter-Conference Match Analysis", "Commissioner Analytics"])
295
+ if st.session_state.historical_data is not None:
296
+ st.session_state.historical_data['Date'] = pd.to_datetime(st.session_state.historical_data['Date'])
297
+ else:
298
+ st.error("Historical data has not been generated yet.")
299
+
300
 
301
  if analytics_option == "Team Workload Analysis":
302
  st.subheader("Historical Data")
303
+ st.pyplot(team_workload_analysis(st.session_state.historical_data, df))
304
  st.subheader("Current Data")
305
+ st.pyplot(team_workload_analysis(st.session_state.schedule_df, df))
306
+
307
 
308
  elif analytics_option == "Match Distribution":
309
  st.subheader("Historical Data")
310
+ st.pyplot(match_distribution(st.session_state.historical_data, df))
311
  st.subheader("Current Data")
312
+ st.pyplot(match_distribution(st.session_state.schedule_df, df))
313
+
314
 
315
  elif analytics_option == "Inter-Conference Match Analysis":
316
  st.subheader("Historical Data")
317
+ st.pyplot(inter_conference_analysis(st.session_state.historical_data, df))
318
  st.subheader("Current Data")
319
+ st.pyplot(inter_conference_analysis(st.session_state.schedule_df, df))
320
+
321
 
322
  elif analytics_option == "Commissioner Analytics":
323
  st.subheader("Historical Data")
324
+ st.pyplot(commissioner_analytics(st.session_state.historical_data, df, commissioners))
325
  st.subheader("Current Data")
326
+ st.pyplot(commissioner_analytics(st.session_state.schedule_df, df, commissioners))
327
+
328
  else:
329
  st.warning("Please generate the schedule first before viewing analytics.")
330