I have made a bar chart with 6 groups and I have manage to hack my way into centering them exactly below each group. Now, the problem is that the value inside of each label is repeating.
My values array contains 6 different values and my label count is on 7. The labelCount needed to be 7 in order for chart to center them correctly. More over, I did set this value to 6 too, thinking that there is an indexing issue when the value formatter is picking values, and labels are still repeating.
I have already tried changing the granularity to all sorts of values and it does not seam to work. Also I fiddled around toggling granularity to true or false, but it does not work either.
Screenshot
var months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun"]
lazy var barChart: BarChartView = {
let chart = BarChartView()
chart.translatesAutoresizingMaskIntoConstraints = false
var inComing = [BarChartDataEntry]()
var outgoing = [BarChartDataEntry]()
for i in 0..<6 {
let entry = BarChartDataEntry(x: Double(i), y: Double.random(in: 10..<100))
inComing.append(entry)
}
for i in 6..<12 {
let entry = BarChartDataEntry(x: Double(i), y: Double.random(in: 10..<100))
outgoing.append(entry)
}
let set1 = BarChartDataSet(entries: inComing, label: "Incoming")
let set2 = BarChartDataSet(entries: outgoing, label: "Outgoing")
let incomingColor = UIColor(red: 51 / 255, green: 51 / 255, blue: 51 / 255, alpha: 1)
set1.colors = [incomingColor]
let outgoingColor = UIColor(red: 153 / 255, green: 0, blue: 0, alpha: 1)
set2.colors = [outgoingColor]
let data = BarChartData(dataSets: [set1, set2])
let barWidth = 0.004
let barSpace = 0.007
let groupSpace = 0.032
let groupCount = 6
data.barWidth = barWidth
let gg = data.groupWidth(groupSpace: groupSpace, barSpace: barSpace)
chart.data = data
chart.xAxis.axisMinimum = 0
chart.xAxis.axisMaximum = gg * Double(groupCount)
set1.drawValuesEnabled = false
set2.drawValuesEnabled = false
chart.xAxis.drawGridLinesEnabled = false
chart.xAxis.drawAxisLineEnabled = true
chart.drawBordersEnabled = true
let formater = IndexAxisValueFormatter.with(values: months)
chart.xAxis.centerAxisLabelsEnabled = true
chart.xAxis.setLabelCount(7, force: true)
chart.xAxis.granularityEnabled = true
chart.xAxis.axisMaxLabels = 6
chart.xAxis.axisMinLabels = 0
chart.xAxis.labelPosition = .bottom
chart.xAxis.valueFormatter = formater
chart.xAxis.drawLimitLinesBehindDataEnabled = false
chart.leftAxis.drawGridLinesEnabled = false
chart.leftAxis.drawAxisLineEnabled = false
chart.rightAxis.drawGridLinesEnabled = false
chart.rightAxis.drawAxisLineEnabled = false
chart.rightAxis.drawLabelsEnabled = false
data.groupBars(fromX: 0, groupSpace: groupSpace, barSpace: barSpace)
chart.drawGridBackgroundEnabled = false
chart.legend.enabled = false
chart.notifyDataSetChanged()
return chart
}()
Related
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 using danielgindi/Charts library. In my main view controller I have table view with 3 prototype cell. One of them is for bar chart, second one is for line chart and third one is for pie chart. There are also 3 dequeue reusable cell method and charts configure methods are inside of them. When I first execute application all my bar charts are drawn without any problem. However, when I add new charts or when I scroll (I am not sure but I think one of them lead weird problem) bar chart view looks weird as it shown below image.
It is shown like second one when I first execute program but after some scrolling or adding new charts it looks first one. Every data set cover x axis. Following is my configureBarChart method.
func configureBarChart(xTitle: IndexAxisValueFormatter, index: Int, chartData: BarChartData, chartType: String) {
barChartView.data?.setDrawValues(false)
barChartView.doubleTapToZoomEnabled = false
barChartView.chartDescription?.enabled = false
barChartView.animate(xAxisDuration: 1)
barChartView.xAxis.drawGridLinesEnabled = false
barChartView.xAxis.valueFormatter = xTitle
barChartView.xAxis.labelCount = index
barChartView.rightAxis.enabled = false
barChartView.xAxis.drawGridLinesEnabled = false
barChartView.xAxis.labelPosition = .bottom
barChartView.xAxis.centerAxisLabelsEnabled = true
barChartView.xAxis.granularity = 1
let leftAxisFormatter = NumberFormatter()
leftAxisFormatter.maximumFractionDigits = 1
barChartView.leftAxis.spaceTop = 0.35
barChartView.leftAxis.axisMinimum = 0
barChartView.leftAxis.drawGridLinesEnabled = false
barChartView.rightAxis.enabled = false
var groupSpace = 0.0
var barSpace = 0.0
var barWidth = 0.0
if (chartData.dataSetCount == 1) {
groupSpace = 0.3
barSpace = 0.0
barWidth = 0.7
} else if (chartData.dataSetCount == 2) {
groupSpace = 0.3
barSpace = 0.05
barWidth = 0.3
} else if (chartData.dataSetCount == 3) {
groupSpace = 0.25
barSpace = 0.05
barWidth = 0.2
} else if (chartData.dataSetCount == 4) {
groupSpace = 0.2
barSpace = 0.05
barWidth = 0.15
}
let groupCount = index
let startYear = 0
chartData.barWidth = barWidth;
barChartView.xAxis.axisMinimum = Double(startYear)
let gg = chartData.groupWidth(groupSpace: groupSpace, barSpace: barSpace)
if (chartType == "clustered") {
barChartView.xAxis.axisMaximum = Double(startYear) + gg * Double(groupCount)
chartData.groupBars(fromX: Double(startYear), groupSpace: groupSpace, barSpace: barSpace)
} else {
barChartView.xAxis.axisMaximum = Double(startYear) + 1 * Double(groupCount)
}
barChartView.setScaleEnabled(false)
if xTitle.values.count >= 10 {
barChartView.setVisibleXRangeMaximum(12)
} else {
barChartView.setVisibleXRangeMaximum(Double(xTitle.values.count)) // When too many data comes I limit it so data's are not covering each other.
}
}
I am also using that bar chart for grouped bar chart that is why there is some barSpace and barWidth code. What could be the reason of changing behavior of chart and how can I fix it ?
Edit: Here is my cellForRowAt method and getting data of bar chart
if MainGrafikVC.barChartDataArray[indexPath.row].dataSetCount != 0 {
cell.barChartView.data = MainGrafikVC.barChartDataArray[indexPath.row]
cell.configureBarChart(xTitle: MainGrafikVC.xTitleArray[indexPath.row], index: MainGrafikVC.barChartDataArray[indexPath.row].getDataSetByIndex(0).entryCount, chartData: MainGrafikVC.barChartDataArray[indexPath.row], chartType: Servisler.servisListesi[MainGrafikVC.indexler[indexPath.row]].chartType)
}
if x10.count > 0 {
var barChartEntry10 = [BarChartDataEntry]()
for i in 0..<x10.count {
let value = BarChartDataEntry(x: Double(i), y: Double(x10[i]) ?? 0.0)
barChartEntry10.append(value)
}
let bar10 = BarChartDataSet(values: barChartEntry10, label: "10")
bar10.colors = ChartColorTemplates.vordiplom()
dataSets.append(bar10)
}
let data = BarChartData(dataSets: dataSets)
MainGrafikVC.barChartDataArray.append(data)
I think the problem is about setVisibleXRangeMaximum because when I comment it everything looks same. However, I need to set visible x axis what could be alternative of it?
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
How can I customize the highlighter in Line Charts? I want to cut the highlight to be drawn only up to the data point. I also want to customize the label on the x-axis where it's highlighted. Below is a reference picture on what I'm trying to achieve.
This is what I've done so far. What I've achieved so far
Below is the code for my Line Chart View Setup
let lineChartView: LineChartView = {
let chart = LineChartView(frame: .zero)
chart.chartDescription = nil
chart.dragEnabled = true
chart.scaleYEnabled = false
chart.scaleXEnabled = true
chart.pinchZoomEnabled = false
chart.drawGridBackgroundEnabled = true
chart.gridBackgroundColor = .clear
chart.legend.enabled = false
chart.zoom(scaleX: 2, scaleY: 1, x: 0, y: 0)
chart.setViewPortOffsets(left: 30, top: 30, right: 30, bottom: 30)
chart.rightAxis.enabled = false
let yAxis = chart.leftAxis
yAxis.enabled = true
yAxis.drawAxisLineEnabled = false
yAxis.drawLabelsEnabled = false
yAxis.gridColor = UIColor(rgba: "#414042")
yAxis.gridLineWidth = 1
yAxis.axisMaximum = 6000
chart.xAxis.enabled = true
chart.xAxis.drawGridLinesEnabled = false
chart.xAxis.drawLabelsEnabled = true
chart.xAxis.drawAxisLineEnabled = true
chart.xAxis.axisLineColor = .darkGray
chart.xAxis.axisLineWidth = 1
chart.xAxis.valueFormatter = IndexAxisValueFormatter(values: ["Jan", "Feb", "Mar", "April", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"])
chart.xAxis.labelPosition = .bottom
chart.xAxis.labelTextColor = .darkGray
chart.xAxis.labelFont = UIFont.sourceSansProLight(withSize: 15.5)
chart.xAxis.granularityEnabled = true
chart.xAxis.granularity = 1
chart.highlightPerTapEnabled = false
chart.backgroundColor = .clear
return chart
}()
And this is the code for adding random data points in the chart and the highlight.
var values: [ChartDataEntry] = []
var highlight: Highlight? = nil
for index in 0..<12 {
let randomValue = Double(arc4random_uniform(5000))
values.append(ChartDataEntry(x: Double(index), y: randomValue))
if index == 4 {
highlight = Highlight(x: Double(index), y: randomValue, dataSetIndex: 0)
}
}
let dataSet = LineChartDataSet(values: values, label: "")
dataSet.highlightEnabled = true
dataSet.drawHorizontalHighlightIndicatorEnabled = false
dataSet.highlightColor = UIColor(rgba: "#1899FF")
dataSet.highlightLineWidth = 1
dataSet.mode = .horizontalBezier
dataSet.circleColors = Array(repeating: UIColor(rgba: "#1899FF"), count: 12)
dataSet.fillColor = UIColor(rgba: "#1899FF")
dataSet.drawCircleHoleEnabled = false
dataSet.drawFilledEnabled = true
dataSet.lineWidth = 0.0
dataSet.drawValuesEnabled = true
dataSet.axisDependency = .left
dataSet.valueFormatter = self
let data = LineChartData(dataSet: dataSet)
data.setDrawValues(true)
data.setValueFont(UIFont.sourceSansProLight(withSize: 15.5))
data.setValueTextColor(UIColor(rgba: "#1899FF"))
lineChartView.data = data
lineChartView.highlightValue(highlight)
For Highlight Area of data point you can use below property and achieve this
All property can use through dataSet so for that you can create LineChartDataSet like below and use different property as per your requirement.
//DataSet
LineChartDataSet *set = [[LineChartDataSet alloc] initWithValues:values label:#"closed"];
set.lineWidth = 2;
Set ChartFill property with your fill color :
set.fill = [ChartFill fillWithColor:<Your Legend Color>];
[set setColor:<Your Legend Color>];
[set setCircleColor:<Your Legend Color>];
[set setCircleHoleColor:<Your Legend Color>];
You need to enable drawfill :
set.drawFilledEnabled = YES;
You can Enable circle with this property :
[set setDrawCirclesEnabled:YES];
You can enable highlight Indicator which dat point is selected will highlight with Vertical Line :
[set setDrawHighlightIndicators:YES];
You can set Circle radius as per your requirement :
[set setCircleRadius:5.0f];
[set setCircleHoleRadius:4.0f];
You can specify line with of highlighted data point also :
[set setHighlightLineWidth:1.0];
[set setHighlightColor:kAppLegend3GraphColorForCAP];
Edit:
for changing font color & type you need to change xAxis color and font as mention below
lineChartView.xAxis.labelFont = UIFont.systemFont(ofSize: 20.0, weight: UIFontWeightRegular)
lineChartView.xAxis.labelTextColor = .orange
For Line limit to data point value I think we can not limit this in current version.
Hope this will help you to achieve your requirement.
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.