IOS 网格线的图表定位

IOS Charts positioning of gridlines

我正在努力寻找如何将图表上的网格线设置为 x 轴上的特定点,以及如何将标签置于对应于一天中时间的线上。我有一个简单的图表,数据代表一天大约有 280 个数据点(每 5 分钟一个数据点)。我想在一天中等于 03:00、06:00、12:00、15:00、18:00 和 21:00 的时间显示网格线并显示相应的标签在网格线下方居中。我也尝试过 LimitLines,它可以将垂直线放置在正确的点,但似乎无法将时间标签与限制线的中心对齐。

我知道这是可以做到的,因为我在网上看到屏幕截图显示了当天特定时间段以网格线(或限制线)为中心的时间标签,但我花了几个小时寻找如何做到这一点我正在画空白。

下面是我的代码(请注意注释掉的试图让限制线起作用的失败尝试)。

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

输出如下,网格线在系统设置的位置,如何控制它们的放置位置?

更新:

在应用了 Stephan Schlecht 非常有用的建议后,我仍然得到奇怪的结果。使用 lineChartView.xAxis.setLabelCount(9, force: true) 我得到:

lineChartView.xAxis.setLabelCount(4, force: true) 我得到:

似乎由于某种原因忽略了 Axis 之后的第一条网格线。

代码是:

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

为了重现,我有以下创建数据的 class(顺便说一句,它是一个存根 class,最终它将包含一个付费的 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   
}  

}

这个class在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

}

文档说:

setLabelCount(int count, boolean force): Sets the number of labels for the y-axis. Be aware that this number is not fixed (if force == false) and can only be approximated. If force is enabled (true), then the exact specified label-count is drawn – this can lead to uneven numbers on the axis.

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

并强制标签 count = 9 如图所示,那么它看起来像这样:

斯蒂芬对这个问题的回答是正确的。要强制网格线和对齐,请使用 setLabelCount(x, force: true) 与我的特定项目相关的额外复杂性以及标签中包含的数据。