Data


  • ChartDataEntry 条目 (一个x下标,一个y值)
  • ChartDataSet 数据集合 (一系列的条目)
  • ChartData 数据 (多个数据集)

ChartDataEntry.swift

//
//  ChartDataEntry.swift
//  Charts
//
//  Created by Daniel Cohen Gindi on 23/2/15.

//
//  Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
//  A port of MPAndroidChart for iOS
//  Licensed under Apache License 2.0
//
//  https://github.com/danielgindi/ios-charts
//

import Foundation

//  Swift标准库定义了一个Equatable协议,要求任何遵循的类型实现等式 == 和不等式 != 对两个该类型进行比较。所有的Swift标准类型自动支持Equatable协议
public class ChartDataEntry: NSObject, Equatable
{
    /// the actual value (y axis)
    /// y值
    public var value = Double(0.0)
    
    /// the index on the x-axis
    /// x坐标值
    public var xIndex = Int(0)
    
    /// optional spot for additional data this Entry represents
    /// 条目 额外可选数据
    public var data: AnyObject?
    
    public override init()
    {
        super.init()
    }
    
    public init(value: Double, xIndex: Int)
    {
        super.init()
        
        self.value = value
        self.xIndex = xIndex
    }
    
    public init(value: Double, xIndex: Int, data: AnyObject?)
    {
        super.init()
        
        self.value = value
        self.xIndex = xIndex
        self.data = data
    }
    
    // MARK: NSObject
    // objective-c : #pragram mark - NSObject
    
    public override func isEqual(object: AnyObject?) -> Bool
    {
        if (object === nil)
        {
            return false
        }
        
        if (!object!.isKindOfClass(self.dynamicType))
        {
            return false
        }
        
        if (object!.data !== data && !object!.data.isEqual(self.data))
        {
            return false
        }
        
        if (object!.xIndex != xIndex)
        {
            return false
        }
        
        if (fabs(object!.value - value) > 0.00001)
        {
            return false
        }
        
        return true
    }
    
    // MARK: NSObject
    // toString
    public override var description: String
    {
        return "ChartDataEntry, xIndex: \(xIndex), value \(value)"
    }
    
    // MARK: NSCopying
    
    public func copyWithZone(zone: NSZone) -> AnyObject
    {
        var copy = self.dynamicType.allocWithZone(zone) as ChartDataEntry
        copy.value = value
        copy.xIndex = xIndex
        copy.data = data
        return copy
    }
}

public func ==(lhs: ChartDataEntry, rhs: ChartDataEntry) -> Bool
{
    if (lhs === rhs)
    {
        return true
    }
    
    if (!lhs.isKindOfClass(rhs.dynamicType))
    {
        return false
    }
    
    if (lhs.data !== rhs.data && !lhs.data!.isEqual(rhs.data))
    {
        return false
    }
    
    if (lhs.xIndex != rhs.xIndex)
    {
        return false
    }
    
    if (fabs(lhs.value - rhs.value) > 0.00001)
    {
        return false
    }
    
    return true
}

ChartDataSet

Swift 提供了三种不同的访问级别。这些访问级别相对于源文件中定义的实体,同时也相对于这些源文件所属的模块。

  1. Public:可以访问自己模块或应用中源文件里的任何实体,别人也可以访问引入该模块中源文件里的所有实体。通常情况下,某个接口或 Framework 是可以被任何人使用时,你可以将其设置为 public 级别。
  2. Internal:可以访问自己模块或应用中源文件里的任何实体,但是别人不能访问该模块中源文件里的实体。通常情况下,某个接口或 Framework 作为内部结构使用时,你可以将其设置为 internal 级别。
  3. Private:只能在当前源文件中使用的实体,称为私有实体。使用 private 级别,可以用作隐藏某些功能的实现细节。

Public 为最高级访问级别,Private 为最低级访问级别。

//
//  ChartDataSet.swift
//  Charts
//
//  Created by Daniel Cohen Gindi on 23/2/15.

//
//  Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
//  A port of MPAndroidChart for iOS
//  Licensed under Apache License 2.0
//
//  https://github.com/danielgindi/ios-charts
//

import Foundation
import UIKit

public class ChartDataSet: NSObject
{
    // 颜色,循环使用
    public var colors = [UIColor]()
    // y值集合
    internal var _yVals: [ChartDataEntry]!
    // y值最大值
    internal var _yMax = Double(0.0)
    // y值最小值
    internal var _yMin = Double(0.0)
    // y值总和
    internal var _yValueSum = Double(0.0)
    
    /// the last start value used for calcMinMax
    internal var _lastStart: Int = 0
    
    /// the last end value used for calcMinMax
    internal var _lastEnd: Int = 0
    
    // 标签
    public var label: String? = "DataSet"
    // 可用
    public var visible = true
    // 是否绘画y值
    public var drawValuesEnabled = true
    
    /// the color used for the value-text
    /// y值文字的种颜色
    public var valueTextColor: UIColor = UIColor.blackColor()
    
    /// the font for the value-text labels
    y值字体
    public var valueFont: UIFont = UIFont.systemFontOfSize(7.0)
    
    /// the formatter used to customly format the values
    // 自定义格式化
    public var valueFormatter: NSNumberFormatter?
    
    /// the axis this DataSet should be plotted against.
    // 根据哪个y坐标, 左?右?
    public var axisDependency = ChartYAxis.AxisDependency.Left

    // 外部可访问属性
    public var yVals: [ChartDataEntry] { return _yVals }
    public var yValueSum: Double { return _yValueSum }
    public var yMin: Double { return _yMin }
    public var yMax: Double { return _yMax }
    
    /// if true, value highlighting is enabled
    // 能否高亮
    public var highlightEnabled = true
    
    /// :returns: true if value highlighting is enabled for this dataset
    // 是否高亮状态
    public var isHighlightEnabled: Bool { return highlightEnabled }
    
    public override init()
    {
        super.init()
    }
    
    public init(yVals: [ChartDataEntry]?, label: String?)
    {
        super.init()
        
        self.label = label
        _yVals = yVals == nil ? [ChartDataEntry]() : yVals
        
        // default color
        colors.append(UIColor(red: 140.0/255.0, green: 234.0/255.0, blue: 255.0/255.0, alpha: 1.0))
        
        self.calcMinMax(start: _lastStart, end: _lastEnd)
        self.calcYValueSum()
    }
    
    // 便利构造方法
    public convenience init(yVals: [ChartDataEntry]?)
    {
        self.init(yVals: yVals, label: "DataSet")
    }
    
    /// Use this method to tell the data set that the underlying data has changed
    // 当数据改变时调用
    public func notifyDataSetChanged()
    {
        calcMinMax(start: _lastStart, end: _lastEnd)
        calcYValueSum()
    }
    
    internal func calcMinMax(#start : Int, end: Int)
    {
        let yValCount = _yVals.count
        
        if yValCount == 0
        {
            return
        }
        
        var endValue : Int
        
        if end == 0 || end >= yValCount
        {
            endValue = yValCount - 1
        }
        else
        {
            endValue = end
        }
        
        _lastStart = start
        _lastEnd = endValue
        
        _yMin = DBL_MAX
        _yMax = -DBL_MAX
        
        for (var i = start; i <= endValue; i++)
        {
            let e = _yVals[i]
            
            if (!e.value.isNaN)
            {
                if (e.value < _yMin)
                {
                    _yMin = e.value
                }
                if (e.value > _yMax)
                {
                    _yMax = e.value
                }
            }
        }
        
        if (_yMin == DBL_MAX)
        {
            _yMin = 0.0
            _yMax = 0.0
        }
    }
    
    private func calcYValueSum()
    {
        _yValueSum = 0
        
        for var i = 0; i < _yVals.count; i++
        {
            _yValueSum += fabs(_yVals[i].value)
        }
    }
    
    public var entryCount: Int { return _yVals!.count; }
    
    public func yValForXIndex(x: Int) -> Double
    {
        let e = self.entryForXIndex(x)
        
        if (e !== nil && e!.xIndex == x) { return e!.value }
        else { return Double.NaN }
    }
    
    /// Returns the first Entry object found at the given xIndex with binary search. 
    /// If the no Entry at the specifed x-index is found, this method returns the Entry at the closest x-index. 
    /// Returns nil if no Entry object at that index.
    public func entryForXIndex(x: Int) -> ChartDataEntry?
    {
        var index = self.entryIndex(xIndex: x)
        if (index > -1)
        {
            return _yVals[index]
        }
        return nil
    }
    
    public func entriesForXIndex(x: Int) -> [ChartDataEntry]
    {
        var entries = [ChartDataEntry]()
        
        var low = 0
        var high = _yVals.count - 1
        
        while (low <= high)
        {
            var m = Int((high + low) / 2)
            var entry = _yVals[m]
            
            if (x == entry.xIndex)
            {
                while (m > 0 && _yVals[m - 1].xIndex == x)
                {
                    m--
                }
                
                high = _yVals.count
                for (; m < high; m++)
                {
                    entry = _yVals[m]
                    if (entry.xIndex == x)
                    {
                        entries.append(entry)
                    }
                    else
                    {
                        break
                    }
                }
            }
            
            if (x > _yVals[m].xIndex)
            {
                low = m + 1
            }
            else
            {
                high = m - 1
            }
        }
        
        return entries
    }
    
    public func entryIndex(xIndex x: Int) -> Int
    {
        var low = 0
        var high = _yVals.count - 1
        var closest = -1
        
        while (low <= high)
        {
            var m = (high + low) / 2
            var entry = _yVals[m]
            
            if (x == entry.xIndex)
            {
                while (m > 0 && _yVals[m - 1].xIndex == x)
                {
                    m--
                }
                
                return m
            }
            
            if (x > entry.xIndex)
            {
                low = m + 1
            }
            else
            {
                high = m - 1
            }
            
            closest = m
        }
        
        return closest
    }
    
    public func entryIndex(entry e: ChartDataEntry, isEqual: Bool) -> Int
    {
        if (isEqual)
        {
            for (var i = 0; i < _yVals.count; i++)
            {
                if (_yVals[i].isEqual(e))
                {
                    return i
                }
            }
        }
        else
        {
            for (var i = 0; i < _yVals.count; i++)
            {
                if (_yVals[i] === e)
                {
                    return i
                }
            }
        }
        
        return -1
    }
    
    /// Returns the number of entries this DataSet holds.
    public var valueCount: Int { return _yVals.count; }
    
    /// Adds an Entry to the DataSet dynamically.
    /// Entries are added to the end of the list.
    /// This will also recalculate the current minimum and maximum values of the DataSet and the value-sum.
    /// :param: e the entry to add
    /// 动态添加 条目 到 数据集,添加到末尾,自动计算最大值,最小值和总和。
    public func addEntry(e: ChartDataEntry)
    {
        var val = e.value
        
        if (_yVals == nil)
        {
            _yVals = [ChartDataEntry]()
        }
        
        if (_yVals.count == 0)
        {
            _yMax = val
            _yMin = val
        }
        else
        {
            if (_yMax < val)
            {
                _yMax = val
            }
            if (_yMin > val)
            {
                _yMin = val
            }
        }
        
        _yValueSum += val
        
        _yVals.append(e)
    }
    
    /// Adds an Entry to the DataSet dynamically.
    /// Entries are added to their appropriate index respective to it's x-index.
    /// This will also recalculate the current minimum and maximum values of the DataSet and the value-sum.
    /// :param: e the entry to add
    public func addEntryOrdered(e: ChartDataEntry)
    {
        var val = e.value
        
        if (_yVals == nil)
        {
            _yVals = [ChartDataEntry]()
        }
        
        if (_yVals.count == 0)
        {
            _yMax = val
            _yMin = val
        }
        else
        {
            if (_yMax < val)
            {
                _yMax = val
            }
            if (_yMin > val)
            {
                _yMin = val
            }
        }
        
        _yValueSum += val
        
        if _yVals.last?.xIndex > e.xIndex
        {
            var closestIndex = entryIndex(xIndex: e.xIndex)
            if _yVals[closestIndex].xIndex < e.xIndex
            {
                closestIndex++
            }
            _yVals.insert(e, atIndex: closestIndex)
            return;
        }
        
        _yVals.append(e)
    }
    
    public func removeEntry(entry: ChartDataEntry) -> Bool
    {
        var removed = false
        
        for (var i = 0; i < _yVals.count; i++)
        {
            if (_yVals[i] === entry)
            {
                _yVals.removeAtIndex(i)
                removed = true
                break
            }
        }
        
        if (removed)
        {
            _yValueSum -= entry.value
            calcMinMax(start: _lastStart, end: _lastEnd)
        }
        
        return removed
    }
    
    public func removeEntry(#xIndex: Int) -> Bool
    {
        var index = self.entryIndex(xIndex: xIndex)
        if (index > -1)
        {
            var e = _yVals.removeAtIndex(index)
            
            _yValueSum -= e.value
            calcMinMax(start: _lastStart, end: _lastEnd)
            
            return true
        }
        
        return false
    }
    
    public func resetColors()
    {
        colors.removeAll(keepCapacity: false)
    }
    
    public func addColor(color: UIColor)
    {
        colors.append(color)
    }
    
    public func setColor(color: UIColor)
    {
        colors.removeAll(keepCapacity: false)
        colors.append(color)
    }
    
    public func colorAt(var index: Int) -> UIColor
    {
        if (index < 0)
        {
            index = 0
        }
        return colors[index % colors.count]
    }
    
    public var isVisible: Bool
    {
        return visible
    }
    
    public var isDrawValuesEnabled: Bool
    {
        return drawValuesEnabled
    }
    
    /// Checks if this DataSet contains the specified Entry.
    /// :returns: true if contains the entry, false if not.
    public func contains(e: ChartDataEntry) -> Bool
    {
        for entry in _yVals
        {
            if (entry.isEqual(e))
            {
                return true
            }
        }
        
        return false
    }
    
    /// Removes all values from this DataSet and recalculates min and max value.
    public func clear()
    {
        _yVals.removeAll(keepCapacity: true)
        _lastStart = 0
        _lastEnd = 0
        notifyDataSetChanged()
    }

    // MARK: NSObject
    
    public override var description: String
    {
        return String(format: "ChartDataSet, label: %@, %i entries", arguments: [self.label ?? "", _yVals.count])
    }
    
    public override var debugDescription: String
    {
        var desc = description + ":"
        
        for (var i = 0; i < _yVals.count; i++)
        {
            desc += "\n" + _yVals[i].description
        }
        
        return desc
    }
    
    // MARK: NSCopying
    
    public func copyWithZone(zone: NSZone) -> AnyObject
    {
        var copy = self.dynamicType.allocWithZone(zone) as ChartDataSet
        copy.colors = colors
        copy._yVals = _yVals
        copy._yMax = _yMax
        copy._yMin = _yMin
        copy._yValueSum = _yValueSum
        copy.label = self.label
        return copy
    }
}

ChartData

//
//  ChartData.swift
//  Charts
//
//  Created by Daniel Cohen Gindi on 23/2/15.

//
//  Copyright 2015 Daniel Cohen Gindi & Philipp Jahoda
//  A port of MPAndroidChart for iOS
//  Licensed under Apache License 2.0
//
//  https://github.com/danielgindi/ios-charts
//

import Foundation
import UIKit

public class ChartData: NSObject
{
    // y最大值
    internal var _yMax = Double(0.0)
    // y最小值
    internal var _yMin = Double(0.0)
    // 左y轴最大值
    internal var _leftAxisMax = Double(0.0)
    // 左y轴最小值
    internal var _leftAxisMin = Double(0.0)
    // 右y轴最大值
    internal var _rightAxisMax = Double(0.0)
    // 右y轴最小值
    internal var _rightAxisMin = Double(0.0)
    // y值总和
    private var _yValueSum = Double(0.0)
    // y值个数
    private var _yValCount = Int(0)
    
    /// the last start value used for calcMinMax
    internal var _lastStart: Int = 0
    
    /// the last end value used for calcMinMax
    internal var _lastEnd: Int = 0
    
    /// the average length (in characters) across all x-value strings
    private var _xValAverageLength = Double(0.0)
    
    internal var _xVals: [String?]!
    internal var _dataSets: [ChartDataSet]!
    
    public override init()
    {
        super.init()
        
        _xVals = [String?]()
        _dataSets = [ChartDataSet]()
    }
    
    public init(xVals: [String?]?, dataSets: [ChartDataSet]?)
    {
        super.init()
        
        _xVals = xVals == nil ? [String?]() : xVals
        _dataSets = dataSets == nil ? [ChartDataSet]() : dataSets
        
        self.initialize(_dataSets)
    }
    
    public init(xVals: [NSObject]?, dataSets: [ChartDataSet]?)
    {
        super.init()
        
        _xVals = xVals == nil ? [String?]() : ChartUtils.bridgedObjCGetStringArray(objc: xVals!)
        _dataSets = dataSets == nil ? [ChartDataSet]() : dataSets
        
        self.initialize(_dataSets)
    }
    
    public convenience init(xVals: [String?]?)
    {
        self.init(xVals: xVals, dataSets: [ChartDataSet]())
    }
    
    public convenience init(xVals: [NSObject]?)
    {
        self.init(xVals: xVals, dataSets: [ChartDataSet]())
    }
    
    public convenience init(xVals: [String?]?, dataSet: ChartDataSet?)
    {
        self.init(xVals: xVals, dataSets: dataSet === nil ? nil : [dataSet!])
    }
    
    public convenience init(xVals: [NSObject]?, dataSet: ChartDataSet?)
    {
        self.init(xVals: xVals, dataSets: dataSet === nil ? nil : [dataSet!])
    }
    
    internal func initialize(dataSets: [ChartDataSet])
    {
        checkIsLegal(dataSets)
        
        calcMinMax(start: _lastStart, end: _lastEnd)
        calcYValueSum()
        calcYValueCount()
        
        calcXValAverageLength()
    }
    
    // calculates the average length (in characters) across all x-value strings
    internal func calcXValAverageLength()
    {
        if (_xVals.count == 0)
        {
            _xValAverageLength = 1
            return
        }
        
        var sum = 1
        
        for (var i = 0; i < _xVals.count; i++)
        {
            sum += _xVals[i] == nil ? 0 : count(_xVals[i]!)
        }
        
        _xValAverageLength = Double(sum) / Double(_xVals.count)
    }
    
    // Checks if the combination of x-values array and DataSet array is legal or not.
    // :param: dataSets
    internal func checkIsLegal(dataSets: [ChartDataSet]!)
    {
        if (dataSets == nil)
        {
            return
        }
        
        for (var i = 0; i < dataSets.count; i++)
        {
            if (dataSets[i].yVals.count > _xVals.count)
            {
                println("One or more of the DataSet Entry arrays are longer than the x-values array of this Data object.")
                return
            }
        }
    }
    
    public func notifyDataChanged()
    {
        initialize(_dataSets)
    }
    
    /// calc minimum and maximum y value over all datasets
    internal func calcMinMax(#start: Int, end: Int)
    {
        
        if (_dataSets == nil || _dataSets.count < 1)
        {
            _yMax = 0.0
            _yMin = 0.0
        }
        else
        {
            _lastStart = start
            _lastEnd = end
            
            _yMin = DBL_MAX
            _yMax = -DBL_MAX
            
            for (var i = 0; i < _dataSets.count; i++)
            {
                _dataSets[i].calcMinMax(start: start, end: end)
                
                if (_dataSets[i].yMin < _yMin)
                {
                    _yMin = _dataSets[i].yMin
                }
                
                if (_dataSets[i].yMax > _yMax)
                {
                    _yMax = _dataSets[i].yMax
                }
            }
            
            if (_yMin == DBL_MAX)
            {
                _yMin = 0.0
                _yMax = 0.0
            }
            
            // left axis
            var firstLeft = getFirstLeft()
            
            if (firstLeft !== nil)
            {
                _leftAxisMax = firstLeft!.yMax
                _leftAxisMin = firstLeft!.yMin
                
                for dataSet in _dataSets
                {
                    if (dataSet.axisDependency == .Left)
                    {
                        if (dataSet.yMin < _leftAxisMin)
                        {
                            _leftAxisMin = dataSet.yMin
                        }
                        
                        if (dataSet.yMax > _leftAxisMax)
                        {
                            _leftAxisMax = dataSet.yMax
                        }
                    }
                }
            }
            
            // right axis
            var firstRight = getFirstRight()
            
            if (firstRight !== nil)
            {
                _rightAxisMax = firstRight!.yMax
                _rightAxisMin = firstRight!.yMin
                
                for dataSet in _dataSets
                {
                    if (dataSet.axisDependency == .Right)
                    {
                        if (dataSet.yMin < _rightAxisMin)
                        {
                            _rightAxisMin = dataSet.yMin
                        }
                        
                        if (dataSet.yMax > _rightAxisMax)
                        {
                            _rightAxisMax = dataSet.yMax
                        }
                    }
                }
            }
            
            // in case there is only one axis, adjust the second axis
            handleEmptyAxis(firstLeft, firstRight: firstRight)
        }
    }
    
    /// calculates the sum of all y-values in all datasets
    internal func calcYValueSum()
    {
        _yValueSum = 0
        
        if (_dataSets == nil)
        {
            return
        }
        
        for (var i = 0; i < _dataSets.count; i++)
        {
            _yValueSum += fabs(_dataSets[i].yValueSum)
        }
    }
    
    /// Calculates the total number of y-values across all ChartDataSets the ChartData represents.
    internal func calcYValueCount()
    {
        _yValCount = 0
        
        if (_dataSets == nil)
        {
            return
        }
        
        var count = 0
        
        for (var i = 0; i < _dataSets.count; i++)
        {
            count += _dataSets[i].entryCount
        }
        
        _yValCount = count
    }
    
    /// returns the number of LineDataSets this object contains
    public var dataSetCount: Int
    {
            if (_dataSets == nil)
            {
                return 0
            }
            return _dataSets.count
    }
    
    /// returns the smallest y-value the data object contains.
    public var yMin: Double
        {
            return _yMin
    }
    
    public func getYMin() -> Double
    {
        return _yMin
    }
    
    public func getYMin(axis: ChartYAxis.AxisDependency) -> Double
    {
        if (axis == .Left)
        {
            return _leftAxisMin
        }
        else
        {
            return _rightAxisMin
        }
    }
    
    /// returns the greatest y-value the data object contains.
    public var yMax: Double
    {
            return _yMax
    }
    
    public func getYMax() -> Double
    {
        return _yMax
    }
    
    public func getYMax(axis: ChartYAxis.AxisDependency) -> Double
    {
        if (axis == .Left)
        {
            return _leftAxisMax
        }
        else
        {
            return _rightAxisMax
        }
    }
    
    /// returns the average length (in characters) across all values in the x-vals array
    public var xValAverageLength: Double
    {
        return _xValAverageLength
    }
    
    /// returns the total y-value sum across all DataSet objects the this object represents.
    public var yValueSum: Double
    {
        return _yValueSum
    }
    
    /// Returns the total number of y-values across all DataSet objects the this object represents.
    public var yValCount: Int
    {
        return _yValCount
    }
    
    /// returns the x-values the chart represents
    public var xVals: [String?]
    {
        return _xVals
    }
    
    ///Adds a new x-value to the chart data.
    public func addXValue(xVal: String?)
    {
        _xVals.append(xVal)
    }
    
    /// Removes the x-value at the specified index.
    public func removeXValue(index: Int)
    {
        _xVals.removeAtIndex(index)
    }
    
    /// Returns the array of ChartDataSets this object holds.
    public var dataSets: [ChartDataSet]
    {
        get
        {
            return _dataSets
        }
        set
        {
            _dataSets = newValue
        }
    }
    
    /// Retrieve the index of a ChartDataSet with a specific label from the ChartData. Search can be case sensitive or not.
    /// IMPORTANT: This method does calculations at runtime, do not over-use in performance critical situations.
    ///
    /// :param: dataSets the DataSet array to search
    /// :param: type
    /// :param: ignorecase if true, the search is not case-sensitive
    /// :returns:
    internal func getDataSetIndexByLabel(label: String, ignorecase: Bool) -> Int
    {
        if (ignorecase)
        {
            for (var i = 0; i < dataSets.count; i++)
            {
                if (dataSets[i].label == nil)
                {
                    continue
                }
                if (label.caseInsensitiveCompare(dataSets[i].label!) == NSComparisonResult.OrderedSame)
                {
                    return i
                }
            }
        }
        else
        {
            for (var i = 0; i < dataSets.count; i++)
            {
                if (label == dataSets[i].label)
                {
                    return i
                }
            }
        }
        
        return -1
    }
    
    /// returns the total number of x-values this ChartData object represents (the size of the x-values array)
    public var xValCount: Int
    {
        return _xVals.count
    }
    
    /// Returns the labels of all DataSets as a string array.
    internal func dataSetLabels() -> [String]
    {
        var types = [String]()
        
        for (var i = 0; i < _dataSets.count; i++)
        {
            if (dataSets[i].label == nil)
            {
                continue
            }
            
            types[i] = _dataSets[i].label!
        }
        
        return types
    }
    
    /// Get the Entry for a corresponding highlight object
    ///
    /// :param: highlight
    /// :returns: the entry that is highlighted
    public func getEntryForHighlight(highlight: ChartHighlight) -> ChartDataEntry?
    {
        if highlight.dataSetIndex >= dataSets.count
        {
            return nil
        }
        else
        {
            return _dataSets[highlight.dataSetIndex].entryForXIndex(highlight.xIndex)
        }
    }
    
    /// Returns the DataSet object with the given label.
    /// sensitive or not.
    /// IMPORTANT: This method does calculations at runtime. Use with care in performance critical situations.
    ///
    /// :param: label
    /// :param: ignorecase
    public func getDataSetByLabel(label: String, ignorecase: Bool) -> ChartDataSet?
    {
        var index = getDataSetIndexByLabel(label, ignorecase: ignorecase)
        
        if (index < 0 || index >= _dataSets.count)
        {
            return nil
        }
        else
        {
            return _dataSets[index]
        }
    }
    
    public func getDataSetByIndex(index: Int) -> ChartDataSet!
    {
        if (_dataSets == nil || index < 0 || index >= _dataSets.count)
        {
            return nil
        }
        
        return _dataSets[index]
    }
    
    public func addDataSet(d: ChartDataSet!)
    {
        if (_dataSets == nil)
        {
            return
        }
        
        _yValCount += d.entryCount
        _yValueSum += d.yValueSum
        
        if (_dataSets.count == 0)
        {
            _yMax = d.yMax
            _yMin = d.yMin
            
            if (d.axisDependency == .Left)
            {
                _leftAxisMax = d.yMax
                _leftAxisMin = d.yMin
            }
            else
            {
                _rightAxisMax = d.yMax
                _rightAxisMin = d.yMin
            }
        }
        else
        {
            if (_yMax < d.yMax)
            {
                _yMax = d.yMax
            }
            if (_yMin > d.yMin)
            {
                _yMin = d.yMin
            }
            
            if (d.axisDependency == .Left)
            {
                if (_leftAxisMax < d.yMax)
                {
                    _leftAxisMax = d.yMax
                }
                if (_leftAxisMin > d.yMin)
                {
                    _leftAxisMin = d.yMin
                }
            }
            else
            {
                if (_rightAxisMax < d.yMax)
                {
                    _rightAxisMax = d.yMax
                }
                if (_rightAxisMin > d.yMin)
                {
                    _rightAxisMin = d.yMin
                }
            }
        }
        
        _dataSets.append(d)
        
        handleEmptyAxis(getFirstLeft(), firstRight: getFirstRight())
    }
    
    public func handleEmptyAxis(firstLeft: ChartDataSet?, firstRight: ChartDataSet?)
    {
        // in case there is only one axis, adjust the second axis
        if (firstLeft === nil)
        {
            _leftAxisMax = _rightAxisMax
            _leftAxisMin = _rightAxisMin
        }
        else if (firstRight === nil)
        {
            _rightAxisMax = _leftAxisMax
            _rightAxisMin = _leftAxisMin
        }
    }
    
    /// Removes the given DataSet from this data object.
    /// Also recalculates all minimum and maximum values.
    ///
    /// :returns: true if a DataSet was removed, false if no DataSet could be removed.
    public func removeDataSet(dataSet: ChartDataSet!) -> Bool
    {
        if (_dataSets == nil || dataSet === nil)
        {
            return false
        }
        
        for (var i = 0; i < _dataSets.count; i++)
        {
            if (_dataSets[i] === dataSet)
            {
                return removeDataSetByIndex(i)
            }
        }
        
        return false
    }
    
    /// Removes the DataSet at the given index in the DataSet array from the data object.
    /// Also recalculates all minimum and maximum values.
    ///
    /// :returns: true if a DataSet was removed, false if no DataSet could be removed.
    public func removeDataSetByIndex(index: Int) -> Bool
    {
        if (_dataSets == nil || index >= _dataSets.count || index < 0)
        {
            return false
        }
        
        var d = _dataSets.removeAtIndex(index)
        _yValCount -= d.entryCount
        _yValueSum -= d.yValueSum
        
        calcMinMax(start: _lastStart, end: _lastEnd)
        
        return true
    }
    
    /// Adds an Entry to the DataSet at the specified index. Entries are added to the end of the list.
    public func addEntry(e: ChartDataEntry, dataSetIndex: Int)
    {
        if (_dataSets != nil && _dataSets.count > dataSetIndex && dataSetIndex >= 0)
        {
            var val = e.value
            var set = _dataSets[dataSetIndex]
            
            if (_yValCount == 0)
            {
                _yMin = val
                _yMax = val
                
                if (set.axisDependency == .Left)
                {
                    _leftAxisMax = e.value
                    _leftAxisMin = e.value
                }
                else
                {
                    _rightAxisMax = e.value
                    _rightAxisMin = e.value
                }
            }
            else
            {
                if (_yMax < val)
                {
                    _yMax = val
                }
                if (_yMin > val)
                {
                    _yMin = val
                }
                
                if (set.axisDependency == .Left)
                {
                    if (_leftAxisMax < e.value)
                    {
                        _leftAxisMax = e.value
                    }
                    if (_leftAxisMin > e.value)
                    {
                        _leftAxisMin = e.value
                    }
                }
                else
                {
                    if (_rightAxisMax < e.value)
                    {
                        _rightAxisMax = e.value
                    }
                    if (_rightAxisMin > e.value)
                    {
                        _rightAxisMin = e.value
                    }
                }
            }
            
            _yValCount += 1
            _yValueSum += val
            
            handleEmptyAxis(getFirstLeft(), firstRight: getFirstRight())
            
            set.addEntry(e)
        }
        else
        {
            println("ChartData.addEntry() - dataSetIndex our of range.")
        }
    }
    
    /// Removes the given Entry object from the DataSet at the specified index.
    public func removeEntry(entry: ChartDataEntry!, dataSetIndex: Int) -> Bool
    {
        // entry null, outofbounds
        if (entry === nil || dataSetIndex >= _dataSets.count)
        {
            return false
        }
        
        // remove the entry from the dataset
        var removed = _dataSets[dataSetIndex].removeEntry(xIndex: entry.xIndex)
        
        if (removed)
        {
            var val = entry.value
            
            _yValCount -= 1
            _yValueSum -= val
            
            calcMinMax(start: _lastStart, end: _lastEnd)
        }
        
        return removed
    }
    
    /// Removes the Entry object at the given xIndex from the ChartDataSet at the
    /// specified index. Returns true if an entry was removed, false if no Entry
    /// was found that meets the specified requirements.
    public func removeEntryByXIndex(xIndex: Int, dataSetIndex: Int) -> Bool
    {
        if (dataSetIndex >= _dataSets.count)
        {
            return false
        }
        
        var entry = _dataSets[dataSetIndex].entryForXIndex(xIndex)
        
        if (entry?.xIndex != xIndex)
        {
            return false
        }
        
        return removeEntry(entry, dataSetIndex: dataSetIndex)
    }
    
    /// Returns the DataSet that contains the provided Entry, or null, if no DataSet contains this entry.
    public func getDataSetForEntry(e: ChartDataEntry!) -> ChartDataSet?
    {
        if (e == nil)
        {
            return nil
        }
        
        for (var i = 0; i < _dataSets.count; i++)
        {
            var set = _dataSets[i]
            
            for (var j = 0; j < set.entryCount; j++)
            {
                if (e === set.entryForXIndex(e.xIndex))
                {
                    return set
                }
            }
        }
        
        return nil
    }
    
    /// Returns the index of the provided DataSet inside the DataSets array of
    /// this data object. Returns -1 if the DataSet was not found.
    public func indexOfDataSet(dataSet: ChartDataSet) -> Int
    {
        for (var i = 0; i < _dataSets.count; i++)
        {
            if (_dataSets[i] === dataSet)
            {
                return i
            }
        }
        
        return -1
    }
    
    public func getFirstLeft() -> ChartDataSet?
    {
        for dataSet in _dataSets
        {
            if (dataSet.axisDependency == .Left)
            {
                return dataSet
            }
        }
        
        return nil
    }
    
    public func getFirstRight() -> ChartDataSet?
    {
        for dataSet in _dataSets
        {
            if (dataSet.axisDependency == .Right)
            {
                return dataSet
            }
        }
        
        return nil
    }
    
    /// Returns all colors used across all DataSet objects this object represents.
    public func getColors() -> [UIColor]?
    {
        if (_dataSets == nil)
        {
            return nil
        }
        
        var clrcnt = 0
        
        for (var i = 0; i < _dataSets.count; i++)
        {
            clrcnt += _dataSets[i].colors.count
        }
        
        var colors = [UIColor]()
        
        for (var i = 0; i < _dataSets.count; i++)
        {
            var clrs = _dataSets[i].colors
            
            for clr in clrs
            {
                colors.append(clr)
            }
        }
        
        return colors
    }
    
    /// Generates an x-values array filled with numbers in range specified by the parameters. Can be used for convenience.
    public func generateXVals(from: Int, to: Int) -> [String]
    {
        var xvals = [String]()
        
        for (var i = from; i < to; i++)
        {
            xvals.append(String(i))
        }
        
        return xvals
    }
    
    /// Sets a custom ValueFormatter for all DataSets this data object contains.
    public func setValueFormatter(formatter: NSNumberFormatter!)
    {
        for set in dataSets
        {
            set.valueFormatter = formatter
        }
    }
    
    /// Sets the color of the value-text (color in which the value-labels are drawn) for all DataSets this data object contains.
    public func setValueTextColor(color: UIColor!)
    {
        for set in dataSets
        {
            set.valueTextColor = color ?? set.valueTextColor
        }
    }
    
    /// Sets the font for all value-labels for all DataSets this data object contains.
    public func setValueFont(font: UIFont!)
    {
        for set in dataSets
        {
            set.valueFont = font ?? set.valueFont
        }
    }
    
    /// Enables / disables drawing values (value-text) for all DataSets this data object contains.
    public func setDrawValues(enabled: Bool)
    {
        for set in dataSets
        {
            set.drawValuesEnabled = enabled
        }
    }
    
    /// Enables / disables highlighting values for all DataSets this data object contains.
    public var highlightEnabled: Bool
        {
        get
        {
            for set in dataSets
            {
                if (!set.highlightEnabled)
                {
                    return false
                }
            }
            
            return true
        }
        set
        {
            for set in dataSets
            {
                set.highlightEnabled = newValue
            }
        }
    }
    
    /// if true, value highlightning is enabled
    public var isHighlightEnabled: Bool { return highlightEnabled }
    
    /// Clears this data object from all DataSets and removes all Entries.
    /// Don't forget to invalidate the chart after this.
    public func clearValues()
    {
        dataSets.removeAll(keepCapacity: false)
        notifyDataChanged()
    }
    
    /// Checks if this data object contains the specified Entry. Returns true if so, false if not.
    public func contains(#entry: ChartDataEntry) -> Bool
    {
        for set in dataSets
        {
            if (set.contains(entry))
            {
                return true
            }
        }
        
        return false
    }
    
    /// Checks if this data object contains the specified DataSet. Returns true if so, false if not.
    public func contains(#dataSet: ChartDataSet) -> Bool
    {
        for set in dataSets
        {
            if (set.isEqual(dataSet))
            {
                return true
            }
        }
        
        return false
    }
    
    /// MARK: - ObjC compatibility
    
    /// returns the average length (in characters) across all values in the x-vals array
    public var xValsObjc: [NSObject] { return ChartUtils.bridgedObjCGetStringArray(swift: _xVals); }
}