The Timeline Atlas

153 years of football tactical evolution, analyzed in Hex


What It Is

An interactive web app analyzing 48,891 FIFA matches from 1872 to 2025, showing how football evolved from 5.4 goals/match (offensive chaos) to 2.6 goals/match (defensive mastery) to 2.7 goals/match (modern equilibrium).

Built entirely in Hex: 28 Python cells for data, 18 metric cells for KPIs, 30+ explore cells for validation, 20+ markdown cells for narrative, and 8 custom HTML panels via IPython.display for Timeline Atlas design. Published with one click.


The Problem

What does 153 years of Football evolution tell us about the modern game?

Why does football look the way it is today?

What has repeatedly played a role in the best performances and results over time?

Based on historical context, from football fans to teams, sponsors and executives, what can FIFA stakeholders expect from the 2026 FIFA World Cup and how can each position for their best game?


The Solution

The Timeline Atlas uses Hex's complete toolkit to deliver an interactive journey through six tactical eras:

Data (Hex Python): Loaded 48,891 matches, classified into 6 eras, calculated 108 metrics
KPIs (Hex Metrics): 18 metric cells displaying goals/match, home advantage, scoring rates
Validation (Hex Explore): 30+ explore charts confirming patterns
Storytelling (Hex Markdown): 20+ narrative cells structuring the story
Enhancement (Hex HTML): 8 custom panels with Panel navigation and Timeline Atlas design
Publishing (Hex App): One-click deploy, 8 panels visible, 112 prep cells hidden
Dataset: International football results from 1872 to 2025


What I Found

The arc: 5.4 → 4.3 → 4.2 → 3.7 → 2.6 → 2.7 goals per match across six eras.

Pioneer (1870s-80s): 5.4 goals/match, 63% high-scoring | Attack at all costs
Formation (1890s-1910s): 4.3 goals/match | A gradual transition
WM Revolution (1920s-40s): 4.2 goals/match, 0.74 home advantage peak | Defense dominates
Total Football (1950s-60s): 3.7 goals/match | Fluidity beats rigidity
Defensive (1970s-80s): 2.6 goals/match, 27% shutouts | Rock bottom
Modern (1990s-2000s): 2.7 goals/match | Balance restored via rule changes

Key insights:

  • Defensive tactics won (52% scoring decline)
  • Home advantage peaked then fell 43% (globalization effect)
  • 1970s-80s defensive crisis forced rule changes (backpass rule increased scoring)
  • Modern 2.7 goals = tactical equilibrium, sustainable for 2026

How Hex Powered It

The Layered Approach

Foundation (Hex Native): Used Hex Python cells for data engineering (pandas processing 48,891 rows). Used Hex metric cells for instant KPI display. Used Hex explore cells to validate every pattern before custom development.

Enhancement (Hex Custom): When I needed Timeline Atlas design fidelity (cream grid backgrounds, orange/teal palette, panel navigation), I used Hex's IPython.display.HTML() to render custom panels—still in Hex Python cells, still leveraging Hex's dependencies.

Publishing (Hex Infrastructure): SetCellsInApp() to show only 8 panels, hide 112 prep cells. One publish button click. Hex handled hosting, responsive design and all. Done.

The Hex Edge

Versatility: Used Python cells, metric cells, explore cells, markdown cells, AND custom HTML—all in one Hex notebook.

Reactive execution: 120+ cells with complex dependencies worked seamlessly via Hex's dependency graph.

Publishing: Complex multi-panel app deployed with one click.

AI integration: Hex Notebook Agent generated 3,500+ lines using Hex's own tools and Hex Thread


Development Journey

What Worked

  • Hex Python for data: Pandas in Hex cells processed 48,891 matches easily
  • Hex explore for validation: Drag-drop charts confirmed patterns in seconds
  • Hex dependencies: Changed classification logic once, 100+ downstream cells updated automatically
  • Hex publishing: One click, app live, no deployment headaches

What Failed (and How It was Fixed)

Charts disappeared in published app

  • Problem: fig.to_json() broke Hex's HTML parser
  • Fix: Used pyo.plot(output_type='div') for Hex-compatible rendering

Dependency errors

  • Problem: Cells referenced undefined variables on publish
  • Fix: Reordered cells, hardcoded static values

Navigation buttons invisible

  • Problem: CSS conflicts with Hex defaults
  • Fix: Unique class prefixes (.pioneer-btn, .formation-btn)

Panel dots stuck

  • Problem: Nav recreated on each panel switch
  • Fix: Moved nav outside panels, updated via JavaScript

Content overflow

  • Problem: Negative margins broke layout
  • Fix: Explicit max-width containers

Variable collisions

  • Problem: Hex's global scope inherited names
  • Fix: Unique prefixes per era

Total: 6 Hex-specific bugs, 6 fixes, ~8 hours debugging

All issues were about understanding Hex's framework (publishing, dependencies, CSS, scope). Once learned, solutions were straightforward.


What Makes This Different

Hybrid Hex architecture: Most projects use Hex Python or explore cells. This uses Python + metrics + explore + markdown + custom HTML, all working together.

Panel navigation: 27 sub-panels with dot indicators and dynamic buttons for easier navigation

Design system: Complete custom Timeline Atlas design system implementation (3px borders, 30px radius, 8px shadows, Nunito 800 typography) while staying in Hex.

Scale: 8 custom HTML panels following identical template, proving the approach is repeatable.

Hex-powered end-to-end: From CSV ingestion to published app, every step happened in Hex.


The Numbers

120+ Hex cells | 48,891 matches | 6 eras | 108 metrics | 24 charts | 8 panels | 3,800 lines of code | All in Hex


Key Lessons

  1. Start with Hex native tools (metric/explore cells) for rapid prototyping
  2. Hex's IPython.display enables custom UI when design matters
  3. Understand Hex's publishing constraints (dependency order, rendering approaches)
  4. Namespace carefully (global scope persists across cells)
  5. Hex Notebook Agent accelerates development (3x faster with Hex-literate assistance)
  6. Hybrid approaches work (native + custom = best of both)

The Bottom Line

From 5.4 to 2.7 goals per match across 153 years—defensive tactics beat attack at all costs, then rule changes restored balance.

Built entirely in Hex using 120+ cells across its complete toolkit: Python for data, metrics for KPIs, explore for validation, markdown for narrative, custom HTML via IPython.display for design, and one-click publishing to deploy.

For 2026: Expect ~2.7 goals/match—tactical equilibrium is here to stay.


Powered by Hex from start to finish

Built With

Share this project:

Updates