Swift Charts marks (AreaMark, BarMark, LineMark, PointMark, RectangleMark, RuleMark) take familiar view modifiers. Styling a chart is mostly the modifiers you already know, applied to marks.
Color, Shape, and Grouping
foregroundStyle accepts any ShapeStyle, opacity sets the alpha, clipShape reshapes a bar, and position(by:) splits a category into side-by-side bars instead of the default vertical stack. A custom enum plots once it conforms to Plottable.
extension Gender: Plottable {
var primitivePlottable: String { rawValue }
}
Chart {
ForEach(stats, id: \.city) { stat in
BarMark(
x: .value("City", stat.city),
y: .value("Population", stat.population)
)
.foregroundStyle(by: .value("Gender", stat.gender))
.clipShape(RoundedRectangle(cornerRadius: 16))
.position(by: .value("Gender", stat.gender))
}
}
foregroundStyle(by:) also makes the framework generate a legend automatically.
Line Styling
lineStyle takes a StrokeStyle, so dashed lines are one argument. interpolationMethod(.catmullRom) curves the line instead of drawing straight segments. A RuleMark draws a threshold line across the plot.
Chart {
RuleMark(y: .value("Limit", 50))
ForEach(Array(numbers.enumerated()), id: \.offset) { index, value in
LineMark(x: .value("Index", index), y: .value("Value", value))
.interpolationMethod(.catmullRom)
.lineStyle(StrokeStyle(lineWidth: 1, dash: [2]))
PointMark(x: .value("Index", index), y: .value("Value", value))
}
}
Annotations Are SwiftUI Views
Every mark takes an annotation modifier with a ViewBuilder, placing a real view next to the data point. Position, alignment, and spacing are parameters.
BarMark(
x: .value("City", stat.city),
y: .value("Population", stat.population)
)
.annotation(position: .bottom, alignment: .trailing, spacing: 16) {
Text(verbatim: stat.population.formatted())
.font(.caption)
}
Annotations can sit above, below, or overlay the mark. Use them sparingly, or the chart drowns in labels.