Swift Charts performance when displaying many data points

I'm currently evaluating Swift Charts to use in my macOS app, where I need to (potentially) display a few millions of data points, ideally all of them at one time. I want to give users the possibility to zoom in & out, so the entire range of values could be displayed at one moment.

However, starting at around 20K data points (on my computer), the Chart takes a little bit to set up, but the window resizing is laggy. The performance seems to decrease linearly (?), when dealing with 100K data points you can barely resize the window and the Chart setup/creation is noticeable enough. Dealing with 500K data points is out of the question, the app is pretty much not useable.

So I'm wondering if anybody else had a similar issue and what can be done? Is there any "magic" Swift Charts setting that could improve the performance? I have a "data decimation" algorithm, and given no choice I will use it, but somehow I was hoping for Swift Charts to gracefully handle at least 100K data points (there are other libs which do this!). Also, limiting the displayed data range is out of the question for my case, this is a crucial feature of the app.

Here's the code that I'm using, but it's the most basic one:

struct DataPoint: Identifiable {
    var id: Double { Double(xValue) }
    let xValue: Int
    let yValue: Double
}

let dataPoints: [DataPoint] = (0..<100_000).map { DataPoint(xValue: $0, yValue: Double($0)) }

struct MyChart: View {
    
    var body: some View {
        Chart(dataPoints) { dataPoint in
            PointMark(x: .value("Index", dataPoint.xValue),
                      y: .value("Y Value", dataPoint.yValue))
        }
    }
}

Some additional info, if it helps:

  • The Chart is included in a AppKit window via NSHostingController (in my sample project the window contains nothing but the chart)
  • The computer is a MacBook Pro, 2019 and is running macOS 10.14

Hey @vbadeasv, did you find a solution to your problem? I have the same problem with data that are bigger than 20000 points and in my case, not rendering the data in full spectrum is also not an option.

I thought I'd pick this up and test it with the new iOS 18 PointPlots.

I setup this code to switch between a ForEach on the PointMarks and a Point Plot.

import SwiftUI
import Charts

@available(iOS 18.0, *)
struct ManyPointsChart: View {
    // Reduced data point count to 10,000 as 100,000 still V. poor performance
    let dataPoints: [DataPoint] = (0..<10_000).map { DataPoint(xValue: $0, yValue: Double($0)) }
    @State var selectedIndex:Int?

    var body: some View {
        Chart {
            if let selectedIndex {
                RuleMark(x: .value("selected", selectedIndex))
            }
            // Original Method
//            ForEach(dataPoints) { dataPoint in
//                PointMark(x: .value("Index", dataPoint.xValue),
//                          y: .value("Y Value", dataPoint.yValue))
//            }

            //New in iOS 18
            PointPlot(
                dataPoints,
                x: .value("Longitude", \.xValue),
                y: .value("Capacity density", \.yValue)
            )
        }
        .chartXSelection(value: $selectedIndex)
        
    }
}

@available(iOS 18.0, *)
#Preview {
    ManyPointsChart()
}

struct DataPoint: Identifiable {
    var id: Double { Double(xValue) }
    let xValue: Int
    let yValue: Double
}

Despite reducing the data points count to 10,000 I still found Selection performance very slow in Preview. (M3 Max MBP)

Performance was improved with the PointPlot vs the PointMarks, but not quite as much as I hoped.

I think I'm using the APIs correctly but would welcome any feedback if not!

With Instruments, I measured hangs event when using the vectorized API on the order of 50-150ms when using relatively small number of data points (500-2000). In order to get reasonable performance, I implement downsampling with LTTB off the main thread before attempting to plot too many points.

If you write your own drawing with CoreGraphics, handling 10K can be done with reasonable UX, except the GPU will kick on when drawing the points (or line) and overheat the iOS device.

Swift Charts performance when displaying many data points
 
 
Q