I have a swift program that displays a chart using Chart. The code includes an X Axis Scale parameter but for some reason the last value (right most) on the x axis does not display. It should display Aug 2023. In checking the array used for the x axis labels I find that the last value is Aug 2023. I do not know how to overcome this obstacle. Any assistance will be appreciated. Below is a picture of the bottom of the chart and the code.
struct CustomChartView: View {
let vm: SQLDataVM = SQLDataVM.shared
let closingValues: [TradingDay]
let fundName: String
let numYears: Int
let maxCloseStruct: TradingDay
let maxClose: Double
let minCloseStruct: TradingDay
let minClose: Double
let yIncrment: Double
let yAxisValues: [Double]
let minTimeStampStruct: TradingDay
let minTimeStamp: Date
var dateComponent = DateComponents()
let maxTimeStampStruct: TradingDay
let maxTimeStamp: Date
var xAxisValues: [Date] = []
init (fundName: String, numYears: Int) {
self.fundName = fundName
self.numYears = numYears
closingValues = self.vm.QueryDatabase(fundName: fundName, numYears: numYears)
maxCloseStruct = self.closingValues.max(by: { (tradingDay1, tradingDay2) -> Bool in
return tradingDay1.close < tradingDay2.close
})!
maxClose = maxCloseStruct.close
minCloseStruct = closingValues.min(by: { (tradingDay1, tradingDay2) -> Bool in
return tradingDay1.close < tradingDay2.close
})!
minClose = minCloseStruct.close
yIncrment = (maxClose - minClose)/4
yAxisValues = [
minClose,
minClose + (1 * yIncrment),
minClose + (2 * yIncrment),
minClose + (3 * yIncrment),
maxClose
]
minTimeStampStruct = closingValues.min(by: { (tradingDay1, tradingDay2) -> Bool in
return tradingDay1.timeStamp < tradingDay2.timeStamp
})!
minTimeStamp = minTimeStampStruct.timeStamp
maxTimeStampStruct = closingValues.max(by: { (tradingDay1, tradingDay2) -> Bool in
return tradingDay1.timeStamp < tradingDay2.timeStamp
})!
maxTimeStamp = maxTimeStampStruct.timeStamp
xAxisValues.append(minTimeStamp)
for i in 1...11 {
dateComponent.month = i
let nextMonth = Calendar.current.date(byAdding: dateComponent, to: minTimeStamp)
xAxisValues.append(nextMonth!)
}
xAxisValues.append(maxTimeStamp)
print("\(xAxisValues[12])") // prints 2023-08-04 00:00:00 +0000
} // end init
var body: some View {
HStack(alignment: .center) {
VStack(alignment: .center) {
Chart(closingValues, id:\.id) {
LineMark(
x: .value("Date", $0.timeStamp, unit: .day),
y: .value("Closing", $0.close)
)
.foregroundStyle(.blue)
} // end chart
.frame(width: 1000, height: 700, alignment: .center)
.chartXAxisLabel(position: .bottom, alignment: .center, spacing: 15) {
Text("Date")
.font(.custom("Arial", size: 20))
}
.chartYAxisLabel(position: .leading, alignment: .center, spacing: 20) {
Text("Closing Value")
.font(.custom("Arial", size: 20))
}
.chartXAxis {
AxisMarks(values: xAxisValues) { value in
if let date = value.as(Date.self) {
AxisValueLabel(horizontalSpacing: -14, verticalSpacing: 10) {
VStack(alignment: .leading) {
Text(ChartMonthFormatter.string(from: date))
.font(.custom("Arial", size: 14))
Text(ChartYearFormatter.string(from: date))
.font(.custom("Arial", size: 14))
} // end v stack
} // end axis label
} // end if statement
AxisGridLine(centered: true, stroke: StrokeStyle(lineWidth: 1))
.foregroundStyle(Color.black)
AxisTick(centered: true, length: 0, stroke: .none)
}
} // end chart x axis
.chartXScale(domain: [xAxisValues[0], xAxisValues[12]])
.chartYAxis {
AxisMarks(position: .leading, values: yAxisValues) { value in
AxisGridLine(centered: true, stroke: StrokeStyle(lineWidth: 1))
.foregroundStyle(Color.black)
AxisTick(centered: true, length: 0, stroke: .none)
AxisValueLabel(horizontalSpacing: 10) {
if let yAxisValue = value.as(Double.self) {
let stringValue = String(format: "$%.02f", yAxisValue)
Text(stringValue)
.font(.custom("Arial", size: 14))
}
}
}
}
.chartYScale(domain: [minClose, maxClose])
.chartPlotStyle { plotArea in
plotArea.background(.white.opacity(0.9))
.border(.black, width: 1)
} // end chart plot style
} // end v stack
.frame(width: 1200, height: 900, alignment: .center)
} // end h stack
} // end some view
}
After some additional research, it turns out that there are several preset styles for the Axis Marks. The aligned style is what I needed. I added that preset to the Axis Marks contained in .chartXAxis section of code. Problem solved. Below is a pic of the updated x axis labels and the updated code for .chartXAxis.
.chartXAxis {
AxisMarks(preset: .aligned, values: xAxisValues) { value in
if let date = value.as(Date.self) {
AxisValueLabel(horizontalSpacing: -14, verticalSpacing: 10) {
VStack(alignment: .leading) {
Text(ChartMonthFormatter.string(from: date))
.font(.custom("Arial", size: 14))
Text(ChartYearFormatter.string(from: date))
.font(.custom("Arial", size: 14))
} // end v stack
} // end axis label
} // end if statement
AxisGridLine(centered: true, stroke: StrokeStyle(lineWidth: 1))
.foregroundStyle(Color.black)
AxisTick(centered: true, length: 0, stroke: .none)
}
} // end chart x axis
.chartXScale(domain: [xAxisValues[0], xAxisValues[12]])