Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Linechart not plotting correctly with large number of points #64

Closed
gesabo opened this issue May 3, 2021 · 20 comments
Closed

Linechart not plotting correctly with large number of points #64

gesabo opened this issue May 3, 2021 · 20 comments
Labels
bug Something isn't working
Projects

Comments

@gesabo
Copy link

gesabo commented May 3, 2021

Is there some number of data points that are too much for a line chart? I'm loading 609 heart rates here, the first chart is using iOS charts and the 2nd is using SwiftUI Charts. It looks like the spike in the middle (a workout) should be tighter together). Anything I can do to fix this? 🤔
IMG_57212197C1E8-1
IMG_95BBF270A45B-1

@willdale
Copy link
Owner

willdale commented May 4, 2021

mmm interesting,

  • what version of the package are you running?
  • What device?
  • Can you post some code?
struct LineChartDemoView: View {
    
    let data: LineChartData = weekOfData()
        
    var body: some View {
        
        LineChart(chartData: data)
            .id(data.id)
            .frame(minWidth: 150, maxWidth: 900, minHeight: 150, idealHeight: 500, maxHeight: 600, alignment: .center)
            .padding(.horizontal)
        
        .navigationTitle("Week of Data")
    }
    
    static func weekOfData() -> LineChartData {
        
        func makeDataSet() -> [LineChartDataPoint] {
            
            let datapoints: [LineChartDataPoint] = (1...600).map { index in
                if index < 240 {
                   return LineChartDataPoint(value: Double.random(in: 50...80))
                } else if index > 241 && index < 250 {
                    return LineChartDataPoint(value: Double.random(in: 90...100))
                } else if index > 251 && index < 290 {
                    return LineChartDataPoint(value: Double.random(in: 100...160))
                } else if index > 291 && index < 300 {
                    return LineChartDataPoint(value: Double.random(in: 160...180))
                } else if index > 301 && index < 350 {
                    return LineChartDataPoint(value: Double.random(in: 90...100))
                } else {
                    return LineChartDataPoint(value: Double.random(in: 60...80))
                }
            }
            return datapoints
        }
        
        let data = LineDataSet(dataPoints:
            makeDataSet(),
        legendTitle: "Steps",
        pointStyle: PointStyle(),
        style: LineStyle(lineColour: ColourStyle(colour: .red), lineType: .curvedLine, strokeStyle: Stroke(lineWidth: 1)))

        
        let chartStyle = LineChartStyle()
        
        return LineChartData(dataSets       : data,
                             metadata       : ChartMetadata(title: "Step Count", subtitle: "Over a Week"),
                             chartStyle     : chartStyle)
        
    }
}

Gives me:

600

Which looks right to me.

And with 2400 data points:

2400

@gesabo
Copy link
Author

gesabo commented May 4, 2021

🤔 @willdale I am running v 2.5.0 on iPhone 11 (iOS 14.5) I tried making sure your code was the same as mine but still seeing the different charts. Can't figure out what might be different between yours and mine?


struct CurrentCard: View {
    var body: some View {
      LineChart(chartData: data)
                         .id(data.id)
                         .yAxisLabels(chartData: data)
                         .frame(minWidth: 150, maxWidth: 900, minHeight: 150, idealHeight: 500, maxHeight: 600, alignment: .center)
                         //.frame(height: 180, alignment: .center)
                        .padding(.horizontal)
    }
    
    
        private func makeLineChartData(heartRates: [CustomHeartRateObject]) -> LineChartData? {

        let data = LineDataSet(
        dataPoints: heartRates.map { LineChartDataPoint(value: $0.doubleValue) },
        legendTitle: "Heart Rates",
        pointStyle: PointStyle(),
        style: LineStyle(lineColour: ColourStyle(colour: .red), lineType: .curvedLine, strokeStyle: Stroke(lineWidth: 1))
        )
        let chartStyle = LineChartStyle()
        

        
          return LineChartData(dataSets       : data,
                             metadata       : ChartMetadata(title: "Heart Rates", subtitle: "Today"),
                             chartStyle     : chartStyle)
                              
                            
    }
    

IMG_1851
IMG_C0B302F2DB83-1

@gesabo
Copy link
Author

gesabo commented May 4, 2021

If its helpful here is the data I am plotting:

66.0
59.0
59.0
59.0
60.0
59.0
61.0
68.0
65.0
61.0
63.0
60.0
61.0
60.0
57.0
58.0
59.0
58.0
60.0
61.0
63.0
62.0
58.0
58.0
72.0
63.0
63.0
62.0
62.0
60.0
59.0
59.0
58.0
56.0
56.0
58.0
58.0
59.0
59.0
59.0
61.0
60.0
61.0
61.0
59.0
59.0
59.0
61.0
59.0
59.0
59.0
59.0
60.0
61.0
59.0
59.0
58.0
58.0
56.0
55.0
52.0
59.0
59.0
59.0
59.0
60.0
62.0
61.0
60.0
63.0
60.0
60.0
60.0
60.0
60.0
60.0
59.0
58.0
58.0
59.0
57.0
55.0
58.0
59.0
58.0
57.0
58.0
58.0
58.0
58.0
60.0
58.0
59.0
57.0
57.0
64.0
59.0
58.0
58.0
58.0
54.0
54.0
53.0
58.0
56.0
55.0
55.0
56.0
55.0
54.0
53.0
54.0
53.0
50.0
56.0
50.0
55.0
58.0
55.0
53.0
55.0
55.0
55.0
54.0
55.0
58.0
56.0
58.0
56.0
55.0
54.0
56.0
56.0
55.0
54.0
57.0
58.0
57.0
58.0
57.0
60.0
56.0
59.0
58.0
66.0
60.0
59.0
60.0
55.0
57.0
58.0
58.0
65.0
63.0
58.0
57.0
55.0
53.0
56.0
55.0
56.0
97.0
121.0
82.0
61.0
60.0
86.0
86.0
95.0
99.0
103.0
108.0
119.0
118.0
116.0
114.0
114.0
114.0
112.0
118.0
133.0
130.0
127.0
126.0
125.0
110.0
103.0
104.0
107.0
107.0
105.0
102.0
102.0
101.0
99.0
111.0
113.0
116.0
112.0
116.0
116.0
107.0
107.0
107.0
106.0
104.0
102.0
102.0
101.0
101.0
103.0
103.0
104.0
104.0
104.0
103.0
103.0
103.0
104.0
102.0
103.0
97.0
92.0
93.0
95.0
95.0
96.0
94.0
94.0
93.0
88.0
88.0
91.0
96.0
93.0
88.0
160.0
128.0
128.0
131.0
141.0
146.0
146.0
136.0
135.0
130.0
131.0
131.0
134.0
142.0
141.0
132.0
127.0
127.0
127.0
123.0
126.0
123.0
120.0
117.0
115.0
114.0
114.0
113.0
113.0
112.0
111.0
113.0
109.0
108.0
109.0
109.0
110.0
110.0
110.0
111.0
156.0
153.0
152.0
159.0
162.0
165.0
161.0
160.0
160.0
159.0
158.0
151.0
147.0
154.0
152.0
152.0
153.0
152.0
159.0
159.0
158.0
157.0
154.0
155.0
156.0
156.0
157.0
152.0
150.0
149.0
147.0
144.0
141.0
139.0
137.0
137.0
128.0
125.0
125.0
124.0
125.0
124.0
124.0
123.0
124.0
126.0
126.0
126.0
132.0
172.0
170.0
166.0
171.0
173.0
172.0
170.0
169.0
166.0
165.0
166.0
166.0
165.0
163.0
179.0
175.0
174.0
171.0
169.0
168.0
171.0
172.0
173.0
172.0
174.0
174.0
172.0
170.0
170.0
167.0
166.0
163.0
164.0
163.0
161.0
163.0
163.0
163.0
161.0
163.0
161.0
163.0
165.0
166.0
167.0
169.0
170.0
170.0
171.0
179.0
178.0
177.0
174.0
171.0
171.0
175.0
176.0
176.0
178.0
178.0
177.0
176.0
175.0
174.0
172.0
171.0
175.0
177.0
178.0
178.0
179.0
180.0
179.0
177.0
174.0
173.0
172.0
172.0
171.0
172.0
173.0
172.0
161.0
161.0
159.0
157.0
155.0
149.0
148.0
147.0
148.0
148.0
150.0
149.0
143.0
142.0
143.0
135.0
135.0
135.0
135.0
132.0
131.0
132.0
128.0
128.0
129.0
129.0
129.0
130.0
131.0
130.0
130.0
131.0
125.0
126.0
123.0
125.0
125.0
126.0
129.0
123.0
123.0
124.0
126.0
124.0
124.0
125.0
123.0
129.0
130.0
128.0
129.0
129.0
126.0
127.0
128.0
127.0
127.0
124.0
119.0
112.0
120.0
102.0
102.0
99.0
94.0
91.0
79.0
78.0
77.0
72.0
73.0
75.0
71.0
74.0
78.0
75.0
78.0
69.0
69.0

@willdale
Copy link
Owner

willdale commented May 4, 2021

This library currently only plots evenly spaced, this would mean if there is an area where there is more data, it will get spread out.

Could that explain it?

@gesabo
Copy link
Author

gesabo commented May 4, 2021

@willdale yes that must be it then, heart rate data from the Apple watch is sampled sporadically (e.g. more frequent during a workout, less frequent during other times of day). 🤔

@willdale
Copy link
Owner

willdale commented May 4, 2021

Is there a date component in CustomHeartRateObject, you could average to the hour, minute, second?

It would be good if the library could handle more time/date based rendering but I'm not sure when I'll get time to look at it.

@gesabo
Copy link
Author

gesabo commented May 4, 2021

@willdale I tried interpolating a HR at every second of the day but that gives me over 56,000 values to chart so far today which I think might be too many as its crashing but I can't tell why.

@willdale
Copy link
Owner

willdale commented May 5, 2021

A couple of Ideas:

To take inspiration from a Garmin app I use; to show a whole day they average to every two minutes - giving a maximum 720 data points for a day , then for workouts there is a separate chart that shows every second.

To take inspiration from Apple; to show a whole day they use a ranged bar chart showing the highest and lowest values in an hour. See Ranged Bar Chart in the ReadMe

@gesabo
Copy link
Author

gesabo commented May 5, 2021

@willdale thanks for taking the time! I will give both a shot and see what works best. Thanks again for a great library. 🍻

@kennedycraig
Copy link

Hi, Will.
I actually am experiencing an issue like this again now that I upgraded to 2.5. The same issue is NOT appearing in 2.3 (I have 2.3 with the same data on a phone and 2.5 on a simulator. The x-axis is being spaced out again and the y axis has disappeared again...
Simulator Screen Shot - iPhone 12 Pro Max - 2021-05-05 at 17 58 44

@willdale willdale added the bug Something isn't working label May 6, 2021
@willdale willdale added this to To do in General Project Board via automation May 6, 2021
@willdale
Copy link
Owner

willdale commented May 6, 2021

I'm working on v2.6 which overhauls all the axes labels. Hopefully this will solve a myriad of problems!

@kennedycraig, Is that using xAxisLabelsFrom: dataPoint()?

@kennedycraig
Copy link

Hi, Will. No, its using .chartData(). Note that the xlabels bug only appears with a rotation modifier. Without the rotation modifier, I works as expected.

                                    xAxisLabelsFrom     : //.chartData(rotation: .degrees(90)),
                                        .chartData(),

@willdale
Copy link
Owner

willdale commented May 6, 2021

Thanks, I'll work on a fix for an up and coming update.

@willdale willdale removed this from To do in General Project Board May 7, 2021
@willdale willdale added this to To do in v2.6 via automation May 7, 2021
@willdale willdale moved this from To do to In progress in v2.6 May 7, 2021
@willdale willdale mentioned this issue May 10, 2021
@willdale
Copy link
Owner

Hopefully v2.6 has fixed this. 🙏

If not feel free to reopen this.

v2.6 automation moved this from In progress to Done May 10, 2021
@kennedycraig
Copy link

For some reason 2.6 is not pulling in Xcode via swift package manager. No matter whether I reset the package cache and/or force update to latest version. Any ideas?

@kennedycraig
Copy link

For some reason 2.6 is not pulling in Xcode via swift package manager. No matter whether I reset the package cache and/or force update to latest version. Any ideas?

Just deleted the dependency and re-added - still get 2.5

@willdale
Copy link
Owner

@kennedycraig fixed in v2.6.1.

Odd issue with git not tracking .swiftpm folder.

@gesabo
Copy link
Author

gesabo commented Aug 20, 2021

@willdale revisiting this, have you given any thought to adding support for time/date plotting as is discussed above? In other words correctly plotting a chart of heart rates even though the samples non equal gaps in between (resting HR every 5 minutes vs. workout HR every second).

@willdale
Copy link
Owner

@gesabo if you want to stick in a pull request, I'm more than happy to review it.

@gesabo
Copy link
Author

gesabo commented Aug 24, 2021

@willdale I would love to if I had those chops 🤣 but I'm not even sure where to start.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
No open projects
v2.6
Done
Development

No branches or pull requests

3 participants