ios-charts combined chart: bars going past right axis of chart - ios

I'm trying to make something similar to this
Im going to have 4 BarChartDataSets grouped, and 2 LineChartDataSets, each data set has 7 data points, the user can add or remove these datasets at will
The bars seem to be grouping fine, and the line chart shows all 7 points
but as I add more BarChartDataSets to the chart, the bars go off the right side of the chart, the line chart stays the same, here is an image sequence of me starting with a single LineChartDataSet, then adding BarChartDataSets one by one, some of the bars have a value of 0, so its hard to see the group, look for the 0 label at the bottom
How can i stop the bars from going off the right of the chart?
Here is the code:
//get data and values from DataMOs in the activeFeeds
var lineChartDataSets = [LineChartDataSet]()
var barChartDataSets = [BarChartDataSet]()
for (key, dayValuesArray) in valuesByFeed {
var barChartDataEntries = [BarChartDataEntry]()
var lineChartDataEntries = [ChartDataEntry]()
var lineChartDataSet: LineChartDataSet!
var barChartDataSet: BarChartDataSet!
var dataEntry: ChartDataEntry
for (index, value) in (dayValuesArray?.enumerated())! {
//create line chart for Demand and Prod feeds
//create bar chart for every other feed
if key == "Demand" || key == "Prod"{
dataEntry = ChartDataEntry(x: Double(self.activeFeeds.count * index), y: Double(value)!)
lineChartDataEntries.append(dataEntry)
} else {
dataEntry = BarChartDataEntry(x: Double(self.activeFeeds.count * index), y: Double(value)!)
barChartDataEntries.append(dataEntry as! BarChartDataEntry)
}
}
//create line chart data set for Demand and Prod feeds
//create bar chart data set for every other feed
if key == "Demand" || key == "Prod"{
lineChartDataSet = LineChartDataSet(values: lineChartDataEntries, label: key)
lineChartDataSet.drawCirclesEnabled = false
} else {
barChartDataSet = BarChartDataSet(values: barChartDataEntries, label: key)
}
switch key {
case "Solar":
barChartDataSet.setColors(UIColor.orange.withAlphaComponent(1.0))
barChartDataSet.valueTextColor = UIColor.white
break
case "Wind":
barChartDataSet.setColors(UIColor.blue.withAlphaComponent(1.0))
barChartDataSet.valueTextColor = UIColor.white
break
case "Battery":
barChartDataSet.setColors(UIColor.green.withAlphaComponent(1.0))
barChartDataSet.valueTextColor = UIColor.white
break
case "Gen":
barChartDataSet.setColors(UIColor.red.withAlphaComponent(1.0))
barChartDataSet.valueTextColor = UIColor.white
break
case "Demand":
lineChartDataSet.setColors(UIColor.purple.withAlphaComponent(1.0))
lineChartDataSet.valueTextColor = UIColor.white
lineChartDataSet.drawFilledEnabled = true
lineChartDataSet.fillColor = UIColor.purple.withAlphaComponent(0.8)
break
case "Prod":
lineChartDataSet.setColors(UIColor.magenta.withAlphaComponent(1.0))
lineChartDataSet.valueTextColor = UIColor.white
lineChartDataSet.drawFilledEnabled = true
lineChartDataSet.fillColor = UIColor.magenta.withAlphaComponent(0.8)
break
default:
break
}
//append to correct data set array
if key == "Demand" || key == "Prod"{
lineChartDataSets.append(lineChartDataSet)
} else {
barChartDataSets.append(barChartDataSet)
}
}
//set chart data
let chartData = CombinedChartData()
chartData.barData = BarChartData(dataSets: barChartDataSets)
chartData.lineData = LineChartData(dataSets: lineChartDataSets)
let activeFeedsCount = self.activeFeeds.count
if activeFeedsCount > 0 {
self.combinedChartView.data = chartData
if chartData.barData.dataSetCount > 1 {
self.combinedChartView.barData?.groupBars(fromX: 0, groupSpace: 1.0, barSpace: 0.5)
self.combinedChartView.notifyDataSetChanged()
}
} else {
self.combinedChartView.data = CombinedChartData()
self.combinedChartView.noDataText = "No Feeds To Show"
}

I was not able to reproduce the problem with the 0 label, but it is possible to use combinedChart.xAxis.axisMaximum to make sure you can see all the bars to the right.
let activeFeeds = 6
func dataSet() {
combinedChart.isUserInteractionEnabled = true
combinedChart.scaleXEnabled = false
combinedChart.scaleYEnabled = false
combinedChart.dragEnabled = true
//combinedChart.xAxis.axisMinimum = 0.0
combinedChart.xAxis.axisMaximum = 100.0
//get data and values from DataMOs in the activeFeeds
var lineChartDataSets = [LineChartDataSet]()
var barChartDataSets = [BarChartDataSet]()
combinedChart.setVisibleXRange(minXRange: 0.0, maxXRange: 26.0)
let arr1 = [17000,16500,16800,16700,17900,17100,18000]
let arr2 = [17000,17500,16900,16800,17200,17105,17000]
let valuesByFeed = ["Solar":arr1, "Wind": arr2, "Battery": arr1, "Gen":arr1, "Demand":arr1, "Prod":arr1]
for (key, dayValuesArray) in valuesByFeed {
var barChartDataEntries = [BarChartDataEntry]()
var lineChartDataEntries = [ChartDataEntry]()
var lineChartDataSet: LineChartDataSet!
var barChartDataSet: BarChartDataSet!
var dataEntry: ChartDataEntry
for (index, value) in (dayValuesArray.enumerated()) {
//create line chart for Demand and Prod feeds
//create bar chart for every other feed
if key == "Demand" || key == "Prod"{
dataEntry = ChartDataEntry(x: Double(self.activeFeeds * index), y: Double(value))
lineChartDataEntries.append(dataEntry)
} else {
dataEntry = BarChartDataEntry(x: Double(self.activeFeeds * index), y: Double(value))
barChartDataEntries.append(dataEntry as! BarChartDataEntry)
}
}
//create line chart data set for Demand and Prod feeds
//create bar chart data set for every other feed
if key == "Demand" || key == "Prod"{
lineChartDataSet = LineChartDataSet(values: lineChartDataEntries, label: key)
lineChartDataSet.drawCirclesEnabled = false
} else {
barChartDataSet = BarChartDataSet(values: barChartDataEntries, label: key)
}
switch key {
case "Solar":
print("case solar")
barChartDataSet.setColors(UIColor.orange.withAlphaComponent(1.0))
barChartDataSet.valueTextColor = UIColor.white
break
case "Wind":
print("case wind")
barChartDataSet.setColors(UIColor.blue.withAlphaComponent(1.0))
barChartDataSet.valueTextColor = UIColor.white
break
case "Battery":
print("case battery")
barChartDataSet.setColors(UIColor.green.withAlphaComponent(1.0))
barChartDataSet.valueTextColor = UIColor.white
break
case "Gen":
print("case gen")
barChartDataSet.setColors(UIColor.red.withAlphaComponent(1.0))
barChartDataSet.valueTextColor = UIColor.white
break
case "Gen2":
print("case gen")
barChartDataSet.setColors(UIColor.red.withAlphaComponent(1.0))
barChartDataSet.valueTextColor = UIColor.white
break
case "Gen3":
print("case gen")
barChartDataSet.setColors(UIColor.red.withAlphaComponent(1.0))
barChartDataSet.valueTextColor = UIColor.white
break
case "Gen4":
print("case gen")
barChartDataSet.setColors(UIColor.red.withAlphaComponent(1.0))
barChartDataSet.valueTextColor = UIColor.white
break
case "Demand":
print("case demand")
lineChartDataSet.setColors(UIColor.purple.withAlphaComponent(1.0))
lineChartDataSet.valueTextColor = UIColor.white
lineChartDataSet.drawFilledEnabled = true
lineChartDataSet.fillColor = UIColor.purple.withAlphaComponent(0.8)
break
case "Prod":
print("case prod")
lineChartDataSet.setColors(UIColor.magenta.withAlphaComponent(1.0))
lineChartDataSet.valueTextColor = UIColor.white
lineChartDataSet.drawFilledEnabled = true
lineChartDataSet.fillColor = UIColor.magenta.withAlphaComponent(0.8)
break
default:
break
}
//append to correct data set array
if key == "Demand" || key == "Prod"{
lineChartDataSets.append(lineChartDataSet)
} else {
barChartDataSets.append(barChartDataSet)
}
}
//set chart data
let chartData = CombinedChartData()
print("bar count: \(barChartDataSets.count)")
print("line count: \(lineChartDataSets.count)")
chartData.barData = BarChartData(dataSets: barChartDataSets)
chartData.lineData = LineChartData(dataSets: lineChartDataSets)
let activeFeedsCount = self.activeFeeds
if activeFeedsCount > 0 {
self.combinedChart.data = chartData
if chartData.barData.dataSetCount > 1 {
self.combinedChart.barData?.groupBars(fromX: 0, groupSpace: 1.0, barSpace: 0.5)
self.combinedChart.notifyDataSetChanged()
}
} else {
self.combinedChart.data = CombinedChartData()
self.combinedChart.noDataText = "No Feeds To Show"
}
}

Related

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)

Showing/Hiding lines with LineChart

I have the following code to display lines on my chart using ChartsRealm. How can I show/hide individual lines on the chart?
let line1 = LineChartDataSet(values: lineChartEntry1, label: "CH4")
let line2 = LineChartDataSet(values: lineChartEntry2, label: "O2")
let line3 = LineChartDataSet(values: lineChartEntry3, label: "H2S")
line1.colors = [NSUIColor.blue]
line2.colors = [NSUIColor.green]
line3.colors = [NSUIColor.red]
let data = LineChartData()
data.addDataSet(line1)
data.addDataSet(line2)
data.addDataSet(line3)
chtChart.data = (data)
As such there is no methods to hide/show data set in Chart library.
But we can do it logically without refreshing page.
Please check below code for the same:
Create LineChartView Extension:
extension LineChartView {
func setLineChartData(xValues: [String], labels: [String],dataSets:[Array<Double>],colors:[UIColor]) {
var dataSetsArray: [LineChartDataSet] = []
let dataSetCount = self.lineData?.dataSets.count
if dataSetCount != nil && dataSetCount! > 0 {
self.data = nil
}
for i in 0..<dataSets.count {
let yVals = dataSets[i]
var dataEntries: [ChartDataEntry] = []
for i in 0..<yVals.count {
let dataEntry = ChartDataEntry(x: Double(i), y: yVals[i])
dataEntries.append(dataEntry)
}
let chartDataSet = LineChartDataSet(values: dataEntries, label: labels[i])
chartDataSet.highlightEnabled = true
chartDataSet.drawHorizontalHighlightIndicatorEnabled = false
chartDataSet.highlightColor = .blue
chartDataSet.highlightLineWidth = 1
chartDataSet.lineWidth = 2.0
chartDataSet.mode = .horizontalBezier
chartDataSet.drawCircleHoleEnabled = true
chartDataSet.drawValuesEnabled = true
chartDataSet.axisDependency = .left
chartDataSet.circleHoleColor = colors[i]
chartDataSet.highlightColor = colors[i]
chartDataSet.colors = [colors[i]]
//Add Data Set Into Sets array
dataSetsArray.append(chartDataSet)
}
let chartData = LineChartData(dataSets: dataSetsArray)
self.data = chartData
self.animate(xAxisDuration: 1.0,easingOption: .easeInExpo)
}
func chartValueSelected(_ chartView: ChartViewBase, entry: ChartDataEntry, highlight: Highlight) {
}
}
By adding one method into LineChartView extension and call it as per your requirements or user actins.
I called it from my segment change method like below :
#IBAction func segmentValueChanged(_ sender: Any) {
switch self.lineSegment.selectedSegmentIndex {
case 0:
let colors = [UIColor.red,UIColor.green,UIColor.blue]
lineChartView.setLineChartData(xValues: months,
labels: ["Monthly Sales","Quarterly Sales","Yearly Sales"],
dataSets: [unitsSold,unitsSold1,unitsSold2],
colors: colors)
break
case 1:
lineChartView.setLineChartData(xValues: months,
labels: ["Monthly Sales"],
dataSets: [unitsSold],
colors: [UIColor.red])
break
case 2:
lineChartView.setLineChartData(xValues: months,
labels: ["Quarterly Sales"],
dataSets: [unitsSold1],
colors: [UIColor.green])
break
case 3:
lineChartView.setLineChartData(xValues: months,
labels: ["Yearly Sales"],
dataSets: [unitsSold2],
colors: [UIColor.blue])
break
default:
break
}
}
you can pass different data what you want in your dataset.
Check below screens for output reference:
My Segments are All | Monthly | Quarterly | Yearly
Hope this will helps you to achieve your requirements!

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, line chart doesn't refresh datas

I have this problem:
everytime I switch between the segments of the segmented control the datas are messed up, but only if I switch in runtime and only in the 0 segment, the 1 segment works flawlessly no matter how many time I switch. Here's a gif that explains what I mean:
How to deal with this problem? Here's some code
the ibaction func of the segmented control
#IBAction func timeSelectionSegControl(_ sender: UISegmentedControl) {
switch sender.selectedSegmentIndex {
case 0:
last7Filler()
case 1:
todayFiller()
case 2:
last30Filler()
default:
break
} }
todayFiller() (the one which works well):
func todayFiller() {
emptyArrays()
low = CoreDataController.shared.loadCigFromSeverityNumber(severity: "Bassa intensità")
mid = CoreDataController.shared.loadCigFromSeverityNumber(severity: "Media intensità")
high = CoreDataController.shared.loadCigFromSeverityNumber(severity: "Alta intensità")
for i in low {
if i.date == currentDate() { //put in arrays xxxA the elements which have the property .date equals to today
lowA.append(i)
}
}
for i in mid {
if i.date == currentDate() {
midA.append(i)
}
}
for i in high {
if i.date == currentDate() {
highA.append(i)
}
}
//low severity fill funcs FOR TIME
if !lowA.isEmpty || !midA.isEmpty || !highA.isEmpty {
fillBarChart()
var lowSeverityDataEntry = [ChartDataEntry]()
let crossReferenceLow = lowA.reduce(into: [String: [Cig]]()) {
$0[$1.time!.returnFirstNcharacters(n: 3), default: []].append($1)}
let sortedKeysLow = Array(crossReferenceLow.keys).sorted(by: <)
for key in sortedKeysLow {
let matchingTerms = values.filter({
$0.range(of: key, options: .caseInsensitive) != nil
})
if matchingTerms.isEmpty {
print("no elements found in \(key)")
} else {
let index = values.index(of: matchingTerms[0])
let indexString = matchingTerms[0]
let first3 = indexString.returnFirstNcharacters(n: 3)
let value = ChartDataEntry(x: Double(index!), y: Double((crossReferenceLow[first3]?.count)!))
lowSeverityDataEntry.append(value)
doubleArray.append(Double(index!))
doubleArrayMax.append(Double((crossReferenceLow[first3]?.count)!))
}
}
let lowSeverityLine = LineChartDataSet(values: lowSeverityDataEntry, label: "Bassa")
lowSeverityLine.colors = [NSUIColor.green]
lowSeverityLine.mode = .cubicBezier
lowSeverityLine.lineCapType = self.lineCap
lowSeverityLine.lineWidth = self.lineWidth
lowSeverityLine.circleRadius = self.circleRadius
lowSeverityLine.circleColors = [NSUIColor.green]
lowSeverityLine.circleHoleColor = NSUIColor.white
lowSeverityLine.circleHoleRadius = self.circleHoleRadius
lowSeverityLine.drawValuesEnabled = false
//mid severity fill funcs FOR TIME
var midSeverityDataEntry = [ChartDataEntry]()
let crossReferenceMid = midA.reduce(into: [String: [Cig]]()) {
$0[$1.time!.returnFirstNcharacters(n: 3), default: []].append($1)}
let sortedKeysMid = Array(crossReferenceMid.keys).sorted(by: <)
for key in sortedKeysMid {
let matchingTerms = values.filter({
$0.range(of: key, options: .caseInsensitive) != nil
})
if matchingTerms.isEmpty {
print("no elements found in \(key)")
} else {
let index = values.index(of: matchingTerms[0])
let indexString = matchingTerms[0]
let first3 = indexString.returnFirstNcharacters(n: 3)
let value = ChartDataEntry(x: Double(index!), y: Double((crossReferenceMid[first3]?.count)!))
midSeverityDataEntry.append(value)
doubleArray.append(Double(index!))
doubleArrayMax.append(Double((crossReferenceMid[first3]?.count)!))
}
}
let midSeverityLine = LineChartDataSet(values: midSeverityDataEntry, label: "Media")
midSeverityLine.colors = [NSUIColor.yellow]
midSeverityLine.mode = .cubicBezier
midSeverityLine.lineCapType = self.lineCap
midSeverityLine.lineWidth = self.lineWidth
midSeverityLine.circleRadius = self.circleRadius
midSeverityLine.circleColors = [NSUIColor.yellow]
midSeverityLine.circleHoleColor = NSUIColor.white
midSeverityLine.circleHoleRadius = self.circleHoleRadius
midSeverityLine.drawValuesEnabled = false
//high severity fill funcs FOR TIME
var highSeverityDataEntry = [ChartDataEntry]()
let crossReferenceHigh = highA.reduce(into: [String: [Cig]]()) {
$0[$1.time!.returnFirstNcharacters(n: 3), default: []].append($1)}
let sortedKeysHigh = Array(crossReferenceHigh.keys).sorted(by: <)
for key in sortedKeysHigh {
let matchingTerms = values.filter({
$0.range(of: key, options: .caseInsensitive) != nil
})
if matchingTerms.isEmpty {
print("no elements found in \(key)")
} else {
let index = values.index(of: matchingTerms[0])
let indexString = matchingTerms[0]
let first3 = indexString.returnFirstNcharacters(n: 3)
let value = ChartDataEntry(x: Double(index!), y: Double((crossReferenceHigh[first3]?.count)!))
highSeverityDataEntry.append(value)
doubleArray.append(Double(index!))
doubleArrayMax.append(Double((crossReferenceHigh[first3]?.count)!))
}
}
let highSeverityLine = LineChartDataSet(values: highSeverityDataEntry, label: "Alta")
highSeverityLine.colors = [NSUIColor.red]
highSeverityLine.mode = .cubicBezier
highSeverityLine.lineCapType = self.lineCap
highSeverityLine.lineWidth = self.lineWidth
highSeverityLine.circleRadius = self.circleRadius
highSeverityLine.circleColors = [NSUIColor.red]
highSeverityLine.circleHoleColor = NSUIColor.white
highSeverityLine.circleHoleRadius = self.circleHoleRadius
highSeverityLine.drawValuesEnabled = false
let data = LineChartData()
data.addDataSet(lowSeverityLine)
data.addDataSet(midSeverityLine)
data.addDataSet(highSeverityLine)
lineChartView.data = data
guard let min = doubleArray.min() else {return}
guard let max = doubleArrayMax.max() else {return}
lineChartView.xAxis.axisMinimum = min
lineChartView.leftAxis.axisMaximum = max
let myXaxis = lineChartView.xAxis
myXaxis.granularity = 1.0
myXaxis.axisMaximum = Double(values.count)
myXaxis.labelPosition = .bottom
myXaxis.gridLineWidth = 0.2
myXaxis.axisLineWidth = 1.0
myXaxis.axisLineColor = UIColor.black
myXaxis.valueFormatter = IndexAxisValueFormatter(values: values)
let yLeftAxis = lineChartView.leftAxis
yLeftAxis.granularity = 1.0
yLeftAxis.axisMinimum = 0.0
yLeftAxis.gridLineWidth = 0.2
yLeftAxis.axisLineWidth = 1.0
yLeftAxis.axisLineColor = UIColor.black
lineChartView.rightAxis.enabled = false
lineChartView.chartDescription?.text = ""
lineChartView.animate(xAxisDuration: 1.0, easingOption: .linear)
} else {
lineChartView.noDataText = "Nessuna sigaretta fumata oggi"
barChartView.noDataText = "Nessuna sigaretta fumata oggi"
} }
last7Filler() func (the one which give me problems):
func last7Filler() {
emptyArrays()
low = CoreDataController.shared.loadCigFromSeverityNumber(severity: "Bassa intensità")
mid = CoreDataController.shared.loadCigFromSeverityNumber(severity: "Media intensità")
high = CoreDataController.shared.loadCigFromSeverityNumber(severity: "Alta intensità")
for i in low {
let first3Date = i.date!.returnFirstNcharacters(n: 3)
for a in past7Days() {
let first3Day = "\(a)-"
if first3Date == first3Day {
lowA.append(i)
}
}
}
for i in mid {
let first3Date = i.date!.returnFirstNcharacters(n: 3)
for a in past7Days() {
let first3Day = "\(a)-"
if first3Date == first3Day {
midA.append(i)
}
}
}
for i in high {
let first3Date = i.date!.returnFirstNcharacters(n: 3)
for a in past7Days() {
let first3Day = "\(a)-"
if first3Date == first3Day {
highA.append(i)
}
}
}
if !lowA.isEmpty || !midA.isEmpty || !highA.isEmpty {
fillBarChart()
var lowSeverityDataEntry = [ChartDataEntry]()
let crossReferenceLow = lowA.reduce(into: [String:[Cig]]() ) {
$0[$1.date!.returnFirstNcharacters(n: 5), default: []].append($1)}
let sortedKeysLow = Array(crossReferenceLow.keys).sorted(by: <)
for key in sortedKeysLow {
let matchingTerms = values.filter({
$0.range(of: key, options: .caseInsensitive) != nil
})
if matchingTerms.isEmpty {
print("no elements found in \(key)")
} else {
let index = values.index(of: matchingTerms[0])
let value = ChartDataEntry(x: Double(index!), y: Double((crossReferenceLow[key]?.count)!))
lowSeverityDataEntry.append(value)
}
}
let lowSeverityLine = LineChartDataSet(values: lowSeverityDataEntry, label: "Bassa")
lowSeverityLine.colors = [NSUIColor.green]
lowSeverityLine.mode = .cubicBezier
lowSeverityLine.lineCapType = self.lineCap
lowSeverityLine.lineWidth = self.lineWidth
lowSeverityLine.circleRadius = self.circleRadius
lowSeverityLine.circleColors = [NSUIColor.green]
lowSeverityLine.circleHoleColor = NSUIColor.white
lowSeverityLine.circleHoleRadius = self.circleHoleRadius
lowSeverityLine.drawValuesEnabled = false
var midSeverityDataEntry = [ChartDataEntry]()
let crossReferenceMid = midA.reduce(into: [String: [Cig]]() ) {
$0[$1.date!.returnFirstNcharacters(n: 5), default: []].append($1)}
let sortedKeysMid = Array(crossReferenceMid.keys).sorted(by: <)
for key in sortedKeysMid {
let matchingTerms = values.filter({
$0.range(of: key, options: .caseInsensitive) != nil
})
if matchingTerms.isEmpty {
print("no elements found in \(key)")
} else {
let index = values.index(of: matchingTerms[0])
let value = ChartDataEntry(x: Double(index!), y: Double((crossReferenceMid[key]?.count)!))
midSeverityDataEntry.append(value)
}
}
let midSeverityLine = LineChartDataSet(values: midSeverityDataEntry, label: "Media")
midSeverityLine.colors = [NSUIColor.yellow]
midSeverityLine.mode = .cubicBezier
midSeverityLine.lineCapType = self.lineCap
midSeverityLine.lineWidth = self.lineWidth
midSeverityLine.circleRadius = self.circleRadius
midSeverityLine.circleColors = [NSUIColor.yellow]
midSeverityLine.circleHoleColor = NSUIColor.white
midSeverityLine.circleHoleRadius = self.circleHoleRadius
midSeverityLine.drawValuesEnabled = false
var highSeverityDataEntry = [ChartDataEntry]()
let crossReferenceHigh = highA.reduce(into: [String: [Cig]]()) {
$0[$1.date!.returnFirstNcharacters(n: 5), default: []].append($1)}
let sortedKeysHigh = Array(crossReferenceHigh.keys).sorted(by: <)
for key in sortedKeysHigh {
let matchingTerms = values.filter({
$0.range(of: key, options: .caseInsensitive) != nil
})
if matchingTerms.isEmpty {
print("no element found in \(key)")
} else {
let index = values.index(of: matchingTerms[0])
let value = ChartDataEntry(x: Double(index!), y: Double((crossReferenceHigh[key]?.count)!))
highSeverityDataEntry.append(value)
}
}
let highSeverityLine = LineChartDataSet(values: highSeverityDataEntry, label: "Alta")
highSeverityLine.colors = [NSUIColor.red]
highSeverityLine.mode = .cubicBezier
highSeverityLine.lineCapType = self.lineCap
highSeverityLine.lineWidth = self.lineWidth
highSeverityLine.circleRadius = self.circleRadius
highSeverityLine.circleColors = [NSUIColor.red]
highSeverityLine.circleHoleColor = NSUIColor.white
highSeverityLine.circleHoleRadius = self.circleHoleRadius
highSeverityLine.drawValuesEnabled = false
let data = LineChartData()
data.addDataSet(lowSeverityLine)
data.addDataSet(midSeverityLine)
data.addDataSet(highSeverityLine)
lineChartView.data = data
lineChartView.notifyDataSetChanged()
lineChartView.data!.notifyDataChanged()
//graphic configuration
let myXaxis = lineChartView.xAxis
myXaxis.granularity = 1.0
myXaxis.axisMinimum = 0.0
myXaxis.axisMaximum = Double(values.count)
myXaxis.labelPosition = .bottom
myXaxis.gridLineWidth = 0.2
myXaxis.axisLineWidth = 1.0
myXaxis.axisLineColor = UIColor.black
myXaxis.valueFormatter = IndexAxisValueFormatter(values: values)
let yLeftAxis = lineChartView.leftAxis
yLeftAxis.granularity = 1.0
yLeftAxis.axisMinimum = 0.0
yLeftAxis.gridLineWidth = 0.2
yLeftAxis.axisLineWidth = 1.0
yLeftAxis.axisLineColor = UIColor.black
lineChartView.rightAxis.enabled = false
lineChartView.chartDescription?.text = ""
lineChartView.animate(xAxisDuration: 1.0, easingOption: .linear)
} else {
lineChartView.noDataText = "Nessuna sigaretta fumata nei scorsi 7 giorni"
barChartView.noDataText = "Nessuna sigaretta fumata nei scorsi 7 giorni"
}
p.s. the func emptyArrays() just gives removeAll() to the arrays low, mid, high, lowA, midA and highA

Charts, HorizontalBarChartView, how set values alignment = Center?

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.

Resources