问题
EDITED: This is a debug video as well.
I use this library to show charts in my Swift iOS app. This is my chart:
X axis is for dates and Y axis is for lifted weight for my athletes.
The ocean blue dots in the middle of the charts that you see it is an intersection between a date and lifted weight. But I am not sure how a chart shows two the same dates and a dot at the middle of dates.
My question is how can I set up X axis to shift Aug 23 to the middle of the screen as well or to fit a dot I don't care should it be shifted or not, I just want to show a dot in the same line of date. Like on image below:
The idea is to show dates under all dots, instead of flexible X axis which right now shows some range of time between one date.
This is my code as you can see I loop my result and create dates list from it and total lifted weight for Y axis. Dates are retrieved from dateValue.timeIntervalSince1970
func setupGraphicWithResults(_ results: [ExerciseSetResult]) {
var oneRMValuesList = [Double]()
var dateList = [Int]()
for exerciseResult in prepareResults(results) {
let oneRMValue = ExeciseResultsService().calculateOneRMValueForResult(exerciseResult)
let formattedOneRMValue = UnitMeasurementService().convertWeightValueToCurrentMeasurementUnit(oneRMValue)
oneRMValuesList.append(formattedOneRMValue)
let dateValue = exerciseResult.date.formatStringToDate()
let dateInt = dateValue.timeIntervalSince1970
dateList.append(Int(dateInt))
}
setChart(datePoints: dateList, values: oneRMValuesList)
}
func setChart(datePoints: [Int], values: [Double]) {
let yAxis = chartView.leftAxis
yAxis.labelFont = UIFont.mainAppFont(11)
yAxis.setLabelCount(5, force: true)
yAxis.labelTextColor = .white
yAxis.labelPosition = .outsideChart
yAxis.axisLineColor = .stackedTipTextColor
yAxis.granularity = 5.0
yAxis.granularityEnabled = true
yAxis.drawGridLinesEnabled = true
yAxis.drawAxisLineEnabled = false
let xAxis = chartView.xAxis
xAxis.labelFont = UIFont.mainAppFont(11)
xAxis.labelTextColor = .white
xAxis.labelPosition = .bottom
xAxis.drawAxisLineEnabled = false
xAxis.drawGridLinesEnabled = false
xAxis.setLabelCount(datePoints.count, force: true)
xAxis.valueFormatter = DateValueFormatter()
xAxis.yOffset = 20.0
chartView.rightAxis.enabled = false
chartView.legend.enabled = false
chartView.chartDescription?.enabled = false
chartView.setExtraOffsets(left: 10, top: 0, right: 20, bottom: 0)
var dataEntries: [ChartDataEntry] = []
for i in 0..<values.count {
let dataEntry = ChartDataEntry(x: Double(datePoints[i]), y: values[i])
dataEntries.append(dataEntry)
}
let lineChartDataSet = LineChartDataSet(entries: dataEntries, label: "")
lineChartDataSet.mode = .cubicBezier
lineChartDataSet.drawCirclesEnabled = true
lineChartDataSet.lineWidth = 2.8
lineChartDataSet.circleRadius = 4
lineChartDataSet.circleHoleRadius = 3.8
lineChartDataSet.circleHoleColor = .stackedLightBlue
lineChartDataSet.setCircleColor(.white)
lineChartDataSet.highlightColor = .stackedLightBlue
//lineChartDataSet.fillColor = .stackedLightBlue
//lineChartDataSet.fillAlpha = 0.2
lineChartDataSet.drawFilledEnabled = true
lineChartDataSet.drawHorizontalHighlightIndicatorEnabled = false
lineChartDataSet.drawVerticalHighlightIndicatorEnabled = false
let gradientColors = [UIColor.stackedLightBlue.cgColor, UIColor.clear.cgColor] as CFArray // Colors of the gradient
let colorLocations:[CGFloat] = [1.0, 0.0] // Positioning of the gradient
let gradient = CGGradient.init(colorsSpace: CGColorSpaceCreateDeviceRGB(), colors: gradientColors, locations: colorLocations) // Gradient Object
lineChartDataSet.fill = Fill.fillWithLinearGradient(gradient!, angle: 90.0)
let lineChartData = LineChartData(dataSet: lineChartDataSet)
lineChartData.setDrawValues(false)
chartView.data = lineChartData
}
回答1:
I suspect that your date values (which are integers, seconds since 1970) have non-zero hour/min/sec component to them. I would suggest that you truncate the time portion such that the time is always 00:00:00. Then, I would rebase your X-axis to work in days. You would divide each of the x values by 24. That way each integer on the X axis is equal to one day.
To get back to proper time format for the X axis, you can update your DateFormatter() class and multiply the value by 24:
public func stringForValue(_ value: Double, axis: AxisBase?) -> String {
var date = Date(timeIntervalSince1970: value * 24)
let format = dateFormatter.string(from: date)
return format
}
Also set your x-axis granularity to 1 so that each day is shown.
Also, be careful with timezones. When you truncate your time to 0 you may have to add back hours such that your time is 00:00:00 in your local timezone - DateFormatter is formatting based on timezone.
回答2:
The chart library will treat your data set as continuous if the x-axis is given as Date
. This will cause weird interpolation behavior in the x-axis if the data is not well spread out.
Instead, you need to create a discrete data set such as (1,2000), (2, 2025) where the x values {1,2} are not Date
types but offsets from a particular day.
You will then have to format the "visible" label to a Date which is what you need (by adding to offset to your previously selected date), using the following method:
func stringForValue(_ value: Double, axis: AxisBase?) -> String
Note by this way, the chart will show discrete data and will not interpolate the x-axis but the formatting will show the proper x-axis date rather than values like {1, 2, 3, ...}
来源:https://stackoverflow.com/questions/57828172/swift-chart-library-how-to-display-x-axis-dates-in-a-right-places