I have a weird issue. I have some data on graph and when new data arrives I am inserting that into graph. But issue is new data plotting is starting from first point of already drawn plot not from last point of plot. The console prints the correct point but the plotting starts from first point of already drawn plot not from last point of already drawn plot. My code for graph set up is here :Code for graph set up and Code for Axis animation
code :
func setGraph() {
let tts = CPTMutableTextStyle()
tts.fontSize = 75.0
tts.color = CPTColor(CGColor: UIColor.blackColor().CGColor)
tts.fontName = "HelveticaNeue-Bold"
self.graph.titleTextStyle = tts
self.graph.title = "Heart Rate vs Time"
self.graph.applyTheme(CPTTheme(named:kCPTPlainWhiteTheme))
let plotSpace = graph.defaultPlotSpace as! CPTXYPlotSpace!
plotSpace.allowsUserInteraction = false
let xRange = plotSpace.xRange.mutableCopy() as! CPTMutablePlotRange
xRange.locationDouble = Double(0)
xRange.lengthDouble = Double(kMaxDataPoints)
plotSpace.xRange = xRange
let yRange = plotSpace.yRange.mutableCopy() as! CPTMutablePlotRange
yRange.locationDouble = Double(0)
yRange.lengthDouble = Double(210)
plotSpace.yRange = yRange
graph.addPlotSpace(plotSpace)
graph.plotAreaFrame!.paddingTop = 0
graph.plotAreaFrame!.paddingRight = 0
graph.plotAreaFrame!.paddingBottom = graphOffset
graph.plotAreaFrame!.paddingLeft = graphOffset
graph.plotAreaFrame!.masksToBorder = false
// Grid line styles
let majorLineStyle = CPTMutableLineStyle()
majorLineStyle.lineWidth = 0.75
majorLineStyle.lineColor = CPTColor.redColor()
let minorLineStyle = CPTMutableLineStyle()
minorLineStyle.lineWidth = 0.25
minorLineStyle.lineColor = CPTColor.blackColor()
//Axis Line colors
let axisLineStyle = CPTMutableLineStyle()
axisLineStyle.lineWidth = 2.0
axisLineStyle.lineColor = CPTColor.blackColor()
//Axis Label colors
let labelTextStyle = CPTMutableTextStyle()
labelTextStyle.textAlignment = CPTTextAlignment.Left
labelTextStyle.color = CPTColor.blackColor()
//Axis title color
let titleTextStyle = CPTMutableTextStyle()
titleTextStyle.textAlignment = CPTTextAlignment.Left
titleTextStyle.color = CPTColor.blackColor()
titleTextStyle.fontSize = 15
let dataSourceLinePlot = CPTScatterPlot()
let lineStyle = CPTMutableLineStyle()
lineStyle.lineWidth = 3.0
lineStyle.lineColor = CPTColor.blueColor()
dataSourceLinePlot.dataLineStyle = lineStyle
dataSourceLinePlot.identifier = kPlotIdentifier
// dataSourceLinePlot.dataSource = self
let xts = CPTMutableTextStyle()
xts.color = CPTColor(componentRed: 255.0, green: 255.0, blue: 255.0, alpha: 1.0)
let dateFormatter = NSDateFormatter()
dateFormatter.dateFormat = "HH:mm:ss"
let timeformatter = CPTTimeFormatter(dateFormatter: dateFormatter)
timeformatter.referenceDate = NSDate().dateByAddingTimeInterval(startTimeInterval)
currentdate = timeformatter.referenceDate
let axisSet = graph.axisSet as! CPTXYAxisSet!
let xAxis = axisSet.xAxis as CPTXYAxis!
xAxis.axisTitle = CPTAxisTitle(text: "Elapsed Time", textStyle: xts)
xAxis.labelFormatter = timeformatter
xAxis.majorGridLineStyle = majorLineStyle
xAxis.minorGridLineStyle = minorLineStyle
xAxis.majorIntervalLength = NSNumber(double: 30.0)
let yAxis = axisSet.yAxis as CPTXYAxis!
yAxis.axisTitle = CPTAxisTitle(text: "Heart Rate", textStyle: xts)
let axisFormatter = NSNumberFormatter()
axisFormatter.maximumFractionDigits = 0
axisFormatter.minimumIntegerDigits = 1
yAxis.labelFormatter = axisFormatter
yAxis.titleOffset = 35.0
yAxis.majorIntervalLength = 20
yAxis.majorGridLineStyle = majorLineStyle
yAxis.minorGridLineStyle = minorLineStyle
yAxis.axisConstraints = CPTConstraints(lowerOffset: 0.0)
graph.addPlot(dataSourceLinePlot)
self.IBviewGraph.hostedGraph = self.graph
setGraphData()
}
func setGraphData()
{
self.plot.dataSource = self
let actualPlotStyle = self.plot.dataLineStyle!.mutableCopy() as! CPTMutableLineStyle
actualPlotStyle.lineWidth = 2.0
actualPlotStyle.lineColor = CPTColor(CGColor: (UIColor.blueColor().CGColor))
self.plot.dataLineStyle = actualPlotStyle
self.plot.interpolation = .Curved
self.graph.addPlot(self.plot)
}
Now when i receive new data :
graphData.removeAtIndex(0)
plot.deleteDataInIndexRange(NSMakeRange(0, 1))
let location = currentIndex
let oldRange = CPTPlotRange(location: location , length: kMaxDataPoints)
let newRange = CPTPlotRange(location: location + 30, length: kMaxDataPoints)
CPTAnimation.animate(plotSpace, property: "xRange", fromPlotRange: oldRange, toPlotRange: newRange, duration: CGFloat(1.0 / kFrameRate))
graphData.append((newTime,data.1))
plot.insertDataAtIndex(UInt(graphData.count - 1), numberOfRecords: 1)
Related
let graph = CPTXYGraph(frame: hostview.bounds)
hostview.hostedGraph = graph
graph.paddingLeft = 0.0
graph.paddingTop = 0.0
graph.paddingRight = 0.0
graph.paddingBottom = 0.0
graph.axisSet = nil
That is my code so far. I would like to plot a function. f(x) = x^2 + 10 should be the function value in this case. I want the x-axis and the y-axis to start at 0 and end at 100.
Can someone help me with implementing this f(x)?
Your initialization logic of the graph should look like below. Use this in viewDidLoad
func initPlot() {
let graph = CPTXYGraph(frame: hostView.bounds)
graph.plotAreaFrame?.masksToBorder = false
hostView.hostedGraph = graph
graph.backgroundColor = UIColor.white.cgColor
graph.paddingBottom = 40.0
graph.paddingLeft = 40.0
graph.paddingTop = 40.0
graph.paddingRight = 40.0
//configure title
let title = "f(x) = x*x + 10"
graph.title = title
//configure axes
let axisSet = graph.axisSet as! CPTXYAxisSet
if let x = axisSet.xAxis {
x.majorIntervalLength = 20
x.minorTicksPerInterval = 1
}
if let y = axisSet.yAxis {
y.majorIntervalLength = 5
y.minorTicksPerInterval = 5
}
let xMin = 0.0
let xMax = 100.0
let yMin = 0.0
let yMax = 100.0
guard let plotSpace = graph.defaultPlotSpace as? CPTXYPlotSpace else { return }
plotSpace.xRange = CPTPlotRange(locationDecimal: CPTDecimalFromDouble(xMin), lengthDecimal: CPTDecimalFromDouble(xMax - xMin))
plotSpace.yRange = CPTPlotRange(locationDecimal: CPTDecimalFromDouble(yMin), lengthDecimal: CPTDecimalFromDouble(yMax - yMin))
//create the plot
plot = CPTScatterPlot()
plot.dataSource = self
graph.add(plot, to: graph.defaultPlotSpace)
}
Additionally you need to implement CPTScatterPlotDataSource, where you define the numberOfRecords and respective X and Y values
extension ViewController: CPTScatterPlotDataSource {
func numberOfRecords(for plot: CPTPlot) -> UInt {
return 100
}
func number(for plot: CPTPlot, field: UInt, record: UInt) -> Any? {
switch CPTScatterPlotField(rawValue: Int(field))! {
case .X:
return record
case .Y:
return (record * record) + 10
default:
return 0
}
}
}
I am using iOS Charts to draw linechart but unable to draw the same graph as shown below in the image. I tried by setting leftAxis.axisMinimum = minValue but it also not working. If the given value is minimum on certain limit it should show in red color as shown in attached image.
func setLineChartWithDateFormat(graphPoints: [GraphPoints], linePosition: CGFloat, minValue: Double = 0, fillColor: UIColor = UIColor(red: 158.0/255.0, green: 188.0/255.0, blue: 136.0/255.0, alpha: 1)) {
var referenceTimeInterval: TimeInterval = 0
if let minTimeInterval = (graphPoints.map { ($0.getDateFromDateTime?.timeIntervalSince1970 ?? 0) }).min() {
referenceTimeInterval = minTimeInterval
}
let formatter = DateFormatter()
formatter.locale = Locale(identifier: "en_US_POSIX")
formatter.dateFormat = "MMM dd"
let xValuesNumberFormatter = ChartXAxisWithFormatter(referenceTimeInterval: referenceTimeInterval, dateFormatter: formatter)
// Define chart entries
var entries = [ChartDataEntry]()
var xAxisValues = [CGFloat]()
for object in graphPoints {
let timeInterval = object.getDateFromDateTime?.timeIntervalSince1970 ?? 0
let xValue = (timeInterval - referenceTimeInterval) / (3600 * 24)
xAxisValues.append(CGFloat(xValue))
let yValue = object.price ?? 0
let entry = ChartDataEntry(x: xValue, y: yValue)
entry.setValue(object.getDateFromDateTime, forKey: "data")
entries.append(entry)
}
var minValue = xAxisValues.min()
let chartDataSet = LineChartDataSet(entries: entries, label: "BPM")
chartDataSet.fillColor = fillColor
/// Data object that encapsulates all data associated with a LineChart.
let chartData = LineChartData()
chartData.addDataSet(chartDataSet)
chartData.setDrawValues(false)
chartDataSet.drawCirclesEnabled = false
chartDataSet.mode = .linear
chartDataSet.colors = [.white]
chartDataSet.fillFormatter = LineChartFillFormatter(value: minValue ?? 0)
// let gradientColors = [gradientColor1.cgColor, gradientColor2.cgColor] as CFArray
// let colorLocations: [CGFloat] = [0.7,0.0]
// guard CGGradient.init(colorsSpace: CGColorSpaceCreateDeviceRGB(), colors: gradientColors, locations: colorLocations) != nil else {
// print("Gradient Error")
// return
// }
chartDataSet.drawFilledEnabled = true
chartDataSet.fillAlpha = 1
chartDataSet.setDrawHighlightIndicators(true)
chartDataSet.drawHorizontalHighlightIndicatorEnabled = false
// lineChart.leftAxis.axisMinimum = minValue
///x axis for chart view
let xAxis: XAxis = self.lineChart.xAxis
xAxis.labelPosition = .bottomInside
xAxis.drawGridLinesEnabled = true //true, if want x Axis grid lines
xAxis.valueFormatter = xValuesNumberFormatter
xAxis.gridColor = gridColor
xAxis.axisLineColor = gridColor
xAxis.labelFont = BSFonts.getFontWithSize(fontType: .iBMPlexSansCond, fontSize: BSFontSize.small)
xAxis.labelTextColor = axisTextColor
xAxis.labelPosition = .bottom
xAxis.spaceMin = 0.5
xAxis.drawAxisLineEnabled = false
xAxis.drawLimitLinesBehindDataEnabled = true
xAxis.granularityEnabled = true
// xAxis.granularity = 2
xAxis.labelWidth = UIDevice.current.isIPad ? 30 : 20
// xAxis.labelCount = 4
///right axis for chart view
let rightAxis: YAxis = lineChart.rightAxis
rightAxis.enabled = false
///y axis of chart view
let leftAxis: YAxis = lineChart.leftAxis
leftAxis.labelPosition = .insideChart
leftAxis.drawGridLinesEnabled = true //true, if want y axis grid lines
leftAxis.drawLabelsEnabled = true
leftAxis.gridColor = gridColor
leftAxis.axisLineColor = gridColor
leftAxis.labelFont = BSFonts.getFontWithSize(fontType: .iBMPlexSansCond, fontSize: BSFontSize.small)
leftAxis.labelTextColor = axisTextColor
leftAxis.labelPosition = .outsideChart
//leftAxis.spaceBottom = 0.3
leftAxis.drawAxisLineEnabled = false
leftAxis.labelCount = 4
/// The data for the chart
lineChart.data = chartData
lineChart.doubleTapToZoomEnabled = false
lineChart.data?.highlightEnabled = true
}
Swift 3.1, Charts, Multiple cells in tableView with HorizontalBarChartView.
Is it possible to align the value - centered?
Setup charts data:.
func refreshData() {
guard let item = self.item, !item.tasks.isEmpty else {
return
}
self.titleName.text = item.name
self.leftNameMargin.constant = CGFloat(30 * item.level)
self.titleName.textColor = UIColor(hexString: item.color)
let font = UIFont.systemFont(ofSize: 17.0, weight: UIFontWeightSemibold)
var colors: [UIColor] = []
var yValues: [Double] = []
var count = 0.0
for task in item.tasks {
count += Double(task.count)
yValues.append(Double(task.count))
colors.append(UIColor(hexString: task.valueColor))
}
let suffix = String(format: NSXLocalization.string(forKey: KEY_STR_PERCENT)) //fixes '%' duplication
let formatter = NumberFormatter()
formatter.roundingMode = .floor
formatter.numberStyle = .percent
formatter.positiveSuffix = suffix
formatter.negativeSuffix = suffix
formatter.zeroSymbol = ""
let dataEntry = BarChartDataEntry(x: 0.0, yValues: yValues.map { ($0 / count) })
let dataSet = BarChartDataSet(values: [dataEntry], label: nil)
dataSet.colors = colors
dataSet.valueTextColor = .white
dataSet.barBorderColor = .black
dataSet.barBorderWidth = 1.0
dataSet.drawValuesEnabled = true
dataSet.valueFormatter = DefaultValueFormatter(formatter: formatter)
let data = BarChartData(dataSets: [dataSet])
data.setValueFont(font)
data.setDrawValues(true)
data.highlightEnabled = true
self.chart.data = data
}
I Reviewed all internal methods in the charts, but never found a way to center the y values.
I need to create graph which is "Heart rate vs time". in xAxis I am showing time which is in format of "HH:mm:ss" and at y Axis its decimal value. My code is as below :
data source for graph:
var graphData:[(String,Double)] = []
let data = ("17:56:35",Double(65))
let data1 = ("18:04:13",Double(95))
let data2 = ("18:8:35",Double(25))
self.graphData.append(data)
self.graphData.append(data1)
self.graphData.append(data2)
Set up graph and plot data code:
func setGraph() {
let tts = CPTMutableTextStyle()
tts.fontSize = 75.0
tts.color = CPTColor(CGColor: UIColor.blackColor().CGColor)
tts.fontName = "HelveticaNeue-Bold"
self.graph.titleTextStyle = tts
self.graph.title = "Heart Rate vs Time"
self.graph.applyTheme(CPTTheme(named:kCPTPlainWhiteTheme))
let plotSpace = graph.defaultPlotSpace as! CPTXYPlotSpace!
plotSpace.allowsUserInteraction = false
let xRange = plotSpace.xRange.mutableCopy() as! CPTMutablePlotRange
xRange.locationDouble = Double(0)
xRange.lengthDouble = Double(1000)
plotSpace.xRange = xRange
let yRange = plotSpace.yRange.mutableCopy() as! CPTMutablePlotRange
yRange.locationDouble = Double(0)
yRange.lengthDouble = Double(210)
plotSpace.yRange = yRange
graph.addPlotSpace(plotSpace)
graph.plotAreaFrame!.paddingTop = 0
graph.plotAreaFrame!.paddingRight = 0
graph.plotAreaFrame!.paddingBottom = graphOffset
graph.plotAreaFrame!.paddingLeft = graphOffset
graph.plotAreaFrame!.masksToBorder = false
// Grid line styles
let majorLineStyle = CPTMutableLineStyle()
majorLineStyle.lineWidth = 0.75
majorLineStyle.lineColor = CPTColor.redColor()
let minorLineStyle = CPTMutableLineStyle()
minorLineStyle.lineWidth = 0.25
minorLineStyle.lineColor = CPTColor.blackColor()
//Axis Line colors
let axisLineStyle = CPTMutableLineStyle()
axisLineStyle.lineWidth = 2.0
axisLineStyle.lineColor = CPTColor.blackColor()
//Axis Label colors
let labelTextStyle = CPTMutableTextStyle()
labelTextStyle.textAlignment = CPTTextAlignment.Left
labelTextStyle.color = CPTColor.blackColor()
//Axis title color
let titleTextStyle = CPTMutableTextStyle()
titleTextStyle.textAlignment = CPTTextAlignment.Left
titleTextStyle.color = CPTColor.blackColor()
titleTextStyle.fontSize = 15
let dataSourceLinePlot = CPTScatterPlot()
let lineStyle = CPTMutableLineStyle()
lineStyle.lineWidth = 3.0
lineStyle.lineColor = CPTColor.blueColor()
dataSourceLinePlot.dataLineStyle = lineStyle
dataSourceLinePlot.identifier = kPlotIdentifier
// dataSourceLinePlot.dataSource = self
let xts = CPTMutableTextStyle()
xts.color = CPTColor(componentRed: 255.0, green: 255.0, blue: 255.0, alpha: 1.0)
let dateFormatter = NSDateFormatter()
dateFormatter.dateFormat = "HH:mm:ss"
let timeformatter = CPTTimeFormatter(dateFormatter: dateFormatter)
timeformatter.referenceDate = NSDate()
let axisSet = graph.axisSet as! CPTXYAxisSet!
let xAxis = axisSet.xAxis as CPTXYAxis!
xAxis.axisTitle = CPTAxisTitle(text: "Elapsed Time", textStyle: xts)
xAxis.labelFormatter = timeformatter
xAxis.majorGridLineStyle = majorLineStyle
xAxis.minorGridLineStyle = minorLineStyle
xAxis.majorIntervalLength = NSNumber(double: 60.0)
let yAxis = axisSet.yAxis as CPTXYAxis!
yAxis.axisTitle = CPTAxisTitle(text: "Heart Rate", textStyle: xts)
let axisFormatter = NSNumberFormatter()
axisFormatter.maximumFractionDigits = 0
axisFormatter.minimumIntegerDigits = 1
yAxis.labelFormatter = axisFormatter
yAxis.titleOffset = 35.0
yAxis.majorIntervalLength = 20
yAxis.majorGridLineStyle = majorLineStyle
yAxis.minorGridLineStyle = minorLineStyle
graph.addPlot(dataSourceLinePlot)
self.IBviewGraph.hostedGraph = self.graph
}
To plot data :
func setGraphData() {
dispatch_sync(dispatch_get_main_queue(), {
let plot = CPTScatterPlot()
plot.dataSource = self
let actualPlotStyle = plot.dataLineStyle!.mutableCopy() as! CPTMutableLineStyle
actualPlotStyle.lineWidth = 2.0
actualPlotStyle.lineColor = CPTColor(CGColor: (UIColor.yellowColor().CGColor))
plot.dataLineStyle = actualPlotStyle
plot.interpolation = .Linear
self.graph.addPlot(plot)
})
}
Data source methods
func numberOfRecordsForPlot(plot: CPTPlot) -> UInt {
return 3
}
func numberForPlot(plot: CPTPlot, field: UInt, recordIndex: UInt) -> AnyObject?{
var num = NSNumber()
let index = Int(recordIndex)
switch field {
case 0://xaxis
return graphData[index].0
case 1://yaxis
return graphData[index].1
default:
break
}
print("coordintes = ",num)
return num
}
My graph is drown but only yAxis points are correct , its not considering xAxis value and so because of that points are at wrong position in graph. I think the value I am passing in method numberForPlot for xAxis is wrong , but don't know how to pass it. Give me some solution.
The x-values in the graphData array are strings. Core Plot expects the datasource to return a numeric value for each index. It's reading the hour from the time string and using that for the x-value.
The x-axis is configured to display numbers in the range 0 to 1,000. Therefore, you need to convert the time data to a number in that range. Keep track of the reference date used to format the axis labels (i.e., store it in an instance variable) and use that to convert the time data to an offset in seconds from the reference date.
How do I render primitives into off screen texture, not directly into the screen?
I have a set of triangles and corresponding color, I just want to draw them the same way I do to screen, but into off screen texture, that I can save into a file.
Can anybody show me a code sample of that?
Ok, I realized it myself. This code does the job, with only exception that it draw too huge triangles, but that is a different topic for Vertex function.
Here is my code:
let fragmentProgram = defaultLibrary.newFunctionWithName("image_fragmentT")
let vertexProgram = defaultLibrary.newFunctionWithName("image_vertexT")
struct VertexT {
var x, y, z, w : Float
var r, g, b, a : Float
}
let vertexDescriptor = MTLVertexDescriptor()
vertexDescriptor.attributes[0].offset = 0
vertexDescriptor.attributes[0].format = .Float4
vertexDescriptor.attributes[0].bufferIndex = 0
vertexDescriptor.attributes[1].offset = 0
vertexDescriptor.attributes[1].format = .Float4
vertexDescriptor.attributes[1].bufferIndex = 0
vertexDescriptor.layouts[0].stepFunction = .PerVertex
vertexDescriptor.layouts[0].stride = sizeof(VertexT)
let pipelineStateDescriptor = MTLRenderPipelineDescriptor()
pipelineStateDescriptor.vertexDescriptor = vertexDescriptor
pipelineStateDescriptor.vertexFunction = vertexProgram
pipelineStateDescriptor.fragmentFunction = fragmentProgram
pipelineStateDescriptor.colorAttachments[0].pixelFormat = .RGBA8Unorm;
pipelineStateDescriptor.colorAttachments[0].blendingEnabled = true
pipelineStateDescriptor.sampleCount = 4
pipelineStateDescriptor.colorAttachments[0].rgbBlendOperation = MTLBlendOperation.Add
pipelineStateDescriptor.colorAttachments[0].alphaBlendOperation = MTLBlendOperation.Add
pipelineStateDescriptor.colorAttachments[0].sourceRGBBlendFactor = MTLBlendFactor.SourceAlpha
pipelineStateDescriptor.colorAttachments[0].sourceAlphaBlendFactor = MTLBlendFactor.SourceAlpha
pipelineStateDescriptor.colorAttachments[0].destinationRGBBlendFactor = MTLBlendFactor.OneMinusSourceAlpha
pipelineStateDescriptor.colorAttachments[0].destinationAlphaBlendFactor = MTLBlendFactor.OneMinusSourceAlpha
let sampleDesc = MTLTextureDescriptor()
sampleDesc.textureType = MTLTextureType.Type2DMultisample
sampleDesc.width = inTexture.width
sampleDesc.height = inTexture.height
sampleDesc.sampleCount = 4
sampleDesc.pixelFormat = .RGBA8Unorm
sampleDesc.storageMode = .Private
sampleDesc.usage = .RenderTarget
let sampletex = device.device.newTextureWithDescriptor(sampleDesc)
let renderPassDescriptor = MTLRenderPassDescriptor()
renderPassDescriptor.colorAttachments[0].texture = sampletex
renderPassDescriptor.colorAttachments[0].resolveTexture = outTexture
renderPassDescriptor.colorAttachments[0].loadAction = .Clear
renderPassDescriptor.colorAttachments[0].clearColor = MTLClearColor(red: 0.0, green: 0.0, blue: 0.0, alpha: 0.0)
renderPassDescriptor.colorAttachments[0].storeAction = .MultisampleResolve
let renderCB = commandQueue.commandBuffer()
let renderCommandEncoder = renderCB.renderCommandEncoderWithDescriptor(renderPassDescriptor)
let pipelineState = try! device.device.newRenderPipelineStateWithDescriptor(pipelineStateDescriptor)
renderCommandEncoder.setRenderPipelineState(pipelineState)
let vertexBuf = device.device.newBufferWithLength(triangles.count * 3 * sizeof(VertexT), options: .CPUCacheModeDefaultCache)
var vBufPointer = [VertexT]()
for i in 0..<triangles.count {
// create buffer here
}
memcpy(vertexBuf.contents(), &vBufPointer, triangles.count * 3 * sizeof(VertexT))
renderCommandEncoder.setVertexBuffer(vertexBuf, offset: 0, atIndex: 0)
renderCommandEncoder.drawPrimitives(.Triangle, vertexStart: 0, vertexCount: triangles.count * 3)
renderCommandEncoder.endEncoding()
renderCB.commit()
renderCB.waitUntilCompleted()
You image now is in outTexture variable.