I'm trying to determine how best to achieve a desired result within Swift Charts.
I'm trying to make a sort-of "reversed" log chart. The use case here is for driving into the details of the percentiles from a series latency values stored within a histogram.
The X axis percentile values I was hoping to achieve was something along the lines of:
10, 50, 90, 99, 99,9, 99.99, 99.999
With those values being fairly evenly distributed across the chart. If I look at this from an inverted sequence of:
( 1 - (some value) ).reversed()
where the values are:
0.00001, 0.0001, 0.0001, 0.001, 0.01, 0.5, 0.1
But I've been struggling with how to start with those values, scale the X axis using a 1-value
kind of setup, and then overlaying the values that are more human readable to achieve the end result.
Any suggestions on how to tackle this scenario with customizing a chart axis?
I found a solution, although I had to go tweaking my origin data to enable it.
I switched the percentiles reported out of my data structure so that they represented 1.0 - the_original_percentile to get numbers into a log range that could be represented. Following that, the keys were figuring out chartXScale
and chartXAxis
with a closure to tweak the values presented as labels using AxisValueLabel
.
For anyone else trying to make a service latency review chart and wanting to view the outliers at wacky high percentiles, here's the gist:
Chart {
ForEach(Converter.invertedPercentileArray(histogram), id: \.0) { stat in
LineMark(
x: .value("percentile", stat.0),
y: .value("value", stat.1)
)
// Use curved line to join points
.interpolationMethod(.monotone)
}
}
.chartXScale(
domain: .automatic(includesZero: false, reversed: true),
type: .log
)
.chartXAxis {
AxisMarks(values: Converter.invertedPercentileArray(histogram).map{ $0.0 }
) { value in
AxisGridLine()
AxisValueLabel(centered: true, anchor: .top) {
if let invertedPercentile = value.as(Double.self) {
Text("\( ( (1 - invertedPercentile)*100.0).formatted(.number.precision(.significantDigits(1...5)))) ")
}
}
}
}
Although of note - at least in Xcode Version 14.3 beta 2 (14E5207e), using "reversed:true" in the ScaleDomain
caused the simulator to crash. (filed as FB12035575)
In a macOS app, there wasn't any issue
Resulting chart: