2016-09-21 861 views
0

我目前正在使用CorePlot库(版本2.1)绘制散点图的iOS应用程序中工作。我的散点图绘制得很好,在下一步中,我想绘制一个半透明的置信椭圆图。我写了一个计算椭圆的主轴和副轴以及所需的旋转角度的类。 My ConfidenceEllipse类实现了一个getPath()方法,该方法返回一个表示要绘制的椭圆的CGPath。在散点图上绘制置信椭圆

func getPath() -> CGPath 
{ 
var ellipse: CGPath 

var transform = CGAffineTransformIdentity 
transform = CGAffineTransformTranslate (transform, CGFloat(-self.meanX), CGFloat(-self.meanY)) 
transform = CGAffineTransformRotate (transform, CGFloat(self.angle)) 
transform = CGAffineTransformTranslate (transform, CGFloat(self.meanX), CGFloat(self.meanY)) 

ellipse = CGPathCreateWithEllipseInRect(CGRectMake (CGFloat(-self.mainHalfAxis), CGFloat(-self.minorHalfAxis), CGFloat(2 * self.mainHalfAxis), CGFloat(2 * self.minorHalfAxis)),&transform) 

return ellipse 
} 

搜索网站一段时间后,似乎注解是要走的路,所以我想这:

let graph  = hostView.hostedGraph! 
let space  = graph.defaultPlotSpace  
let ellipse = ConfidenceEllipse(chiSquare: 5.991) 
ellipse.analyze(self.samples) 

let annotation = CPTPlotSpaceAnnotation (plotSpace: space!, anchorPlotPoint: [0,0]) 
let overlay = CPTBorderedLayer (frame: graph.frame) 
overlay.outerBorderPath = ellipse.getPath() 

let fillColor = CPTColor.yellowColor() 
overlay.fill = CPTFill (color: fillColor) 

annotation.contentLayer = overlay 
annotation.contentLayer?.opacity = 0.5 
graph.addAnnotation(annotation) 

这样做,会给我下面 Screenshot 正如你可以看到,叠加层占据了整个框架的大小,这似乎是合乎逻辑的,因为在创建对象时我通过了框架的尺寸。我也尝试将构造函数留空,但覆盖层完全不显示。所以我想知道,有什么我在这里失踪?

回答

0

您需要缩放椭圆以匹配绘图。使用绘图区域bounds作为注释图层的框架,并将注释附加到绘图区域。在x和y方向上缩放椭圆以匹配绘图空间使用的转换以适合绘图区域中的绘图。

编辑: 在研究边框图层的工作方式后,我意识到我的建议不起作用。 CPTBorderedLayer设置outerBorderPath在图层边界发生变化时自动设置。不要尝试影响图层边框,请将椭圆绘制到图像中,并将其用作边框图层的fill。您应该调整图层的大小,使椭圆恰好适合内部。

+0

你说得对,我忘了缩放椭圆形。我尝试使用绘图区域和椭圆的边界初始化边界注记,稍后缩放边界注释,以便它完全覆盖散点图上带点的区域,但不幸的是,椭圆仍然不显示。注释仍然显示为矩形。你认为我设置outerBorderPath是罪魁祸首吗?这发生在阅读以下帖子后http://stackoverflow.com/questions/11588862/changing-the-layer-shape-for-cptplotspaceannotation。 – Neckelatius

0

未能使注解正常工作后,我决定采取不同的道路。我的最终解决方案在于将原始散点图与第二个散点图叠加,其中只包含一个数据点,即我的置信椭圆的中心。下面的代码

func drawConfidenceEllipse() { 

    let graph  = hostView.hostedGraph! 
    let plotSpace = graph.defaultPlotSpace as! CPTXYPlotSpace 

    let scaleX = (graph.bounds.size.width - graph.paddingLeft - graph.paddingRight)/CGFloat(plotSpace.xRange.lengthDouble) 
    let scaleY = (graph.bounds.size.height - graph.paddingTop - graph.paddingBottom)/CGFloat(plotSpace.yRange.lengthDouble) 

    let analysis = ConfidenceEllipse(chiSquare: 5.991) 
    analysis.analyze(self.samples) 
    let unscaledPath = analysis.getPath() 

    let bounds = CGPathGetBoundingBox(unscaledPath) 

    var scaler = CGAffineTransformIdentity 
    scaler = CGAffineTransformScale (scaler, scaleX, scaleY) 
    scaler = CGAffineTransformTranslate (scaler, CGFloat (-bounds.origin.x), CGFloat (-bounds.origin.y)) 
    let scaledPath = CGPathCreateCopyByTransformingPath (unscaledPath, &scaler) 
    let scaledBounds = CGPathGetPathBoundingBox(scaledPath) 

    let symbol = CPTPlotSymbol() 
    symbol.symbolType = CPTPlotSymbolType.Custom 
    symbol.customSymbolPath = scaledPath 
    symbol.fill = CPTFill (color: CPTColor.yellowColor().colorWithAlphaComponent(0.25)) 
    symbol.size = CGSize (width: scaledBounds.size.width, height: scaledBounds.size.height) 

    let lineStyle = CPTMutableLineStyle() 
    lineStyle.lineWidth = 1 
    lineStyle.lineColor = CPTColor.yellowColor() 

    symbol.lineStyle = lineStyle 

    let ellipse = CPTScatterPlot (frame: hostView.frame) 
    ellipse.title = "Confidence Ellipse" 
    ellipse.delegate = self 
    ellipse.dataSource = self 
    ellipse.plotSymbol = symbol 
    ellipse.dataLineStyle = nil 

    graph.addPlot(ellipse) 

}

下面是最终结果的截图:

95% Confidence Ellipse on top of scatter plot

希望这有助于