How can I set specific colors for an individual bubble in an iOS Charts bubble chart dependent on its y-value? Just like it is shown in one of the screenshot on the iOS Charts GitHub site here.
So all top level bubbles should be the same color, all middle ones another, etc...
I already tried to change the color like that:
chartDataSet.colors = [UIColor.red, UIColor.orange, UIColor.green]
But that only changes the color for every x value.
Full Code
That is my full code for setting the bubble chart:
func getDetailedAnalytics() {
let currentTeacherDetailedAnalyticsUrl = TEACHER_DETAILED_ANALYTICS_URL + currentTeacherCourseId
Alamofire.request(currentTeacherDetailedAnalyticsUrl).responseJSON { response in
let result = response.result
if let dict = result.value as? Dictionary<String, AnyObject> {
let firstDateValue = dict["0"] as? Dictionary<String, AnyObject>
let secondDateValue = dict["1"] as? Dictionary<String, AnyObject>
let thirdDateValue = dict["2"] as? Dictionary<String, AnyObject>
let fourthDateValue = dict["3"] as? Dictionary<String, AnyObject>
let fifthDateValue = dict["4"] as? Dictionary<String, AnyObject>
let firstDateLow = firstDateValue?["numberValuesUnder50"] as! Int
let firstDateMiddle = firstDateValue?["numberValuesInMiddle"] as! Int
let firstDateHigh = firstDateValue?["numberValuesOver75"] as! Int
let secondDateLow = secondDateValue?["numberValuesUnder50"] as! Int
let secondDateMiddle = secondDateValue?["numberValuesInMiddle"] as! Int
let secondDateHigh = secondDateValue?["numberValuesOver75"] as! Int
let thirdDateLow = thirdDateValue?["numberValuesUnder50"] as! Int
let thirdDateMiddle = thirdDateValue?["numberValuesInMiddle"] as! Int
let thirdDateHigh = thirdDateValue?["numberValuesOver75"] as! Int
let fourthDateLow = fourthDateValue?["numberValuesUnder50"] as! Int
let fourthDateMiddle = fourthDateValue?["numberValuesInMiddle"] as! Int
let fourthDateHigh = fourthDateValue?["numberValuesOver75"] as! Int
let fifthDateLow = fifthDateValue?["numberValuesUnder50"] as! Int
let fifthDateMiddle = fifthDateValue?["numberValuesInMiddle"] as! Int
let fifthDateHigh = fifthDateValue?["numberValuesOver75"] as! Int
self.analyticsData = [25, 62, 88, 25, 62, 88, 25, 62, 88, 25, 62, 88, 25, 62, 88]
self.analyticsAmountsData = [firstDateLow, firstDateMiddle, firstDateHigh, secondDateLow, secondDateMiddle, secondDateHigh, thirdDateLow, thirdDateMiddle, thirdDateHigh, fourthDateLow, fourthDateMiddle, fourthDateHigh, fifthDateLow, fifthDateMiddle, fifthDateHigh]
self.setBubbleChart(dataPoints: self.dateBubble, values: self.analyticsData, amounts: self.analyticsAmountsData)
}
}
}
func setBubbleChart(dataPoints: [Int], values: [Int], amounts: [Int]) {
var dataEntries: [BubbleChartDataEntry] = []
for i in 0..<dataPoints.count {
let dataEntry = BubbleChartDataEntry(x: Double(dataPoints[i]), y: Double(values[i]), size: (CGFloat(amounts[i])))
dataEntries.append(dataEntry)
}
let format = NumberFormatter()
format.generatesDecimalNumbers = false
format.zeroSymbol = ""
let formatter = DefaultValueFormatter(formatter: format)
let chartDataSet = BubbleChartDataSet(values: dataEntries, label: "")
let chartData = BubbleChartData(dataSet: chartDataSet)
bubbleView.doubleTapToZoomEnabled = false
bubbleView.scaleXEnabled = false
bubbleView.scaleYEnabled = false
bubbleView.highlightPerTapEnabled = false
bubbleView.highlightPerDragEnabled = false
let firstLegend = LegendEntry.init(label: "Below 50", form: .default, formSize: CGFloat.nan, formLineWidth: CGFloat.nan, formLineDashPhase: CGFloat.nan, formLineDashLengths: nil, formColor: UIColor.black)
let secondLegend = LegendEntry.init(label: "Between 50 and 75", form: .default, formSize: CGFloat.nan, formLineWidth: CGFloat.nan, formLineDashPhase: CGFloat.nan, formLineDashLengths: nil, formColor: UIColor.black)
let thirdLegend = LegendEntry.init(label: "Over 75", form: .default, formSize: CGFloat.nan, formLineWidth: CGFloat.nan, formLineDashPhase: CGFloat.nan, formLineDashLengths: nil, formColor: UIColor.black)
bubbleView.chartDescription = nil
bubbleView.legend.entries = [firstLegend, secondLegend, thirdLegend]
bubbleView.data = chartData
bubbleView.animate(xAxisDuration: 2.0, yAxisDuration: 2.0)
let xAxis: XAxis = bubbleView.xAxis
xAxis.drawAxisLineEnabled = false
xAxis.drawGridLinesEnabled = false
xAxis.drawLabelsEnabled = false
xAxis.axisMinimum = 0
xAxis.axisMaximum = 10
let leftAxis: YAxis = bubbleView.leftAxis
leftAxis.drawAxisLineEnabled = false
leftAxis.drawGridLinesEnabled = false
leftAxis.setLabelCount(2, force: true)
leftAxis.axisMinimum = 0
leftAxis.axisMaximum = 100
let rightAxis: YAxis = bubbleView.rightAxis
rightAxis.drawAxisLineEnabled = false
rightAxis.drawGridLinesEnabled = false
rightAxis.drawLabelsEnabled = false
}
All bubbles with the value 25 should be the same color (e.g. red), all bubbles with the value 62 should be the same color (e.g. orange), and all bubbles with the value 88 should be the same color (e.g. green).
Take a look at my answer over here: Different colors for bars in BarChart depend on value
But essentially you need to write a custom function that returns a UIColor depending on the value.
func setColor(value: Double) -> UIColor{
if(value < 30){
return UIColor.red
}
else if(value <= 70 && value >= 30){
return UIColor.orange
}
else if(value > 70){
return UIColor.green
}
else { //In case anything goes wrong
return UIColor.black
}
}
And then set the colors like this
chartDataSet.colors.append(setColor(dataValue))
Hope this helps!
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 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
Using third party "charts".the input format of values are Double and response also in double.For example, my input is a=12,b=13,c=20,d=25 when it comes in graph showing like a=12.0,b=13.0,c=20.0,d=25.0
here is my code
func updateChartData() {
let skipped = 12
let correct = 13
let wrong = 20
let timedOut = 25
let track = ["Skipped", "Right", "Wrong", "Not Attended"]
let money = [skipped, correct, wrong, timedOut]
var entries = [PieChartDataEntry]()
for (index, value) in money.enumerated() {
let entry = PieChartDataEntry()
entry.y = Double(value)
entry.label = track[index]
entries.append( entry)
}
// 3. chart setup
let set = PieChartDataSet( values: entries, label: "Pie Chart")
// this is custom extension method. Download the code for more details.
var colors: [UIColor] = []
for _ in 0..<money.count {
let red = Double(arc4random_uniform(256))
let green = Double(arc4random_uniform(256))
let blue = Double(arc4random_uniform(256))
let color = UIColor(red: CGFloat(red/255), green: CGFloat(green/255), blue: CGFloat(blue/255), alpha: 1)
colors.append(color)
}
set.colors = colors
let data = PieChartData(dataSet: set)
viewPieCharts.data = data
viewPieCharts.noDataText = "No data available"
// user interaction
viewPieCharts.isUserInteractionEnabled = true
let d = Description()
d.text = "iOSCharts.io"
viewPieCharts.chartDescription = d
viewPieCharts.centerText = "Pie Chart"
viewPieCharts.holeRadiusPercent = 0.5
viewPieCharts.transparentCircleColor = UIColor.clear
}
I want the values without decimal point.
Just insert this code
let format = NumberFormatter()
format.numberStyle = .none
let formatter = DefaultValueFormatter(formatter: format)
data.setValueFormatter(formatter)
after
let data = PieChartData(dataSet: set)
Override IValueFormatter and set it to your PieChartData instance
class MyValueFormatter : IValueFormatter {
func stringForValue(_ value: Double,
entry: ChartDataEntry,
dataSetIndex: Int,
viewPortHandler: ViewPortHandler?) -> String {
return String(format: "%.0f", value)
}
}
data.setValueFormatter(MyValueFormatter())
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.