Xcode 动态实时更新折线图

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/35339479/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-15 08:31:41  来源:igfitidea点击:

Xcode dynamic live update line chart

swiftxcodeios-charts

提问by AdamM

I am trying to create a line chart in which I will continuously plot data so the graph can be observed in real time updating, will be plotting around 5 points or so a second. The kind of graph I am looking for will look something like the graph shown here

我正在尝试创建一个折线图,我将在其中连续绘制数据,以便可以在实时更新中观察图形,将绘制大约 5 个点左右。我正在寻找的图表类型将类似于此处显示的图表

https://www.vanmil.org/live-heart-rate-with-ios-and-meteor/

https://www.vanmil.org/live-heart-rate-with-ios-and-meteor/

or

或者

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

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

I have been playing about with several different charting frameworks such as iOS charts, but I can't seem to get the exact graph I am looking for where live updates can be charted with an evolving X-Axis.

我一直在使用几种不同的图表框架,例如 iOS 图表,但我似乎无法获得我正在寻找的确切图表,其中可以使用不断发展的 X 轴绘制实时更新图表。

Using iOS charts, I managed to create a sort of evolving graph, example code below.

使用 iOS 图表,我设法创建了一种演化图,示例代码如下。

@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.0005, secondNum: 0.0015)
        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 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.0005, secondNum: 0.0015)
    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())
}

But if you try it out, you can see it is fairly jerky, plus every x axis label updates, I was hoping to have the X axis continue to evolve and just have it animate off the screen as the plotting continues like the one shown in the example.

但是如果你试一试,你会发现它相当生涩,加上每个 x 轴标签更新,我希望 X 轴继续发展,并在绘图继续时让它动画离开屏幕,就像图中所示的那样这个例子。

Does anyone know any charting software that would allow me to replicate this type of graph, or if this effect can be achieved using iOS charts?

有谁知道任何图表软件可以让我复制这种类型的图表,或者是否可以使用 iOS 图表来实现这种效果?

Edit:

编辑:

I am trying to achieve this type of plotting example

我正在尝试实现这种类型的绘图示例

http://www.code4app.net/ios/Dynamic-plot-curve-line-like-stock-chart/52d68b75cb7e84802f8b5340

http://www.code4app.net/ios/Dynamic-plot-curve-line-like-stock-chart/52d68b75cb7e84802f8b5340

Just hopefully a lot smoother,

只是希望顺利很多,

回答by Chris Gunawardena

Now this can be done using iOS charts:

现在这可以使用 iOS 图表来完成:

override func viewDidLoad() {
    super.viewDidLoad()

    //charts
    self.lineChartView.delegate = self
    let set_a: LineChartDataSet = LineChartDataSet(yVals: [ChartDataEntry](), label: "a")
    set_a.drawCirclesEnabled = false
    set_a.setColor(UIColor.blueColor())

    let set_b: LineChartDataSet = LineChartDataSet(yVals: [ChartDataEntry](), label: "b")
    set_b.drawCirclesEnabled = false
    set_b.setColor(UIColor.greenColor())

    self.lineChartView.data = LineChartData(xVals: [String](), dataSets: [set_a, set_b])

    timer = NSTimer.scheduledTimerWithTimeInterval(0.010, target:self, selector: #selector(ViewController.updateCounter), userInfo: nil, repeats: true)
}


// add point
var i = 0
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)
    self.lineChartView.data?.addXValue(String(i))
    self.lineChartView.setVisibleXRange(minXRange: CGFloat(1), maxXRange: CGFloat(50))  
    self.lineChartView.notifyDataSetChanged()
    self.lineChartView.moveViewToX(CGFloat(i))  
    i = i + 1
}

回答by CaglayanSerbetci

I have updated Chris Code to Charts 3.0

我已将 Chris Code 更新为 Charts 3.0

override func viewDidLoad() {
    super.viewDidLoad()

    //charts
    self.chartView.delegate = self
    let set_a: LineChartDataSet = LineChartDataSet(values:[ChartDataEntry(x: Double(0), y: Double(0))], label: "voice")
    set_a.drawCirclesEnabled = false
    set_a.setColor(UIColor.blue)

    let set_b: LineChartDataSet = LineChartDataSet(values: [ChartDataEntry(x: Double(0), y: Double(0))], label: "flow")
    set_b.drawCirclesEnabled = false
    set_b.setColor(UIColor.green)

    self.chartView.data = LineChartData(dataSets: [set_a,set_b])
    timer = Timer.scheduledTimer(timeInterval: 0.010, target: self, selector: #selector(updateCounter), userInfo: nil, repeats: true)
    }

    // add point
    var i = 1
    func updateCounter() {
    self.chartView.data?.addEntry(ChartDataEntry(x: Double(i), y: reading_a![i]), dataSetIndex: 0)
    self.chartView.data?.addEntry(ChartDataEntry(x:Double(i) , y:reading_b![i] ), dataSetIndex: 1)
    self.chartView.setVisibleXRange(minXRange: Double(1), maxXRange: Double(1000))
    self.chartView.notifyDataSetChanged()
    self.chartView.moveViewToX(Double(i))
    i = i + 1

}

回答by Ross Stepaniak

I just made a small that does exactly what you need. It inserts 4 points per second scrolling the chart automatically to new data. (the scroll is smooth, new data is being redrawn well, seriously I don't know why you don't want to give a chance to this approach) You may scroll the chart back to see all its previous points. The chart cells/slices are being reused so you can use this for infinite charts, like displaying heart beat chart for few hours.

我只是做了一个小,正是你需要的。它每秒插入 4 个点,自动将图表滚动到新数据。(滚动很流畅,新数据正在重新绘制,严重的是我不知道您为什么不想给这种方法一个机会)您可以向后滚动图表以查看其以前的所有点。图表单元格/切片正在重复使用,因此您可以将其用于无限图表,例如显示几个小时的心跳图表。

enter image description here

在此处输入图片说明

Please take a look and let me know what you think.

请看一看,让我知道您的想法。

回答by Ross Stepaniak

If you don't manage to find a proper third-party for this, I recommend you to use the following approach:

如果您无法为此找到合适的第三方,我建议您使用以下方法:

  1. Use a tableview rotated 90? counterclockwise.
  2. Implement your custom UIViewthat contains the code to draw (your graph/chart vertex), and then add into into your cell's root view.
  3. Insert 5 cells per second dynamically into the tableview's datasource.
  1. 使用旋转 90 度的 tableview?逆时针。
  2. 实现UIView包含要绘制的代码(您的图形/图表顶点)的自定义,然后添加到单元格的根视图中。
  3. 每秒动态插入 5 个单元格到 tableview 的数据源中。

I know its time consuming to implement this engine but this will work 100%. I'm planning to create an open-source project for this. But sadly I don't have any good code to share yet.

我知道实现这个引擎很耗时,但这将 100% 工作。我计划为此创建一个开源项目。但遗憾的是,我还没有任何好的代码可以分享。