Swiftui Charts

I have a SwiftUI LineMark chart that inverts the y axis when the data the chart is plotting is all zeros. I'm expecting the y axis 0 to be at the bottom but when the data is all zeros it's at the top. Below is an example demonstrating the problem:

import SwiftUI import Charts

struct ChartView: View { let data: [Double] = [0,0,0,0,0]

var body: some View {
    Chart {
        ForEach(data.indices, id: \.self) { index in
            LineMark(
                x: .value("Index", index),
                y: .value("Value", data[index])
            )                
        }
    }
    .chartYAxis {

            AxisMarks(values: [0, 10, 20, 30, 40, 50]) { value in
                AxisValueLabel()
                AxisTick()
                AxisGridLine()
            }

    }
    .padding()
}

}

I can't use .chartYScale(domain: ) because it overrides the chartYAxis where the real code creates custom a leading and trailing y axis.

Does anyone have any suggestions how I may fix this?

Answered by DTS Engineer in 825727022

Our engineering teams need to investigate this issue, as resolution may involve changes to Apple's software. Please file a bug report, include a small Xcode project and some directions that can be used to reproduce the problem, and post the FB number here once you do.

Bug Reporting: How and Why? has tips on creating your bug report.

Very strange indeed.

I've tried using RuleMark as explained here: https://stackoverflow.com/questions/78873602/reverse-y-axis-of-swiftui-chart

But get the same flipping.

It does not occur if all values are equal but non zero:

let data: [Double] = [10, 10, 10, 10, 10]

Looks like a side effect of a "zero divide" (between the default minimum zero of y axis and the found max which is also 0) : when all values are equal, it wrongly computes the orientation (as you will see, chartYScale corrects this by providing the orientation).

You should file a bug report.

I found a solution using chartYScale:

struct ChartView: View { 
    
    let data: [Double] = [0, 0, 0, 0, 0] 
    var body: some View {
        Chart {
            ForEach(data.indices, id: \.self) { index in
                LineMark(
                    x: .value("Index", index),
                    y: .value("Value", data[index])
                )
            }
        }
        .chartYScale(domain: [0, 50])  // <<-- Added this
        
        .chartYAxis {
            
            AxisMarks(values: [0, 10, 20, 30, 40, 50]) { value in
                AxisValueLabel()
                AxisTick()
                AxisGridLine()
            }
            
        }
        .padding()
    }
}

Thanks Claude, I agree it is rather strange and feels like a bug.

I should explain that in the real code I’ve created a generic view containing a chart that can plot different types of data e.g. speed, temperature, pressure with different scales. In one case temperature and humidity are shown at the same time using different leading and trailing scales. The scales for the data are part of the data model. This means I can’t use a static scale for chartYScale, the scale needs to adjust depending on the data being plotted.

I found a work around using chartYScale and pass a function to chartYScale that returns a range e.g.
.chartYScale( domain: self.yAxisDomain(), type: .linear )

The function works out what the scale should be depending on the data being plotted and is scale in the data model. The crucial thing is the function needs to produce the same scale as the code under chartYAxis, then scales values are as expected and no inversion occurs.

Our engineering teams need to investigate this issue, as resolution may involve changes to Apple's software. Please file a bug report, include a small Xcode project and some directions that can be used to reproduce the problem, and post the FB number here once you do.

Bug Reporting: How and Why? has tips on creating your bug report.

Thanks DTS Engineer.

I've raised bug: FB16531231.

Swiftui Charts
 
 
Q