I've yet to truly learn how to read and understand - then interpret the Apple Docs so that I can write new code - and it actually compiles. So my biggest outstanding question is - - -
How do I read/comprehend the Apple Charts Documentation?
I've got nothing but heartache reading the docs.
The docs for Charts Framework are improving - but I still have WrapRage.
What's up with Apple's color sense - those objects are not Pink?
Have you found that lines plot outside the bounding box of your Chart?
I found that by default the Chart does NOT clip the marks to the assumed plot area of the chart. So I had to go looking for a way to turn on this behavior. It is the Chart modifier:
.clipped(antialiased: true)
Apple Support said it was NOT a bug. Even when the chart's line lays on top of a button, that now cannot be pressed.
Have you got Charts Questions - send me a TOOT on iosdev.space.
Have you noticed that the Chart( data ) { ... } construct is an implicit loop. And since it is a loop over the data... any content in that loop will be repeatly drawn on the plot.
Constant marks - should NOT be placed inside that loop. Items like RuleMark() are typically a one-off type of item. See: Practice Good Charting Structure. That annotation font for "Average: 68" was not Bold/Strong... it is an artifact of repeated drawing and looping.
There is a Charting detail that I don't understand ... yet. There is this plot...
struct Plot<Content> where Content : ChartContent
A mechanism for grouping chart contents into a single entity.
What does it do? What could a stone-age coder like me do with a Chart that contained a Plot... that contained multiple... pieces of content?
I don't know what to call this thing I've been searching for in the Chart API. I want a chart, with multiple Y axis data domains. I want multiple series plotted, but not using the same scale on the Y axis.
Let me find a picture...
I had hopes that the Plot structure was going to do this complex multiple-series chart. My current thinking is to draw multiple Charts in the ZStack { ... } layered on top of each other...
I've done some hardcore exploring of the Charts API and it still boggles my brain. What is the codex that is used to write such hard-to-understand documentation? How do they manage to write a document that is literately useless?
I didn't notice for months. The coordinate system inversion that Charts naturally does... did you notice that ZERO is at the bottom of your chart Y axis - YEAH! I know - an INVERTED fast one.... sweet Apple!
But here is when I did notice... trying to use and understand the struct PlotDimensionScaleRange object that cannot be instantiated.
Go ahead and try it...
When you do manage to create the Range - Charts will invert the inversion and leave the Zero up at the top of your graph - WHY?
How do I create a chart that groups yearly quarterly sales for multiple locations?
You use the position(by:) modifier - of course.
The art of rounding numbers to "nice" values is... well a mystery too me. I wonder if there is a mathematical study of this process... or is it a human desire and ability to find "round" numbers? So after a bit of searching turns out I'm not the only one searching... and there are some known algorithms.
Ref: Choosing an attractive linear scale for a graph's Y Axis
You might enjoy reading the Wikipedia article about rounding - I did.
This response has Swift Code as well as other language versions:
Nice Label Algorithm for Charts with minimum ticks - Stack Overflow
This response on Stack Overflow has an interesting view of Chart Axis configuration. Response by Sweeper:
Styling chart axes
You can add the axis ticks simply using AxisTick, and the axis lines can be added with AxisGridLine. .foregroundStyle can be added to both of these.
The grid lines "through" the chart that you see are also AxisGridLines added by SwiftUI by default. The defaults will not be added if you use the AxisMarks initialiser that takes a @AxisMarkBuilder closure.
In total, you need 3 sets of AxisMarks for each axis:
one set for the axis labels, every 1 for the y axis, and every 100 for the x axis
one set for the axis ticks, every 0.2 for the y axis, and every 20 for the x axis
one set for the axis grid line. You only need one line for each axis, positioned at the minimum value of each axis' domain.
Additionally, the tick marks should be offsetted, so that the grid lines go though the ticks.
Here is a complete example, where the y axis is (-2, 2), and x axis is (0, 400).
Below is the code:
struct Foo: Identifiable {
let id: Double
let y: Double
}
let data: [Foo] = (0..<400).map { Foo(id: Double($0), y: log2(1 - Double.random(in: 0..<1)) / -10 - 1) }
struct ContentView: View {
var body: some View {
Chart(data) {
LineMark(
x: .value("x", $0.id),
y: .value("y", $0.y)
)
.interpolationMethod(.catmullRom)
.lineStyle(StrokeStyle(lineWidth: 1))
}
.chartXAxisLabel(position: .bottom, alignment: .center) {
Text("X Axis")
}
.chartXScale(domain: [0, 400])
.chartXAxis {
AxisMarks(position: .bottom, values: .stride(by: 100)) {
AxisValueLabel(anchor: .top)
}
AxisMarks(position: .bottom, values: .stride(by: 20)) { value in
if value.index != 0 { // the leftmost value does not need a tick
AxisTick(length: 8, stroke: .init(lineWidth: 1))
.offset(y: -4)
}
}
AxisMarks(position: .bottom, values: [0]) {
AxisGridLine(stroke: .init(lineWidth: 1))
}
}
.chartYAxisLabel(position: .leading, alignment: .center) {
Text("Y Label")
}
.chartYScale(domain: [-2, 2])
.chartYAxis {
AxisMarks(position: .leading, values: .stride(by: 1)) {
AxisValueLabel()
}
AxisMarks(position: .leading, values: .stride(by: 0.2)) { value in
if value.index != 0 { // the bottommost value does not need a tick
AxisTick(length: 8, stroke: .init(lineWidth: 1))
.offset(x: 4)
}
}
AxisMarks(position: .leading, values: [-2]) {
AxisGridLine(stroke: .init(lineWidth: 1))
}
}
.padding()
.aspectRatio(1, contentMode: .fit)
}
}
Look at all the Chart configuration beyond the data...
The Axis config has the chartXScale(domain:) and the chartYScale(domain:) these are simple two value arrays like [0, 400] or [-2, 2].
AxisMarks has position (like .bottom or .leading) and
and you want a text label maybe ("X Axis").
AxisTick has properties length and stroke. And perhaps offset.
AxisGridLine has stroke and lineWidth.