user2529173
user2529173

Reputation: 1924

ios charts label for every bar

I'm using ios charts to display a bar chart. That looks like this:

enter image description here

What I want to achive are the labels in the red box (for all bars, I just didn't want to repeat this so often... :P ). That means that every bar get its own "title" label so the user sees the name of the category for every value.

Another question would be: The more bars I add, the smaller the bars get. Can I somehow put the BarChartView into a scroll view, set the width of the bars to a static value and for example, there are 20 more values, the user just scrolls to the right to see more values?

Edit code:

  func entries(for chart:ChartType, content:ChartContent, max:Int = Int.max)->[ChartDataEntry]{
    let transactions = manager.transactions.value
    let grouped = content == .category ? transactions.categorise({$1.category}) : transactions.categorise({$1.payee})
    var entries:[ChartDataEntry] = []
    let formatter = NumberFormatter()
    formatter.locale = Locale.current
    formatter.numberStyle = .currency

    for i in 0..<grouped.count {
      let c = Array(grouped.keys)[i]
      let ts = grouped[c]!
      var sum = 0.0
      ts.forEach{k,t in
        if t.expense{
           sum +=  Double(t.value)
        }
      }
      if chart == .pie{
        let entry =  PieChartDataEntry(value: sum, label: "\(c)")
        if entries.count < max{
          entries.append(entry)
        }else{
          entries.sort(by: {$0.0.y > $0.1.y})
          break
        }

      }else if chart == .bar{
        let entry =  BarChartDataEntry(x: Double(i), y: sum, data: c as AnyObject?)
        if entries.count < max{
          entries.append(entry)
        }else{
          entries.sort(by: {$0.0.y > $0.1.y})
          break
        }
      }

    }


    return entries
  }

  func showBarChart(content: ChartContent){
    // Do any additional setup after loading the view.

    let data = BarChartData()
    let content = entries(for: .bar, content: content)
    let ds1 = BarChartDataSet(values: content, label: "")

    let xAxis=XAxis()
    let chartFormmater = ChartFormatter()
    chartFormmater.content = content as! [BarChartDataEntry]

    for i in 0..<content.count{

      chartFormmater.stringForValue(Double(i), axis: xAxis)
    }

    xAxis.valueFormatter=chartFormmater
    barChartView.xAxis.valueFormatter=xAxis.valueFormatter
    barChartView.xAxis.labelPosition = .bottom


    ds1.colors = ChartColorTemplates.material()

    data.addDataSet(ds1)

    self.barChartView.data = data

    self.barChartView.gridBackgroundColor = NSUIColor.white



    self.barChartView.animate(xAxisDuration: 0.0, yAxisDuration: 1.0)
  }
@objc(BarChartFormatter)
class ChartFormatter:NSObject,IAxisValueFormatter{

  var content:[BarChartDataEntry]!

  func stringForValue(_ value: Double, axis: AxisBase?) -> String {
    return content[Int(value)].data as! String
  }

}

New Screenshot: enter image description here

Upvotes: 4

Views: 14091

Answers (4)

Hernan Arber
Hernan Arber

Reputation: 1636

To Complement the previous answers, if you DO WANT to display all values and you have more than 25 Values, remember to modify the Hardcoded Limit for the LabelCount within AxisBase.swift, Like this:

    open var labelCount: Int
    {
        get
        {
            return _labelCount
        }
        set
        {
            _labelCount = newValue
            // WHY?
            // This limits the Amount of Labels We can Display: (Removing) -> Comment OUT
//            
//            if _labelCount > 25
//            {
//                _labelCount = 25
//            }
//            if _labelCount < 2
//            {
//                _labelCount = 2
//            }
//            
            forceLabelsEnabled = false
        }
    }

I Hope this Helps :-)

Upvotes: 1

user5886755
user5886755

Reputation:

you can implement this below code, to solve you both the problems.

Here in below function, I'm passing two parameters, i.e dataPoints : x-Axis Labels, and values : values for bars. It also solves your scrolling problem.

func setChart(dataPoints: [String], values: [Float])
{
    barChartView.noDataText = "You need to provide data for the chart."

    for i in 1..<values.count
    {
        let dataEntry = BarChartDataEntry(x: Double(i), yValues: [Double(values[i])])
        dataEntries.append(dataEntry)
    }

    let chartDataSet:BarChartDataSet!

    let chartDataSet = BarChartDataSet(values: dataEntries, label: "BarChart Data")
    let chartData = BarChartData(dataSet: chartDataSet)
    barChartView.data = chartData
    barChartView.xAxis.valueFormatter = IndexAxisValueFormatter(values: dataPoints)
    barChartView.xAxis.granularityEnabled = true
    barChartView.xAxis.drawGridLinesEnabled = false
    barChartView.xAxis.labelPosition = .bottom
    barChartView.xAxis.labelCount = 30
    barChartView.xAxis.granularity = 2
    barChartView.leftAxis.enabled = true
    //barChartView.leftAxis.labelPosition = .outsideChart
    //barChartView.leftAxis.decimals = 0
    let minn = Double(values.min()!) - 0.1
    barChartView.leftAxis.axisMinimum = Double(values.min()! - 0.1)
    //barChartView.leftAxis.granularityEnabled = true
    //barChartView.leftAxis.granularity = 1.0
    //barChartView.leftAxis.labelCount = 5
    barChartView.leftAxis.axisMaximum = Double(values.max()! + 0.05)
    barChartView.data?.setDrawValues(false)
    barChartView.pinchZoomEnabled = true
    barChartView.scaleYEnabled = true
    barChartView.scaleXEnabled = true
    barChartView.highlighter = nil
    barChartView.doubleTapToZoomEnabled = true
    barChartView.chartDescription?.text = ""
    barChartView.rightAxis.enabled = false


    barChartView.animate(xAxisDuration: 2.0, yAxisDuration: 2.0, easingOption: .easeInOutQuart)
    chartDataSet.colors = [UIColor(red: 0/255, green: 76/255, blue: 153/255, alpha: 1)]

}

OR

How to set x-axis labels?

Since Swift 3.0.1, we can also do:

let labels = ["Value 1", "Value 2", "Value 3"]

barChartView.xAxis.valueFormatter = IndexAxisValueFormatter(values:labels)
//Also, you probably we want to add:

barChartView.xAxis.granularity = 1

Hope it helps you.

Upvotes: 10

James Lim
James Lim

Reputation: 83

to answer both your first and second question. What I would recommend you to do would be to have a side scrolling collection view. Inside each collection view cell you can include the title the bar and the value. This would help you all as you repeat as many graphs as you want and like you request you want a scroll view.

Upvotes: 0

muescha
muescha

Reputation: 1539

you can implement IAxisValueFormatter in your own classes:

for this you need only to implement this method:

func stringForValue(_ value: Double, axis: AxisBase?) -> String

Examples:

or you follow the RayWenderlich Tutorial "Using Realm and Charts with Swift 3 in iOS 10":

you have to set some delegates and more but this is the key code snippet for a custom formatter:

// MARK: axisFormatDelegate
extension ViewController: IAxisValueFormatter {

  func stringForValue(_ value: Double, axis: AxisBase?) -> String {
    let dateFormatter = DateFormatter()
    dateFormatter.dateFormat = “HH:mm.ss”
    return dateFormatter.string(from: Date(timeIntervalSince1970: value))
  }
}

Upvotes: 2

Related Questions