Dan*_*iel 5 swiftui swiftui-charts
我有一个图表,其中包含在 x 轴上跨越多天的WeatherKit.HourWeather对象。但是,我想排除夜间时间。看起来我可以使用 ChartXScale 修改器来做到这一点,如下所示:
let myDataSeperatedByHours = arrayWithAllDates.filter { ... }.sorted(...) // Array of WeatherKit.HourWeather objects filtered by isDaylight = true and sorted by date
let allDaytimeDates = myDataSeperatedByHours.map { $0.date } //only the Date objects
Chart {
ForEach(myDataSeperatedByHours, id: \.date) { hourData in
LineMark(
x: .value("hour", hourData.date),
y: .value("value", hourData.value)
)
}
}
.chartXAxis {
AxisMarks(position: .bottom, values: allDaytimeDates) { axisValue in
if let date = axisValue.as(Date.self) {
AxisValueLabel(
"\(Self.shortTimeFormatter.calendar.component(.hour, from: date))"
)
}
}
}
.chartXScale(domain: allDaytimeDates, type: .category)
Run Code Online (Sandbox Code Playgroud)
然而,图表仍然显示没有值的部分。(夜间)我希望晚上的时候把所有东西都移走。我在下图中将其标记为绿色。也许我必须使用两个相邻的图表。每天一张,但我不敢相信只用一张图表是不可能做到的。
我创建了一个示例应用程序,您可以在此处下载和测试: https: //github.com/Iomegan/DateChartIssue
根据域参数的图表比例修改器文档:
图表中 x 轴的可能数据值。您可以使用 ClosedRange 定义域以表示数字或日期值(例如,0 ... 500),并使用数组定义域以表示分类值(例如,[“A”、“B”、“C”])
对于日期类型值,该函数似乎需要一个范围,但由于您指定了一个数组,因此该方法调用会陷入困境。
您可以提供修改推断域的自动缩放域,而不是直接提供域。要将域设置为您计算的allDaytimeDates使用量:
.chartXScale(domain: .automatic(dataType: Date.self) { dates in
dates = allDaytimeDates
})
Run Code Online (Sandbox Code Playgroud)
您可以尝试多种方法来忽略 X 轴上的夜间日期刻度。更简单且不推荐的方法是在线条标记中提供 X 轴值作为 aString而不是Date。
指定 X 轴值的问题是,Date您只能提供轴刻度的范围,并且您现在不能选择多个范围作为轴的刻度,同样,您不能指定刻度来忽略某些范围或值(即夜间)。通过将 X 轴值指定为字符串,您将能够忽略夜间值:
LineMark(
x: .value("hour", "\(hourData.date)"),
y: .value("value", hourData.value)
)
Run Code Online (Sandbox Code Playgroud)
这种方法的缺点是从该图中获得的温度变化是错误的,因为所有数据点都将被平等地分开,无论其日期值如何。
首选方法是手动调整第二天数据点的 X 轴位置。对于您的场景,您可以创建一个DayHourWeather具有自定义 X 位置值的类型:
struct DayHourWeather: Plottable {
let position: TimeInterval // Manually calculated X-axis position
let date: Date
let temp: Double
let series: String // The day this data belongs to
var primitivePlottable: TimeInterval { position }
init?(primitivePlottable: TimeInterval) { nil }
init(position: TimeInterval, date: Date, temp: Double, series: String) {
self.position = position
self.date = date
self.temp = temp
self.series = series
}
}
Run Code Online (Sandbox Code Playgroud)
您可以自定义position数据,将白天的图移得更近,而忽略夜间值。DayHourWeather然后你可以从你的 s创建s HourWeather:
/// assumes `hourWeathers` are filtered containing only day time data and already sorted
func getDayHourWeathers(from hourWeathers: [HourWeather]) -> [DayHourWeather] {
let padding: TimeInterval = 10000 // distance between lat day's last data point and next day's first data point
var translation: TimeInterval = 0 // The negetive translation required on X-axis for certain day
var series: Int = 0 // Current day series
var result: [DayHourWeather] = []
result.reserveCapacity(hourWeathers.count)
for (index, hourWeather) in hourWeathers.enumerated() {
defer {
result.append(
.init(
position: hourWeather.date.timeIntervalSince1970 - translation,
date: hourWeather.date,
temp: hourWeather.temp,
series: "Day \(series + 1)"
)
)
}
guard
index > 0,
case let lastWeather = hourWeathers[index - 1],
!Calendar.current.isDate(lastWeather.date, inSameDayAs: hourWeather.date)
else { continue }
// move next day graph to left occupying previous day's night scale
translation = hourWeather.date.timeIntervalSince1970 - (result.last!.position + padding)
series += 1
}
return result
}
Run Code Online (Sandbox Code Playgroud)
现在要绘制图表,您可以使用新创建的DayHourWeather值:
var body: some View {
let dayWeathers = getDayHourWeathers(from: myDataSeperatedByHours)
Chart {
ForEach(dayWeathers, id: \.date) { hourData in
LineMark(
x: .value("hour", hourData.position), // custom X-axis position calculated
y: .value("value", hourData.temp)
)
.foregroundStyle(by: .value("Day", hourData.series))
}
}
.chartXScale(domain: dayWeathers.first!.position...dayWeathers.last!.position) // provide scale range for calculated custom X-axis positions
}
Run Code Online (Sandbox Code Playgroud)
请注意,通过上述更改,您的 X 轴标记将显示您的自定义 X 轴位置。要将其更改回您想要显示的实际日期标签,您可以指定自定义 X 轴标签:
.chartXAxis {
AxisMarks(position: .bottom, values: dayWeathers) {
AxisValueLabel(
"\(Self.shortTimeFormatter.calendar.component(.hour, from: dayWeathers[$0.index].date))"
)
}
}
Run Code Online (Sandbox Code Playgroud)
valuesfor 的参数仅AxisMarks接受项目数组Plottable,这就是需要确认DayHourWeatherto的原因。Plottable经过上述更改后,获得的图表将类似于以下内容:
请注意,我为每天的数据创建了不同的系列。虽然您可以将它们组合成一个系列,但我建议您不要这样做,因为您要删除部分 X 轴刻度,因此生成的图表会误导查看者。
| 归档时间: |
|
| 查看次数: |
3990 次 |
| 最近记录: |