N1MM's statistics window. `StatisticsPivot` counts the contacts under one row field and one column field, with the row total, the running total and the column totals N1MM prints. The fields are N1MM's own two lists: 29 down the rows, 20 of them across the columns, sorted the way N1MM's SQL sorts them, so zone 10 comes after zone 2 and 80M before 20M. The window has N1MM's two tabs. The table is the grid with `Tot` and `Accum` and a `Total` line; the graph is a stacked column per row, one segment per column, in one of N1MM's twelve palettes. "Include Dupes & X-QSOs" counts the contacts left out of the claimed score and the ones marked as dupes. Checked against a 3775-contact CQ WW SSB log: 3762 counted, which is what `select count(*) ... where CLAIMEDQSO = 1 and ContactType <> 'D'` returns, and the per-band totals match band by band. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PdAYHcdRktqKry7nk414TU
28 lines
850 B
C#
28 lines
850 B
C#
using Nonemm.Core;
|
|
|
|
namespace Nonemm.Session;
|
|
|
|
/// One field the statistics window can put down the rows or across the columns.
|
|
/// `Headings` holds two entries for the fields that print two label columns.
|
|
public sealed class StatisticsField
|
|
{
|
|
private readonly Func<Qso, DateTime, PivotKey> read;
|
|
|
|
internal StatisticsField(string name, Func<Qso, DateTime, PivotKey> read, params string[] headings)
|
|
{
|
|
Name = name;
|
|
this.read = read;
|
|
Headings = headings.Length > 0 ? headings : [name];
|
|
}
|
|
|
|
public string Name { get; }
|
|
|
|
public IReadOnlyList<string> Headings { get; }
|
|
|
|
/// `startUtc` is when the contest started: the five, ten and fifteen minute
|
|
/// fields count from it.
|
|
public PivotKey KeyOf(Qso qso, DateTime startUtc) => read(qso, startUtc);
|
|
|
|
public override string ToString() => Name;
|
|
}
|