[main]: add 27/07
Build and Push Docker Image / build (push) Successful in 11s

This commit is contained in:
John Gatward
2026-07-28 11:19:25 +01:00
parent 91a636232d
commit 6756012f53
5 changed files with 56 additions and 62 deletions
+30 -28
View File
@@ -1,28 +1,30 @@
Date,Absolute Position,Relative Position,Number of Players,Number of Teams,Points on Scattergories,Ciaran,Jay,Sam,Drew,Theo,Tom,Ellora,Chloe,Jamie,Christine,Mide,Ellie Date,Absolute Position,Number of Players,Number of Teams,Points on Scattergories,Ciaran,Jay,Sam,Drew,Theo,Tom,Ellora,Chloe,Jamie,Christine,Mide,Ellie,Elliot,Kira
17/03/2025,9,0.692,2,13,10,1,1,0,0,0,0,0,0,0,0,0,0 17/03/2025,9,2,13,10,1,1,0,0,0,0,0,0,0,0,0,0,0,0
24/03/2025,14,0.933,2,15,4,1,1,0,0,0,0,0,0,0,0,0,0 24/03/2025,14,2,15,4,1,1,0,0,0,0,0,0,0,0,0,0,0,0
31/03/2025,8,0.444,4,18,7,1,1,1,1,0,0,0,0,0,0,0,0 31/03/2025,8,4,18,7,1,1,1,1,0,0,0,0,0,0,0,0,0,0
07/04/2025,9,0.563,2,16,6,1,1,0,0,0,0,0,0,0,0,0,0 07/04/2025,9,2,16,6,1,1,0,0,0,0,0,0,0,0,0,0,0,0
28/04/2025,9,0.529,3,17,5,1,1,1,0,0,0,0,0,0,0,0,0 28/04/2025,9,3,17,5,1,1,1,0,0,0,0,0,0,0,0,0,0,0
26/05/2025,6,0.5,2,12,8,0,1,0,0,1,0,0,0,0,0,0,0 26/05/2025,6,2,12,8,0,1,0,0,1,0,0,0,0,0,0,0,0,0
02/06/2025,12,0.857,3,14,4,1,1,1,0,0,0,0,0,0,0,0,0 02/06/2025,12,3,14,4,1,1,1,0,0,0,0,0,0,0,0,0,0,0
16/06/2025,6,0.545,3,11,6,1,1,1,0,0,0,0,0,0,0,0,0 16/06/2025,6,3,11,6,1,1,1,0,0,0,0,0,0,0,0,0,0,0
30/06/2025,5,0.833,4,6,8,1,1,1,0,0,1,0,0,0,0,0,0 30/06/2025,5,4,6,8,1,1,1,0,0,1,0,0,0,0,0,0,0,0
14/07/2025,5,0.625,3,8,8,1,1,0,0,0,0,1,0,0,0,0,0 14/07/2025,5,3,8,8,1,1,0,0,0,0,1,0,0,0,0,0,0,0
21/07/2025,4,0.5,2,8,9,1,1,0,0,0,0,0,0,0,0,0,0 21/07/2025,4,2,8,9,1,1,0,0,0,0,0,0,0,0,0,0,0,0
28/07/2025,6,0.375,4,16,4,1,1,1,0,0,0,1,0,0,0,0,0 28/07/2025,6,4,16,4,1,1,1,0,0,0,1,0,0,0,0,0,0,0
04/08/2025,4,0.4,3,10,11,1,1,0,0,0,0,1,0,0,0,0,0 04/08/2025,4,3,10,11,1,1,0,0,0,0,1,0,0,0,0,0,0,0
15/09/2025,4,0.333,4,12,5,1,1,1,0,0,0,1,0,0,0,0,0 15/09/2025,4,4,12,5,1,1,1,0,0,0,1,0,0,0,0,0,0,0
22/09/2025,5,0.417,3,12,5,1,0,1,0,0,1,0,0,0,0,0,0 22/09/2025,5,3,12,5,1,0,1,0,0,1,0,0,0,0,0,0,0,0
29/09/2025,8,0.727,2,11,5,0,1,0,1,0,0,0,0,0,0,0,0 29/09/2025,8,2,11,5,0,1,0,1,0,0,0,0,0,0,0,0,0,0
24/11/2025,8,0.889,3,9,6,1,1,0,0,0,0,1,0,0,0,0,0 24/11/2025,8,3,9,6,1,1,0,0,0,0,1,0,0,0,0,0,0,0
05/01/2026,4,0.5,4,8,6,1,1,0,0,0,0,0,1,1,0,0,0 05/01/2026,4,4,8,6,1,1,0,0,0,0,0,1,1,0,0,0,0,0
26/01/2026,7,0.583,2,12,10,1,1,0,0,0,0,0,0,0,0,0,0 26/01/2026,7,2,12,10,1,1,0,0,0,0,0,0,0,0,0,0,0,0
02/02/2026,7,0.7,2,10,5,1,1,0,0,0,0,0,0,0,0,0,0 02/02/2026,7,2,10,5,1,1,0,0,0,0,0,0,0,0,0,0,0,0
16/02/2026,9,0.5,3,18,6,0,1,0,1,0,0,0,0,0,1,0,0 16/02/2026,9,3,18,6,0,1,0,1,0,0,0,0,0,1,0,0,0,0
23/02/2026,6,0.6,2,10,10,1,1,0,0,0,0,0,0,0,0,0,0 23/02/2026,6,2,10,10,1,1,0,0,0,0,0,0,0,0,0,0,0,0
09/03/2026,6,1,5,6,10,1,1,1,0,0,0,0,1,0,0,1,0 09/03/2026,6,5,6,10,1,1,1,0,0,0,0,1,0,0,1,0,0,0
30/03/2026,2,0.133,4,15,12,1,1,1,1,0,0,0,0,0,0,0,0 30/03/2026,2,4,15,12,1,1,1,1,0,0,0,0,0,0,0,0,0,0
27/04/2026,2,0.222,2,9,7,1,1,0,0,0,0,0,0,0,0,0,0 27/04/2026,2,2,9,7,1,1,0,0,0,0,0,0,0,0,0,0,0,0
11/05/2026,7,0.777,4,9,6,1,1,0,0,0,0,0,1,0,0,0,1 11/05/2026,7,4,9,6,1,1,0,0,0,0,0,1,0,0,0,1,0,0
18/05/2026,8,0.666,3,12,6,1,1,1,0,0,0,0,0,0,0,0,0 18/05/2026,8,3,12,6,1,1,1,0,0,0,0,0,0,0,0,0,0,0
08/06/2026,8,5,11,4,1,1,1,0,0,0,0,0,0,0,0,0,1,1
27/07/2026,12,3,13,5,1,1,1,0,0,0,0,0,0,0,0,0,0,0
1 Date Absolute Position Relative Position Number of Players Number of Teams Points on Scattergories Ciaran Jay Sam Drew Theo Tom Ellora Chloe Jamie Christine Mide Ellie Elliot Kira
2 17/03/2025 9 0.692 2 13 10 1 1 0 0 0 0 0 0 0 0 0 0 0 0
3 24/03/2025 14 0.933 2 15 4 1 1 0 0 0 0 0 0 0 0 0 0 0 0
4 31/03/2025 8 0.444 4 18 7 1 1 1 1 0 0 0 0 0 0 0 0 0 0
5 07/04/2025 9 0.563 2 16 6 1 1 0 0 0 0 0 0 0 0 0 0 0 0
6 28/04/2025 9 0.529 3 17 5 1 1 1 0 0 0 0 0 0 0 0 0 0 0
7 26/05/2025 6 0.5 2 12 8 0 1 0 0 1 0 0 0 0 0 0 0 0 0
8 02/06/2025 12 0.857 3 14 4 1 1 1 0 0 0 0 0 0 0 0 0 0 0
9 16/06/2025 6 0.545 3 11 6 1 1 1 0 0 0 0 0 0 0 0 0 0 0
10 30/06/2025 5 0.833 4 6 8 1 1 1 0 0 1 0 0 0 0 0 0 0 0
11 14/07/2025 5 0.625 3 8 8 1 1 0 0 0 0 1 0 0 0 0 0 0 0
12 21/07/2025 4 0.5 2 8 9 1 1 0 0 0 0 0 0 0 0 0 0 0 0
13 28/07/2025 6 0.375 4 16 4 1 1 1 0 0 0 1 0 0 0 0 0 0 0
14 04/08/2025 4 0.4 3 10 11 1 1 0 0 0 0 1 0 0 0 0 0 0 0
15 15/09/2025 4 0.333 4 12 5 1 1 1 0 0 0 1 0 0 0 0 0 0 0
16 22/09/2025 5 0.417 3 12 5 1 0 1 0 0 1 0 0 0 0 0 0 0 0
17 29/09/2025 8 0.727 2 11 5 0 1 0 1 0 0 0 0 0 0 0 0 0 0
18 24/11/2025 8 0.889 3 9 6 1 1 0 0 0 0 1 0 0 0 0 0 0 0
19 05/01/2026 4 0.5 4 8 6 1 1 0 0 0 0 0 1 1 0 0 0 0 0
20 26/01/2026 7 0.583 2 12 10 1 1 0 0 0 0 0 0 0 0 0 0 0 0
21 02/02/2026 7 0.7 2 10 5 1 1 0 0 0 0 0 0 0 0 0 0 0 0
22 16/02/2026 9 0.5 3 18 6 0 1 0 1 0 0 0 0 0 1 0 0 0 0
23 23/02/2026 6 0.6 2 10 10 1 1 0 0 0 0 0 0 0 0 0 0 0 0
24 09/03/2026 6 1 5 6 10 1 1 1 0 0 0 0 1 0 0 1 0 0 0
25 30/03/2026 2 0.133 4 15 12 1 1 1 1 0 0 0 0 0 0 0 0 0 0
26 27/04/2026 2 0.222 2 9 7 1 1 0 0 0 0 0 0 0 0 0 0 0 0
27 11/05/2026 7 0.777 4 9 6 1 1 0 0 0 0 0 1 0 0 0 1 0 0
28 18/05/2026 8 0.666 3 12 6 1 1 1 0 0 0 0 0 0 0 0 0 0 0
29 08/06/2026 8 5 11 4 1 1 1 0 0 0 0 0 0 0 0 0 1 1
30 27/07/2026 12 3 13 5 1 1 1 0 0 0 0 0 0 0 0 0 0 0
+6 -3
View File
@@ -22,6 +22,9 @@ app = Flask(__name__)
def get_data_frame(filename): def get_data_frame(filename):
df = pd.read_csv(filename) df = pd.read_csv(filename)
df["Date"] = pd.to_datetime(df["Date"], dayfirst=True) df["Date"] = pd.to_datetime(df["Date"], dayfirst=True)
# Relative Position is derived, not entered manually, so it can never
# drift out of sync with Absolute Position / Number of Teams.
df["Relative Position"] = df["Absolute Position"] / df["Number of Teams"]
df = df.sort_values("Date").reset_index(drop=True) df = df.sort_values("Date").reset_index(drop=True)
return df return df
@@ -50,7 +53,7 @@ def generate_position_trend(df):
df["Relative Percentile"] = df["Relative Position"] * 100 df["Relative Percentile"] = df["Relative Position"] * 100
df["Rolling Avg (5)"] = df["Relative Percentile"].rolling( df["Rolling Avg (5)"] = df["Relative Percentile"].rolling(
5, min_periods=1).mean() 5, min_periods=1).mean()
df["Attendees"] = build_hovertext(df, constants.PLAYER_NAME_COLUMNS) df["Attendees"] = build_hovertext(df, constants.get_player_columns(df))
X = sm.add_constant(df["Date_ordinal"]) X = sm.add_constant(df["Date_ordinal"])
model = sm.OLS(df["Relative Percentile"], X).fit() model = sm.OLS(df["Relative Percentile"], X).fit()
@@ -146,7 +149,7 @@ def generate_player_impact(df):
overall_percentile = df["Relative Position"].mean() * 100 overall_percentile = df["Relative Position"].mean() * 100
rows = [] rows = []
for name in constants.PLAYER_NAME_COLUMNS: for name in constants.get_player_columns(df):
if name not in df.columns: if name not in df.columns:
continue continue
attended = df[df[name] == 1] attended = df[df[name] == 1]
@@ -245,7 +248,7 @@ def generate_scattergories_chart(df):
def generate_player_participation(df): def generate_player_participation(df):
"""Heatmap of which player attended which game.""" """Heatmap of which player attended which game."""
player_cols = [c for c in constants.PLAYER_NAME_COLUMNS if c in df.columns] player_cols = [c for c in constants.get_player_columns(df) if c in df.columns]
df_players = df[player_cols] df_players = df[player_cols]
fig = px.imshow( fig = px.imshow(
df_players.T, df_players.T,
+16 -28
View File
@@ -8,39 +8,27 @@ def ordinal(n):
return f"{n}{suffix}" return f"{n}{suffix}"
PLAYER_NAME_COLUMNS = [ # Columns that describe the quiz night itself rather than an individual
"Ciaran", # player's attendance. Any dataframe column not in this set is treated as a
"Jay", # player name, so new players are picked up automatically from data.csv
"Sam", # without needing a code change.
"Drew", NON_PLAYER_COLUMNS = {
"Theo", "Date",
"Tom", "Absolute Position",
"Ellora", "Relative Position",
"Chloe",
"Jamie",
"Christine",
"Mide",
"Ellie",
]
FEATURE_COLUMNS = {
"Number of Players", "Number of Players",
"Number of Teams", "Number of Teams",
"Points on Scattergories", "Points on Scattergories",
"Ciaran",
"Jay",
"Sam",
"Drew",
"Theo",
"Tom",
"Ellora",
"Chloe",
"Jamie",
"Christine",
"Mide",
"Ellie",
} }
def get_player_columns(df):
"""Return the list of player-name columns present in df, in CSV order."""
return [c for c in df.columns if c not in NON_PLAYER_COLUMNS]
FEATURE_COLUMNS = NON_PLAYER_COLUMNS - {"Date", "Relative Position"}
ATTENDANCE_COLORSCHEME = [ ATTENDANCE_COLORSCHEME = [
[0, "#E4ECF6"], [1, "#1e3a8a"] [0, "#E4ECF6"], [1, "#1e3a8a"]
] ]
+3 -2
View File
@@ -1,11 +1,12 @@
from constants import PLAYER_NAME_COLUMNS, ordinal import constants
from constants import ordinal
def generate_player_table(df): def generate_player_table(df):
header = [["Player", "Appearances", "Avg. Relative Percentile", "Spent"]] header = [["Player", "Appearances", "Avg. Relative Percentile", "Spent"]]
player_stats = [] player_stats = []
for name in PLAYER_NAME_COLUMNS: for name in constants.get_player_columns(df):
if name in df.columns: if name in df.columns:
attended = df[df[name] == 1] attended = df[df[name] == 1]
n = len(attended) n = len(attended)
+1 -1
View File
@@ -14,7 +14,7 @@ def _max_team_streak(dates):
def _max_player_streak(df): def _max_player_streak(df):
names = [col for col in df.columns if col in set(constants.PLAYER_NAME_COLUMNS)] names = constants.get_player_columns(df)
max_streak, max_name = 1, names[0] max_streak, max_name = 1, names[0]
for name in names: for name in names:
local_max = current = 0 local_max = current = 0