如何使用每天1个单位的Swift图表创建x轴,而不是每个数据点1个单位?

时间:2016-06-30 03:56:18

标签: swift charts

我有一张采用时间序列数据的图表。时间序列数据每天最多记录一次,但是时间不规则。即,数据可能如下所示:

    func setChartData(data: ([String], [Double])) {
        var yVals1 = [ChartDataEntry]()
        for i in 0 ..< data.0.count {
            yVals1.append(ChartDataEntry(value: data.1[i], xIndex: i))
        }

        let set1: LineChartDataSet = LineChartDataSet(yVals: yVals1, label: nil)
        set1.axisDependency = .Left 

        set1.setColor(UIColor(red:0.502, green:0.580, blue:0.784, alpha:1.000))
        set1.lineWidth = 2.0
        set1.fillAlpha = 1
        set1.fillColor = UIColor(red:0.502, green:0.580, blue:0.784, alpha:1.000)
        set1.highlightColor = UIColor.whiteColor()
        set1.drawValuesEnabled = false
        set1.drawCirclesEnabled = false
        set1.drawFilledEnabled = true


        var dataSets : [LineChartDataSet] = [LineChartDataSet]()
        dataSets.append(set1)

        let data: LineChartData = LineChartData(xVals: data.0, dataSets: dataSets)
        data.setValueTextColor(UIColor.whiteColor())

        let legend = lineChartView.legend
        legend.enabled = false

        let xAxis = lineChartView.xAxis
        xAxis.drawGridLinesEnabled = false
        xAxis.drawAxisLineEnabled = false
        xAxis.labelPosition = .Bottom

        let rightAxis = lineChartView.rightAxis
        rightAxis.drawAxisLineEnabled = false
        rightAxis.drawLabelsEnabled = false
        rightAxis.drawGridLinesEnabled = false

        let leftAxis = lineChartView.leftAxis
        leftAxis.drawAxisLineEnabled = false
        leftAxis.gridColor = UIColor.blackColor().colorWithAlphaComponent(0.1)
        leftAxis.gridLineWidth = 2


        self.lineChartView.data = data
    }

使用图表,我的折线图以每个数据点一个单位填充x轴(例如,在上面的示例中,x轴上将有5个单位,而不是〜120天)

如何使用范围内所有日期的单位创建x轴?

我的图表代码:

      function registerDevice(fp,uid)
  {
    $.ajax({
         type: "POST",
         async: true,
         url: "backend.php",
         data: {"fp": fp, "uid" : uid},
         success: function(output) {
          var json = eval('(' + output + ')');
          var status = json['status'];
          if(status == "success")
          {
            //redirect user.
            setTimeout(function(){
                    //do what you need here
                    <?php
                    if(isset($_GET['goto'])) 
                      {
                        echo 'window.location.replace("'.$_GET["goto"].'");';
                      }
                      else
                      {
                        echo 'window.location.replace("index.php");';         
                      }
                    ?>
            }, 2000);
          }
          else
          {
            $("#login-msg").text("Something went wrong. Please try again.");
            $("#login-alert").fadeTo(4000, 500).slideUp(500, function(){
            $("#login-alert").hide();
            });
          }
         },
         error: function(error) {
          $("#login-msg").text("There was an unknown error.");
          $("#login-alert").fadeTo(4000, 500).slideUp(500, function(){
          $("#login-alert").hide();
        });
         }
    });
  }

Here is a screenshot of the graph in my app.

2 个答案:

答案 0 :(得分:0)

不是直接传递数据点,而是转换数据点以将所有相关天数包括为x值(1天间隔,即使当天没有关联的y值)并适当填写y值,其中它们存在。

  1. 构建一个每天包含1个元素的x值数组
  2. 如果那天有值,则将值添加到y值数组。否则将nil添加到y值数组。
  3. 代码:

    struct StatsViewModel {
    
        var exercise: Exercise
    
        var workoutDates: ([String], [Double?]) {
            if let lastWorkout = exercise.workoutDiary.last, firstWorkout = exercise.workoutDiary.first {
                var dates = [String]()
                var stats = [Double?]()
                let ti:NSTimeInterval = 24*60*60 //one day
                let dateFrom = firstWorkout.date
                let dateTo = lastWorkout.date
    
                var nextDate =  dateFrom
                let endDate = dateTo.dateByAddingTimeInterval(ti)
    
                while nextDate.compare(endDate) == NSComparisonResult.OrderedAscending
                {
                    dates.append(nextDate.myPrettyString)
                    let workout = exercise.workoutDiary.filter { $0.date.myPrettyString == nextDate.myPrettyString }.first
                    if let workout = workout {
                        stats.append(Double(workout.totalVolume))
                    } else {
                        stats.append(nil)
                    }
                    nextDate = nextDate.dateByAddingTimeInterval(ti)
                }           
                return (dates, stats)
            }
            return ([], [])
        }
    }
    

    从上面生成的数据点创建ChartDataEntry,占nil:

    var statsViewModel: StatsViewModel!
    
    override func viewDidLoad() {
        setChartData(statsViewModel.workoutDates)
    }
    
    func setChartData(data: ([String], [Double?])) {
        var yVals1 = [ChartDataEntry]()
        for i in 0 ..< data.0.count {
            if let yval = data.1[i] {
                yVals1.append(ChartDataEntry(value: yval, xIndex: i))
            }
        }
        let set1: LineChartDataSet = LineChartDataSet(yVals: yVals1, label: nil)
        var dataSets : [LineChartDataSet] = [LineChartDataSet]()
        dataSets.append(set1)
    
        let data: LineChartData = LineChartData(xVals: data.0, dataSets: dataSets)
        data.setValueTextColor(UIColor.whiteColor())
        ...
    }
    

答案 1 :(得分:0)

由于Chart API的更改,已接受的答案已过时。

ChartDataEntry值必须包含(x, y): (Double, Double),并且不能 包含String,尽管您改用自定义显示格式器来显示数据。

设置MonthTimeXAxisValueFormatter来实现协议IAxisValueFormatter以返回String值:

class MonthTimeXAxisValueFormatter: IAxisValueFormatter {
  func stringForValue(_ value: Double, axis: AxisBase?) -> String {
    let dateFormatter = DateFormatter()
    dateFormatter.dateFormat = "dd MMM"
    let timeStamp = Date(timeIntervalSince1970: value)
    return dateFormatter.string(from: timeStamp)
  }
}
// Setup the x-axis with this formatter.
lineChart.xAxis.valueFormatter = MonthTimeXAxisValueFormatter()

此处的x值应生成为:

  func chartDataPoints(from xYValues: [Date: Double]) -> [ChartDataEntry] {
    assert(!xYValues.isEmpty)
    var dataPoints: [ChartDataEntry] = []
    var startDate = xYValues.keys.sorted(by: <).first!
    let endDate = xYValues.keys.sorted(by: >).first!

    repeat {
      guard let yValue = xYValues[startDate] else {
        startDate = startDate.advanced(by: TimeInterval(24 * 60 * 60))
        continue
      }
      dataPoints.append(ChartDataEntry(x: Double(startDate.timeIntervalSince1970), y: yValue))
      startDate = startDate.advanced(by: TimeInterval(24 * 60 * 60))
    } while startDate <= endDate
    return dataPoints
  }