How to label axes in Swift Charts?
Asked Answered
K

2

23

I'm trying to add axis unit labels to a chart built with Swift Charts.

For example:

import SwiftUI
import Charts

struct ContentView: View {
    
    struct ChartData: Identifiable {
        var id: Double { xVal }
        let xVal: Double
        let yVal: Double
    }
    
    let data: [ChartData] = [
        .init(xVal: -5, yVal: 5),
        .init(xVal: 0, yVal: 10),
        .init(xVal: 5, yVal: 20),
    ]
    
    var body: some View {
        Chart(data) {
            LineMark(
                x: .value("Position", $0.xVal),
                y: .value("Height", $0.yVal)
            )
        }
        .chartYAxis {
            AxisMarks(position: .leading)
        }
    }
    
}

Chart output, with the desired labels annotated in red: enter image description here

How can we create axis labels like those in red above - or otherwise add units/descriptions to our axes?

Kleeman answered 6/7, 2022 at 6:59 Comment(1)
I assume PlottableValue.Label should be shown (at least, not sure about colors) but they are not, so this looks like a bug - submit feedback to Apple).Nauseate
K
24

This is the correct modifier:

Chart {
    ...
}
.chartXAxisLabel("Position (meters)")

You can also provide a custom view like this:


Chart {
    ...
}
.chartXAxisLabel(position: .bottom, alignment: .center) {
    Text("Position (meters)")
}
Kleeman answered 31/8, 2022 at 19:58 Comment(0)
C
14

One way to create those red labels is to use a combination of Text with VStack or HStack as needed. The text can be rotated using rotationEffect(). This is the original code with modifications:

struct ContentView: View {
    
    struct ChartData: Identifiable {
        var id: Double { xVal }
        let xVal: Double
        let yVal: Double
    }
    
    let data: [ChartData] = [
        .init(xVal: -5, yVal: 5),
        .init(xVal: 0, yVal: 10),
        .init(xVal: 5, yVal: 20),
    ]
    
    var body: some View {
        HStack(alignment: .center, spacing: 0) {
            Text("Height(cm)")
                .rotationEffect(Angle(degrees: -90))
                .foregroundColor(.red)
            VStack {
                Chart(data) {
                    LineMark(
                        x: .value("Position", $0.xVal),
                        y: .value("Height", $0.yVal)
                    )
                }
                .chartYAxis {
                    AxisMarks(position: .leading)
                }
                Text("Position(meters)")
                    .foregroundColor(.red)
            }
        }
        .frame(width: 350, height: 400, alignment: .center)
    }
}

This is the resulting layout:

enter image description here

Use AxisMarks() to change the default axis marks including labels, grid lines and tick marks. Within AxisMarks individual axis labels can be assigned using AxisValueLabel(). Text() is formatted as an individual label for AxisValueLabel()'s content.

When AxisMarks is used, the default grid lines and tick marks disappear, so they have been added back using AxisGridLine() and AxisTick(). The following code should be added immediately following Chart{} and replacing the original .chartYAxis():

.chartXAxis {
    AxisMarks(position: .bottom, values: .automatic) { value in
        AxisGridLine(centered: true, stroke: StrokeStyle(dash: [1, 2]))
        AxisTick(centered: true, stroke: StrokeStyle(dash: [1, 2]))
        AxisValueLabel() {
            if let intValue = value.as(Int.self) {
                Text("\(intValue) m")
                    .font(.system(size: 10))
            }
        }
    }
}

.chartYAxis {
    AxisMarks(position: .leading, values: .automatic) { value in
        AxisGridLine(centered: true, stroke: StrokeStyle(lineWidth: 1))
        AxisValueLabel() {
            if let intValue = value.as(Int.self) {
                Text("\(intValue) cm")
                .font(.system(size: 10))
            }
        }
    }
} 

The chart with custom labels will look like this: enter image description here

Canary answered 7/7, 2022 at 13:12 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.