Search code examples
swiftios-charts

Allow PieChartView to hide labels for tiny slices in Swift


I'm making a chart by using chart iOS framework. but the value will overlay when the slice is tiny. How can I hide it? This question is similar to this GitHub link, But I don't understand how it works. Do I just need to add the code in my View Controller or drag the PieChartRenderer.swift file to my project?

Can someone explain to me how to use the pull request or some open public function...

Sorry I'm new in iOS framework.

enter image description here

This is my code.

@IBOutlet weak var myChart: PieChartView!

var valueColors = [UIColor]()
var dataEntries = [PieChartDataEntry]()
var record = [Record]()
var category = [String]()
var categoryTotal : [Double] = []
var categoryArray : [String] = []

func setDataCount() {
    valueAndColor()

    let set = PieChartDataSet(values: dataEntries, label: nil)

    set.colors = valueColors
    set.valueLinePart1OffsetPercentage = 0.8
    set.valueLinePart1Length = 0.2
    set.valueLinePart2Length = 0.4
    set.xValuePosition = .outsideSlice
    set.yValuePosition = .outsideSlice
    set.selectionShift = 0.0

    let data = PieChartData(dataSet: set)
    let Formatter:ChartFormatter = ChartFormatter()
    data.setValueFormatter(Formatter)
    data.setValueFont(.systemFont(ofSize: 11, weight: .light))
    data.setValueTextColor(.black)

    myChart.data = data
    myChart.highlightValues(nil)
}

func setup(pieChartView chartView: PieChartView) {
    chartView.usePercentValuesEnabled = true
    chartView.drawSlicesUnderHoleEnabled = true
    chartView.holeRadiusPercent = 0.58
    chartView.chartDescription?.enabled = false
    chartView.drawCenterTextEnabled = true
    chartView.centerAttributedText = attributedString;
    chartView.drawHoleEnabled = true
    chartView.rotationAngle = 0
    chartView.rotationEnabled = true
    chartView.highlightPerTapEnabled = true
}

func valueAndColor(){
    for i in 0..<categoryArray.count{
        let dataEntry = PieChartDataEntry(value: categoryTotal[i], label: categoryArray[i % categoryArray.count])
        dataEntries.append(dataEntry)

        if categoryArray[i] == "吃喝" {
            valueColors.append(UIColor.yellow)
        }else if categoryArray[i] == "交通"{
            valueColors.append(UIColor.red)
        }...
 }

Solution

  • Create a custom formatter, I set the minNumber as 10.0 and the empty string is returned when a value is less than the minNumber, otherwise the value is returned.

    public class ChartFormatter: NSObject, IValueFormatter{
    
        public func stringForValue(_ value: Double, entry: ChartDataEntry, dataSetIndex: Int, viewPortHandler: ViewPortHandler?) -> String {
    
            let total = UserDefaults.standard.double(forKey: "totalValue")
    
            var valueToUse = value/total * 100
            valueToUse = Double(round(10*valueToUse)/10)
            print("valueToUse: \(valueToUse)")
            let minNumber = 10.0
    
            if(valueToUse<minNumber) {
                return ""
            }
            else {
                return String(valueToUse) + "%"
            }
        }
    
    }    
    

    Then make sure you set the totalValue variable, store it in UserDefaults (to make it possible to access it in the formatter) and set the formatter for your graph

        var totalValue = 0.0
    
        let units = [10.0, 4.0, 6.0, 3.0, 12.0, 16.0]
        for a in units {
            totalValue += a
        }
        UserDefaults.standard.set(totalValue, forKey: "totalValue")
    
        let formatter:ChartFormatter = ChartFormatter()
    
        data.setValueFormatter(formatter)
    

    Result:

    Result