Why are my Swift Chart Lines Running of the Left Edge?

92 Views Asked by At

I have my first application for Swift Charts.

I am using LineMark to create a chart linked to an array that updates live with data from the CoreMotion Gyro.

All looks good, except the line's left edge keeps extending off the left of the chart. I am (I think) using .chartXScale to limit the number of data points.

Here is what's happening:

Blah Blah

Right Chart Data Extending on to & past Left Chart

Here is my code:

Updated to full code to demonstrate my challenge. :-)

//
//  ContentView.swift
//
//  Created by Jim on 10/18/23.
//

import SwiftUI
import SwiftData
import CoreMotion
import Charts


private var dataPointsCollected: Int = 0
private var pointsToShowInGraph: Int = 50
private var readingsPerSecond: Double = 10.0

private var gyro: CMRotationRate = CMRotationRate()

struct ContentView: View {
   
   struct MotionDataPoint: Identifiable {
      let xGyro: Double
      let yGyro: Double
      var myIndex: Int = 0
      var id: UUID
   }
   
   //setup motion manager
   let motionManager = CMMotionManager()
   let queue = OperationQueue()
   let gyroQueue = OperationQueue()
   
   @State private var gyroMinX: Double = 0
   @State private var gyroMinY: Double = 0
   
   @State private var gyroMaxX: Double = 0
   @State private var gyroMaxY: Double = 0
   
   @State var motionDataPoints: [MotionDataPoint] = []
   
   
   var body: some View {
      ScrollView {
         HStack {
            Chart {
               ForEach(motionDataPoints) { element in
                  LineMark(x: .value("Date", element.myIndex), y: .value("xGyro", element.xGyro))
               }
            }
            .chartYScale(domain: [gyroMinX, gyroMaxX])
            .chartXScale(domain: (dataPointsCollected - pointsToShowInGraph)...dataPointsCollected)
            .padding()
            
            Chart {
               ForEach(motionDataPoints) { element in
                  LineMark(x: .value("Date", element.myIndex), y: .value("yGyro", element.yGyro))
               }
            }
            .chartYScale(domain: [gyroMinY, gyroMaxY])
            .chartXScale(domain: (dataPointsCollected - pointsToShowInGraph)...dataPointsCollected)
            .padding()
            
         }
         Spacer()
      }
      .onAppear{
         var disIndex = 0
         self.motionManager.accelerometerUpdateInterval = 1 / readingsPerSecond
         self.motionManager.gyroUpdateInterval = 1 / readingsPerSecond
         
         self.motionManager.startGyroUpdates(to: self.gyroQueue){
            (gData: CMGyroData?, error: Error?) in
            
            disIndex += 1
            dataPointsCollected += 1
            
            gyro = gData!.rotationRate
            
            gyroMinX = Double(gyro.x) <= gyroMinX ? Double(gyro.x) : gyroMinX
            gyroMinY = Double(gyro.y) <= gyroMinY ? Double(gyro.y) : gyroMinY
            
            gyroMaxX = Double(gyro.x) > gyroMaxX ? Double(gyro.x) : gyroMaxX
            gyroMaxY = Double(gyro.y) > gyroMaxY ? Double(gyro.y) : gyroMaxY
            
            let myNextPoint:MotionDataPoint = MotionDataPoint(xGyro: Double(gyro.x), yGyro: Double(gyro.y), myIndex: disIndex, id: UUID())
            
            motionDataPoints.append(myNextPoint)
            
            print(myNextPoint)
         }
      }
      .padding(.horizontal, 60)
   }
}


#Preview {
   ContentView()
      .modelContainer(for: Item.self, inMemory: true)
}

Here is some sample data:

[
MotionDataPoint(xGyro: 0.002995523624122143, yGyro: -0.00013928332191426307, myIndex: 1670, id: F70FADE4-DBF3-4161-9680-78A2255357DA)
MotionDataPoint(xGyro: 0.0005464806454256177, yGyro: -0.002513757674023509, myIndex: 1671, id: A9F03AF0-306A-428B-AE82-3A0178F0D9B1)
MotionDataPoint(xGyro: 0.0013382384786382318, yGyro: -0.0008562062866985798, myIndex: 1672, id: 05FF9244-8AD7-498C-A074-6AB49E69B379)
MotionDataPoint(xGyro: 0.0038045919500291348, yGyro: -0.0035627768374979496, myIndex: 1673, id: AC489079-E9E7-49C6-9337-B631C46D2371)
MotionDataPoint(xGyro: 0.002945722546428442, yGyro: -0.003768639173358679, myIndex: 1674, id: FD1EA75F-51BC-493C-A1B2-D9C5EBC28E7A)
MotionDataPoint(xGyro: 0.001017327536828816, yGyro: -0.0017092167399823666, myIndex: 1675, id: 48854F29-03E7-482F-8775-C50A463E33C3)
MotionDataPoint(xGyro: 0.002241050126031041, yGyro: -0.0024264061357825994, myIndex: 1676, id: 364B768C-6981-4B52-B6D7-B1CF67C901AA)
MotionDataPoint(xGyro: 0.0018780612153932452, yGyro: -0.0032445292454212904, myIndex: 1677, id: D1C142A2-1DAF-4594-8D2B-D08542058B5B)
MotionDataPoint(xGyro: 0.003510312642902136, yGyro: -0.002469815546646714, myIndex: 1678, id: 3FF46648-A9BB-49EB-885C-1B75CA90A2FF)
MotionDataPoint(xGyro: 0.0018868496408686042, yGyro: -0.0037585191894322634, myIndex: 1679, id: 53AE4385-3976-47D0-814F-A464AE32F82F)
MotionDataPoint(xGyro: 0.00293347192928195, yGyro: -0.0020847225096076727, myIndex: 1680, id: CA0777CA-2378-46BF-9E87-EADCE4F89EF6)
MotionDataPoint(xGyro: 0.002621882129460573, yGyro: -0.0023576964158564806, myIndex: 1681, id: 6CE333F1-2D8D-4FEC-9BED-D16D7E82F95A)
MotionDataPoint(xGyro: 0.0033164345659315586, yGyro: -0.0010048106778413057, myIndex: 1682, id: 12DFCF6E-3761-478B-92DB-C8B4C659ABEF)
MotionDataPoint(xGyro: 0.003251187037676573, yGyro: -0.002168345730751753, myIndex: 1683, id: F449655F-82D5-4775-8E11-F60E59146603)
MotionDataPoint(xGyro: 0.0027534421533346176, yGyro: -0.0016245282022282481, myIndex: 1684, id: 8703ABB7-DAC3-4F2C-A16D-2DA779B4467A)
MotionDataPoint(xGyro: 0.0016586167039349675, yGyro: -0.0022655511274933815, myIndex: 1685, id: 66EE7CFA-56DC-46B9-9B8A-745A920DD664)
MotionDataPoint(xGyro: 0.003239469137042761, yGyro: -0.0023470439482480288, myIndex: 1686, id: E2A6304E-54F9-4E9C-8C54-80E7A2C1FAA9)
MotionDataPoint(xGyro: 0.0018285263795405626, yGyro: -0.0022173479665070772, myIndex: 1687, id: 3403645A-ECA2-4942-8255-DA0219FB9E6E)
MotionDataPoint(xGyro: 0.0025068335235118866, yGyro: -0.002010420197620988, myIndex: 1688, id: 11844C72-F6A9-4B88-A061-88753CEC7D42)
MotionDataPoint(xGyro: -1.651159800530877e-05, yGyro: -0.004343349486589432, myIndex: 1689, id: DA7205EF-5AF0-4599-B713-26C8D48081FD)
MotionDataPoint(xGyro: 0.00011265171633567661, yGyro: -0.0027984497137367725, myIndex: 1690, id: 843DAF19-00CB-49BD-998F-ABDADFA0813F)
MotionDataPoint(xGyro: 0.0026959178503602743, yGyro: -0.002263953210785985, myIndex: 1691, id: 4CE3100C-04E6-4A8A-A203-5C9AC77D26A0)
MotionDataPoint(xGyro: 0.0018618159228935838, yGyro: -0.0037875475827604532, myIndex: 1692, id: AE1E20EF-2A04-4B65-BB5A-D74CA89BC857)
MotionDataPoint(xGyro: 0.002329733222723007, yGyro: -0.0020450414158403873, myIndex: 1693, id: F665A840-23A3-4D2D-BA5F-95CF19CCAC90)
MotionDataPoint(xGyro: 0.002743322169408202, yGyro: -0.0038605183362960815, myIndex: 1694, id: E54B456E-18BD-4C2B-B387-E25A86268A1C)
MotionDataPoint(xGyro: 0.0024253407027572393, yGyro: -0.0025904567446559668, myIndex: 1695, id: 7C56E126-5C46-4641-B189-AA9435854D4D)
MotionDataPoint(xGyro: 0.0023616913240402937, yGyro: -0.001811748486943543, myIndex: 1696, id: 481AD7D5-AEDE-49B2-8D00-61A6DF8FA613)
MotionDataPoint(xGyro: 0.003597131697461009, yGyro: -0.0013749900972470641, myIndex: 1697, id: A85D949C-FB69-4EC6-881A-A7496693DC2F)
MotionDataPoint(xGyro: 0.0027806065045297146, yGyro: -0.0019795275293290615, myIndex: 1698, id: 3F456FCA-1BF5-4739-AF49-4DD2D210172A)
MotionDataPoint(xGyro: 0.0029609024059027433, yGyro: -0.0013795174891129136, myIndex: 1699, id: 98C68BDA-CBA0-44BD-AE31-D19DBA77FAD9)
MotionDataPoint(xGyro: 0.002417883835732937, yGyro: -0.0025864620693027973, myIndex: 1700, id: 8AF705A4-7028-4FFA-AD13-E456FE8715F2)
MotionDataPoint(xGyro: 0.002466619713231921, yGyro: -0.001517469179816544, myIndex: 1701, id: 80DA0A4C-31D1-4D14-959D-3EF48308D394)
MotionDataPoint(xGyro: 0.003311374457553029, yGyro: -0.0027110979426652193, myIndex: 1702, id: 5ED2808F-0443-465D-8FA4-3E4B7122DD86)
MotionDataPoint(xGyro: 0.002266882685944438, yGyro: -0.002989664673805237, myIndex: 1703, id: 0D7056DB-2E0D-448D-863B-EE87F5EEA49C)
MotionDataPoint(xGyro: 0.0018112158868461847, yGyro: -0.003584614722058177, myIndex: 1704, id: 233660B4-70A6-4059-A305-4C06458BA3D8)
MotionDataPoint(xGyro: 0.0008130630594678223, yGyro: -0.002692455891519785, myIndex: 1705, id: A047A7DE-E1AE-431F-961A-DD1CBD99BB1B)
MotionDataPoint(xGyro: 0.0012929646763950586, yGyro: -0.0020455741323530674, myIndex: 1706, id: 49E9EA5F-2DBA-4F44-B19D-EC96C418BD3C)
MotionDataPoint(xGyro: 0.0023731428664177656, yGyro: -0.003385144053027034, myIndex: 1707, id: DF6CEE45-665E-4E47-A68D-9D9EAAC44F20)
MotionDataPoint(xGyro: 0.0008159925346262753, yGyro: -0.0029859361238777637, myIndex: 1708, id: 0D119072-8F9A-4B2F-A4CB-A1AA1D419BE5)
MotionDataPoint(xGyro: 0.002784334821626544, yGyro: -0.002366218715906143, myIndex: 1709, id: F1C3AE5D-B88F-4E79-AC52-C8DEE5553EB9)
MotionDataPoint(xGyro: 0.0019531622529029846, yGyro: -0.003552923211827874, myIndex: 1710, id: 0300CFEF-6D9B-43EE-BEE2-EF744C169BAE)
MotionDataPoint(xGyro: 0.0003211772127542645, yGyro: -0.003236273303627968, myIndex: 1711, id: 472A05DB-2DD4-4646-AAB5-BF798101781C)
MotionDataPoint(xGyro: 0.0031941954512149096, yGyro: -0.0026101642288267612, myIndex: 1712, id: 73A971D1-6F41-4E30-A435-FE810459F8BE)
MotionDataPoint(xGyro: 0.0027363980188965797, yGyro: -0.0032352081034332514, myIndex: 1713, id: B1BD1EDF-313F-4D99-BC79-DA654C781ED3)
MotionDataPoint(xGyro: 0.0013305152533575892, yGyro: -0.0032708945218473673, myIndex: 1714, id: AF1B1009-75DB-4712-B724-B2543E4980C3)
]

I don't see or understand why my lines keep extending to the left past their "view".

Any help or pointers would be greatly appreciated.

1

There are 1 best solutions below

0
HirsuteJim On BEST ANSWER

After lots of exploration, I found the causes (there were two):

  1. The main reason is that I was charting the entire (continuously growing) array of data instead of charting a slice of the array containing the most recently added 50 data points of the array.
  2. I was using my own incremented counter as the X-axis. This caused all kinds of bizarre behavior (e.g., the charted line moving ever so slowly to the right until it was off the screen). Once I switched to a timestamp value for the X-axis, all worked fine.