Is there a way to estimate where a ChartLimitLine and a LineChartDataSet intersect on a graph? - ios

I am using the Charts pod library in my app. I have a limit line that intersects a LineChartDataSet and I would like to estimate at what x-value the intersection takes place. I could not find a specific function for this in the library (unless I am missing something), and so I am wondering what the best way to go about trying to do this is?
I am creating the limit line as follows:
let line2 = ChartLimitLine(limit: 0, label: "Break-Even")
line2.lineColor = .lightGray
line2.valueTextColor = .lightGray
line2.labelPosition = .topRight
line2.lineWidth = 1
line2.lineDashLengths = [3]
chartView.leftAxis.addLimitLine(line2)
And this is how I am adding my data to my chart (there are two series, two lines).
var todayDataValues : [ChartDataEntry] = [ ]
var expiryDataValues : [ChartDataEntry] = [ ]
for (index, item) in todayValues.enumerated() {
todayDataValues.append(ChartDataEntry(x: doubleSpots[index], y: item))
}
for (index, item2) in expiryValues.enumerated() {
expiryDataValues.append(ChartDataEntry(x: doubleSpots[index], y: item2))
}
let set1 = LineChartDataSet(entries: todayDataValues, label: "Today")
set1.mode = .linear set1.drawCirclesEnabled = false
set1.setColor(UIColor(named: "TodayLine")!) set1.lineWidth = 3
set1.highlightColor = .systemGray let set2 = LineChartDataSet(entries: expiryDataValues, label: self.selectedExpiry) set2.mode = .linear
set2.setColor(UIColor(named: "ExpiryLine")!) set2.lineWidth = 3
set2.drawCirclesEnabled = false set2.highlightColor = .systemGray let data = LineChartData(dataSets: [set1, set2]) data.setDrawValues(false)
self.lineChartView.data = data
Neither data set has an x value of 0 (where my limit line is), but I am asking how I can make a calculation based on the equation of the line drawn between the two points that does intersect 0 - what the x-value might be.

Related

LineChart with optional Y parameter swift

Require a LineChart where in it allows y value as nil. As when no data for that particular day(x) is there the line should just go forward.
Currently I have researched on SwiftChart & Charts but both doesn't provide that functionality.
Please refer below image for more understanding.
As you can see Sunday, Monday & Wednesday there is data Tuesday there is no data so the line just continues from Monday to Wednesday.
How can I achieve this or if there is any library that can help me achieve this.
You can just skip some X value in https://github.com/danielgindi/Charts
private func setupChart() {
let leftAxis = chart.leftAxis
leftAxis.axisMinimum = 0
leftAxis.axisMaximum = 100
leftAxis.granularity = 10
let rightAxis = chart.rightAxis
rightAxis.enabled = false
let xAxis = chart.xAxis
xAxis.axisMinimum = 0
xAxis.axisMaximum = 7
xAxis.labelPosition = .bottom
xAxis.granularity = 1
}
private func setupChartData() {
var dataEntries: [ChartDataEntry] = []
for i in 0...7 {
if i % 2 == 0 {
let value = arc4random_uniform(100) + 1
if value != 0 {
let dataEntry = ChartDataEntry(x: Double(i), y: Double(value))
dataEntries.append(dataEntry)
}
}
}
let dataSet = LineChartDataSet(entries: dataEntries, label: "")
let data = LineChartData(dataSet: dataSet)
chart.data = data
}

How to remove static string "DataSet" from Legends of Pie Chart for danielgindi/Charts ios?

I am using danielgindi/Charts for iOS/Swift. There is an extra Legend Entry with label "DataSet" displays in Pie Chart as seen in this image:
When I traced, I found there are two entries in the array of LegendEntry found in the PieChartView legend, i.e. PieChartView.legend.entries, where as I have only one object in my array.
Here is the code:
let dataSet = PieChartDataSet()
dataSet.drawIconsEnabled = false
dataSet.setColor(AppColors.selectedMenuItem)
dataSet.sliceSpace = 3
dataSet.iconsOffset = CGPoint(x: 0, y: 40)
dataSet.selectionShift = 5
var totalRevenuePer:Double = 0.0
_ = arrRevenue.map({ (objRevenue) -> Void in
if let percentage = Double(objRevenue.per ?? "0.0"), percentage != 0.0{
dataSet.append(PieChartDataEntry(value: percentage, label: "\((objRevenue.rev_center_name ?? "") + " " + objRevenue.revenue.currencyString())"))
totalRevenuePer += percentage
}
})
var colors = AppColors.TenderColors
if totalRevenuePer < 100{ colors.append(.clear) }
dataSet.colors = colors
let data = PieChartData(dataSet: dataSet)
data.setValueFormatter(PercentageFormatter())
data.setValueFont(NSUIFont.systemFont(ofSize: 11))
data.setValueTextColor(.white)
pieChart.data = data
pieChart.highlightValue(nil)
let legend = pieChart.legend
legend.textColor = .white
legend.entries.last?.label = ""
pieChart.animate(yAxisDuration: 1.4, easingOption: .easeInOutQuad)
// Refresh chart with new data
pieChart.notifyDataSetChanged()
Appreciate any help, thank you.
It's a property of PieChartDataSet
The default value, if you don't set your own, is "DataSet"
let dataSet = PieChartDataSet()
// provide your own
dataSet.label = "My Label"
// or, no label
dataSet.label = ""

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 not index properly

I'm populating a Combined Chart having a Line Chart and a Grouped Bar Chart BUT
the bars are not coming up as expected. They're not in sync with xAxis indexes. Any help will be appreciated.
Combined Chart Image: Line + Grouped Bar
For the image I've attached, bars should be in sync with each month but they are not.
Here's the code:
private func setLineChartWith(data: [Double]) {
var lineChartEntries: [ChartDataEntry] = []
for i in 0..<data.count {
let lineChartEntry = ChartDataEntry(value: data[i], xIndex: i)
lineChartEntries.append(lineChartEntry)
}
let lineDataSet = LineChartDataSet(yVals: lineChartEntries, label: "Line")
lineDataSet.lineWidth = 3
lineDataSet.circleRadius = 4
lineDataSet.mode = .CubicBezier
lineDataSet.highlightEnabled = true
let lineChartData = LineChartData(xVals: datesData, dataSets: [lineDataSet])
chartData.lineData = lineChartData
}
// MARK: Bar Chart Code
func setBarChartWith(data: [Double], secondaryData: [Double]?) {
var barChartEntries1: [BarChartDataEntry] = []
var barChartEntries2: [BarChartDataEntry] = []
for i in 0..<data.count {
barChartEntries1.append(BarChartDataEntry(value: data[i], xIndex: i))
barChartEntries2.append(BarChartDataEntry(value: data[i], xIndex: i))
}
let barDataSet = BarChartDataSet(yVals: barChartEntries1, label: "Bar1")
barDataSet.barSpace = 0.5
barDataSet.highlightEnabled = true
barDataSet.barShadowColor = UIColor.clearColor()
let barDataSet2 = BarChartDataSet(yVals: barChartEntries1, label: "Bar2")
barDataSet2.barSpace = 0.5
barDataSet2.highlightEnabled = true
barDataSet2.barShadowColor = UIColor.clearColor()
var dataSets : [BarChartDataSet] = [BarChartDataSet]()
dataSets.append(barDataSet)
dataSets.append(barDataSet2)
let barChartData = BarChartData(xVals: datesData, dataSets: dataSets)
chartData.barData = barChartData
}
Probably you are using a library to create your graphic. This bibliotca have this problem, the items are limited in the x-axis. The graph divides them so that the User can understand even without some data. You will realize that it always starts on the first index and ends on the last index of the array so it takes some data from the middle of the x-axis. Thus the User can understand the graph and the graph is not overloaded. There is no right solution in the library for this but you can try to zoom the graph or the labels on the x axis. Increasing the width of the graph should also help.
set those in class level
var barCartDataSet : [IChartDataSet] = []
var colNamesArray : [String]!
//call this function as many time as you needed means how much bars you need in one group
setChartData("Test Lable", values: [2.0,3.0] , color: UIColor.darkGrayColor())
//After that at last call this
setChartDataSet(colNamesArray, chartDataSet: barCartDataSet)
//Functios
func setChartData(lableName: String, values: [Double] , color : UIColor) {
var dataEntries: [BarChartDataEntry] = []
for i in 0..<values.count {
let dataEntry = BarChartDataEntry(value: values[i], xIndex: i)
dataEntries.append(dataEntry)
}
let chartDataSet = BarChartDataSet(yVals: dataEntries, label: lableName)
barCartDataSet.append(chartDataSet)
//changing color
chartDataSet.colors = [color]
}
func setChartDataSet(dataPoints: [String], chartDataSet : [IChartDataSet]) {
BarChartDrawingView.noDataText = "You need to provide data for the chart."
let chartData = BarChartData(xVals: dataPoints, dataSets: chartDataSet)
chartData.groupSpace = 0.8
BarChartDrawingView.data = chartData
BarChartDrawingView.xAxis.labelPosition = .Bottom
//Description Text
BarChartDrawingView.descriptionText = " "
}
sorry for bad English. Hope it helps :)

Many Gradient Fill in same lineChart Swift for iOS-Charts

let gradientColors = [UIColor.cyanColor().CGColor, UIColor.clearColor().CGColor] // Colors of the gradient
let colorLocations:[CGFloat] = [1.0, 0.0] // Positioning of the gradient
let gradient = CGGradientCreateWithColors(CGColorSpaceCreateDeviceRGB(), gradientColors, colorLocations) // Gradient Object
set.fill = ChartFill.fillWithLinearGradient(gradient!, angle: 90.0) // Set the Gradient
set.drawFilledEnabled = true // Draw the Gradient
Result
I want to have many fill depending of xAxis value like this :
It's possible to do this ??
Solution:
The solution is to use many dataset, from the second one, the first value for each data need to be same the last value of the previous dataset so at the end it will look like you have one dataset
ex:
let dollars1 = [1453.0,2352,5431,1442] // last value = first value of next dataset
let dollars2 = [1442.0,2234,8763,4453] // last value = first value of next dataset
let dollars3 = [4453.0,3456,7843,5678] // last value = first value of next dataset
func setChartData(months : [String]) {
var yVals1 : [ChartDataEntry] = [ChartDataEntry]()
for var i = 0; i < months.count; i++ {
yVals1.append(ChartDataEntry(value: dollars1[i], xIndex: i))
}
let set1: LineChartDataSet = LineChartDataSet(yVals: yVals1, label: "First Set")
set1.axisDependency = .Left // Line will correlate with left axis values
set1.setColor(UIColor.redColor().colorWithAlphaComponent(0.5))
set1.setCircleColor(UIColor.redColor())
set1.lineWidth = 2.0
set1.circleRadius = 6.0
set1.fillAlpha = 1
set1.fillColor = UIColor.redColor()
set1.drawFilledEnabled = true
var yVals2 : [ChartDataEntry] = [ChartDataEntry]()
for var i = 0; i < months.count; i++ {
yVals2.append(ChartDataEntry(value: dollars2[i], xIndex: i))
}
let set2: LineChartDataSet = LineChartDataSet(yVals: yVals2, label: "Second Set")
set2.axisDependency = .Left // Line will correlate with left axis values
set2.setColor(UIColor.greenColor().colorWithAlphaComponent(0.5))
set2.setCircleColor(UIColor.greenColor())
set2.lineWidth = 2.0
set2.circleRadius = 6.0
set2.fillAlpha = 1
set2.fillColor = UIColor.greenColor()
set2.drawFilledEnabled = true
var yVals3 : [ChartDataEntry] = [ChartDataEntry]()
for var i = 0; i < months.count; i++ {
yVals3.append(ChartDataEntry(value: dollars3[i], xIndex: i))
}
let set3: LineChartDataSet = LineChartDataSet(yVals: yVals3, label: "Second Set")
set3.axisDependency = .Left // Line will correlate with left axis values
set3.setColor(UIColor.blueColor().colorWithAlphaComponent(0.5))
set3.setCircleColor(UIColor.blueColor())
set3.lineWidth = 2.0
set3.circleRadius = 6.0
set3.fillAlpha = 65 / 255.0
set3.fillColor = UIColor.blueColor()
set3.drawFilledEnabled = true
//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(xVals: months, dataSets: dataSets)
data.setValueTextColor(UIColor.whiteColor())
//5 - finally set our data
self.lineChartView.data = data
}
Yes its possible to do that gradient fill you want ,just replace below line and add some color so you can check.
set.fill = ChartFill.fillWithLinearGradient(gradient!, angle: 90.0)
Set the angle 180 so it will work
set.fill = ChartFill.fillWithLinearGradient(gradient!, angle: 180.0)

Resources