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); }
}