I have this simple implementation of charts for iOS. And I'm looking for a way to align the labels at the center of each bar.
What I've accomplished so far was to position the labels inside each bar. I'm stuck at this point, as I don't see any way to achieve centering the label.
Here is a screenshot of what I've accomplished.
A snippet of the code used to setup this view.
func prepareHorizontalBarChart() {
var entries1 = [BarChartDataEntry]()
var entries2 = [BarChartDataEntry]()
var entries3 = [BarChartDataEntry]()
let values:[String] = ["1/22", "1/25", "1/30"]
let bar1 = BarChartDataEntry(x: Double(0), y: Double(4), icon: nil, data: "1/22" as AnyObject)
entries1.append(bar1)
let bar2 = BarChartDataEntry(x: Double(1), y: Double(6))
entries2.append(bar2)
let bar3 = BarChartDataEntry(x: Double(2), y: Double(2))
entries3.append(bar3)
let set1 = BarChartDataSet(values: entries1, label: "test")
set1.drawIconsEnabled = false
let set2 = BarChartDataSet(values: entries2, label: "test")
set1.drawIconsEnabled = false
let set3 = BarChartDataSet(values: entries3, label: "test")
set1.drawIconsEnabled = false
set1.colors = [UIColor.purple]
set2.colors = [UIColor.magenta]
set3.colors = [UIColor.red]
let data = BarChartData(dataSets: [set1, set2, set3])
data.setValueFont(UIFont(name: "HelveticaNeue-Light", size: 10))
data.barWidth = 0.2
let formatter = NumberFormatter()
formatter.numberStyle = .none
formatter.maximumFractionDigits = 0
formatter.multiplier = 1.0
let defaultValueFormatter = DefaultValueFormatter(formatter: formatter)
data.setValueFormatter(defaultValueFormatter)
horizontalBarChart.zoomOut()
horizontalBarChart.fitBars = true
horizontalBarChart.data = data
horizontalBarChart.xAxis.drawGridLinesEnabled = false // disable horizontal grid lines
// horizontalBarChart.xAxis.enabled = false
horizontalBarChart.chartDescription?.enabled = false
horizontalBarChart.xAxis.valueFormatter = IndexAxisValueFormatter(values: values)
horizontalBarChart.xAxis.labelPosition = .bottom
horizontalBarChart.rightAxis.enabled = false
horizontalBarChart.leftAxis.axisMinimum = 0
horizontalBarChart.legend.verticalAlignment = .top
horizontalBarChart.legend.horizontalAlignment = .center
horizontalBarChart.legend.orientation = .vertical
horizontalBarChart.drawValueAboveBarEnabled = false
horizontalBarChart.legend.enabled = false
horizontalBarChart.animate(xAxisDuration: 2.0, yAxisDuration: 2.0)
}
Goto Charts and look for HorizontalBarChartRender class, find a method called draw values and changed value for text alignment to center.
or: Search for these two lines
let x = transformed[k].x + (drawBelow ? negOffset : posOffset)
replace it with
let x = buffer.rects[k].origin.x + buffer.rects[k].size.width / 2.2
if !viewPortHandler.isInBoundsTop(rect.origin.y) { break }
comment out this line
Related
I am using LineChartView in collection view cells, but randomly when I scroll sometimes orange/brown axis lines are being displayed.
Code I used to create LineChartView
let view = LineChartView()
view.translatesAutoresizingMaskIntoConstraints = false
view.chartDescription?.enabled = false
view.xAxis.drawGridLinesEnabled = false
view.xAxis.drawLabelsEnabled = false
view.xAxis.drawAxisLineEnabled = false
view.xAxis.enabled = false
view.xAxis.axisLineColor = .clear
view.rightAxis.enabled = false
view.rightAxis.axisLineColor = .clear
view.leftAxis.enabled = false
view.leftAxis.axisLineColor = .clear
view.drawBordersEnabled = false
view.legend.enabled = false
let values = (0..<32).map { (i) -> ChartDataEntry in
let val = Double(arc4random_uniform(10) + 3)
return ChartDataEntry(x: Double(i), y: val)
}
let set1 = LineChartDataSet(entries: values)
set1.drawCirclesEnabled = false
set1.drawValuesEnabled = false
set1.drawCircleHoleEnabled = false
set1.setColor(UIColor.black)
view.data = LineChartData(dataSets: [set1])
Using danielgindi / Charts (3.6.0)
supplement to # Raja Kishan's suggestion
// for tapping
view.highlightPerTapEnabled = false
// for dragging
view.highlightPerDragEnabled = false
For plotting graphs I use the Charts framework from this site https://github.com/danielgindi/Charts. I want to know if it possible to center the x- and y-axis to look like this:
I tried to move the x-Axis and the left-Axis to center, but it only moves the label values but not the axes, as you can see in the below picture
Here is an example of my code:
var lineChartView: LineChartView!
override func viewDidLoad() {
super.viewDidLoad()
self.view.backgroundColor = .white
lineChartView = LineChartView(frame: CGRect(x: 0, y: 0, width: self.view.frame.width, height: self.view.frame.height))
lineChartView?.delegate = self
self.view.addSubview(lineChartView!)
let ys1 = Array(0..<100).map { x in ChartDataEntry(x: Double(x) / 10, y: sin(Double(x) / 10)) }
let ys2 = Array(0..<100).map { x in ChartDataEntry(x: Double(x) / 10, y: cos(Double(x) / 10)) }
let data = LineChartData()
let ds1 = LineChartDataSet(entries: ys1, label: "sine")
ds1.colors = [NSUIColor.red]
ds1.drawCirclesEnabled = false
ds1.drawValuesEnabled = false
ds1.mode = .cubicBezier
data.addDataSet(ds1)
let ds2 = LineChartDataSet(entries: ys2, label: "cosine")
ds2.colors = [NSUIColor.blue]
ds2.drawCirclesEnabled = false
ds2.drawValuesEnabled = false
ds2.mode = .cubicBezier
data.addDataSet(ds2)
self.lineChartView.data = data
lineChartView.xAxis.enabled = true
lineChartView.xAxis.labelPosition = .bottom
lineChartView.xAxis.yOffset = -self.view.frame.height/2
lineChartView.rightAxis.enabled = false
// left axis
lineChartView.leftAxis.xOffset = -self.view.frame.width/2
}
you can try this code, you might need to set chart.setVisibleRange too
chart.xAxis.granularity = 1
chart.leftAxis.granularity = 1
chart.leftAxis.axisMaximum = maxYValue
chart.xAxis.axisMaximum = maxXValue
chart.xAxis.axisMinimum = -maxXValue
chart.leftAxis.axisMinimum = -maxYValue
I'm trying to show my data in charts, but I have issue when I try to do that with multiple lines. The lines behave strangely, I tried many things, but I could not fix it in any way. Here is a picture of this
I'm using Xcode(Version 10.1 (10B61)), Swift 4.2, Charts 3.2.1
let dollars1 = [1453.0,2352,5431,1442,5451,6486,1173,5678,9234,1345,9411,2212]
let dollars2 = [5641.0,2234,8763,4453,4548,6236,7321,3458,2139,399,1311,5612]
let dollars3 = [6541.0,3456,7843,5678,5877,7323,7111,6456,5143,4562,6311,10412]
var yVals1 : [ChartDataEntry] = [ChartDataEntry]()
for i in 0..<dollars1.count {
yVals1.append(ChartDataEntry(x: dollars1[i], y: Double(i)))
}
let set1: LineChartDataSet = LineChartDataSet(values: yVals1, label: "First Set")
set1.axisDependency = .left // Line will correlate with left axis values
set1.setColor(UIColor.red.withAlphaComponent(0.5))
set1.setCircleColor(UIColor.clear)
set1.lineWidth = 2.0
set1.fillAlpha = 65 / 255.0
set1.fillColor = UIColor.red
set1.highlightColor = UIColor.yellow
set1.drawCircleHoleEnabled = false
var yVals2 : [ChartDataEntry] = [ChartDataEntry]()
for i in 0..<dollars2.count {
yVals2.append(ChartDataEntry(x: dollars2[i], y: Double(i)))
}
let set2: LineChartDataSet = LineChartDataSet(values: yVals2, label: "Second Set")
set2.axisDependency = .left // Line will correlate with left axis values
set2.setColor(UIColor.green.withAlphaComponent(0.5))
set2.setCircleColor(UIColor.clear)
set2.lineWidth = 2.0
set2.fillAlpha = 65 / 255.0
set2.fillColor = UIColor.green
set2.highlightColor = UIColor.yellow
set2.drawCircleHoleEnabled = false
var yVals3 : [ChartDataEntry] = [ChartDataEntry]()
for i in 0..<dollars3.count {
yVals3.append(ChartDataEntry(x: dollars3[i], y: Double(i)))
}
let set3: LineChartDataSet = LineChartDataSet(values: yVals3, label: "Third Set")
set3.axisDependency = .left // Line will correlate with left axis values
set3.setColor(UIColor.blue.withAlphaComponent(0.5))
set3.setCircleColor(UIColor.clear)
set3.lineWidth = 2.0
set3.fillAlpha = 65 / 255.0
set3.fillColor = UIColor.blue
set3.highlightColor = UIColor.yellow
set3.drawCircleHoleEnabled = false
//3 - create an array to store our LineChartDataSets
var dataSets : [LineChartDataSet] = [LineChartDataSet]()
dataSets.append(set1)
dataSets.append(set2)
dataSets.append(set3)
//4 - pass our months in for our x-axis label value along with our dataSets
let data: LineChartData = LineChartData(dataSets: dataSets)
data.setValueTextColor(UIColor.white)
//5 - finally set our data
self.lineCharts.data = data
Iam using SwiftChart git library :- https://github.com/gpbl/SwiftChart
click to see in image
enter image description here
here is the code :-
let chart = Chart(frame: CGRect(x: 0, y: 0, width: 200, height: 100))
let series = ChartSeries([0, 6.5, 2, 8, 4.1, 7, -3.1, 10, 8])
chart.add(series)
I am working On a Bar Chart in iOS Swift
Code:
let chartDataSet: BarChartDataSet!
chartDataSet = BarChartDataSet(values: dataEntries, label: "Rupee Date-->")
chartDataSet.colors = [AppColors.barChartColor]
chartDataSet.highlightColor = AppColors.barChartHighlightColor
chartDataSet.valueTextColor = UIColor.black
chartDataSet.values = dataEntries
let chartData = BarChartData(dataSet: chartDataSet)
chartData.setDrawValues(true)
cell.barChartView.drawValueAboveBarEnabled = true
cell.barChartView.xAxis.valueFormatter = IndexAxisValueFormatter(values:monthDateArray as! [String])
cell.barChartView.animate(xAxisDuration: 1.0, yAxisDuration: 1.0)
cell.barChartView.data = chartData
cell.barChartView.xAxis.granularity = 1.0
cell.barChartView.setVisibleXRange(minXRange: 7, maxXRange: 7)
cell.barChartView.leftAxis.axisMinimum = 0
cell.barChartView.drawValueAboveBarEnabled = true
Questions
How to show values above bars, like 4.0, 3.0 etc.
The bar always opens at 0 position. I want the bar to open always at the current date position, and on scrolling, we can show all data.
Try this extension:-
//Bar chart extensio to set custom xAxia and yAxis
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: [String], label: String) {
var dataEntries: [BarChartDataEntry] = []
for i in 0..<yValues.count {
let dataEntry = BarChartDataEntry(x: Double(i), y: Double(yValues[i])!)
dataEntries.append(dataEntry)
}
let chartDataSet = BarChartDataSet(values: dataEntries, label: label)
chartDataSet.colors = [NSUIColor(red: 0/255.0, green: 110/255.0, blue: 194/255.0, alpha: 1.0)]
chartDataSet.valueFont = NSUIFont.systemFont(ofSize: 13)
let chartData = BarChartData(dataSet: chartDataSet)
let chartFormatter = BarChartFormatter(labels: xValues)
let xAxis = XAxis()
xAxis.valueFormatter = chartFormatter
self.xAxis.valueFormatter = xAxis.valueFormatter
self.drawValueAboveBarEnabled = true
self.data = chartData
}
}
Call function:-
#IBOutlet var chartView: BarChartView!
...
chartView.setBarChartData(xValues: dates, yValues: Leads, label: "Leads")
Where dates and Leads are array of strings
Answer for Question 1
By Mr. Mahajan Code and some with this Functionality:-
Code:
cell.barChartView.xAxis.valueFormatter = IndexAxisValueFormatter(values:monthDateArray as! [String])
cell.barChartView.animate(xAxisDuration: 1.0, yAxisDuration: 1.0)
cell.barChartView.xAxis.granularity = 1.0
cell.barChartView.setVisibleXRange(minXRange: 7, maxXRange: 7)
cell.barChartView.leftAxis.axisMinimum = 0
cell.barChartView.xAxis.granularityEnabled = true
cell.barChartView.xAxis.drawGridLinesEnabled = false
cell.barChartView.xAxis.labelPosition = .bottom
cell.barChartView.chartDescription?.text = ""
cell.barChartView.rightAxis.enabled = false
cell.barChartView.animate(xAxisDuration: 2.0, yAxisDuration: 2.0, easingOption: .easeInOutQuart)
Answer for Question 2
Code:
let date = Date()
let formatter = DateFormatter()
formatter.dateFormat = "dd"
let result = formatter.string(from: date)
var myDoubleX = Double(result)
myDoubleX = myDoubleX! - 1.5
cell.barChartView.moveViewToX(myDoubleX!)
SWIFT 4.2
For the Daniel Gindi Chart if you want to add two different value at the top of the bar candle if you have noticed there are one stand alone properties in the BarChartDataEntry named icon you can convert your text in to image and add that image as an icon to populate at the top of the bar candle.
Here I have done the same thing with the CandleStickChartView and it's Base class is BarLineChartViewBase. You can access this properties in the BarChart too.
Let's focus on the code.
Here I have an array of the BloodPressure Readings which is having Systolic and Diastolic Value. and circulate the loop to make a CandleChartDataEntry / BarChartDataEntry
for (index, bloodPressure) in bloodPressureData.enumerated() {
let systolicDouble = bloodPressure.value.systolic.doubleValue.rounded(toPlaces: 0)
let diastolicDouble = bloodPressure.value.diastolic.doubleValue.rounded(toPlaces: 0)
let high = max(Int(systolicDouble), Int(diastolicDouble))
let low = min(Int(systolicDouble), Int(diastolicDouble))
let imageLabel = " \(Int(systolicDouble))-\(Int(diastolicDouble)) "
let label = UILabel(frame: CGRect(x: 0, y: 0, width: 40, height: 10))
label.numberOfLines = 0
label.textAlignment = .center
label.textColor = UIColor.black
label.backgroundColor = UIColor.clear
label.layer.cornerRadius = 3.0
label.font = UIFont(name: "Montserrat-Regular", size: 8.0)
label.text = imageLabel
label.sizeToFit()
let image = UIImage.imageWithLabel(label: label)
let dataEntry = CandleChartDataEntry(x: Double(index), shadowH: CGFloat(high), shadowL: CGFloat(low), open: CGFloat(high), close: CGFloat(low), icon: image)
let dataBarEntry = BarChartDataEntry(x: Double(index), y: CGFloat(high), icon: image)
entries.append(dataEntry)
}
Here I have created a separate UIImage extension which is rendering UILabel in to UIImage
extension UIImage {
class func imageWithLabel(label: UILabel) -> UIImage {
UIGraphicsBeginImageContextWithOptions(label.bounds.size, false, 0.0)
label.layer.render(in: UIGraphicsGetCurrentContext()!)
let img = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return img!
}
}
by that extension you can covert your text in to image and add that image as an icon while you are preparing your BarChartDataEntry/CandleChartDataEntry
Note: To make it clearly visible at the top of the candle you need to set the offset of the icon by using this property
let set1 = CandleChartDataSet(entries: entries, label: "Blood Pressure")
set1.iconsOffset = CGPoint(x: 0, y: -8)
set1.drawValuesEnabled = false // Disable drawable value
Here I am attaching the outcome of it:
Thank you
😄
I experience a number of issues with the horizontal bar chart since I updated to the last version of ios-chart (3.0.0).
First thing is that I had labels for the x axis on the charts. With the new version of ios-charts I had to write my own formatter nevertheless only every second label get displayed now. The second problem is that the bar does not reach the value indicated on the y-axis. What I mean by that is that if I give the bar a value of 4 the height of the bar is actually not long enough to reach the 4.0 label on the y-axis. Those 2 issues are illustrated in this picture.
picture of the problems
Here is my code for the value formatter:
#objc(BarChartFormatter)
public class BarChartFormatter: NSObject, IAxisValueFormatter{
var labelArray : [String] = ["text1", "text2", "text3", "text4", "text5", "text6", "text7", "text8", "text9", "text10"]
public func stringForValue(_ value: Double, axis: AxisBase?) -> String {
return labelArray[Int(value)]
}
}
And here is the code for the bar chart
horizontalBarChartView.noDataText = "You need to provide data for the chart."
horizontalBarChartView.isUserInteractionEnabled = false
horizontalBarChartView.drawGridBackgroundEnabled = false
horizontalBarChartView.drawValueAboveBarEnabled = false
horizontalBarChartView.legend.enabled = false
horizontalBarChartView.drawBarShadowEnabled = false
horizontalBarChartView.chartDescription?.text = ""
horizontalBarChartView.setExtraOffsets(left: 0, top: 0, right: 0, bottom: 0)
// Right y axis
let barRightAxis = horizontalBarChartView.leftAxis
barRightAxis.drawGridLinesEnabled = false
barRightAxis.enabled = false
let formato:BarChartFormatter = BarChartFormatter()
let xaxis:XAxis = XAxis()
// Left y axis
let barLeftAxis = horizontalBarChartView.rightAxis
let count = 5
barLeftAxis.setLabelCount(count, force: true)
barLeftAxis.drawGridLinesEnabled = false
barLeftAxis.axisLineWidth = 2
barLeftAxis.axisLineColor = UIColor.white
barLeftAxis.labelTextColor = UIColor.white
barLeftAxis.axisMinimum = 0.0
barLeftAxis.axisMaximum = 4.0
barLeftAxis.granularityEnabled = true
barLeftAxis.granularity = 1.0
barLeftAxis.decimals = 0
// x axis
let barXaXis = horizontalBarChartView.xAxis
barXaXis.drawGridLinesEnabled = false
barXaXis.axisLineColor = UIColor.white
barXaXis.axisLineWidth = 2
barXaXis.labelTextColor = UIColor.white
barXaXis.labelPosition = .bottomInside
barXaXis.granularityEnabled = true
barXaXis.granularity = 1.0
barXaXis.decimals = 0
var dataEntries: [BarChartDataEntry] = []
var colors: [UIColor] = []
let theScoreVec = [1.0, 2.0, 3.0, 4.0, 3.0, 0.0, 2.0, 0.0, 1.0, 4.0]
for i in 0..<10 {
let theScore = theScoreVec[i]
if (theScore == 0.0){
colors.append(UIColor.clear)
let dataEntry = BarChartDataEntry(x: Double(i), y : Double(4.0))
dataEntries.append(dataEntry)
} else {
colors.append(UIColor.red)
let dataEntry = BarChartDataEntry(x: Double(i), y: Double(theScore))
dataEntries.append(dataEntry)
}
}
xaxis.valueFormatter = formato
barXaXis.valueFormatter = xaxis.valueFormatter
for i in 0..<10{
formato.stringForValue(Double(i), axis: xaxis)
}
xaxis.valueFormatter = formato
barXaXis.valueFormatter = xaxis.valueFormatter
let chartDataSet = BarChartDataSet(values: dataEntries, label: "Completion")
chartDataSet.colors = colors
let chartData = BarChartData(dataSet: chartDataSet)
chartData.setDrawValues(false)
horizontalBarChartView.data = chartData
Here I also use some kind of hack because when one enters a value of 0.0 for a BarChartDataEntry the bars and the x axis have a significant offset. Therefore I create bars with a fake value and give them a transparent color.
Do one you had a similar issue with the library and know where it comes from ? Or maybe has even solved it ?
Thanks in advance for the help.