tiny.zen.diagram.domain
Defined in diagram.
API (7)
Actions
Public operations.
Types and contracts
Public types and contracts.
Values and defaults
Public values and defaults.
Source
Source: lib/zen/src/diagram/domain.zig
zig
const std = @import("std");const model = @import("model.zig");const root = @import("root.zig");const spec = root.spec;const Bounds = model.Bounds;pub fn expand(min: *f64, max: *f64, kind: spec.ScaleKind, base: f64) void { if (min.* != max.*) return; switch (kind) { .linear => { min.* -= 0.5; max.* += 0.5; }, .log => { const factor = @sqrt(base); min.* /= factor; max.* *= factor; }, }}pub fn ratio(value: f64, min: f64, max: f64, kind: spec.ScaleKind, base: f64) !f64 { const scaled_value = try scaled(value, kind, base); const scaled_min = try scaled(min, kind, base); const scaled_max = try scaled(max, kind, base); return (scaled_value - scaled_min) / (scaled_max - scaled_min);}fn scaled(value: f64, kind: spec.ScaleKind, base: f64) !f64 { return switch (kind) { .linear => value, .log => if (value > 0) std.math.log(f64, base, value) else error.InvalidScale, };}pub const max_ticks = 6;const even_tick_count = 5;pub const Ticks = struct { values: [max_ticks]f64, count: usize, pub fn slice(self: *const Ticks) []const f64 { std.debug.assert(self.count <= max_ticks); return self.values[0..self.count]; }};pub fn ticks(min: f64, max: f64, kind: spec.ScaleKind, base: f64) !Ticks { std.debug.assert(min < max); return switch (kind) { .linear => evenTicks(min, max, kind, base), .log => logTicks(min, max, base), };}fn evenTicks(min: f64, max: f64, kind: spec.ScaleKind, base: f64) !Ticks { var result = Ticks{ .values = undefined, .count = even_tick_count }; const scaled_min = try scaled(min, kind, base); const scaled_max = try scaled(max, kind, base); for (result.values[0..even_tick_count], 0..) |*value, index| { const tick_ratio = @as(f64, @floatFromInt(index)) / (even_tick_count - 1); const placed = scaled_min + (scaled_max - scaled_min) * tick_ratio; value.* = switch (kind) { .linear => placed, .log => std.math.pow(f64, base, placed), }; } return result;}fn logTicks(min: f64, max: f64, base: f64) !Ticks { std.debug.assert(min > 0); std.debug.assert(base > 1); const epsilon = 1e-9; const power_min: i64 = @intFromFloat(@ceil(std.math.log(f64, base, min) - epsilon)); const power_max: i64 = @intFromFloat(@floor(std.math.log(f64, base, max) + epsilon)); if (power_max < power_min + 1) return evenTicks(min, max, .log, base); const decade_count: usize = @intCast(power_max - power_min + 1); const stride = (decade_count + max_ticks - 1) / max_ticks; std.debug.assert(stride >= 1); var result = Ticks{ .values = undefined, .count = 0 }; for (0..max_ticks) |index| { const power = power_min + @as(i64, @intCast(index * stride)); if (power > power_max) break; result.values[result.count] = std.math.pow(f64, base, @as(f64, @floatFromInt(power))); result.count += 1; } std.debug.assert(result.count >= 2); return result;}pub fn validate(bounds: Bounds) !void { if (bounds.x_kind == .log) { if (bounds.categorical) return error.InvalidScale; if (bounds.x_min <= 0 or bounds.x_max <= 0) return error.InvalidScale; } if (bounds.y_kind == .log and (bounds.y_min <= 0 or bounds.y_max <= 0)) return error.InvalidScale;}test "linear ticks split the range evenly" { const result = try ticks(0, 100, .linear, 10); try std.testing.expectEqual(@as(usize, 5), result.count); try std.testing.expectEqual(@as(f64, 0), result.values[0]); try std.testing.expectEqual(@as(f64, 25), result.values[1]); try std.testing.expectEqual(@as(f64, 100), result.values[4]);}test "log ticks land on decades" { const result = try ticks(1, 1000, .log, 10); try std.testing.expectEqual(@as(usize, 4), result.count); for ([_]f64{ 1, 10, 100, 1000 }, result.slice()) |expected, actual| { try std.testing.expectApproxEqRel(expected, actual, 1e-9); }}test "log ticks cover fractional decades" { const result = try ticks(0.001, 10, .log, 10); try std.testing.expectEqual(@as(usize, 5), result.count); for ([_]f64{ 0.001, 0.01, 0.1, 1, 10 }, result.slice()) |expected, actual| { try std.testing.expectApproxEqRel(expected, actual, 1e-9); }}test "log ticks thin wide ranges by whole decades" { const result = try ticks(1, 1e9, .log, 10); try std.testing.expectEqual(@as(usize, 5), result.count); for ([_]f64{ 1, 100, 1e4, 1e6, 1e8 }, result.slice()) |expected, actual| { try std.testing.expectApproxEqRel(expected, actual, 1e-9); }}test "log ticks fall back to even placement inside one decade" { const result = try ticks(2, 8, .log, 10); try std.testing.expectEqual(@as(usize, 5), result.count); try std.testing.expectApproxEqRel(@as(f64, 2), result.values[0], 1e-9); try std.testing.expectApproxEqRel(@as(f64, 4), result.values[2], 1e-9); try std.testing.expectApproxEqRel(@as(f64, 8), result.values[4], 1e-9);}test "log ticks honor the configured base" { const result = try ticks(1, 32, .log, 2); try std.testing.expectEqual(@as(usize, 6), result.count); for ([_]f64{ 1, 2, 4, 8, 16, 32 }, result.slice()) |expected, actual| { try std.testing.expectApproxEqRel(expected, actual, 1e-9); }}Source: lib/zen/src/diagram/root.zig:5
zig
pub const domain = @import("domain.zig");Audit
| Definitions | 8 |
|---|---|
| Public names | 8 |
| Members | 2 |
| Version | 26.7.0 |
| Revision | daab053ee433 |