具有两个数据集的条形图:如何并排放置条形图而不是堆叠?

问题描述 投票:0回答:1

我正在尝试创建一个条形图,它并排显示两个数据集:当前值和平均值。无论我尝试什么,条形图总是堆积如山。

根据我发现的所有信息,这应该可以通过使用

.foregroundStyle(by: .value(...))
和/或
.position(by: .value(...))
来实现。然而,这在这里不起作用。

首先,我很乐意将这些条并排放置。最终目标是将平均条形图稍微偏移到当前条形图后面。

import SwiftUI
import Charts

struct ContentView: View {
    let currentData: [DayData] = (1...15).map { DayData(day: $0, value: Double.random(in: 20...100)) }
    let averageData: [DayData] = (1...15).map { DayData(day: $0, value: Double.random(in: 50...70)) }
    
    var body: some View {
        Chart {
            ForEach(currentData) { day in
                BarMark(
                    x: .value("Day", day.day),
                    y: .value("Current", day.value)
                )
                .foregroundStyle(by: .value("Data Type", "Current"))
                .position(by: .value("Data Type", "Current"))
            }
            
            ForEach(averageData) { day in
                BarMark(
                    x: .value("Day", day.day),
                    y: .value("Average", day.value)
                )
                .foregroundStyle(by: .value("Data Type", "Average"))
                .position(by: .value("Data Type", "Average"))
            }
        }
        .frame(height: 300)
        .padding()
        .chartXAxis {
            AxisMarks(values: currentData.map { $0.day }) { _ in
                AxisTick()
                AxisGridLine()
                AxisValueLabel()
            }
        }
    }
}

// Datensatz für einen Tag
struct DayData: Identifiable {
    let id = UUID()
    let day: Int
    let value: Double
}

#Preview {
    ContentView()
}

enter image description here

swiftui swiftcharts
1个回答
0
投票

这是因为图表的 X 轴是数值数据,而不是分类数据(字符串)。

如果您改为写

x: .value("Day", "\(day.day)")
,则条形图将如您所愿并排排列。由于这是分类数据,因此您也不需要显式地将所有 x 标签传递给
AxisMarks

如果你想保持数据的数值,你需要为条形指定一个

width:
,并传递
axis
span
position(by:)
参数,因为 SwiftUI 无法自动计算出这些数值数据。

ForEach(currentData) { day in
    BarMark(
        x: .value("Day", day.day),
     // this example works for categorical data too if you prefer that
     // x: .value("Day", "\(day.day)"),
        y: .value("Current", day.value),
        width: 12
    )
    .foregroundStyle(by: .value("Data Type", "Current"))
    .position(by: .value("Data Type", "Current"), axis: .horizontal, span: 20)
}

ForEach(averageData) { day in
    BarMark(
        x: .value("Day", day.day),
        y: .value("Average", day.value),
        width: 12
    )
    .foregroundStyle(by: .value("Data Type", "Average"))
    .position(by: .value("Data Type", "Average"), axis: .horizontal, span: 20)
}
.zIndex(-1)

在这里,我使每个条形的宽度略大于

span
的一半,并将平均条形设置为较低的 z-index。我认为这就是您说希望平均柱位于当前柱“后面”时的意思。

您传递给

width
span
的值不需要是简单的数字。他们是
MarkDimension
。阅读文档以了解有关可以使用它们做什么的更多信息。

© www.soinside.com 2019 - 2024. All rights reserved.