diff --git a/.dockerignore b/.dockerignore index 99a4800..75e7472 100644 --- a/.dockerignore +++ b/.dockerignore @@ -31,5 +31,4 @@ data.csv # Docker itself Dockerfile docker-compose.yml -.dockerignore - +.dockerignore \ No newline at end of file diff --git a/.gitignore b/.gitignore index 1c69b55..454e8af 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ .idea .venv +dist/ __pycache__/ diff --git a/AGENTS.md b/AGENTS.md deleted file mode 100644 index 1182e67..0000000 --- a/AGENTS.md +++ /dev/null @@ -1,62 +0,0 @@ -# AGENTS.md — The Hope Pub Quiz Dashboard - -## Overview -Single-page Flask dashboard that reads `data.csv` (one row per quiz night) and renders summary statistics, a player cost table, and five Plotly charts via a Jinja2 template. No database — the CSV is the sole data store. - -## Running the App -```bash -uv sync # install deps from uv.lock / pyproject.toml -PYTHONPATH=src python src/app.py # run from project root — resolves data.csv correctly -``` -> **Path gotcha:** `app.py` reads `data.csv` with a bare relative path, so the CWD must be the **project root**. `PYTHONPATH=src` puts `src/` on the import path so local modules resolve. - -## Data Shape (`data.csv`) -- **One row = one quiz night** -- Columns: `Date` (DD/MM/YYYY), `Absolute Position`, `Relative Position` (float 0–1, 0=1st/best, 1=last), `Number of Players`, `Number of Teams`, `Points on Scattergories`, then one binary column per player (1=attended, 0=absent). -- Date parsing uses `dayfirst=True`; the DataFrame is sorted ascending by date on every load. - -## Module Responsibilities -| File | Role | -|---|---| -| `src/app.py` | Flask route, five Plotly chart builders, data loading | -| `src/stats.py` | `generate_stats(df)` → `(stats_dict, highlights_list)` tuple | -| `src/player_table.py` | `generate_player_table(df)` → flat list-of-lists; cost hard-coded at **£3/quiz** | -| `src/constants.py` | Player names, regression features, colour scheme, `ordinal(n)` helper | -| `src/templates/index.html` | Renders `highlights` list, `stats` dict, `player_table`, and `plots` dict | - -## Key Conventions - -### Adding/Removing a Player -1. Update `constants.PLAYER_NAME_COLUMNS` (ordered list — controls display order everywhere). -2. Update `constants.FEATURE_COLUMNS` (set — controls which columns feed the regression model). -3. Add the new binary column to `data.csv`. - -### `generate_stats` Return Value -Returns a **tuple** `(stats, highlights)`: -- `highlights` — list of `{"label": str, "value": str, "detail": str}` dicts; rendered as 6 KPI cards. -- `stats` — plain `dict` of human-readable `label: value` pairs; rendered as a secondary list. - -The `index()` route unpacks both: `stats, highlights = generate_stats(df)`. - -### Plots Pipeline -1. Build a Plotly figure in `app.py` using `Relative Position` directly (or `Relative Position * 100` for percentile display), where **lower = better**. -2. Serialise: `json.dumps(fig, cls=plotly.utils.PlotlyJSONEncoder)`. -3. Store in the `plots` dict under a **snake_case key** (e.g. `"position_trend"`). -4. The template renders every entry automatically: `Plotly.newPlot("{{ key }}", ...)` — key is both the `
` and JS target. - -Current charts (in render order): `position_trend`, `player_impact`, `scattergories_vs_position`, `player_participation`, `calendar`. - -### `player_table` Structure -`[0]` = header row, `[1:-1]` = data rows sorted by appearances descending, `[-1]` = totals footer. The template uses `player_table[1:-1]` for `` and `player_table[-1]` for ``. - -### `Relative Position` Convention -Raw data stores `Relative Position` (0=best). The dashboard keeps this convention everywhere: lower values are better in stats, tables, and chart labels. If a chart uses percentile text, it is `Relative Position * 100` (still lower = better). - -### `ordinal(n)` Helper -Lives in `constants.py`. Returns e.g. `"1st"`, `"22nd"`, `"63rd"`. Import where needed: `from constants import ordinal`. - -### Player Impact Chart -Shows average relative percentile when each player attends. Only players with **>= 3 appearances** are shown (`MIN_APPEARANCES = 3` in `generate_player_impact`). Green bar = below overall average (better); red = above (worse). - -## Frontend -No build step. Tailwind CSS (`cdn.tailwindcss.com`) and Plotly (`cdn.plot.ly/plotly-3.0.1.min.js`) loaded from CDN. Charts use `{ responsive: true, displayModeBar: false }` config. diff --git a/dist/index.html b/dist/index.html deleted file mode 100644 index d72648a..0000000 --- a/dist/index.html +++ /dev/null @@ -1,506 +0,0 @@ - - - - - - - The Hope Pub Quiz - - - - - - - -
-
-

Performance Dashboard

-

The Hope Pub Quiz

-

Trying to convince ourselves we're not stupid

-
-
- -
- - -
-

At a Glance

-
- -
- 23 - Quizzes Played - Since Mar 2025 -
- -
- 61st - Avg. Relative Percentile - Lower = better finishing position -
- -
- 4th place - Best Finish - Out of 12 teams -
- -
- 68th - Recent Form - ↑ declining vs overall (lower is better) -
- -
- 5 - Top-Half Finishes - 22% of all games -
- -
- 4 wks - Best Streak - Consecutive weeks attended -
- -
-
- - -
- - -
-

More Stats

-
- -
-
Top-half finishes
-
5 of 23 (22%)
-
- -
-
Average teams per night
-
11.8
-
- -
-
Average squad size
-
2.9 players
-
- -
-
Average Scattergories score
-
6.9 pts
-
- -
-
Best Scattergories score
-
11 pts
-
- -
-
Longest individual streak
-
14 weeks (Jay)
-
- -
-
- - -
-

Squad

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- Player - - Appearances - - Avg. Relative Percentile - - Spent -
- Jay - - 22 - - 62nd - - £66.00 -
- Ciaran - - 20 - - 62nd - - £60.00 -
- Sam - - 9 - - 59th - - £27.00 -
- Ellora - - 5 - - 52nd - - £15.00 -
- Drew - - 3 - - 56th - - £9.00 -
- Tom - - 2 - - 62nd - - £6.00 -
- Chloe - - 2 - - 75th - - £6.00 -
- Theo - - 1 - - 50th - - £3.00 -
- Jamie - - 1 - - 50th - - £3.00 -
- Christine - - 1 - - 50th - - £3.00 -
- Mide - - 1 - - 100th - - £3.00 -
- Total - - 67 - - — - - £201.00 -
-
- -
- - -
-

Charts

-
- -
-
- -
- -
-
- -
- -
-
- -
- -
-
- -
- -
-
- -
- -
-
- -
- - - - - - - \ No newline at end of file