spb/metrika Public
Stata-class statistics, GPU-accelerated by Apple Silicon. Native Swift — no Electron, no Python runtime, no compromises.
Swift 92.4%
HTML 3.3%
R 3%
Shell 1.3%
1//2// PlotView.swift3// Metrika4//5// Author: Simon-Pierre Boucher6// Contact: contact@spboucher.ai7// Copyright © 2026 Simon-Pierre Boucher. All rights reserved.8//910import Charts11import SwiftUI12import ZQGraphics1314/// Swift Charts rendering of the session's latest plot spec. The custom15/// Metal renderer takes over past ~1M points (v0.3, CLAUDE.md §7).16struct PlotView: View {17 @Environment(SessionModel.self) private var model1819 /// Past this many points, Swift Charts degrades — the Metal renderer20 /// takes over (overridable for tests via METRIKA_METAL_THRESHOLD).21 private static let metalThreshold: Int = {22 if let text = ProcessInfo.processInfo.environment["METRIKA_METAL_THRESHOLD"],23 let value = Int(text) {24 return value25 }26 return 100_00027 }()2829 var body: some View {30 if let plot = model.lastPlot,31 plot.kind == .scatter,32 plot.series.reduce(0, { $0 + $1.x.count }) > Self.metalThreshold {33 MetalScatterPane(plot: plot)34 .accessibilityLabel("Metal scatter renderer")35 } else if let plot = model.lastPlot {36 Chart {37 ForEach(Array(plot.series.enumerated()), id: \.offset) { _, series in38 ForEach(series.x.indices, id: \.self) { index in39 switch plot.kind {40 case .scatter:41 PointMark(42 x: .value(plot.xLabel, series.x[index]),43 y: .value(plot.yLabel, series.y[index])44 )45 .symbolSize(20)46 .foregroundStyle(by: .value("Series", series.label))47 case .line, .kdensity:48 LineMark(49 x: .value(plot.xLabel, series.x[index]),50 y: .value(plot.yLabel, series.y[index])51 )52 .foregroundStyle(by: .value("Series", series.label))53 case .histogram:54 BarMark(55 x: .value(plot.xLabel, series.x[index]),56 y: .value(plot.yLabel, series.y[index])57 )58 .foregroundStyle(by: .value("Series", series.label))59 }60 }61 }62 }63 .chartXAxisLabel(plot.xLabel)64 .chartYAxisLabel(plot.yLabel)65 .padding(12)66 } else {67 ContentUnavailableView(68 "No plot", systemImage: "chart.xyaxis.line",69 description: Text("Run a graph command to see it here.")70 )71 }72 }73}74