返回

SwiftUI Charts:解决Y轴标签过近问题

IOS

SwiftUI Charts:解决 Y 轴标签与图表边缘过近的问题

在使用 SwiftUI Charts 构建数据可视化时,一个常见的问题是 Y 轴标签与图表边缘过于靠近,影响美观和可读性。如何有效地调整 Y 轴位置,增加标签的“呼吸空间”,成为需要解决的问题。本文章分析原因并提供几种解决方案。

问题分析

默认情况下,SwiftUI Charts 尝试最大化图表的使用空间。这可能会导致 Y 轴的标签紧贴图表的边缘。想要实现偏移效果,需要在轴的呈现方式上做调整。

解决方案一:使用 chartYAxisAxisMarks

利用 chartYAxis 修饰符结合 AxisMarks 来自定义 Y 轴,可以更精确地控制标签的位置和间距。此方法通过显式设置 AxisMarksposition 属性为 .leading,可以控制标签出现在轴的左侧,避免标签过于靠近边缘。此外,调整 AxisValueLabelanchor 可以微调标签对齐方式。

操作步骤:

  1. 使用 chartYAxis 修饰符包裹图表。
  2. chartYAxis 中,使用 AxisMarks 定义 Y 轴的刻度线、网格线和标签。
  3. 设置 AxisMarksposition 参数为 .leading
  4. 通过调整 AxisValueLabelanchor 属性,比如 anchor: .trailing,可以使标签靠右对齐,与轴线之间产生间距。
  5. 使用 .chartYAxisLabel 控制 Y轴标题和图表的间距。

代码示例:

import SwiftUI
import Charts

struct UserTypesChart: View {
    @State var data: [RowPlottableData]

    var body: some View {
        GroupBox("User Totals Chart") {
            Chart(data) { inRowData in
                ForEach(inRowData.data, id: \.userType) { inUserTypeData in
                    BarMark(
                        x: .value("Date", inRowData.date),
                        y: .value("Users", inUserTypeData.value)
                    )
                    .foregroundStyle(by: .value("User Type", inUserTypeData.userType))
                }
            }
            .chartYAxisLabel("Users", spacing: 12)
            .chartYAxis {
                AxisMarks(preset: .aligned, position: .leading) { _ in
                    AxisGridLine()
                    AxisValueLabel(anchor: .trailing) // 调整标签对齐方式
                }
            }
            .chartXAxisLabel("Date", alignment: .bottom)
            .chartXAxis {
                AxisMarks(preset: .aligned, position: .bottom) { _ in
                    AxisGridLine()
                    AxisValueLabel()
                }
            }
        }
        .padding()
    }

    struct RowPlottableData: Identifiable {
        let id = UUID()
        let date: Date
        let data: [UserTypeData]
    }

    struct UserTypeData: Identifiable {
        let id = UUID()
        let userType: String
        let value: Int
    }

    // 用于预览的数据
    static var sampleData: [RowPlottableData] = [
        RowPlottableData(date: Date(timeIntervalSince1970: 1698326400), data: [
            UserTypeData(userType: "New", value: 25),
            UserTypeData(userType: "Established", value: 75)
        ]),
        RowPlottableData(date: Date(timeIntervalSince1970: 1698412800), data: [
            UserTypeData(userType: "New", value: 30),
            UserTypeData(userType: "Established", value: 70)
        ])
    ]
}

#Preview {
    UserTypesChart(data: UserTypesChart.sampleData)
}

注意: position: .leading 指定轴线和标签位于图表的起始位置(通常是左侧),可以理解为将 Y 轴整体左移,从而为标签提供更多空间。anchor: .trailing 通过调整锚点,将文本的尾部对齐到指定位置,可以实现标签的右对齐,产生视觉上的间距。

解决方案二:控制X轴日期分组的粒度

若数据点过于密集,也会导致图表元素挤在一起,此时适当调整 X 轴的日期分组粒度,也能有效改善 Y 轴标签的显示效果。Chart 默认根据数据密度自动推断 X 轴的分组方式。 如果默认分组不满足需求,可进行手动指定。

操作步骤:

  1. 分析数据的日期分布情况,判断是否过于密集。
  2. 使用 .chartXAxis 修饰符自定义 X 轴。
  3. 根据需要使用 AxisMarksstride 参数,例如: stride: .daystride: .hour

代码示例:

在之前代码示例的基础上,添加或者修改 chartXAxis部分。

            .chartXAxis {
                AxisMarks(preset: .aligned, position: .bottom, stride: .day) { value in // 指定按天显示
                    AxisGridLine()
                    AxisValueLabel(format: .dateTime.day().month()) // 调整标签的格式
                }
            }

stride: .day 表示X轴上的刻度线和标签将按天显示,避免过度拥挤。format可以对日期格式化显示。根据数据的实际间隔调整stride的参数,如 .hour, .day, .month, .year等,并配合format使用,可以灵活控制X轴日期标签的展示。

总结

上述方法并非互斥,可以结合使用,灵活调整 SwiftUI Charts 中 Y 轴标签的位置。 理解 AxisMarks 各个参数的作用,才能更加有效的控制图表显示。