ライブラリチャート(Daniel Gindiから)をバージョン2(Swift 2.3)から3(Swift 3)に移行するのに苦労しています。
基本的に、xラベル(日付)を対応するプロットに正しく配置することはできません。
これはバージョン2で以前持っていたものです:
バージョン2では、7日目、8日目、10日目、11日目の値がありました。そのため、真ん中の1日が欠落していましたが、ラベルはプロットと正しく一致していました。
そしてこれがバージョン3で私が持っているものです:
バージョン3では、x軸の「ラベル」がdoubleに置き換えられ(日付の場合、1970年以降のtimeInterval)、フォーマッターを介してフォーマットされています。したがって、グラフは9番目の値を正しく外挿するため、グラフはより「正確」になりましたが、対応するプロットの下にラベルを配置する方法が見つかりません。
これは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 ""
}
}
したがって、ここでの値は正しく、フォーマットは正しく、グラフの形状は正しいですが、ラベルと対応するプロットの配置は適切ではありません。ご協力いただきありがとうございます
はい、わかった!
参照時間間隔(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 ...
X軸に必要なラベルの数が正確にわかっている場合は、このコードを記述して解決できます。たとえば、x軸に7つのラベルを表示する必要がある場合は、これで十分です。理由はチャートライブラリが2つのx軸ポイント間の間隔を適切に計算していないため、プロットとラベルの不一致があります。指定された数のラベルに対してライブラリを強制的にプロットすると、問題は解決したようです。
let xAxis = chart.xAxis
xAxis.centerAxisLabelsEnabled = false
xAxis.setLabelCount(7, force: true) //enter the number of labels here
私はこの答えを使用してこの問題を解決しました 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
}
これが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