Background:
The graphs that I've added to my app plot data in realtime. Data is sent to the app over a BLE connection and I plot the data on the graph as it comes in. The graphs start off with no data in them. All of the graphs plot similar sets of data, just for different components, so if I can get one working they should all work.
A graph has two line series that plot readings from two different sensors. The are two y-axes on the graph, each plotting the reading from one of the sensors. The x-axis is a time series, it's values should correspond with when the readings come in over BLE.
Currently, I can't seem to get the graph to plot new points when I add a new data. If I pre-populate my data array with datapoints before i create the datasource helper object, those points are plotted on the graph correctly. Here is the relevant code for one of the line series:
@objcMembers class DataModel: NSObject { var date: Date! var value: NSNumber! init(date: Date, value: NSNumber) { self.date = date self.value = value } }
When data comes in for one of the plots, it's stored as a DataModel object and added to an array like:
var oilTempReadings: [DataModel] = []
These are the class types I'm using for my axes and data series:
var xAxisTemp: IGCategoryDateTimeXAxis! var yAxisTemp: IGNumericYAxis! var temperatureLineSeries: IGLineSeries! var temperatureDataSource: IGCategoryDateSeriesDataSourceHelper!
And this is how I'm setting up my datasource helper:
temperatureDataSource = IGCategoryDateSeriesDataSourceHelper.init(data: bleManager.coolantTempReadings, valuePath: "value", andDatePath: "date") temperatureLineSeries.yAxis = yAxisTemp temperatureLineSeries.xAxis = xAxisTemp temperatureLineSeries.dataSource = temperatureDataSource graph.add(xAxisTemp) graph.add(yAxisTemp) graph.addSeries(temperatureLineSeries)
If I have test data in the coolantTempReadings array at this point, they are immediately populated in the graph when I add the graph to the subview. However, when new data comes in and I try to insert it into the graph, it doesn't show up. This is how I'm trying to insert the new data:
graph.insertItem(at: bleManager.coolantTempReadings.count - 1, with: temperatureDataSource)
Any ideas why the graphs aren't updating with the new data?
Hi,
Sorry for such a late reply. I'm attaching a small sample that demonstrates a moving line chart with 2 series on a date axis. It should be pretty straight forward: a chart updates each datasource helper with a new value on a 1 second interval.
Let me know if you have any issues.LineChartDataInsert.zip
I switched back to my branch that was using the refresh() function after each new data point came in and did some profiling. There don't seem to be any memory leaks; CoreGraphics allocates a lot of memory over time, but it's being consistently released and the amount persistent memory being used is staying fairly static.
I had to disable the "Record reference counts" option in the profiler because I'm running in to this issue https://forums.developer.apple.com/thread/97592 so hopefully that's not skewing my tests. But looking back on previous crash logs and watching the performance while profiling, the issue seems to be the CPU usage. All crash logs on this branch list "CPU Usage" as the crash reason, and I can see CPU usage slowly increase over time while refreshing the graphs. Commenting out the graph.refresh() function stops it from crashing.
I suspect that forcing a graph refresh every second on multiple graphs just ends up being too much to render as the amount of data increases in the graphs.
I've considered using the refresh() method, but at the same time dropping the oldest data point off of my array every time a new one comes in, once there's a decent amount of data in the graph. This should give it the effect of a "moving" graph, which I eventually want anyway. But if possible, I'd like to get it working the recommended way using graph.insertItem(at:), so that I don't have to worry how older devices will handle the refresh() method.
The values for the two different series arrive over BLE one after the other. So they aren't be updated simultaneously, but they are synchronous. I added some debug output and there are always the same number of values in each series, except right after the temperature series gets updated, at which point there's one more value in that series than the door position series.
That's alright, I only need the graph to update once the data for both series has been updated.
Is there something else I need to do to cause the graph to update with new data after calling the graph.insertItem(at:) function? Is there something else I could be doing that could cause that function to no longer work?
When you update your data with the new readings, are you only updating one of the two series? I think the reason you're not seeing any updates might be because of this. When the chart shows multiple series it expects them to have the same number of data points and will fall back on the lowest point count. Try adding readings to both series, or if there isn't a valid value to add, add a nan to the other series.
Using refresh forces the chart to update everything, which is more suitable when the entire datasource changes, but should still work here. The slowdown could indicate a memory leak, but this will require some profiling.
Is there any additional info you want me to provide?