iOS Charts - How to set the y values under the x axis - ios

I'm using the danielgindi/Charts library and I'm trying to put the Y Value under the X axis.
At the moment I have this:
And I need this:
My code:
private func setupBarChart(){
var barChart = BarChartView(frame: frame)
barChartContainer.addSubview(barChart)
let labels = ["Ericsson", "Siemens", "Huawei", "Ericsson", "Siemens"]
barChartContainer.addConstraintsWithFormat("H:|[v0]|", views: barChart)
barChartContainer.addConstraintsWithFormat("V:|[v0]|", views: barChart)
let entry1 = BarChartDataEntry(x: 0, y: 3670)
let set1 = BarChartDataSet(values: [entry1], label: labels[0])
set1.setColor(UIColor.cnBlue)
let entry2 = BarChartDataEntry(x: 1, y: 2292)
let set2 = BarChartDataSet(values: [entry2], label: labels[1])
set2.setColor(UIColor.cnBlue)
let entry3 = BarChartDataEntry(x: 2, y: 3670)
let set3 = BarChartDataSet(values: [entry3], label: labels[2])
set3.setColor(UIColor.cnBlue)
let entry4 = BarChartDataEntry(x: 3, y: 2292)
let set4 = BarChartDataSet(values: [entry4], label: labels[3])
set4.setColor(UIColor.cnBlue)
let entry5 = BarChartDataEntry(x: 4, y: 675)
let set5 = BarChartDataSet(values: [entry5], label: labels[4])
set5.setColor(UIColor.cnBlue)
let data = BarChartData(dataSets: [set1, set2, set3, set4, set5])
barChart.data = data
barChart.drawGridBackgroundEnabled = false
barChart.drawValueAboveBarEnabled = false
barChart.drawBordersEnabled = false
barChart.legend.enabled = false
barChart.chartDescription?.text = "Sites per technology"
barChart.chartDescription?.textAlign = .center
barChart.chartDescription?.position = CGPoint(x: barChartContainer.bounds.width/2, y: 0)
barChart.xAxis.labelPosition = .bottom
barChart.xAxis.drawGridLinesEnabled = false
barChart.xAxis.wordWrapEnabled = true
barChart.xAxis.labelFont = .cnFont(ofSize: 14, weight: .semibold)
barChart.xAxis.valueFormatter = DefaultAxisValueFormatter(block: {(index, _) in
return labels[Int(index)]
})
barChart.leftAxis.enabled = false
barChart.rightAxis.enabled = false
barChart.drawValueAboveBarEnabled = false
barChart.doubleTapToZoomEnabled = false
barChart.pinchZoomEnabled = false
barChart.scaleXEnabled = false
barChart.scaleYEnabled = false
barChart.setExtraOffsets(left: 10, top: 10, right: 10, bottom: 10)
barChart.fitBars = true
barChart.animate(xAxisDuration: 1, yAxisDuration: 1, easingOption: .easeInOutCirc)
}
Do I have to make a custom AxisRenderer and if so can you give me some leads on this? I have been searching for examples but I still haven't been able to understand how to get what I need with the renderer.
Thank you in advance!

You can implement IAxisValueFormatter protocol this way
struct Label {
var text: String
var value: Double
}
public class DayAxisValueFormatter: NSObject, IAxisValueFormatter {
var xToY = [Double: Label]()
public func stringForValue(_ value: Double, axis: AxisBase?) -> String {
return "\(xToY[value]!.text ),\n\(xToY[value]!.value)"
}
}
Then assign this formatter to x axis
let f = DayAxisValueFormatter(chart: chartView)
f.xToY = [
0: Label(text: "Biemens", value: 6354),
1: Label(text: "Siemens", value: 2344),
2: Label(text: "Ericsson", value: 2345),
3: Label(text: "Huawei", value: 5241),
4: Label(text: "Shmericsson", value: 3525)
]
barChart.xAxis.valueFormatter = f

Related

show all axis lines without zoom linechart

Hello i want to see all records in line-chart but without zoom, at this time if i don't zoom it does not show lines u can see in screenshots please guide me This image is Without Zoom, for example if there are 100 records i want to draw all lines but without zoom i need to see them
After zoom i can see lines
this is how i set data
func setDataCount() {
// lineChartView.clear()
var systolicArray :[ChartDataEntry] = []
var diastolicArray:[ChartDataEntry] = []
var pulseArray:[ChartDataEntry] = []
systolicArray.removeAll()
diastolicArray.removeAll()
pulseArray.removeAll()
let systolicSortingByDate = systolic.sorted(by: { $0.date > $1.date})
// print("---Dumb:\(dump(systolicSortingByDate))")
for data in systolic {
let timeIntervalForDate: TimeInterval = AppData.stringToDate(date: data.date).timeIntervalSince1970
let systolicChart = ChartDataEntry(x: Double(timeIntervalForDate), y: Double(data.systolicReading), icon: #imageLiteral(resourceName: "editprofile"))
systolicArray.append(systolicChart)
}
for data in diastolic {
let timeIntervalForDate: TimeInterval = AppData.stringToDate(date: data.date).timeIntervalSince1970
let diastolicChart = ChartDataEntry(x: Double(timeIntervalForDate), y: Double(data.diastolicReading), icon: #imageLiteral(resourceName: "editprofile"))
diastolicArray.append(diastolicChart)
}
for data in pulse {
let timeIntervalForDate: TimeInterval = AppData.stringToDate(date: data.date).timeIntervalSince1970
let diastolicChart = ChartDataEntry(x: Double(timeIntervalForDate), y: Double(data.pulseReading), icon: #imageLiteral(resourceName: "editprofile"))
pulseArray.append(diastolicChart)
}
print("SystolicCount:\(systolic.count)")
let set1 = LineChartDataSet(values: systolicArray, label: "Systolic")
set1.drawIconsEnabled = false
set1.highlightLineDashLengths = [5, 2.5]
set1.setColor(UIColor().HexToColor(hexString: "ff8a00"))
set1.setCircleColor((UIColor().HexToColor(hexString: "ff8a00")))
set1.lineWidth = 4
set1.circleRadius = 3
set1.drawCircleHoleEnabled = true
set1.valueFont = .systemFont(ofSize: 9)
set1.formLineDashLengths = [5, 2.5]
set1.formLineWidth = 2
set1.formSize = 15
let set2 = LineChartDataSet(values: diastolicArray, label: "Diastolic")
set2.drawIconsEnabled = false
set2.setColor(.black)
set2.setCircleColor(.black)
set2.lineWidth = 4
set2.circleRadius = 3
set2.drawCircleHoleEnabled = true
set2.valueFont = .systemFont(ofSize: 9)
set2.formLineDashLengths = [5, 2.5]
set2.formLineWidth = 2
set2.formSize = 15
let set3 = LineChartDataSet(values: pulseArray, label: "Pulse")
set3.drawIconsEnabled = false
set3.setColor(UIColor().HexToColor(hexString: "e83636"))
set3.setCircleColor(UIColor().HexToColor(hexString: "e83636"))
set3.lineWidth = 4
set3.circleRadius = 3
set3.drawCircleHoleEnabled = true
set3.valueFont = .systemFont(ofSize: 9)
set3.formLineDashLengths = [5, 2.5]
set3.formLineWidth = 2
set3.formSize = 15
lineChartView.rightAxis.enabled = true
lineChartView.xAxis.setLabelCount(systolicArray.count, force: false)
let data = LineChartData(dataSets: [set1,set2,set3])
lineChartView.data = data
let xAxisValue = lineChartView.xAxis
xAxisValue.valueFormatter = axisFormatDelegate
xAxisValue.setLabelCount(4, force: false)
lineChartView.animate(xAxisDuration: 3, yAxisDuration: 3)
// lineChartView.xAxis.granularity = 0.5
}

How can I show first value and last value in line Chart

I'm using charts library and i'm trying to add first value and last value on line chart graph.Please let me know how can I achieve it. I have tried customising drawValue method in linechartrenderer but didn't worked.
Here is my code
var months = ["Dec 15", "Jun 16", "Dec 16", "Jun 17", "Dec 17", "Jun 18"]
var unitsSold = [50.0, 25.0, 50.0, 75.0, 100.0, 75.0]
Viewdidload:
setChart(dataPoints: months, values: unitsSold)
Method:
func setChart(dataPoints: [String], values: [Double]) {
var dataEntries: [ChartDataEntry] = []
for i in 0..<dataPoints.count {
let dataEntry = ChartDataEntry(x: Double(i), y: values[i], data: dataPoints[i] as AnyObject)
dataEntries.append(dataEntry)
}
let chartDataSet = LineChartDataSet(values: dataEntries, label: nil)
chartDataSet.setColor(UIColor(red: 53/255, green: 85/255, blue: 123/255, alpha: 1))
chartDataSet.circleRadius = 5
chartDataSet.circleHoleRadius = 2
chartDataSet.drawValuesEnabled = false
chartDataSet.drawCirclesEnabled = false
let chartData = LineChartData(dataSets: [chartDataSet])
defaultChartView.data = chartData
defaultChartView.xAxis.valueFormatter = IndexAxisValueFormatter(values: months)
defaultChartView.xAxis.labelPosition = .bottom
defaultChartView.xAxis.drawGridLinesEnabled = false
//lineChartView.xAxis.avoidFirstLastClippingEnabled = true
defaultChartView.xAxis.axisMinimum = 0
defaultChartView.xAxis.granularity = 1
defaultChartView.rightAxis.drawAxisLineEnabled = false
defaultChartView.rightAxis.drawLabelsEnabled = false
defaultChartView.rightAxis.enabled = false
defaultChartView.leftAxis.drawAxisLineEnabled = false
defaultChartView.leftAxis.axisMinimum = 0.0
defaultChartView.leftAxis.drawLabelsEnabled = false
//lineChartView.leftAxis.drawGridLinesEnabled = false
//lineChartView.leftAxis.granularityEnabled = false
defaultChartView.pinchZoomEnabled = true
defaultChartView.doubleTapToZoomEnabled = true
defaultChartView.legend.enabled = false
defaultChartView.chartDescription?.text = " "
}
viewDidLoad:
guard let firstMonth = months.first, let lastMonth = months.last else {
return
}
let myMonths = [firstMonth, lastMonth]
guard let firstValue = unitsSold.first, let lastValue = unitsSold.last else {
return
}
let myValues = [firstValue, lastValue]
setChart(dataPoints: myMonths, values: myValues)
Solution is go to linechartrenderer file and replace drawValues method
open override func drawValues(context: CGContext)
{
guard
let dataProvider = dataProvider,
let lineData = dataProvider.lineData
else { return }
if isDrawingValuesAllowed(dataProvider: dataProvider)
{
var dataSets = lineData.dataSets
let phaseY = animator.phaseY
var pt = CGPoint()
for i in 0 ..< dataSets.count
{
guard let dataSet = dataSets[i] as? ILineChartDataSet else { continue }
if !shouldDrawValues(forDataSet: dataSet)
{
continue
}
let valueFont = dataSet.valueFont
guard let formatter = dataSet.valueFormatter else { continue }
let trans = dataProvider.getTransformer(forAxis: dataSet.axisDependency)
let valueToPixelMatrix = trans.valueToPixelMatrix
let iconsOffset = dataSet.iconsOffset
// make sure the values do not interfear with the circles
var valOffset = Int(dataSet.circleRadius * 1.75)
if !dataSet.isDrawCirclesEnabled
{
valOffset = valOffset / 2
}
_xBounds.set(chart: dataProvider, dataSet: dataSet, animator: animator)
for j in stride(from: _xBounds.min, through: min(_xBounds.min + _xBounds.range, _xBounds.max), by: 1)
{
guard let e = dataSet.entryForIndex(j) else { break }
if(j == 0 || j == dataSet.entryCount - 1)
{
pt.x = CGFloat(e.x)
pt.y = CGFloat(e.y * phaseY)
pt = pt.applying(valueToPixelMatrix)
if (!viewPortHandler.isInBoundsRight(pt.x))
{
break
}
if (!viewPortHandler.isInBoundsLeft(pt.x) || !viewPortHandler.isInBoundsY(pt.y))
{
continue
}
if dataSet.isDrawValuesEnabled {
ChartUtils.drawText(
context: context,
text: formatter.stringForValue(
e.y,
entry: e,
dataSetIndex: i,
viewPortHandler: viewPortHandler),
point: CGPoint(
x: pt.x,
y: pt.y - CGFloat(valOffset) - valueFont.lineHeight),
align: .center,
attributes: [NSAttributedStringKey.font: valueFont, NSAttributedStringKey.foregroundColor: dataSet.valueTextColorAt(j)])
}
if let icon = e.icon, dataSet.isDrawIconsEnabled
{
ChartUtils.drawImage(context: context,
image: icon,
x: pt.x + iconsOffset.x,
y: pt.y + iconsOffset.y,
size: icon.size)
}
}
else{
}
}
}
}
}
Set below property of X axis
barChartView.xAxis.setLabelCount(2, force: true)

How to add string labels( xAxis labels) to horizontal bar in Charts framework

I am using charts framework for drawing charts. I need to add some strings in left of every bars. In my code always there are two bars, one for Income and one for Expense. I want to show these string aside of every bar.
Below you can see my codes:
let ys1 = [model.totalIncome, abs(model.totalExpense)]
var yse1 = ys1.enumerated().map { x, y -> BarChartDataEntry in
return BarChartDataEntry(x: Double(x), y: y)
}
let count = 2
let data = BarChartData()
let ds1 = BarChartDataSet(values: yse1, label: "")
ds1.colors = [UIColor.red, UIColor.blue]
// Number formatting of Values
ds1.valueFormatter = YAxisValueFormatter()
ds1.valueFont = UIFont(fontType: .H6)!
ds1.valueTextColor = UIColor.dark_text
// Data set
data.addDataSet(ds1)
horizontalBarChartView.data = data
// General setting
horizontalBarChartView.xAxis.drawLabelsEnabled = false
horizontalBarChartView.setScaleEnabled(false)
// Grid
horizontalBarChartView.xAxis.drawGridLinesEnabled = false
horizontalBarChartView.leftAxis.gridLineDashLengths = [15.0, 15.0]
horizontalBarChartView.leftAxis.gridColor = UIColor.palette_28
horizontalBarChartView.rightAxis.drawGridLinesEnabled = false
// Disable number formatting of leftAxis and rightAxis
horizontalBarChartView.leftAxis.enabled = false
horizontalBarChartView.rightAxis.enabled = false
horizontalBarChartView.xAxis.valueFormatter =
IndexAxisValueFormatter(values: ["Income","Expense"])
horizontalBarChartView.xAxis.granularityEnabled = true
horizontalBarChartView.xAxis.granularity = 1
// setViewPortOffsets
let digitCount = Int(data.yMax).digitCount
let leftOffcet: CGFloat = digitCount > 2 ? CGFloat((digitCount - 1) * 10) : 10.0
horizontalBarChartView.setViewPortOffsets(left: leftOffcet, top: 0, right: 0, bottom: 50)
horizontalBarChartView.leftAxis.axisMinimum = 0
And my view:
lazy var horizontalBarChartView: HorizontalBarChartView = {
let chartView = HorizontalBarChartView()
chartView.contentMode = .scaleAspectFit
chartView.drawBordersEnabled = false
chartView.drawGridBackgroundEnabled = false
chartView.gridBackgroundColor = UIColor.clear
chartView.legend.enabled = false
chartView.chartDescription = nil
chartView.highlighter = nil
chartView.clipsToBounds = true
chartView.translatesAutoresizingMaskIntoConstraints = false
return chartView
}()
I guess below code should add these labels, however, it is not working
horizontalBarChartView.xAxis.valueFormatter = IndexAxisValueFormatter(values: ["Income","Expense"])
horizontalBarChartView.xAxis.granularityEnabled = true
horizontalBarChartView.xAxis.granularity = 1
Update
See orange rectangle. I need these labels.
I am using an extension for this
extension BarChartView {
private class BarChartFormatter: NSObject, IAxisValueFormatter {
var labels: [String] = []
func stringForValue(_ value: Double, axis: AxisBase?) -> String {
return labels[Int(value)]
}
init(labels: [String]) {
super.init()
self.labels = labels
}
}
func setBarChartData(xValues: [String], yValues: [Double], label: String) {
var dataEntries: [BarChartDataEntry] = []
for i in 0..<yValues.count {
let dataEntry = BarChartDataEntry(x: Double(i), y: yValues[i])
dataEntries.append(dataEntry)
}
let chartDataSet = BarChartDataSet(values: dataEntries, label: label)
let chartData = BarChartData(dataSet: chartDataSet)
let chartFormatter = BarChartFormatter(labels: xValues)
let xAxis = XAxis()
xAxis.valueFormatter = chartFormatter
self.xAxis.valueFormatter = xAxis.valueFormatter
self.data = chartData
}
}
you can use this in code like this
chartView.setBarChartData(xValues: xEntries, yValues: yEntries, label: "Income")
where,
//You need to add values dynamically
var yEntries: [Double] = [1000, 200, 500]
var xEntries: [String] = ["Income1", "Income2", "Income3"]
Hope this works.
Charts framework is a great tool for drawing charts. You should study it perfectly. I used an old code in our project (copy/paste), so it caused some problems for drawing xAxis labels in my chart.
Just comment below line:
horizontalBarChartView.xAxis.drawLabelsEnabled = false
When you create your BarChartDataSet you can pass the label.
let data = BarChartData()
let ds1 = BarChartDataSet(values: yse1, label: "Income")
ds1.colors = [UIColor.red, UIColor.blue]
Hope this helps.
self.ChartObj.xAxis.valueFormatter = DefaultAxisValueFormatter(block: {(index, _) in
print(index)
return YourArray.object(at: Int(index)) as! String
})
self.ChartObj.xAxis.setLabelCount(YourArray.count, force: true)
Try this code

iOS-Charts grouped bar chart with size to fit

I recently added "barChartData.groupBars(fromX: 0, groupSpace: 0.5, barSpace: 0.03)" to my Bar Chart so that I don't have overlapping bars and I can't figure it out how to set the width to fit (no horizontal overflow)
func setupGroupedBarChartData(values1: [String], values2: [String], barLabel1: String, barLabel2: String, barColor1: UIColor, barColor2: UIColor) -> BarChartData {
let dataValues1 = values1.flatMap{ Double($0) }
let dataValues2 = values2.flatMap{ Double($0) }
var dataEntries1: [BarChartDataEntry] = []
var dataEntries2: [BarChartDataEntry] = []
for i in 0..<dataValues1.count {
let dataEntry1 = BarChartDataEntry(x: Double(i), y: dataValues1[i])
dataEntries1.append(dataEntry1)
let dataEntry2 = BarChartDataEntry(x: Double(i), y: dataValues2[i])
dataEntries2.append(dataEntry2)
}
let chartDataSet1 = BarChartDataSet(values: dataEntries1, label: barLabel1)
chartDataSet1.colors = [barColor1]
chartDataSet1.valueTextColor = AppColors.lightText
let chartDataSet2 = BarChartDataSet(values: dataEntries2, label: barLabel2)
chartDataSet2.colors = [barColor2]
chartDataSet2.valueTextColor = AppColors.lightText
var groupedDataSet : [BarChartDataSet] = [BarChartDataSet]()
groupedDataSet.append(chartDataSet1)
groupedDataSet.append(chartDataSet2)
let barChartData = BarChartData(dataSets: groupedDataSet)
barChartData.groupBars(fromX: 0, groupSpace: 0.5, barSpace: 0.03)
//display data as integer
let format = NumberFormatter()
format.generatesDecimalNumbers = false
let formatter = DefaultValueFormatter(formatter: format)
barChartData.setValueFormatter(formatter)
return barChartData
}
You can use like this :
You calculation will be like below :
// (barWidth + barSpace) * (no.of.bars) + groupSpace = 1.00 -> interval per "group"
In your code :
barChartData.groupBars(fromX: 0, groupSpace: 0.14, barSpace: 0.03)
barChartData.barWidth = 0.4
barChartView.xAxis.axisMinimum = 0
barChartView.xAxis.axisMaximum = 23

How to use xAxis with Label in Charts-frameworks

As title,After I check How to add Strings on X Axis in iOS-charts? this post. I still don't know where can I put "formato.stringForValue(Double(i), axis: taxis)" in for-in loop, as I know, when I implement this protocol ,this function will send out a "String".My question is how does it connect to my xAxis data??
Following is my code ,please refer to it.
//setChartData
func setChart(dataPoints:[String],values:[Double]){
self.barChartView.noDataText = "You need to provide data for the chart."
let xaxis = XAxis()
let fomatter = BarChartFomatter()
fomatter.setValues(values: dataPoints)
var dataEntries:[BarChartDataEntry] = []
for i in 0..<dataPoints.count{
let dataEntry = BarChartDataEntry(x: Double(i), y: values[i])
*fomatter.stringForValue(Double(i), axis: xaxis)*
dataEntries.append(dataEntry)
}
let chartDataSet = BarChartDataSet(values: dataEntries, label: "Units Sold")
let data = BarChartData(dataSet: chartDataSet)
xaxis.valueFormatter = fomatter
self.barChartView.backgroundColor = UIColor.clear
self.barChartView.xAxis.drawLabelsEnabled = false
self.barChartView.chartDescription?.enabled = false
self.barChartView.legend.enabled = false
self.barChartView.rightAxis.enabled = false
self.barChartView.xAxis.valueFormatter = xaxis.valueFormatter
self.barChartView.xAxis.labelPosition = .bottom
//self.barChartView.description = "Test String"
barChartView.xAxis.granularityEnabled = true
barChartView.xAxis.granularity = 1.0 //default granularity is 1.0, but it is better to be explicit
barChartView.xAxis.decimals = 0
self.barChartView.data = data
}
And my BarChartFomatter as follow:
import UIKit
#objc(BarChartFomatter)
open class BarChartFomatter: NSObject,IAxisValueFormatter {
var names = [String]()
public func stringForValue(_ value: Double, axis: AxisBase?) -> String {
return names[Int(value)]
}
public func setValues(values:[String]){
self.names = values
}
}
Result:
There is no text under the chart
Please help me , thanks

Resources