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

Live data Line Chart #754

Closed
AdamMak opened this issue Feb 12, 2016 · 12 comments
Closed

Live data Line Chart #754

AdamMak opened this issue Feb 12, 2016 · 12 comments

Comments

@AdamMak
Copy link

AdamMak commented Feb 12, 2016

I am looking to create a graph that will plot live data onto a line chart, need to plot around 5 a second, I am trying to create something like this

http://www.highcharts.com/demo/dynamic-update

I have had some moderate success with the Line Chart, but it is very jerky. The code I have tried so far looks like this

@IBOutlet weak var chartView: LineChartView!
var xAxisArray : [String]?
var yAxisArray : [Double]?
var date : NSDate?
var dateFormatter : NSDateFormatter?

override func viewDidLoad() {
    super.viewDidLoad()

    self.title = "Live Graph"

    let stringArray = NSMutableArray()
    let numberArray = NSMutableArray()

    dateFormatter = NSDateFormatter()
    dateFormatter!.dateFormat = "HH:mm:ss"
    date = NSDate()

    //Insert random values into chart
    for(var i = 0; i < 40; i++)
    {
        date = date!.dateByAddingTimeInterval(0.3)
        let stringDate = dateFormatter?.stringFromDate(date!)
        stringArray.addObject(stringDate!)
        let randomNum = self.randomBetweenNumbers(0.005, secondNum: 0.015)
        numberArray.addObject(randomNum)
    }

    xAxisArray = stringArray as NSArray as? [String]
    yAxisArray = numberArray as NSArray as? [Double]

    configureChart()
    setData()

    NSTimer.scheduledTimerWithTimeInterval(0.2, target: self, selector: "updateChart", userInfo: nil, repeats: true)
}

func configureChart()
{
    //Chart config
    chartView.descriptionText = ""
    chartView.noDataTextDescription = "Add Data"
    chartView.drawGridBackgroundEnabled = false
    chartView.dragEnabled = true
    chartView.rightAxis.enabled = false
    chartView.doubleTapToZoomEnabled = false
    chartView.legend.enabled = false

    //Configure xAxis
    let chartXAxis = chartView.xAxis as ChartXAxis
    chartXAxis.labelPosition = .Bottom
    chartXAxis.setLabelsToSkip(5)

    //configure yAxis
    chartView.zoom(1.0, scaleY: 1.0, x: 0.0, y: 0.0)
}

func randomBetweenNumbers(firstNum: CGFloat, secondNum: CGFloat) -> CGFloat{
    return CGFloat(arc4random()) / CGFloat(UINT32_MAX) * abs(firstNum - secondNum) + min(firstNum, secondNum)
}

func randomDoubles(firstNum : Double, secondNum : Double) ->Double
{
    return Double(arc4random()) / Double(UINT32_MAX) * abs(firstNum - secondNum) + min(firstNum, secondNum)
}

func updateChart()
{
    let mutableArray = NSMutableArray()
    for(var i = 1; i < xAxisArray?.count; i++)
    {
        mutableArray.addObject(xAxisArray![i])
    }

    date = date!.dateByAddingTimeInterval(1.0)
    let str = dateFormatter!.stringFromDate(date!)
    mutableArray.addObject(str)

    xAxisArray = mutableArray as NSArray as? [String]

    //Numbers
    let numberArray = NSMutableArray()
    for(var i = 1; i < yAxisArray?.count; i++)
    {
        numberArray.addObject(yAxisArray![i])
    }

    let randomNum = self.randomBetweenNumbers(0.005, secondNum: 0.015)
    let convertToDouble = Double(randomNum)

    numberArray.addObject(convertToDouble)

    yAxisArray = numberArray as NSArray as? [Double]

    setData()

}

func setData()
{
    // 1 - creating an array of data entries
    var yVals1 : [ChartDataEntry] = [ChartDataEntry]()
    for var i = 0; i < xAxisArray!.count; i++ {
        yVals1.append(ChartDataEntry(value: yAxisArray![i], xIndex: i))
    }

    // 2 - create a data set with our array
    let set1: LineChartDataSet = LineChartDataSet(yVals: yVals1, label: "")

    set1.axisDependency = .Left // Line will correlate with left axis values
    set1.setColor(UIColor.blueColor().colorWithAlphaComponent(0.5)) // our line's opacity is 50%
    set1.setCircleColor(UIColor.blueColor()) // our circle will be dark red
    set1.lineWidth = 2.0
    set1.circleRadius = 6.0 // the radius of the node circle
    set1.fillAlpha = 65 / 255.0
    set1.fillColor = UIColor.blueColor()
    set1.highlightColor = UIColor.whiteColor()
    set1.drawCircleHoleEnabled = true
    set1.drawFilledEnabled = true

    //3 - create an array to store our LineChartDataSets
    var dataSets : [LineChartDataSet] = [LineChartDataSet]()
    dataSets.append(set1)

    //4 - pass our months in for our x-axis label value along with our dataSets
    let data: LineChartData = LineChartData(xVals: xAxisArray, dataSets: dataSets)

    //5 - finally set our data
    self.chartView.data = data

    //Clear text color
    chartView.data?.setValueTextColor(UIColor.clearColor())
}

I would like to have the x axis scroll similar to the example shown above. Is there a way to do this with iOS charts at present? Or is the charting framework not really made for live data charts like this?

Any help would be much appreciated

@AdamMak AdamMak changed the title Live data Live data Chart Feb 12, 2016
@AdamMak AdamMak changed the title Live data Chart Live data Line Chart Feb 12, 2016
@chris-gunawardena
Copy link
Contributor

chris-gunawardena commented Jul 23, 2016

You don't have to keep copying data from one array to another, init the charts with empty array and you can later add to it using addEntry().
`

    //init code
    self.lineChartView.delegate = self
    let set_a: LineChartDataSet = LineChartDataSet(yVals: [ChartDataEntry](), label: "a")
    let set_b: LineChartDataSet = LineChartDataSet(yVals: [ChartDataEntry](), label: "b")
    self.lineChartView.data = LineChartData(xVals: [String](), dataSets: [set_a, set_b])
    self.lineChartView.setVisibleXRange(minXRange: CGFloat(1), maxXRange: CGFloat(50))  

    // add point code
    self.lineChartView.data?.addEntry(ChartDataEntry(value: readings[0], xIndex: i), dataSetIndex: 0)
    self.lineChartView.data?.addEntry(ChartDataEntry(value: readings[1], xIndex: i), dataSetIndex: 1)
    self.lineChartView.data?.addXValue(String(i))
    self.lineChartView.notifyDataSetChanged()
    self.lineChartView.moveViewToX(CGFloat(i))        

`

@liuxuan30
Copy link
Member

@chris-gunawardena thanks for answering all similar questions :)

@ghost
Copy link

ghost commented Aug 22, 2016

I want ot make a live chart live stock market charts which update and draw in every second update on chart can you help me please
i'm using oanda api's

@chris-gunawardena
Copy link
Contributor

@MuhammadUsmanZiaAkram This should get you started. http://stackoverflow.com/questions/35339479/xcode-dynamic-live-update-line-chart/38543318#38543318

@ghost
Copy link

ghost commented Aug 22, 2016

@chris-gunawardena thanks Dear

@ikyh
Copy link

ikyh commented Aug 22, 2017

@chris-gunawardena Hello..! In this function:
func updateCounter() {
self.lineChartView.data?.addEntry(ChartDataEntry(value: reading_a[i], xIndex: i), dataSetIndex: 0)
self.lineChartView.data?.addEntry(ChartDataEntry(value: reading_b[i], xIndex: i), dataSetIndex: 1)
What is reading_a[i] and reading_b[i]? I am not getting it.
I also want to implement live data to graphView.
Only doing the code that you mentioned here will do the work??http://stackoverflow.com/questions/35339479/xcode-dynamic-live-update-line-chart/38543318#38543318
Please help..!

@chris-gunawardena
Copy link
Contributor

@ikyh That's the y value to be drawn. which can be any number.

@ikyh
Copy link

ikyh commented Aug 23, 2017

@chris-gunawardena Thank you

@tushar1210
Copy link

How to put a custom background image ?

@prashant3285
Copy link

prashant3285 commented Aug 8, 2019

@chris-gunawardena , when I am running the code you share, I am getting 95% cpu usage continuously, is that normal for such a high data rate plotting. In my case i need ECG plotting at 8ms continuously.
Swift 4.2 - tried with Chart release 3.2.0 and 3.3.0 - same results.


import UIKit
import Charts
class ViewController: UIViewController,IAxisValueFormatter,ChartViewDelegate {

@IBOutlet var chartsVw: LineChartView!
@IBOutlet var lblMessage: UILabel!

var timerForHRValue = Timer()
var startDate : Date?

override func viewDidLoad() {
    super.viewDidLoad()
    
    startDate = Date()
    //charts
    self.chartsVw.delegate = self
    let set_a: LineChartDataSet = LineChartDataSet(entries:[ChartDataEntry(x: Double(0), y: Double(0))], label: "voice")
    set_a.drawCirclesEnabled = false
    set_a.setColor(UIColor.red)
    set_a.drawValuesEnabled = false
    self.chartsVw.pinchZoomEnabled = false
    self.chartsVw.doubleTapToZoomEnabled = false
    self.chartsVw.data = LineChartData(dataSets: [set_a])
    timerForHRValue = Timer.scheduledTimer(timeInterval: 0.008, target: self, selector: #selector(updateCounter), userInfo: nil, repeats: true)
}

// add point
var i = 1
@objc func updateCounter() {
    let number1 = Int.random(in: 0 ... 100)
    
    if (self.chartsVw.data?.entryCount)! > 310 {
        self.chartsVw.data?.removeEntry(xValue: 0, dataSetIndex: 0)
    }
    
    self.chartsVw.data?.addEntry(ChartDataEntry(x: Double(i), y: Double(number1)), dataSetIndex: 0)
    self.chartsVw.setVisibleXRange(minXRange: 1, maxXRange: 300)
    self.chartsVw.notifyDataSetChanged()
    i = i + 1
}


//MARK: -
func stringForValue(_ value: Double, axis: AxisBase?) -> String {
    return ""
}

}

@chris-gunawardena
Copy link
Contributor

@prashant3285 at 8ms you are updating it 125 times a second but maybe you can try to batch the readings and update the chart 30 fps or every 33ms. (Push the readings into an array buffer and read from it every 33ms).

@prashant3285
Copy link

@chris-gunawardena Thanks for your prompt response. I saw a 10ms timer on your demo code so I tried 8ms timer. I also tested 32ms and 40ms timer with multiple data point entry at the same time, but I am not getting smooth graph animation. The cpu consumption does comes down to 40% which is still high. on Android the 8ms timer works just fine. Also tested Scichart iOS ECG demo, their animation is very smooth and cpu is at 10% max. I think they are using GPU unlike CPU in ios charts.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants