IOS Графики позиционирования линий сетки - PullRequest
0 голосов
/ 14 марта 2020

Я изо всех сил пытаюсь выяснить, как установить линии сетки на моем графике, чтобы указать c точек на оси x и центрировать метки на линиях, соответствующих времени суток. У меня есть простой график, данные представляют день примерно с 280 точками данных (по одному на каждые 5 минут). Я хочу показать линии сетки в моменты времени, равные 03:00, 06:00, 12:00, 15:00, 18:00 и 21:00, и показать соответствующие метки по центру под линиями сетки. Я также попробовал LimitLines, который работает для размещения вертикальных линий в правильных точках, но, похоже, нет возможности выровнять метки времени с центром линий ограничения.

Я знаю это может быть сделано, потому что я видел скриншоты онлайн, показывающие метки времени, центрированные на линиях сетки (или лимитах) для определенных c периодов дня, но я часами искал, как это сделать, и я рисую пустую .

Мой код ниже (обратите внимание на закомментированную неудачную попытку заставить работать предельные значения).

let tideHeights = LineChartDataSet(entries: dataEntries)
    tideHeights.drawCirclesEnabled = false
    tideHeights.colors = [NSUIColor.black]

    //let timings = ["00:00", "03:00", "06:00", "12:00", "15:00", "18:00", "21:00"]

    let data = LineChartData(dataSet: tideHeights)

    lineChartView.xAxis.valueFormatter = IndexAxisValueFormatter(values: dataPoints)

    //lineChartView.xAxis.drawGridLinesEnabled = false
    //let gridLine = values.count / timings.count
    //var xPos = 0

    //for label in timings {
        //let limitLine = ChartLimitLine(limit: Double(xPos), label: label)
        //limitLine.labelPosition = .bottomLeft
        //limitLine.lineWidth = 0.5
        //limitLine.lineColor = .black
        //limitLine.valueTextColor = .black
        //lineChartView.xAxis.addLimitLine(limitLine)
        //xPos += gridLine

    //}

    lineChartView.xAxis.labelCount = 7
    lineChartView.xAxis.labelPosition = .bottom

    lineChartView.xAxis.granularity = 1
    lineChartView.xAxis.avoidFirstLastClippingEnabled = true
    lineChartView.legend.enabled = false
    lineChartView.data = data

Вывод ниже, линии сетки находятся в установленных системных положениях, как я могу контролировать где они находятся? iPhone screenshot

Обновление:

После применения очень полезного предложения Штефана Шлехта я все еще получаю странные результаты. С lineChartView.xAxis.setLabelCount(9, force: true) я получаю:

enter image description here

и с lineChartView.xAxis.setLabelCount(4, force: true) я получаю:

enter image description here

По некоторым причинам кажется, что 1-ая линия сетки после Оси игнорируется.

Код:

lineChartView.xAxis.valueFormatter = IndexAxisValueFormatter(values: dataPoints)

    let marker = ChartMarker()
    marker.setMinuteInterval(interval: 5)
    marker.chartView = lineChartView
    lineChartView.marker = marker

    lineChartView.xAxis.setLabelCount(4, force: true)
    lineChartView.xAxis.avoidFirstLastClippingEnabled = true
    lineChartView.xAxis.labelPosition = .bottom
    lineChartView.leftAxis.labelPosition = .insideChart
    lineChartView.rightAxis.drawLabelsEnabled = false
    lineChartView.legend.enabled = false

    lineChartView.data = data
    lineChartView.data?.highlightEnabled = true

Обновление 2

Воспроизвести У меня есть следующий класс, который создает данные (кстати, это класс-заглушка, в конечном итоге он будет содержать платный API, поэтому сейчас я генерирую данные для целей тестирования:

class TideHeights {
var tideHeights = [Double]()
var tideTimes = [Date]()
var strTimes = [String]()
var intervalMins = 5

init (intervalMins: Int) {
    self.intervalMins = intervalMins
    let slots = 24 * 60.0 / Double(intervalMins)
    let seconds = 24 * 60 * 60.0 / slots
    let radians = 2 * Double.pi / slots
    let endDate = Date().endOfDay

    var date = Date().startOfDay
    var radianOffset = 0.0


    repeat {
        tideHeights.append(sin(radianOffset) + 1)
        tideTimes.append(date)

        let timeFormatter = DateFormatter()
        timeFormatter.dateFormat = "HH:mm"
        strTimes.append(timeFormatter.string(from: date))

        date = date.advanced(by: seconds)
        radianOffset += radians

    } while date <= endDate   
}  

}

этот класс создан и используется для рисования графика в следующих двух функциях ViewController.

func drawChart() -> Void {

    let tideData = TideHeights(intervalMins: 5)

    lineChartView.dragEnabled = true
    lineChartView.setScaleEnabled(false)
    lineChartView.pinchZoomEnabled = false

    setChartValues(dataPoints: tideData.strTimes, values: tideData.tideHeights)

}

func setChartValues(dataPoints: [String], values: [Double]) -> Void {

    //initialise and load array of chart data entries for drawing
    var dataEntries: [ChartDataEntry] = []
    for i in 0..<values.count {
        let dataEntry = ChartDataEntry(x: Double(i), y: values[i])
        dataEntries.append(dataEntry)
    }

    let tideHeights = LineChartDataSet(entries: dataEntries)
    tideHeights.drawCirclesEnabled = false
    tideHeights.colors = [NSUIColor.black]

    let gradientColors = [ChartColorTemplates.colorFromString("#72E700").cgColor,
                              ChartColorTemplates.colorFromString("#724BEB").cgColor]

    let gradient = CGGradient(colorsSpace: nil, colors: gradientColors as CFArray, locations: nil)!

    tideHeights.fillAlpha = 0.7
    tideHeights.fill = Fill(linearGradient: gradient, angle: 90)
    tideHeights.drawFilledEnabled = true

    let data = LineChartData(dataSet: tideHeights)

    lineChartView.xAxis.valueFormatter = IndexAxisValueFormatter(values: dataPoints)

    let marker = ChartMarker()
    marker.setMinuteInterval(interval: 5)
    marker.chartView = lineChartView
    lineChartView.marker = marker

    lineChartView.xAxis.setLabelCount(4, force: true)
    lineChartView.xAxis.avoidFirstLastClippingEnabled = true
    lineChartView.xAxis.labelPosition = .bottom
    lineChartView.leftAxis.labelPosition = .insideChart
    lineChartView.rightAxis.drawLabelsEnabled = false
    lineChartView.legend.enabled = false

    lineChartView.data = data
    lineChartView.data?.highlightEnabled = true

}

Ответы [ 2 ]

1 голос
/ 15 марта 2020

Документация гласит:

setLabelCount (int count, boolean force): Устанавливает количество меток для оси y. Имейте в виду, что это число не является фиксированным (если force == false) и может быть только приблизительно. Если сила включена (true), то отображается точное заданное количество меток - это может привести к неравномерным числам на оси.

см. https://weeklycoding.com/mpandroidchart-documentation/axis-general/

Примечание: хотя ось y упоминается в документации к функции, на самом деле она может применяться к обеим осям.

Поэтому вместо

lineChartView.xAxis.labelCount = 7

используйте

lineChartView.xAxis.setLabelCount(9, force: true)

Примечание: вам нужно 9 меток, а не 7.

Тест

Если объединить синусоидальную волну в 288 точек с вашим кодом выше

for i in 0...288 {
    let val = sin(Double(i) * 2.0 * Double.pi / 288.0) + 1
    dataEntries.append(ChartDataEntry(x: Double(i), y: val))
}

и заставляет количество меток = 9, как показано, тогда это выглядит так:

forced label count screenshot

0 голосов
/ 17 марта 2020

Стефан был прав в своем ответе на этот вопрос. Чтобы форсировать линии сетки и выравнивание, используйте setLabelCount(x, force: true) дополнительную сложность, связанную с моим конкретным c проектом и данными, содержащимися в метках.

...