web-dev-qa-db-ja.com

ios Charts 3.0-xラベル(日付)をプロットに揃える

ライブラリチャート(Daniel Gindiから)をバージョン2(Swift 2.3)から3(Swift 3)に移行するのに苦労しています。

基本的に、xラベル(日付)を対応するプロットに正しく配置することはできません。

これはバージョン2で以前持っていたものです:

バージョン2では、7日目、8日目、10日目、11日目の値がありました。そのため、真ん中の1日が欠落していましたが、ラベルはプロットと正しく一致していました。 Charts 2


そしてこれがバージョン3で私が持っているものです:

バージョン3では、x軸の「ラベル」がdoubleに置き換えられ(日付の場合、1970年以降のtimeInterval)、フォーマッターを介してフォーマットされています。したがって、グラフは9番目の値を正しく外挿するため、グラフはより「正確」になりましたが、対応するプロットの下にラベルを配置する方法が見つかりません。 Charts 3

これはx軸の私のコードです:

 let chartView = LineChartView()
 ...
 let xAxis = chartView.xAxis
 xAxis.labelPosition = .bottom
 xAxis.labelCount = entries.count
 xAxis.drawLabelsEnabled = true
 xAxis.drawLimitLinesBehindDataEnabled = true
 xAxis.avoidFirstLastClippingEnabled = true

 // Set the x values date formatter
 let xValuesNumberFormatter = ChartXAxisFormatter()
 xValuesNumberFormatter.dateFormatter = dayNumberAndShortNameFormatter // e.g. "wed 26"
 xAxis.valueFormatter = xValuesNumberFormatter

これが私が作成したChartXAxisFormatterクラスです:

import Foundation
import Charts

class ChartXAxisFormatter: NSObject {
    var dateFormatter: DateFormatter?
}

extension ChartXAxisFormatter: IAxisValueFormatter {

    func stringForValue(_ value: Double, axis: AxisBase?) -> String {
        if let dateFormatter = dateFormatter {

            let date = Date(timeIntervalSince1970: value)
            return dateFormatter.string(from: date)
        }

        return ""
    }

}

したがって、ここでの値は正しく、フォーマットは正しく、グラフの形状は正しいですが、ラベルと対応するプロットの配置は適切ではありません。ご協力いただきありがとうございます

9
Frédéric Adda

はい、わかった!

参照時間間隔(x軸の「0」)を定義する必要があります。次に、各x値の追加の時間間隔を計算します。

ChartXAxisFormatterは次のようになります。

import Foundation
import Charts

class ChartXAxisFormatter: NSObject {
    fileprivate var dateFormatter: DateFormatter?
    fileprivate var referenceTimeInterval: TimeInterval?

    convenience init(referenceTimeInterval: TimeInterval, dateFormatter: DateFormatter) {
        self.init()
        self.referenceTimeInterval = referenceTimeInterval
        self.dateFormatter = dateFormatter
    }
}


extension ChartXAxisFormatter: IAxisValueFormatter {

    func stringForValue(_ value: Double, axis: AxisBase?) -> String {
        guard let dateFormatter = dateFormatter,
        let referenceTimeInterval = referenceTimeInterval
        else {
            return ""
        }

        let date = Date(timeIntervalSince1970: value * 3600 * 24 + referenceTimeInterval)
        return dateFormatter.string(from: date)
    }

}

そして、データエントリを作成すると、次のように機能します。

// (objects is defined as an array of struct with date and value)

// Define the reference time interval
var referenceTimeInterval: TimeInterval = 0
if let minTimeInterval = (objects.map { $0.date.timeIntervalSince1970 }).min() {
        referenceTimeInterval = minTimeInterval
    }


    // Define chart xValues formatter
    let formatter = DateFormatter()
    formatter.dateStyle = .short
    formatter.timeStyle = .none
    formatter.locale = Locale.current

    let xValuesNumberFormatter = ChartXAxisFormatter(referenceTimeInterval: referenceTimeInterval, dateFormatter: xValuesFormatter)



    // Define chart entries
    var entries = [ChartDataEntry]()
    for object in objects {
        let timeInterval = object.date.timeIntervalSince1970
        let xValue = (timeInterval - referenceTimeInterval) / (3600 * 24)

        let yValue = object.value
        let entry = ChartDataEntry(x: xValue, y: yValue)
        entries.append(entry)
    }

// Pass these entries and the formatter to the Chart ...

結果ははるかに良いです(ちなみに私は立方体を削除しました): enter image description here

16
Frédéric Adda

X軸に必要なラベルの数が正確にわかっている場合は、このコードを記述して解決できます。たとえば、x軸に7つのラベルを表示する必要がある場合は、これで十分です。理由はチャートライブラリが2つのx軸ポイント間の間隔を適切に計算していないため、プロットとラベルの不一致があります。指定された数のラベルに対してライブラリを強制的にプロットすると、問題は解決したようです。

 let xAxis = chart.xAxis
 xAxis.centerAxisLabelsEnabled = false
 xAxis.setLabelCount(7, force: true) //enter the number of labels here
2
Haseeb Mohamed

私はこの答えを使用してこの問題を解決しました https://stackoverflow.com/a/44554613/2087608

私の場合、これらのオフセットはX軸の値を特定の時刻に調整することによるものだと思いました。

これが私のコードです

for i in 0..<valuesViewModel.entries.count {
  let dataEntry = ChartDataEntry(x: roundDate(date: valuesViewModel.entries[i].date).timeIntervalSince1970, y: valuesViewModel.entries[i].value)
  dataEntries.append(dataEntry)
}



func roundDate(date: Date) -> Date {
  var comp: DateComponents = Calendar.current.dateComponents([.year, .month, .day], from: date)
  comp.timeZone = TimeZone(abbreviation: "UTC")!
  let truncated = Calendar.current.date(from: comp)!
  return truncated
}
0
theDC

これがxValuesNumberFormatterのソリューションです

let xValuesFormatter = DateFormatter()
    xValuesFormatter.dateFormat = "MM/dd"
let xValuesNumberFormatter = ChartXAxisFormatter(referenceTimeInterval: referenceTimeInterval, dateFormatter: xValuesFormatter)
    xValuesNumberFormatter.dateFormatter = xValuesFormatter // e.g. "wed 26"
    xAxis.valueFormatter = xValuesNumberFormatter
0
Usama Ali