SwiftUI可视化图表框架Charts
SwiftUI可视化图表框架Charts

SwiftUI可视化图表框架Charts

SwiftUI 的 Charts 是一个非常强大且直观的框架,专门用于创建数据可视化图表。它引入了简洁的 API 来轻松创建各种类型的图表,比如柱状图、折线图、饼图等。以下是一些关于 SwiftUI Charts 的关键概念和使用方式。

基本结构

在 SwiftUI 中创建图表,需要导入 Charts 模块

import Charts

使用 Chart 视图:

import SwiftUI
import Charts

struct ContentView: View {
    var data: [SalesData] = [
        SalesData(month: "Jan", sales: 200),
        SalesData(month: "Feb", sales: 150),
        SalesData(month: "Mar", sales: 300)
    ]

    var body: some View {
        Chart(data) { item in
            BarMark(
                x: .value("Month", item.month),
                y: .value("Sales", item.sales)
            )
        }
        .frame(height: 300)
        .padding()
    }
}

struct SalesData: Identifiable {
    let id = UUID()
    let month: String
    let sales: Int
}

支持的图表类型

SwiftUI Charts 支持多种类型的图表,每种类型都有其独特的 Mark,用来绘制对应的图表形态。以下是 SwiftUI Charts 目前支持的主要图表类型:

1、柱状图 (Bar Chart)

标记类型: BarMark

用于展示分类数据之间的比较。

既支持垂直柱状图,也支持水平柱状图。

Chart(data) {
    BarMark(
        x: .value("Category", $0.category),
        y: .value("Value", $0.value)
    )
}

2、折线图 (Line Chart)

标记类型: LineMark

用于表示连续数据的趋势。

通常用在时间序列数据的可视化中。

Chart(data) {
    LineMark(
        x: .value("Time", $0.time),
        y: .value("Value", $0.value)
    )
}

3、面积图 (Area Chart)

标记类型: AreaMark

用于展示数据随时间的变化,并填充曲线下方的区域。

可以叠加多个 AreaMark 创建堆叠图。

Chart(data) {
    AreaMark(
        x: .value("Date", $0.date),
        y: .value("Count", $0.count)
    )
}

4、散点图 (Scatter Plot)

标记类型: PointMark

用于表示两个变量之间的关系。

可以通过形状、大小或颜色来区分类别。

Chart(data) {
    PointMark(
        x: .value("X Value", $0.x),
        y: .value("Y Value", $0.y)
    )
}

5、饼图 / 环形图 (Pie/Donut Chart)

标记类型: 使用 SectorMark

适用于展示分类数据的占比。

通过调整起点和终点角度绘制。

Chart(data) { item in
    SectorMark(
        angle: .value("Sales", item.sales)
    )
    .foregroundStyle(by: .value("Month", item.month))
}

SectorMark默认情况下,它会将所有数据的数值加总,并根据每个数据占总数的比例生成一个完整的圆。数据被映射成扇形角度,但它们没有视觉上的区分,导致它们叠加在一起,看起来像一个单一的圆。

因此,希望饼图能按某个参数分区并以不同颜色显示,可以通过设置 foregroundStyle 来实现。

6、组合图表 (Combination Charts)

组合标记: 使用多种 Mark 叠加。

例如,将柱状图和折线图组合在一起:

Chart(data) {
    BarMark(
        x: .value("Category", $0.month),
        y: .value("Value", $0.sales)
    )
    LineMark(
        x: .value("Category", $0.month),
        y: .value("Value", $0.sales)
    )
}

7、雷达图 (Radar Chart)

目前 Radar Charts 并未原生支持,需要通过自定义绘制来实现。

8、条形图 (Horizontal Bar Chart)

标记类型: 水平的 BarMark,将 x 和 y 值互换。

Chart(data) {
    BarMark(
        x: .value("Value", $0.sales),
        y: .value("Category", $0.month)
    )
}

自定义图表样式

颜色:可以自定义每个 Mark 的颜色。

图例:通过 .chartLegend() 添加图例。

轴样式:自定义轴线、刻度和标签。

BarMark(
    x: .value("Category", "Electronics"),
    y: .value("Revenue", 1000)
)
.foregroundStyle(Color.blue)

数据动态更新

Charts 的数据源可以绑定到动态数据模型,从而支持实时更新。

@State private var salesData = [
    SalesData(month: "Jan", sales: 200),
    SalesData(month: "Feb", sales: 150)
]

Button("Add Data") {
    salesData.append(SalesData(month: "Mar", sales: 300))
}

Mark参数

在 SwiftUI 的 Charts 中,每个 Mark 都有多个参数,因为它们提供了高度的灵活性和可定制性。这些参数控制图表的外观和行为,使其适配不同的数据结构和可视化需求。

参考示例

struct SampleRating {
    let place: String
    let rating: Int
    
    static let ratings: [SampleRating] = [
        SampleRating(place: "Bellagio", rating: 88),
        SampleRating(place: "Paris", rating: 75),
        SampleRating(place: "Treasure Island", rating: 33),
        SampleRating(place: "Excalibur", rating: 88)
    ]
}

struct VegasChart: View {
    var body: some View {
        Chart(SampleRating.ratings, id: \.place) { rating in
            SectorMark(angle: .value("Ratings", rating.rating), innerRadius: .ratio(0.5), angularInset: 1)
                .cornerRadius(7)
                .foregroundStyle(by: .value("Place", rating.rating))
        }
        .padding()
        .frame(height: 500)
    }
}

在这段SectorMark的代码中:

1)angle控制扇形的角度大小:.value(“Ratings”, rating.rating) 表示从数据中取 rating.rating 作为角度值,并将该数据绑定到图表的 “Ratings” 维度。

2)innerRadius设置扇形的内半径:.ratio(0.5) 表示内半径是图表外半径的 50%。

3)angularInset设置扇形的间隔角度:angularInset: 1 表示在每个扇形之间留出 1° 的间隙, 提高了可视化的清晰度,特别是在扇形数据较多时。

4)cornerRadius设置扇形的边缘圆角:.cornerRadius(7) 会使扇形的外边缘变得平滑。

5)foregroundStyle设置扇形的不同颜色:.value(“Place”, rating.rating) 将数据绑定到 “Place” 维度, Charts 会自动为不同的 “Place” 分配不同的颜色。通过颜色区分数据类别,提高数据的可读性

高级功能

组合图表:在一个图表中叠加不同类型的 Mark。

动画效果:通过 withAnimation 添加动态效果。

筛选数据:使用 SwiftUI 的 Filter。

实用场景

数据可视化:展示统计数据(如财务报表、用户增长趋势)。

健康和活动:显示步数、心率等。

科学实验:展示实验结果图表。

总结

SwiftUI Charts 是高度灵活的工具,可以通过以上类型以及自定义样式满足大多数数据可视化需求。

参考文章

iOS 18, SwiftUI 6, & Swift 6: 从零开始构建iOS应用程序, 涵盖visionOS, macOS, watchOS:https://www.bilibili.com/video/BV1b6421f7Px?spm_id_from=333.788.videopod.episodes&vd_source=f21219cb93118beac6a36b0ef961df6a&p=11

扩展知识

Argument ‘x’ must precede argument ‘y’报错

如果遇到以下报错:

Argument 'x' must precede argument 'y'
Replace 'y: .value("Category", $0.month),
x: .value("Value", $0.sales)' with 'x: .value("Value", $0.sales), y: .value("Category", $0.month)'

问题原因为:在 SwiftUI 的 Charts 框架中,参数的顺序有特定要求。BarMark 的参数顺序规定 x 必须在 y 之前。提示 Argument ‘x’ must precede argument ‘y’ 的原因正是因为代码中将 y 参数写在了 x 参数之前,违反了 API 的定义。

解决方案:根据提示修改参数的顺序即可。

BarMark(
    x: .value("Value", $0.sales), // x 参数在前
    y: .value("Category", $0.month) // y 参数在后
)

设置X轴和Y轴的范围

如果想要调整图表的X轴和Y轴范围,可以通过chartXScale和chartYScale进行调整:

Chart(SampleRating.ratings, id: \.trip) { rating in
    PointMark(x: .value("Year", rating.trip), y: .value("Ratings", rating.trip - 2020 + 88))
    LineMark(x: .value("Year", rating.trip), y: .value("Ratings", rating.rating))
}
.chartXScale(domain: 2020...2024)
.chartYScale(domain: 1...100)

chartXScale 和 chartYScale 是用于设置图表的 X 轴 和 Y 轴范围的修饰符。它们控制图表显示数据的范围,并帮助调整坐标轴的显示。

chartXScale(domain:):用于设置 X 轴的显示范围。可以定义一个 domain,例如 2020…2025,表示 X 轴的范围从 2020 到 2025。

chartYScale(domain:):用于设置 Y 轴的显示范围。可以定义一个 domain,例如 1…100,表示 Y 轴的范围从 1 到 100。

如果您认为这篇文章给您带来了帮助,您可以在此通过支付宝或者微信打赏网站开放者。

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注