Reputation: 1924
I'm using ios charts to display a bar chart. That looks like this:
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
}
}
Upvotes: 4
Views: 14091
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
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
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
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:
DefaultAxisValueFormatter -> here you can use a block to add your custom calculation
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