【问题标题】:How do I create an x-axis with Swift Charts with 1 unit per day instead of 1 unit per data point?如何使用每天 1 个单位而不是每个数据点 1 个单位的 Swift 图表创建 x 轴?
【发布时间】:2016-06-30 03:56:17
【问题描述】:

我有一个需要时间序列数据的图表。时间序列数据每天最多记录一次,但不定期。即,数据可能如下所示:

1/1, 1500
1/13, 1600
1/14, 1700
2/22, 1800
5/1, 1400

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

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

我的图表代码:

    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
    }

【问题讨论】:

    标签: swift charts


    【解决方案1】:

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

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

    代码:

    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())
        ...
    }
    

    【讨论】:

      【解决方案2】:

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

      ChartDataEntry 值必须由 (x, y): (Double, Double) 组成,并且不能 包含String,尽管您使用自定义显示格式化程序来显示数据。

      设置一个实现IAxisValueFormatter 协议的MonthTimeXAxisValueFormatter 以返回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
        }
      

      【讨论】:

        猜你喜欢
        • 2012-11-03
        • 1970-01-01
        • 2013-05-10
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-04-30
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多