如何在SwiftUI中按年份分组显示折线图线条?
SwiftUI Charts 按年份分组折线图解决方案
问题原因
你当前的代码仅为单个数据点按年份设置了颜色,但LineMark默认会将所有数据点按X轴顺序连接成一条折线,因此即使颜色不同,依然是同一条线,无法实现按年份分组的多条折线效果。
解决方案
要实现每年一条独立折线,需先将数据按年份分组,再为每个年份的数据集单独绘制LineMark。具体步骤如下:
- 为
Sales结构体添加年份计算属性,简化分组操作; - 将样本数据按年份分组为字典;
- 在
Chart中遍历每个年份的分组数据,分别绘制折线。
修改后的完整代码
import SwiftUI import Charts struct Sales { let id = UUID() let period: Date let value: Double init(value: Double, year: Int, month: Int) { self.value = value var dateComponents = DateComponents() dateComponents.year = year dateComponents.month = month let calendar = Calendar.current self.period = calendar.date(from: dateComponents)! } } extension Sales { static var sampleData = [ Sales(value: 300, year: 2020, month: 1), Sales(value: 230, year: 2020, month: 2), Sales(value: 190, year: 2020, month: 3), Sales(value: 250, year: 2020, month: 4), Sales(value: 270, year: 2020, month: 5), Sales(value: 280, year: 2020, month: 6), Sales(value: 290, year: 2020, month: 7), Sales(value: 400, year: 2020, month: 8), Sales(value: 300, year: 2020, month: 9), Sales(value: 360, year: 2020, month: 10), Sales(value: 400, year: 2020, month: 11), Sales(value: 450, year: 2020, month: 12), Sales(value: 320, year: 2021, month: 1), Sales(value: 280, year: 2021, month: 2), Sales(value: 300, year: 2021, month: 3), Sales(value: 390, year: 2021, month: 4), Sales(value: 400, year: 2021, month: 5), Sales(value: 450, year: 2021, month: 6), Sales(value: 420, year: 2021, month: 7), Sales(value: 500, year: 2021, month: 8), Sales(value: 550, year: 2021, month: 9), Sales(value: 490, year: 2021, month: 10), Sales(value: 600, year: 2021, month: 11), Sales(value: 650, year: 2021, month: 12), Sales(value: 400, year: 2022, month: 1), Sales(value: 330, year: 2022, month: 2), Sales(value: 430, year: 2022, month: 3), Sales(value: 450, year: 2022, month: 4), Sales(value: 600, year: 2022, month: 5), Sales(value: 650, year: 2022, month: 6), Sales(value: 550, year: 2022, month: 7), Sales(value: 580, year: 2022, month: 8), Sales(value: 600, year: 2022, month: 9), Sales(value: 650, year: 2022, month: 10), Sales(value: 600, year: 2022, month: 11), Sales(value: 800, year: 2022, month: 12) ] // 添加年份计算属性,方便分组 var year: Int { Calendar.current.component(.year, from: period) } } struct TesteYearView: View { // 按年份分组数据 private let groupedData: [Int: [Sales]] = { Dictionary(grouping: Sales.sampleData, by: { $0.year }) }() var body: some View { VStack { Chart { // 遍历排序后的年份,绘制对应折线 ForEach(Array(groupedData.keys).sorted(), id: \.self) { year in ForEach(groupedData[year]!) { datum in LineMark( x: .value("Month", datum.period, unit: .month), y: .value("Value", datum.value) ) } .foregroundStyle(by: .value("Year", year)) .symbol { Circle() .frame(width: 5) } .interpolationMethod(.catmullRom) // 可选:让折线过渡更平滑 } } .chartLegend(position: .bottom) // 显示年份图例 } .frame(height: 400) .padding() .chartYAxis(.hidden) Spacer() } }
额外说明
- 通过
Dictionary(grouping:)将数据按年份分组,确保每个年份的数据集独立; - 外层
ForEach遍历排序后的年份,内层ForEach绘制对应年份的每个数据点; .foregroundStyle(by:)会自动为不同年份分配不同颜色,并生成图例;- 可选的
.interpolationMethod(.catmullRom)可以让折线过渡更平滑,提升视觉效果。
内容的提问来源于stack exchange,提问作者Marcus Porto
相关产品推荐
相关产品推荐

