ios Charts 3.0 - Совместите метки x (даты) с графиками

Мне сложно перенести библиотечные диаграммы (от Дэниела Гинди) с версии 2 (Swift 2.3) на 3 (Swift 3).

По сути, я не могу правильно выровнять метки x (даты) с соответствующими графиками.

Это то, что у меня было раньше в версии 2:

В версии 2 у меня были значения для дней 7, 8, 10 и 11. Таким образом, мне не хватало дня в середине, но метки были правильно выровнены с графиками. «Графики


А вот что у меня в версии 3:

В версии 3 «метки» на оси x теперь заменены на double (для дат это timeInterval с 1970 года) и отформатированы с помощью средства форматирования. Итак, несомненно, график теперь более "правильный", поскольку диаграмма правильно экстраполирует значение для 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 ""
    }

}

Итак, значения здесь правильные, форматирование правильное, форма диаграммы правильная, но выравнивание меток с соответствующими графиками плохое. Спасибо за вашу помощь


person Frédéric Adda    schedule 18.01.2017    source источник
comment
Я смог воспроизвести с помощью Charts 3.0.0 и Charts 3.0.1. В то же время у меня есть код, использующий Charts 3.0.0 в отдельном проекте, который не страдает от этих проблем. Возможно, эта ошибка обнаруживается при некоторой комбинации настроек графика?   -  person Alex    schedule 19.01.2017
comment
У меня был ответ репозитория Charts на Github: по-видимому, это происходит при использовании временных интервалов по оси x, потому что Charts использует интерполяцию, чтобы определить, какие метки отображать.   -  person Frédéric Adda    schedule 19.01.2017
comment
Причина смещения: xAxis.avoidFirstLastClippingEnabled = true   -  person Jojo Narte    schedule 15.03.2018


Ответы (4)


Хорошо понял!

Вы должны определить эталонный временной интервал («0» для оси x). А затем вычислите дополнительный временной интервал для каждого значения 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: formatter)



    // 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 ...

Результат намного лучше (я, кстати, удалил кубик):  введите описание изображения здесь

person Frédéric Adda    schedule 31.01.2017
comment
Я думаю это то, что я сделал - person Frédéric Adda; 16.03.2017
comment
Что такое xValuesFormatter? - person shoujo_sm; 20.11.2017
comment
Тем не менее я не могу решить эту проблему. Не могли бы вы объяснить это ясно? Спасибо - person Manish Mahajan; 27.11.2018
comment
В ответе @ FrédéricAdda отсутствует несколько вещей, которые я хотел бы уточнить: (1) Я думаю, вы хотели передать formatter в xValuesNumberFormatter, а не xValuesFormatter (2) код этого не показывает, но xValuesNumberFormatter должен быть установлен на вашем диаграмма .... другими словами: yourChartView.xAxis.valueFormatter = xValuesNumberFormatter - person GarySabo; 11.01.2019
comment
@GarySabo, не могли бы вы предложить что-нибудь на моем ссылка? - person Matrosov Alexander; 01.10.2019
comment
Я также не понял, как это настроить. Что такое xValuesFormatter? - person Matrosov Alexander; 01.10.2019

Если вы точно знаете, сколько меток вам нужно на оси X, вы можете написать этот код, чтобы решить эту проблему. Например, если мне нужно, чтобы на оси X появилось семь меток, тогда этого должно быть достаточно. Причина в том, что Библиотека диаграмм неправильно рассчитывает интервалы между двумя точками оси X и, следовательно, несовпадение графика и метки. Когда мы заставляем библиотеку строить график с заданным количеством меток, проблема, похоже, исчезла.

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

вот решение 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
person Usama Ali    schedule 09.12.2019

Я решил эту проблему, используя этот ответ 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
}
person theDC    schedule 21.04.2020