Chessalyzer

Comparing groups of games

Analyze two filtered groups in one pass and diff their heatmaps.

Some questions are really comparisons in disguise: do high-rated players use the center differently than beginners? The runs option lets you analyze several groups — each with its own trackers and filter — in a single call:

import { analyzePGN } from 'chessalyzer';
import { generateComparisonHeatmap, tileTracker } from 'chessalyzer/trackers';

const high = tileTracker();
const low = tileTracker();

await analyzePGN('games.pgn', {
    runs: [
        { trackers: [high], filter: (game) => Number(game.headers?.WhiteElo) > 2000 },
        { trackers: [low], filter: (game) => Number(game.headers?.WhiteElo) < 1700 },
    ],
});

Each run accumulates into its own tracker instances: on our example file, high.state sees only alice's 2114-Elo game (7 half-moves), while low.state sees only blunderbuss' 1650 game (4 half-moves).

One instance per group

Pass distinct tracker instances to each run (tileTracker() twice, not one instance reused). The same instance cannot appear twice in a single analyzePGN call — its state would mix both groups together.

Diffing two heatmaps

generateComparisonHeatmap(stateA, stateB, fn) runs the same per-square function over both states and returns the percentage difference per square: positive means group A scored higher, negative means group B did, and 0 whenever either side has nothing to compare. The result is a regular HeatmapData ({ grid, min, max }), so printHeatmap works on it — blue cells favor group B, orange cells favor group A:

const diff = generateComparisonHeatmap(high.state, low.state, ({ data, square }) => {
    const cell = data.squares[square];
    return (cell.w.total.occupiedFor * 100) / data.movesTotal;
});

Asking "where did white pieces spend their time?" for both groups on the example file:

// diff.grid — percentage points, files a–h, rank 8 on top
        a      b      c      d      e       f       g      h
8     0.00   0.00   0.00   0.00   0.00    0.00    0.00   0.00
7     0.00   0.00   0.00   0.00   0.00    0.00    0.00   0.00
6     0.00   0.00   0.00   0.00   0.00    0.00    0.00   0.00
5     0.00   0.00   0.00   0.00   0.00    0.00    0.00   0.00
4     0.00   0.00   0.00   0.00   0.00    0.00    0.00   0.00
3     0.00   0.00   0.00   0.00   0.00    0.00    0.00   0.00
2     0.00   0.00   0.00   0.00 -600.00  300.00   33.33  0.00
1     0.00   0.00   0.00 -40.00   0.00 -133.33    0.00  0.00

Comparison heatmap 1

With one game per group this is illustrative rather than insightful — but you can already see the high-Elo game pushing a pawn to e4 early (=e2 empties faster, hence −600%) while the low-Elo game opened with f3. Feed it two real cohorts of a few thousand games and the same code tells you where styles actually differ.

Comparable data is needed

Note that the f3 square in the heatmap is completely white, yet this was white's first move in the lower-Elo game. This is because we don't have a value to compare against since in the high-Elo game this square was never occupied. This would result in a infinitely higher value which can't be displayed meaningfully. With a greater sample size this will not be a problem anymore.

For a more meaningful example check out the following heatmap, running the same analysis on a bigger PGN file with real games. A clear trend is visible here: the higher rated player takes control over the center more often than a lower rated player.

Comparison heatmap 2

On this page