Swift 3.1, Charts, Multiple cells in tableView with HorizontalBarChartView.
Is it possible to align the value - centered?
Setup charts data:.
func refreshData() {
guard let item = self.item, !item.tasks.isEmpty else {
return
}
self.titleName.text = item.name
self.leftNameMargin.constant = CGFloat(30 * item.level)
self.titleName.textColor = UIColor(hexString: item.color)
let font = UIFont.systemFont(ofSize: 17.0, weight: UIFontWeightSemibold)
var colors: [UIColor] = []
var yValues: [Double] = []
var count = 0.0
for task in item.tasks {
count += Double(task.count)
yValues.append(Double(task.count))
colors.append(UIColor(hexString: task.valueColor))
}
let suffix = String(format: NSXLocalization.string(forKey: KEY_STR_PERCENT)) //fixes '%' duplication
let formatter = NumberFormatter()
formatter.roundingMode = .floor
formatter.numberStyle = .percent
formatter.positiveSuffix = suffix
formatter.negativeSuffix = suffix
formatter.zeroSymbol = ""
let dataEntry = BarChartDataEntry(x: 0.0, yValues: yValues.map { ($0 / count) })
let dataSet = BarChartDataSet(values: [dataEntry], label: nil)
dataSet.colors = colors
dataSet.valueTextColor = .white
dataSet.barBorderColor = .black
dataSet.barBorderWidth = 1.0
dataSet.drawValuesEnabled = true
dataSet.valueFormatter = DefaultValueFormatter(formatter: formatter)
let data = BarChartData(dataSets: [dataSet])
data.setValueFont(font)
data.setDrawValues(true)
data.highlightEnabled = true
self.chart.data = data
}
I Reviewed all internal methods in the charts, but never found a way to center the y values.
Related
I am using iOS Charts to draw linechart but unable to draw the same graph as shown below in the image. I tried by setting leftAxis.axisMinimum = minValue but it also not working. If the given value is minimum on certain limit it should show in red color as shown in attached image.
func setLineChartWithDateFormat(graphPoints: [GraphPoints], linePosition: CGFloat, minValue: Double = 0, fillColor: UIColor = UIColor(red: 158.0/255.0, green: 188.0/255.0, blue: 136.0/255.0, alpha: 1)) {
var referenceTimeInterval: TimeInterval = 0
if let minTimeInterval = (graphPoints.map { ($0.getDateFromDateTime?.timeIntervalSince1970 ?? 0) }).min() {
referenceTimeInterval = minTimeInterval
}
let formatter = DateFormatter()
formatter.locale = Locale(identifier: "en_US_POSIX")
formatter.dateFormat = "MMM dd"
let xValuesNumberFormatter = ChartXAxisWithFormatter(referenceTimeInterval: referenceTimeInterval, dateFormatter: formatter)
// Define chart entries
var entries = [ChartDataEntry]()
var xAxisValues = [CGFloat]()
for object in graphPoints {
let timeInterval = object.getDateFromDateTime?.timeIntervalSince1970 ?? 0
let xValue = (timeInterval - referenceTimeInterval) / (3600 * 24)
xAxisValues.append(CGFloat(xValue))
let yValue = object.price ?? 0
let entry = ChartDataEntry(x: xValue, y: yValue)
entry.setValue(object.getDateFromDateTime, forKey: "data")
entries.append(entry)
}
var minValue = xAxisValues.min()
let chartDataSet = LineChartDataSet(entries: entries, label: "BPM")
chartDataSet.fillColor = fillColor
/// Data object that encapsulates all data associated with a LineChart.
let chartData = LineChartData()
chartData.addDataSet(chartDataSet)
chartData.setDrawValues(false)
chartDataSet.drawCirclesEnabled = false
chartDataSet.mode = .linear
chartDataSet.colors = [.white]
chartDataSet.fillFormatter = LineChartFillFormatter(value: minValue ?? 0)
// let gradientColors = [gradientColor1.cgColor, gradientColor2.cgColor] as CFArray
// let colorLocations: [CGFloat] = [0.7,0.0]
// guard CGGradient.init(colorsSpace: CGColorSpaceCreateDeviceRGB(), colors: gradientColors, locations: colorLocations) != nil else {
// print("Gradient Error")
// return
// }
chartDataSet.drawFilledEnabled = true
chartDataSet.fillAlpha = 1
chartDataSet.setDrawHighlightIndicators(true)
chartDataSet.drawHorizontalHighlightIndicatorEnabled = false
// lineChart.leftAxis.axisMinimum = minValue
///x axis for chart view
let xAxis: XAxis = self.lineChart.xAxis
xAxis.labelPosition = .bottomInside
xAxis.drawGridLinesEnabled = true //true, if want x Axis grid lines
xAxis.valueFormatter = xValuesNumberFormatter
xAxis.gridColor = gridColor
xAxis.axisLineColor = gridColor
xAxis.labelFont = BSFonts.getFontWithSize(fontType: .iBMPlexSansCond, fontSize: BSFontSize.small)
xAxis.labelTextColor = axisTextColor
xAxis.labelPosition = .bottom
xAxis.spaceMin = 0.5
xAxis.drawAxisLineEnabled = false
xAxis.drawLimitLinesBehindDataEnabled = true
xAxis.granularityEnabled = true
// xAxis.granularity = 2
xAxis.labelWidth = UIDevice.current.isIPad ? 30 : 20
// xAxis.labelCount = 4
///right axis for chart view
let rightAxis: YAxis = lineChart.rightAxis
rightAxis.enabled = false
///y axis of chart view
let leftAxis: YAxis = lineChart.leftAxis
leftAxis.labelPosition = .insideChart
leftAxis.drawGridLinesEnabled = true //true, if want y axis grid lines
leftAxis.drawLabelsEnabled = true
leftAxis.gridColor = gridColor
leftAxis.axisLineColor = gridColor
leftAxis.labelFont = BSFonts.getFontWithSize(fontType: .iBMPlexSansCond, fontSize: BSFontSize.small)
leftAxis.labelTextColor = axisTextColor
leftAxis.labelPosition = .outsideChart
//leftAxis.spaceBottom = 0.3
leftAxis.drawAxisLineEnabled = false
leftAxis.labelCount = 4
/// The data for the chart
lineChart.data = chartData
lineChart.doubleTapToZoomEnabled = false
lineChart.data?.highlightEnabled = true
}
I am writing an iOS App in Swift 4.2
I am using Charts library to display Horizontal Bar Chart. I need to set its xAxis Values. Only last value is being displayed.
Issue Screenshot:
Code Snippet:
#IBOutlet var chartView: HorizontalBarChartView!
override func viewDidLoad() {
super.viewDidLoad()
let xAxis = chartView.xAxis
xAxis.labelPosition = .bottom
xAxis.labelFont = .systemFont(ofSize: 10)
xAxis.drawAxisLineEnabled = false
xAxis.drawGridLinesEnabled = false
xAxis.granularity = 1
xAxis.enabled=true
xAxis.setLabelCount(3, force: false) //Not working as per expectations
xAxis.valueFormatter=IndexAxisValueFormatter(values: ["A","B","C"]) //Not working as per expectations
self.setDataCount(3,values:[142000,122400,100110])
chartView.animate(yAxisDuration: 2.5)
}
func setDataCount(_ count: Int, values:[Double]) {
let barWidth = 2.0
let spaceForBar = 4.0
var n=0
let yVals = (0..<count).map { (i) -> BarChartDataEntry in
let val = values[n]
n+=1
return BarChartDataEntry(x: Double(i)*spaceForBar, y: val)
}
let set1 = BarChartDataSet(entries: yVals, label: "DataSet")
set1.drawIconsEnabled = false
let data = BarChartData(dataSet: set1)
data.setValueFont(UIFont(name:"HelveticaNeue-Light", size:10)!)
data.barWidth = barWidth
chartView.data = data
//let xAxis = chartView.xAxis
//xAxis.setLabelCount(3, force: false)
//xAxis.valueFormatter=IndexAxisValueFormatter(values: ["A","B","C"])
}
I tried to find solutions:
xAxis.valueFormatter=IndexAxisValueFormatter(values: ["A","B","C"])
but these are not working.
This is happening because the default functionality of IndexAxisValueFormatter
You have to code your own custom IAxisValueFormatter like this
final class CustomFormatter: IAxisValueFormatter {
var labels: [String] = []
func stringForValue(_ value: Double, axis: AxisBase?) -> String {
let count = self.labels.count
guard let axis = axis, count > 0 else {
return ""
}
let factor = axis.axisMaximum / Double(count)
let index = Int((value / factor).rounded())
if index >= 0 && index < count {
return self.labels[index]
}
return ""
}
}
Then use it like
let customFormater = CustomFormater()
customFormater.labels = ["A","B","C"]
chartView.xAxis.valueFormatter = customFormater
Make sure the size/count of the data and labels is the same or it wont give you the desired results.
I updated your given code please check changes.
I hope its work for you.
class ViewController: UIViewController {
#IBOutlet var chartView: HorizontalBarChartView!
override func viewDidLoad() {
super.viewDidLoad()
let xAxis = chartView.xAxis
xAxis.labelPosition = .bottom
xAxis.labelFont = .systemFont(ofSize: 10)
xAxis.drawAxisLineEnabled = false
xAxis.drawGridLinesEnabled = false
xAxis.granularity = 1
xAxis.enabled=true
xAxis.setLabelCount(3, force: false) //Not working as per expectations
xAxis.valueFormatter = IndexAxisValueFormatter(values: ["A","B","C"])//AxisValueFormatter(values: ["A","B","C"]) //Not working as per expectations
self.setDataCount(3,values:[142000,122400,100110])
chartView.animate(yAxisDuration: 2.5)
}
func setDataCount(_ count: Int, values:[Double]) {
let yVals = (0..<count).map { (i) -> BarChartDataEntry in
let val = values[i]
return BarChartDataEntry(x: Double(i), y: val)
}
let set1 = BarChartDataSet(values: yVals, label: "DataSet")
set1.drawIconsEnabled = false
let data = BarChartData(dataSet: set1)
data.setValueFont(UIFont(name:"HelveticaNeue-Light", size:10)!)
//data.barWidth = barWidth
chartView.data = data
//let xAxis = chartView.xAxis
//xAxis.setLabelCount(3, force: false)
//xAxis.valueFormatter=IndexAxisValueFormatter(values: ["A","B","C"])
}
}
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
}
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
Im implementing a barchart and I've managed to assign the data and labels. However, when i load the barchart, it only shows 3/7 of my labels and I'm not sure why.
the labels show up when i interact with the chart but they go glitchy.
I'm sorry if i haven't explained myself well but i have uploaded a .gif showing my problem.
I really need some help with the formatting of the labels on the xAxis. it would be much appreciated.
Thanks in advance.
gif of problem
i think you have used this library(https://github.com/danielgindi/Charts) ... i have set x-Axis using delegate method of chart
func ChartView()
{
xAxis.drawGridLinesEnabled = false
xAxis.drawLabelsEnabled = true
xAxis.labelPosition = .Bottom
xAxis.axisMinimum = 0.0
xAxis.labelCount = ITEM_COUNT
xAxis.granularity = 1.0
xAxis.valueFormatter = self
self.updateChartData()
}
func updateChartData()
{
self.chartView.data = nil
self.setChartData()
}
func generateLineData() -> LineChartData
{
let d = LineChartData()
let entries = NSMutableArray()
var weightstr = String()
var datestr = String()
entries.addObject(ChartDataEntry(x: Double(index), y: ( Double(dic[setvalue]as! String)!)))
let set = LineChartDataSet(values: entries as? [ChartDataEntry] , label: "X-title")
set.setColor(colorWithHexString("#FE1643"))
set.lineWidth = 2.5
set.setCircleColor( UIColor.whiteColor())
set.circleHoleColor = NSUIColor.greenColor()
set.circleRadius = 5.0
set.circleHoleRadius = 2.5
set.fillColor = UIColor.redColor()
set.mode = .HorizontalBezier
set.valueTextColor = UIColor.lightGrayColor()
set.drawValuesEnabled = true
set.valueFont = UIFont(name: "Exo-Regular", size: FOntSIZE(10.0))!
set.axisDependency = .Left
d.addDataSet(set)
return d
}
func setChartData()
{
let data = CombinedChartData()
data.lineData = self.generateLineData()
self.chartView.xAxis.axisMaximum = Double(months.count)-1
self.chartView.data = data
}
func chartValueSelected(chartView: ChartViewBase, entry: ChartDataEntry, highlight: Highlight)
{
print("chartValueSelected")
}
func chartValueNothingSelected(chartView: ChartViewBase)
{
print("chartValueNothingSelected")
}
func stringForValue(value: Double, axis: AxisBase?) -> String
{
return months[Int(round(value)) % months.count] as! String
}