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
Related
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)
func setMarkeronmap(isFitAllPins : Bool)
{
var myTagValue : Int = 0
var bounds = GMSCoordinateBounds()
// loop for set marker icon image
for item in self.arrFirstThirty
{
if let jsonDict = item as? NSDictionary
{
var floatLat = Double()
var floatLong = Double()
if let temp = jsonDict.value(forKey: "Latitude") as? String {
floatLat = Double ((jsonDict.value(forKey: "Latitude") as? String)!)!
floatLong = Double((jsonDict.value(forKey: "Longtitude") as? String)!)!
}
else {
floatLat = Double ((jsonDict.value(forKey: "Latitude") as? NSNumber)!)
floatLong = Double((jsonDict.value(forKey: "Longtitude") as? NSNumber)!)
}
self.Mapview.isMyLocationEnabled = true
let mapMarker = GMSMarker()
mapMarker.position = CLLocationCoordinate2DMake(floatLat
, floatLong)
bounds = bounds.includingCoordinate(mapMarker.position)
self.myImageView.image = UIImage (named: "\((jsonDict.value(forKey: "CompanyBrand") as! String).lowercased())_map_pin")
var sourceView = UIView()
sourceView = self.viewMarker
let copiedView: UIView = sourceView.copyView()
copiedView.tag = myTagValue
let image = self.image(with: copiedView)
mapMarker.icon = image
mapMarker.tracksViewChanges = true
mapMarker.map = self.Mapview
mapMarker.userData = myTagValue
mapMarker.zIndex = Int32(myTagValue)
myTagValue += 1
}
}
If I keep only above code then map scrolling is too smooth as required. But when I add below code then map scrolling is not smooth.
// loop for set marker iconView
myTagValue = 10000
for item in self.arrFirstThirty
{
if let jsonDict = item as? NSDictionary
{
var floatLat = Double()
var floatLong = Double()
if let temp = jsonDict.value(forKey: "Latitude") as? String {
floatLat = Double ((jsonDict.value(forKey: "Latitude") as? String)!)!
floatLong = Double((jsonDict.value(forKey: "Longtitude") as? String)!)!
}
else {
floatLat = Double ((jsonDict.value(forKey: "Latitude") as? NSNumber)!)
floatLong = Double((jsonDict.value(forKey: "Longtitude") as? NSNumber)!)
}
let mapMarker = GMSMarker()
mapMarker.position = CLLocationCoordinate2DMake(floatLat
, floatLong)
bounds = bounds.includingCoordinate(mapMarker.position)
Mapview.needsUpdateConstraints()
var strCurrType = String("Euro")
if Defaults[PDUserDefault.CurrencyNameEnglish] != nil && Defaults[PDUserDefault.CurrencyRate] != nil
{
strCurrType = Defaults[PDUserDefault.CurrencyNameSymbol]!
let abc = ("\((jsonDict.value(forKey: "FuelPrice") as? String)!)")
let strPrice = Float(abc.replacingOccurrences(of: ",", with: ".", options: .literal, range: nil))
var updatedPrice = Float(Defaults[PDUserDefault.CurrencyRate]!)! * strPrice!
updatedPrice = (updatedPrice * 1000).rounded() / 1000
var finalPrice = String.init(format: "%.3f", updatedPrice)
if Defaults[PDUserDefault.LanguageType] == "1"
{
finalPrice = finalPrice.replacingOccurrences(of: ",", with: ".")
}
else
{
finalPrice = finalPrice.replacingOccurrences(of: ".", with: ",")
}
self.lblmarkername.text = ("\(finalPrice) \(strCurrType!)")
let strokeTextAttributes = [
NSStrokeColorAttributeName : UIColor.init(red: 1.0/255.0, green: 123.0/255.0, blue: 146.0/255.0, alpha: 1.0),NSForegroundColorAttributeName : UIColor.white,NSStrokeWidthAttributeName : -3.0,] as [String : Any]
self.lblmarkername.attributedText = NSAttributedString(string: ("\(finalPrice) \(strCurrType!)"), attributes: strokeTextAttributes)
}
else
{
strCurrType = Defaults[PDUserDefault.CurrencyNameSymbol]!
let abc = ("\((jsonDict.value(forKey: "FuelPrice") as? String)!)")
var strmyPrice = Float(abc.replacingOccurrences(of: ",", with: ".", options: .literal, range: nil))
strmyPrice = (strmyPrice! * 1000).rounded() / 1000
var finalPrice = String.init(format: "%.3f", strmyPrice!)
if Defaults[PDUserDefault.LanguageType] == "1"
{
finalPrice = finalPrice.replacingOccurrences(of: ",", with: ".")
}
else
{
finalPrice = finalPrice.replacingOccurrences(of: ".", with: ",")
}
self.lblmarkername.text = ("\(finalPrice) \(strCurrType!)")
let strokeTextAttributes = [
NSStrokeColorAttributeName : UIColor.init(red: 1.0/255.0, green: 123.0/255.0, blue: 146.0/255.0, alpha: 1.0),NSForegroundColorAttributeName : UIColor.white,NSStrokeWidthAttributeName : -3.0,] as [String : Any]
self.lblmarkername.attributedText = NSAttributedString(string: ("\(finalPrice) \(strCurrType!)"), attributes: strokeTextAttributes)
}
var sourceView = UIView()
sourceView = self.viewMarker2
let copiedView: UIView = sourceView.copyView()
copiedView.tag = myTagValue
mapMarker.iconView = copiedView
mapMarker.tracksViewChanges = true
mapMarker.map = self.Mapview
mapMarker.userData = myTagValue
mapMarker.zIndex = Int32(myTagValue)
myTagValue += 1
markerArray.add(mapMarker)
}
}
if isFitAllPins
{
let update = GMSCameraUpdate.fit(bounds, withPadding: 80)
self.Mapview.animate(with: update)
}
}
Using first loop, I had added marker with image only. And then in second loop I have added prices over the market image because I have to keep prices always on top without hiding behind the marker image. But if I add prices this way, Map scrolling is not smooth. So please anyone can help me on this?
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"
}
}
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.
I am attempting to create a crosshair (vertical line) for my graph in Swift. I have looked over the various Objective-C examples of how to do this, and have mimicked them in the code below:
class viewController: UIViewController {
#IBOutlet weak var graphView: CPTGraphHostingView!
var plot1: CPTScatterPlot!
var plot2: CPTScatterPlot!
var plot3: CPTScatterPlot!
var plotDataSource1: CPTFunctionDataSource?
var plotDataSource2: CPTFunctionDataSource?
var plotDataSource3: CPTFunctionDataSource?
var markerAnnotation: CPTPlotSpaceAnnotation?
override func viewDidLoad() {
super.viewDidLoad()
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
initPlot()
}
func initPlot() {
configureHostView()
configureGraph()
configureChart()
configureAxes()
}
func configureHostView() {
graphView.allowPinchScaling = true
print("host con called")
}
func configureGraph() {
// 1 - Create the graph
let graph = CPTXYGraph(frame: graphView.bounds)
graph.plotAreaFrame?.masksToBorder = true
graphView.hostedGraph = graph
// 2 - Configure the graph
graph.applyTheme(CPTTheme(named: kCPTPlainWhiteTheme))
graph.fill = CPTFill(color: CPTColor.clearColor())
graph.paddingBottom = 0.0
graph.paddingLeft = 0.0
graph.paddingTop = 0.0
graph.paddingRight = 0.0
// 3 - Set up styles
let titleStyle = CPTMutableTextStyle()
titleStyle.color = CPTColor.blackColor()
titleStyle.fontName = "HelveticaNeue-Bold"
titleStyle.fontSize = 16.0
titleStyle.textAlignment = .Center
graph.titleTextStyle = titleStyle
// 4 - Set up plot space
let xMin = -10.0
let xMax = 10.0
let yMin = -10.0
let yMax = 10.0
guard let plotSpace = graph.defaultPlotSpace as? CPTXYPlotSpace else { return }
plotSpace.allowsUserInteraction = true
plotSpace.xRange = CPTPlotRange(locationDecimal: CPTDecimalFromDouble(xMin), lengthDecimal: CPTDecimalFromDouble(xMax - xMin))
plotSpace.yRange = CPTPlotRange(locationDecimal: CPTDecimalFromDouble(yMin), lengthDecimal: CPTDecimalFromDouble(yMax - yMin))
print("graph con called")
}
func configureChart() {
// 1 - Set up the three plots
plot1 = CPTScatterPlot()
plot2 = CPTScatterPlot()
plot3 = CPTScatterPlot()
// 2 - Set up line style
let lineStyle1 = CPTMutableLineStyle()
lineStyle1.lineColor = CPTColor.blueColor()
lineStyle1.lineWidth = 0.5
let lineStyle2 = CPTMutableLineStyle()
lineStyle2.lineColor = CPTColor.redColor()
lineStyle2.lineWidth = 0.5
let lineStyle3 = CPTMutableLineStyle()
lineStyle3.lineColor = CPTColor.greenColor()
lineStyle3.lineWidth = 0.5
// 3 - Add plots to graph
guard let graph = graphView.hostedGraph else { return }
plot1.delegate = self
plot2.delegate = self
plot3.delegate = self
//let function: CPTDataSourceFunction? = cos
let block1 = {(x: Double) -> Double in
return sin(x)
}
let block2 = {(x: Double) -> Double in
return 1/x
}
let block3 = {(x: Double) -> Double in
return log(x)
}
//if (block != nil) {
plotDataSource1 = CPTFunctionDataSource(forPlot: plot1, withBlock: block1)
plot1.dataSource = plotDataSource1
//}
plotDataSource2 = CPTFunctionDataSource(forPlot: plot2, withBlock: block2)
plot2.dataSource = plotDataSource2
plotDataSource3 = CPTFunctionDataSource(forPlot: plot3, withBlock: block3)
plot3.dataSource = plotDataSource3
plot1.dataLineStyle = lineStyle1
plot2.dataLineStyle = lineStyle2
plot3.dataLineStyle = lineStyle3
graph.addPlot(plot1, toPlotSpace: graph.defaultPlotSpace)
graph.addPlot(plot2, toPlotSpace: graph.defaultPlotSpace)
graph.addPlot(plot3, toPlotSpace: graph.defaultPlotSpace)
print("chart con called")
}
func configureAxes() {
// 1 - Configure styles
let axisLineStyle = CPTMutableLineStyle()
axisLineStyle.lineWidth = 2.0
axisLineStyle.lineColor = CPTColor.blackColor()
let majorGridLineStyle: CPTMutableLineStyle = CPTMutableLineStyle()
majorGridLineStyle.lineWidth = 0.75
majorGridLineStyle.lineColor = CPTColor.grayColor()
let minorGridLineStyle: CPTMutableLineStyle = CPTMutableLineStyle()
minorGridLineStyle.lineWidth = 0.25
minorGridLineStyle.lineColor = CPTColor.whiteColor()
guard let axisSet = graphView.hostedGraph?.axisSet as? CPTXYAxisSet else { return }
// 3 - Configure the x-axis
let axisStyle = CPTMutableTextStyle()
axisStyle.fontSize = 6.0
//
let crosshair = CPTXYAxis()
crosshair.hidden = false
crosshair.coordinate = CPTCoordinate.Y
crosshair.plotSpace = graphView.hostedGraph?.defaultPlotSpace
crosshair.axisConstraints = CPTConstraints(lowerOffset: 10.0)
crosshair.labelingPolicy = CPTAxisLabelingPolicy.None
crosshair.separateLayers = true
crosshair.preferredNumberOfMajorTicks = 6
crosshair.minorTicksPerInterval = 0
let cStyle: CPTMutableLineStyle = CPTMutableLineStyle()
cStyle.lineWidth = 4.0
cStyle.lineColor = CPTColor.orangeColor()
crosshair.axisLineStyle = cStyle
crosshair.majorTickLineStyle = nil
//
let x: CPTXYAxis = axisSet.xAxis!
x.labelingPolicy = .Automatic
x.title = ""
x.labelTextStyle = axisStyle
let y: CPTXYAxis = axisSet.yAxis!
y.labelingPolicy = .Automatic
y.title = ""
y.labelTextStyle = axisStyle
axisSet.axes = [x, y, crosshair]
let hitAnnotationTextStyle: CPTMutableTextStyle = CPTMutableTextStyle()
hitAnnotationTextStyle.color = CPTColor.blackColor()
hitAnnotationTextStyle.fontName = "Helvetica-Bold"
hitAnnotationTextStyle.fontSize = 6
let textLayer: CPTTextLayer = CPTTextLayer(text: "Annotation", style: hitAnnotationTextStyle)
textLayer.cornerRadius = 3.0
textLayer.paddingLeft = 2.0
textLayer.paddingTop = 2.0
textLayer.paddingRight = 2.0
textLayer.paddingBottom = 2.0
textLayer.hidden = false
let graph = CPTXYGraph(frame: graphView.bounds)
let plotSpace = graph.defaultPlotSpace as? CPTXYPlotSpace
let annotation: CPTPlotSpaceAnnotation = CPTPlotSpaceAnnotation(plotSpace: plotSpace!, anchorPlotPoint: [0, 0])
annotation.contentLayer = textLayer
graph.addAnnotation(annotation)
self.markerAnnotation = annotation
print("axes con called")
}
}
extension viewController: CPTPlotSpaceDelegate, CPTPlotDataSource, CPTScatterPlotDelegate {
func numberOfRecordsForPlot(plot: CPTPlot) -> UInt {
print("1")
return (self.plotDataSource1?.dataPlot.cachedDataCount)!
}
func numbersForPlot(plot: CPTPlot, field fieldEnum: UInt, recordIndex index: UInt) -> AnyObject {
print("2")
return (self.plotDataSource1?.dataPlot.cachedDoubleForField(UInt(fieldEnum), recordIndex: UInt(index)))!
}
func plotSpace(space: CPTPlotSpace, willDisplaceBy displacement: CGPoint) -> CGPoint {
print("3")
return CGPointMake(0.0, 0.0)
}
func plotSpace(space: CPTPlotSpace, willChangePlotRangeTo newRange: CPTPlotRange, forCoordinate coordinate: CPTCoordinate) -> CPTPlotRange? {
print("4")
var updatedRange: CPTPlotRange? = nil
let xySpace: CPTXYPlotSpace = (space as! CPTXYPlotSpace)
switch coordinate {
case CPTCoordinate.X:
updatedRange = xySpace.xRange
case CPTCoordinate.Y:
updatedRange = xySpace.yRange
default:
break
}
return updatedRange!
}
func plotSpace(space: CPTPlotSpace, shouldHandlePointingDeviceDownEvent event: UIEvent, atPoint point: CGPoint) -> Bool {
print("5")
let xySpace: CPTXYPlotSpace = (space as! CPTXYPlotSpace)
let graphy = xySpace.graph!
let crosshair = graphy.axisSet!.axes![2] as? CPTXYAxis
var plotPoint = space.plotPointForEvent(event)
let annotation: CPTPlotSpaceAnnotation = self.markerAnnotation!
let textLayer: CPTTextLayer = (annotation.contentLayer as! CPTTextLayer)
var xNumber = plotPoint![CPTCoordinate.X.rawValue]
var yNumber = plotPoint![CPTCoordinate.Y.rawValue]
if xySpace.xRange.containsNumber(xNumber) {
let x: Int = Int(Double(xNumber))
let y: Int = Int(Double(yNumber))
xNumber = x
yNumber = y
let xValue: String = (graphView.hostedGraph!.axisSet?.axes?[0].labelFormatter!.stringForObjectValue(xNumber)!)!
let yValue: String = (graphView.hostedGraph!.axisSet?.axes?[1].labelFormatter!.stringForObjectValue(yNumber)!)!
textLayer.text = "\(xValue), \(yValue)"
textLayer.hidden = false
annotation.anchorPlotPoint = [xNumber, yNumber]
crosshair!.orthogonalPosition = xNumber
crosshair!.hidden = false
} else {
textLayer.hidden = true
crosshair!.hidden = true
}
return false
}
func plotSpace(space: CPTPlotSpace, shouldHandlePointingDeviceDraggedEvent event: UIEvent, atPoint point: CGPoint) -> Bool {
print("6")
return self.plotSpace(space, shouldHandlePointingDeviceDraggedEvent: event, atPoint: point)
}
func plotSpace(space: CPTPlotSpace, shouldHandlePointingDeviceUpEvent event: UIEvent, atPoint point: CGPoint) -> Bool {
print("7")
return false
}
}
The data I am trying to index is created from a CPTFunctionDataSource, so what I am trying to do might be more complicated. Any assistance is appreciated...