4

is it possible to create a Pie / Donut chart using Apple's new Swift Charts framework?

there are images of a pie chart shown in the WWDC videos. Any help or code sample on how to create the pie chart will be much appreciated.

Thanks

shinto Joseph
  • 1,039
  • 3
  • 16
  • 27
  • Not supported yet, you can use `Circle()` & `trim` to build one though. – Timmy Sep 16 '22 at 09:41
  • Thanks @Timmy, I am moving from my custom library to the apple one and in the WWDC they are shown pie chart in the examples, but couldn't find any documentation – shinto Joseph Sep 16 '22 at 10:32
  • 1
    I got reply from Apple Developer Technical Support that, Currently there is no support for pie charts in Swift Charts. I recommend filing an enhancement request asking for this functionality – shinto Joseph Sep 28 '22 at 08:37

3 Answers3

11

Swift Charts does not (yet?) support polar geometry, which is what you need to build pie charts.

I would recommend using a Canvas and drawing the information yourself, something like this:

struct Pie: View {

    @State var slices: [(Double, Color)]

    var body: some View {
        Canvas { context, size in
            let total = slices.reduce(0) { $0 + $1.0 }
            context.translateBy(x: size.width * 0.5, y: size.height * 0.5)
            var pieContext = context
            pieContext.rotate(by: .degrees(-90))
            let radius = min(size.width, size.height) * 0.48
            var startAngle = Angle.zero
            for (value, color) in slices {
                let angle = Angle(degrees: 360 * (value / total))
                let endAngle = startAngle + angle
                let path = Path { p in
                    p.move(to: .zero)
                    p.addArc(center: .zero, radius: radius, startAngle: startAngle, endAngle: endAngle, clockwise: false)
                    p.closeSubpath()
                }
                pieContext.fill(path, with: .color(color))

                startAngle = endAngle
            }
        }
        .aspectRatio(1, contentMode: .fit)
    }
}

struct Pie_Previews: PreviewProvider {
    static var previews: some View {
        Pie(slices: [
            (2, .red),
            (3, .orange),
            (4, .yellow),
            (1, .green),
            (5, .blue),
            (4, .indigo),
            (2, .purple)
        ])
    }
}

enter image description here

To make a donut chart, clip the canvas as the first thing you do in the rendering closure:

let donut = Path { p in
    p.addEllipse(in: CGRect(origin: .zero, size: size))
    p.addEllipse(in: CGRect(x: size.width * 0.25, y: size.height * 0.25, width: size.width * 0.5, height: size.height * 0.5))
}
context.clip(to: donut, style: .init(eoFill: true))

enter image description here

jrturton
  • 118,105
  • 32
  • 252
  • 268
1

iOS 17 and later

As of iOS 17, pie and donut charts are now included in Apple's Charts framework.


Simple pie chart example:

enter image description here

Add a SectorMark to create a pie chart.

import Charts

struct ContentView: View {
    var body: some View {
        Chart(PieData.data, id: \.id) { element in
            SectorMark(
                angle: .value("Count", element.count)
            )
            .foregroundStyle(by: .value("Type", element.type))
        }
        .frame(width: 350, height: 350)
    }
}

Simple doughnut chart:

enter image description here

Add an innerRadius to the SectorMark to create a donut.

struct ContentView: View {
    var body: some View {
        Chart(PieData.data, id: \.id) { element in
            SectorMark(
                angle: .value("Count", element.count),
                innerRadius: .ratio(0.5)
            )
            .foregroundStyle(by: .value("Type", element.type))
        }
        .frame(width: 350, height: 350)
    }
}

Pie chart with added features:

enter image description here

Add angularInset to create spacing between sectors.

Add annotation to label the sectors.

Add chartLegend to hide the chart's legend.

struct ContentView: View {
    var body: some View {
        Chart(data, id: \.id) { element in
            SectorMark(
                angle: .value("Count", element.count),
                angularInset: 2.0
            )
            .foregroundStyle(by: .value("Type", element.type))
            .annotation(position: .overlay, alignment: .center) {
                VStack {
                    Text(element.type)
                        .font(.caption)
                    Text("\(element.count, format: .number.precision(.fractionLength(0)))")
                        .font(.caption)
                }
            }
        }
        .chartLegend(.hidden)
        .frame(width: 350, height: 350)
    }
}

Doughnut chart with added features:

enter image description here

Add angularInset to provide spacing between sectors.

Add cornerRadius to add rounded corners to the sectors.

Add annotation to label sectors.

struct ContentView: View {
    var body: some View {
        Chart(data, id: \.id) { element in
            SectorMark(
                angle: .value("Count", element.count),
                innerRadius: .ratio(0.5),
                angularInset: 2.0
            )
            .cornerRadius(5)
            .foregroundStyle(by: .value("Type", element.type))
            .annotation(position: .overlay, alignment: .center) {
                    Text("\(element.count, format: .number.precision(.fractionLength(0)))")
                        .font(.caption)
                        .foregroundColor(.white)
            }
        }
        .frame(width: 350, height: 350)
    }
}

Example data used above:

let data = [
    ShapeModel(type: "Circle",    count: 12),
    ShapeModel(type: "Square",    count: 10),
    ShapeModel(type: "Triangle",  count: 21),
    ShapeModel(type: "Rectangle", count: 15),
    ShapeModel(type: "Hexagon",   count: 8)
]

struct ShapeModel: Identifiable {
    var type: String
    var count: Double
    var id = UUID()
}
Marcy
  • 4,611
  • 2
  • 34
  • 52
  • Is there a way to move the annotations outside of the pie chart? – Fast Jun 11 '23 at 10:36
  • Possibly but in my testing only the overlay and centered annotation seems to work with pie charts at this time. – Marcy Jun 11 '23 at 18:15
-7

Yes it is possible in Apple's new swift UI by using charts, swiftUI and foundation libraries

  • 2
    Even though OP asks whether it's possible, he wants to know _how_. This answer is not helpful as it is. – DarkDust Sep 16 '22 at 09:54
  • thanks @DarkDust for the clarification, in the WWDC video they are showing many more types of charts including pie but there is no code or sample or documentation :( – shinto Joseph Sep 16 '22 at 10:31
  • As it’s currently written, your answer is unclear. Please [edit] to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Sep 21 '22 at 10:54