projections convergence graph axis labels

This commit is contained in:
Emil Lerch 2026-06-26 18:08:18 -07:00
parent 243f3c40bf
commit 76d00b8dfe
Signed by: lobo
GPG key ID: A7B62D657EF764F8
2 changed files with 19 additions and 12 deletions

View file

@ -75,9 +75,12 @@ pub const RenderedForecast = struct {
}
};
/// Thin RGB wrapper over `renderConvergenceToSurface` for the TUI's
/// kitty path: renders without axis labels, extracts RGB, frees the
/// surface.
/// RGB wrapper over `renderConvergenceToSurface` for the inline kitty
/// path (CLI + TUI). Renders WITH axis labels baked in: unlike the
/// projection chart - whose callers stamp their own labels into the
/// cell grid - nothing draws the forecast chart's labels separately,
/// so the years y-ticks + observation-date x-endpoints go into the
/// surface here (matching the PNG export).
pub fn renderConvergenceChart(
io: std.Io,
alloc: std.mem.Allocator,
@ -86,7 +89,7 @@ pub fn renderConvergenceChart(
height_px: u32,
th: theme.Theme,
) !ChartResult {
var rendered = try renderConvergenceToSurface(io, alloc, points, width_px, height_px, th, false);
var rendered = try renderConvergenceToSurface(io, alloc, points, width_px, height_px, th, true);
defer rendered.deinit(alloc);
return .{
.rgb_data = try rendered.extractRgb(alloc),

View file

@ -13,8 +13,9 @@
//! The glyph set is intentionally minimal - just what axis labels and
//! chart legends need: digits, `$`, `.`, `,`, `-`, `%`, the `T`/`B`/`M`
//! magnitude suffixes emitted by `format.fmtLargeNum`, and the
//! lowercase letters `t`/`h`/`e`/`n`/`o`/`w` for the comparison
//! chart's "then"/"now" legend. Space and unknown chars render blank.
//! lowercase letters `t`/`h`/`e`/`n`/`o`/`w` (comparison-chart
//! "then"/"now" legend) plus `y` (convergence "years" axis ticks).
//! Space and unknown chars render blank.
//!
//! Coordinates are in surface pixels; `scale` multiplies the 5x7 cell
//! (so `scale = 3` renders 15x21 glyphs). Drawing is clipped to the
@ -62,15 +63,17 @@ const glyph_T: Glyph = .{ 0x1F, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04 };
const glyph_B: Glyph = .{ 0x1E, 0x11, 0x11, 0x1E, 0x11, 0x11, 0x1E };
const glyph_M: Glyph = .{ 0x11, 0x1B, 0x15, 0x15, 0x11, 0x11, 0x11 };
// Lowercase letters - just what the comparison chart's "then"/"now"
// legend needs (t, h, e, n, o, w). 5x7, low 5 bits per row. Named
// `lc_*` to avoid colliding with the `glyph_w`/`glyph_h` cell dims.
// Lowercase letters: the comparison chart's "then"/"now" legend
// (t, h, e, n, o, w) plus `y` for the convergence "years" axis ticks.
// 5x7, low 5 bits per row. Named `lc_*` to avoid colliding with the
// `glyph_w`/`glyph_h` cell dims.
const lc_t: Glyph = .{ 0x08, 0x08, 0x1C, 0x08, 0x08, 0x08, 0x0C };
const lc_h: Glyph = .{ 0x10, 0x10, 0x10, 0x1E, 0x12, 0x12, 0x12 };
const lc_e: Glyph = .{ 0x00, 0x00, 0x0E, 0x11, 0x1F, 0x10, 0x0E };
const lc_n: Glyph = .{ 0x00, 0x00, 0x1E, 0x12, 0x12, 0x12, 0x12 };
const lc_o: Glyph = .{ 0x00, 0x00, 0x0E, 0x11, 0x11, 0x11, 0x0E };
const lc_w: Glyph = .{ 0x00, 0x00, 0x11, 0x11, 0x15, 0x15, 0x0A };
const lc_y: Glyph = .{ 0x00, 0x00, 0x11, 0x11, 0x0E, 0x04, 0x08 };
/// Look up the bitmap for a character. Unknown characters (including
/// space) render blank.
@ -91,6 +94,7 @@ fn glyphFor(ch: u8) Glyph {
'n' => lc_n,
'o' => lc_o,
'w' => lc_w,
'y' => lc_y,
else => blank,
};
}
@ -230,13 +234,13 @@ test "drawText renders the comma glyph (so thousands separators show)" {
try testing.expectEqual(@as(usize, 5), draw.countColor(&sfc, white));
}
test "drawText renders the lowercase legend letters (then/now)" {
test "drawText renders the lowercase glyphs (then/now legend + years axis)" {
const alloc = testing.allocator;
var sfc = try Surface.init(.image_surface_rgb, alloc, 64, 16);
defer sfc.deinit(alloc);
const white = [3]u8{ 0xFF, 0xFF, 0xFF };
// "thenow" exercises all six lowercase glyphs; none may be blank.
drawText(&sfc, 1, 1, 1, white, "thenow");
// "thenowy" exercises all seven lowercase glyphs; none may be blank.
drawText(&sfc, 1, 1, 1, white, "thenowy");
try testing.expect(draw.countColor(&sfc, white) > 30);
}