{"id":18334779,"url":"https://github.com/importryan/feedplot","last_synced_at":"2025-04-09T19:25:06.735Z","repository":{"id":107425288,"uuid":"423300086","full_name":"importRyan/FeedPlot","owner":"importRyan","description":null,"archived":false,"fork":false,"pushed_at":"2021-11-01T01:19:30.000Z","size":20,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-02-15T11:44:48.382Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Swift","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/importRyan.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-11-01T01:17:45.000Z","updated_at":"2021-11-01T01:17:49.000Z","dependencies_parsed_at":"2023-05-17T11:00:23.803Z","dependency_job_id":null,"html_url":"https://github.com/importRyan/FeedPlot","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/importRyan%2FFeedPlot","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/importRyan%2FFeedPlot/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/importRyan%2FFeedPlot/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/importRyan%2FFeedPlot/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/importRyan","download_url":"https://codeload.github.com/importRyan/FeedPlot/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248096549,"owners_count":21047074,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-05T19:52:23.425Z","updated_at":"2025-04-09T19:25:06.711Z","avatar_url":"https://github.com/importRyan.png","language":"Swift","funding_links":[],"categories":[],"sub_categories":[],"readme":"# FeedPlot\n## Depict streaming sensor data feeds in resizable scatterplot rendered by Metal.\n\nThis package is an experimental stub to contrast with alternative options.\n\n## How It Works\n\n1. `FPDataStore` — Caches incoming series-colored data and vends a moving window of data\n\n2. `FPMetalPlotView` — Renders recent data points at a rate you choose:\n - as fast as Metal deems ideal (e.g., 60/120 fps)\n - only when commanded (e.g., NSView.setNeedsDisplay() or FPMetalPlotView.updatePlot()) \n - toggling between the above and paused (energy efficiency)\n \n3. `FPShaders.metal` — Shaders scale data into (a) your explicit data bounds and (b) the current viewport pixel area\n\nOptional: `FeedPlotView` — If using SwiftUI, this wraps the MTKView subclass above\nOptional: `FPDataProvider` — Directly vend data points to `FPMetalPlotView` from your own cache\n\n## Usage Sketch\n\nExample output: A 2D scatterplot of incoming accelerometer data.\nY-axis: The amplitude of each of the three accelerometer axes, separately colored.\nX-axis: Incremented by time point, but you could assign an epoch value instead.\n\n1. `addPointInAllDataSeries()` A new data point is color-coded, assigned an x-value, and added to the cache\n2. `FeedPlotView` Instructs Metal to render as fast as it wants, provides a data source to the `FPMetalPlotView` and offers a callback containing a reference to the `FPMetalPlotView` for you to store for later use if desired (e.g., to manually refresh the plot)\n3. `updateYScale` An example of how to rescale the plot's data bounds. Calling `dataStore.setBounds()` ensures the `FPDataStore` vends the new bounds for the next render pass and asks the `FPMetalPlotView` to redraw itself if in a paused state. Scaling is non-destructive: points that are outside of the new bounds simply won't appear in the rendered viewport.\n\n```\nstruct FeedPlotFixedSize: View {\n\n    @StateObject var controller: FeedPlotController \n    // or simply pass an otherwise retained object\n\n    let size: CGSize\n\n    var body: some View {\n        FeedPlotView(.drawAtMonitorFPS, from: controller.dataStore) { [weak controller] in\n            controller?.plot = $0\n        }\n        .frame(width: size.width, height: size.height)\n    }\n\n}\n\nclass FeedPlotController: ObservableObject {\n\n    public weak var plot: FPPlot? = nil\n    private let dataStore: (FPDataProvider \u0026 FPDataStore)\n    public private(set) var seriesColors: [FPColor]\n\n}\n\nextension FeedPlotController: GraphController {\n\n    public func addPointInAllSeries(_ point: [Float]) {\n        let lastX = dataStore.data.last?.point.x ?? 0\n        let newX = Float(latestX + 1)\n        let points = zip(point.indices, point).map { (index, y) in\n            FPColoredDataPoint(point: .init(x: latest, y: y, z: 0), color: seriesColors[index])\n        }\n        dataStore.addData(points: points)\n    }\n\n    public func updateYScale(min: Double, max: Double) {\n        var bounds = dataStore.bounds\n        bounds.yAxis = Float(min)...Float(max)\n        dataStore.setBounds(bounds)\n        plot?.updatePlot()\n    }\n\n}\n\n```\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fimportryan%2Ffeedplot","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fimportryan%2Ffeedplot","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fimportryan%2Ffeedplot/lists"}