Search code examples
swiftswiftuiswiftui-charts

Hiding a zero annotation on a Swift Charts donut chart


I have made a donut chart in Swift Charts. It can have 3 segments representing items in the user's data with problems (red), warnings (orange) or normal items (secondary / neutral colour).

Sometimes the segments might have a zero value, but I have noticed that the annotation still displays zero and it looks messy. I would like to hide this.

In this image, the zero annotation of the absent orange segment is circled in blue.

Donnut chart with unwanted zero annotation highlighted in blue

Here is my code:

Chart(data, id: \.category) { element in
    Plot {
        SectorMark(
            angle: .value("Count", element.count),
            // These settings make the red and orange sections more prominent
            innerRadius: .inset(element.category == .Nominal ? 32 : 40),
            outerRadius: .inset(element.category == .Nominal ? 8 : 0),
            angularInset: 2.0
        )
            .cornerRadius(4)
            .foregroundStyle(by: .value("Category", element.category.rawValue))
            // Here is the styling for the annotations
            .annotation(position: .overlay, alignment: .center) {
                Text("\(element.count)")
                    .font(.title3)
                    .fontWeight(.semibold)
                    .foregroundStyle(Color.systemGroupedBackground.opacity(0.8))
            }
        }
            .accessibilityLabel(element.category.rawValue.capitalized)
            .accessibilityValue("\(element.count) items")
    }
        .chartForegroundStyleScale(
            domain: IssueCategory.allCases,
            range: [.red, .orange, .secondary.opacity(0.5)]
        )
        .chartPlotStyle { plotArea in
            plotArea
                .background(Color.clear)
                .cornerRadius(8)
        }
        .accessibilityChartDescriptor(self)
        .chartXAxis(.visible)
        .chartXScale(domain: 0...drugs.count)
        .chartYScale(range: .plotDimension(endPadding: -8))
        .chartLegend(.hidden)
        .chartBackground { proxy in
            Text("\(drugs.count)")
                .font(.title)
                .fontWeight(.semibold)
                .foregroundStyle(.secondary)
        }
            .frame(height: 196)

In summary, I'm hoping to hide the annotation (a number label in my case) if it is zero and thus it's segment is not being displayed.


Solution

  • .annotation takes a @ViewBuilder closure, so you can just use an if statement:

    .annotation(position: .overlay, alignment: .center) {
        if element.count > 0 {
            Text("\(element.count)")
        }
    }