CarlosBF CarlosBF - 3 months ago 37
Swift Question

Multiple scatterplots using Core Plot and Swift

I'm trying to find a way to add two different scatterplots to a single graph but i wasn't able so far. I've found some examples in Objective-C but nothing in Swift, just the Scatterplot example in the CorePlot 2.1 release, but it plots the same data in two different line colors.

This is what i have so far (only one scatter plot is plotted):

import UIKit
import CorePlot

class ViewController : UIViewController, CPTScatterPlotDataSource {
private var scatterGraph : CPTXYGraph? = nil

typealias plotDataType = [CPTScatterPlotField : Double]
private var dataForPlot = [plotDataType]()
@IBOutlet var graphView: UIView!

// MARK: Initialization

override func viewDidAppear(animated : Bool)
{
super.viewDidAppear(animated)

// Create graph from theme
let newGraph = CPTXYGraph(frame: CGRectZero)
newGraph.applyTheme(CPTTheme(named: kCPTDarkGradientTheme))

let hostingView = graphView as! CPTGraphHostingView
hostingView.hostedGraph = newGraph

// Paddings
newGraph.paddingLeft = 10.0
newGraph.paddingRight = 10.0
newGraph.paddingTop = 10.0
newGraph.paddingBottom = 10.0

// Plot space
let plotSpace = newGraph.defaultPlotSpace as! CPTXYPlotSpace
//plotSpace.allowsUserInteraction = true
plotSpace.yRange = CPTPlotRange(location:0, length:10)
plotSpace.xRange = CPTPlotRange(location:0, length:10)

// Axes
let axisSet = newGraph.axisSet as! CPTXYAxisSet

if let x = axisSet.xAxis {
x.majorIntervalLength = 2
x.orthogonalPosition = 2.0
x.minorTicksPerInterval = 2

}

if let y = axisSet.xAxis {
y.majorIntervalLength = 2
y.minorTicksPerInterval = 5
y.orthogonalPosition = 2.0

y.delegate = self
}

// Create a blue plot area
let boundLinePlot = CPTScatterPlot(frame: CGRectZero)
let blueLineStyle = CPTMutableLineStyle()
blueLineStyle.miterLimit = 1.0
blueLineStyle.lineWidth = 3.0
blueLineStyle.lineColor = CPTColor.blueColor()
boundLinePlot.dataLineStyle = blueLineStyle

boundLinePlot.identifier = "Blue Plot"
boundLinePlot.dataSource = self
newGraph.addPlot(boundLinePlot)

// Add plot symbols
let symbolLineStyle = CPTMutableLineStyle()
symbolLineStyle.lineColor = CPTColor.blackColor()
let plotSymbol = CPTPlotSymbol.ellipsePlotSymbol()
plotSymbol.fill = CPTFill(color: CPTColor.blueColor())
plotSymbol.lineStyle = symbolLineStyle
plotSymbol.size = CGSize(width: 10.0, height: 10.0)

// Put an area gradient under the plot above
let areaColor = CPTColor(componentRed: 0.3, green: 1.0, blue: 0.3, alpha: 0.8)
let areaGradient = CPTGradient(beginningColor: areaColor, endingColor: CPTColor.clearColor())
areaGradient.angle = -90.0
let areaGradientFill = CPTFill(gradient: areaGradient)

// Add some initial data
var contentArray = [plotDataType]()

let plotData1: plotDataType = [.X: 0, .Y: 5]
let plotData2: plotDataType = [.X: 5, .Y: 0]
contentArray.append(plotData1)
contentArray.append(plotData2)
self.dataForPlot = contentArray

self.scatterGraph = newGraph


}

// MARK: - Plot Data Source Methods

func numberOfRecordsForPlot(plot: CPTPlot) -> UInt
{
return UInt(self.dataForPlot.count)
}

func numberForPlot(plot: CPTPlot, field: UInt, recordIndex: UInt) -> AnyObject?
{
let plotField = CPTScatterPlotField(rawValue: Int(field))

if let num = self.dataForPlot[Int(recordIndex)][plotField!] {

return num as NSNumber

}
else {
return nil
}
}

// MARK: - Axis Delegate Methods

func axis(axis: CPTAxis, shouldUpdateAxisLabelsAtLocations locations: NSSet!) -> Bool
{
if let formatter = axis.labelFormatter {
let labelOffset = axis.labelOffset

var newLabels = Set<CPTAxisLabel>()

for tickLocation in locations {
if let labelTextStyle = axis.labelTextStyle?.mutableCopy() as? CPTMutableTextStyle {

if tickLocation.doubleValue >= 0.0 {
labelTextStyle.color = CPTColor.greenColor()
}
else {
labelTextStyle.color = CPTColor.redColor()
}

let labelString = formatter.stringForObjectValue(tickLocation)
let newLabelLayer = CPTTextLayer(text: labelString, style: labelTextStyle)

let newLabel = CPTAxisLabel(contentLayer: newLabelLayer)
newLabel.tickLocation = tickLocation as! NSNumber
newLabel.offset = labelOffset

newLabels.insert(newLabel)
}

axis.axisLabels = newLabels
}
}

return false
}
}


This gives me a single line, but i want to add an additional line with a different data.

Any suggestions?

Answer

For a starter, create two CPTScatterPlots (e.g. boundLinePlot1 & boundLinePlot2)and configure them with different colors and different identifier then add them

boundLinePlot1.identifier = "Blue Plot"
boundLinePlot2.identifier = "Green Plot"

newGraph.addPlot(boundLinePlot1) 
newGraph.addPlot(boundLinePlot2)

Now in the Plot Data Source Methods (numberOfRecordsForPlot & numberForPlot) calculate return value based on plot.identifier

if plot.identifier == "Blue Plot" {
    return dataForPlot1[Int(recordIndex)][plotField!]
} else {
    return dataForPlot2[Int(recordIndex)][plotField!]
}
Comments