ios - 使用 Core-Plot 的实时图上未说明的水平线

标签 ios objective-c core-plot

我正在尝试在同一张图上使用 4 个单独的图来绘制 4 channel 输入流的实时图。目前我正在从文本文件中获取这些数据,但最终会使用蓝牙获取这些数据。我的情节本身工作正常,但核心情节似乎在第一个数据集级别的绘图开始时为每个情节绘制了一条额外的水平线。我认为这与 core-plot 试图在开始显示之前绘制所有点有关。下图显示了这些线,而实际波形,方波,正在绘制中。

enter image description here

随着绘图的进行和 x 轴显示范围的变化,这些线会消失。就像在这里:

enter image description here

以下是我的代码的相关部分。它基于 Ray Wenderlich 的散点图教程和 Eric Skrooch 的实时绘图示例。 (我希望我拼对了这些名字!)。就我个人而言,我认为这是核心情节中的错误,而不是编码错误。非常感谢任何有关如何摆脱这些令人不安的线条的帮助!谢谢!

-(void)configurePlots {

    //Get graph and plot space
    CPTGraph *graph = self.hostView.hostedGraph;
    CPTXYPlotSpace *plotSpace = (CPTXYPlotSpace *) graph.defaultPlotSpace;

    //Create the four plots
    CPTScatterPlot *channel1Plot = [[CPTScatterPlot alloc]init];
    channel1Plot.dataSource = self;
    channel1Plot.identifier = @"channel1";
    [graph addPlot:channel1Plot toPlotSpace:plotSpace];

    CPTScatterPlot *channel2Plot = [[CPTScatterPlot alloc]init];
    channel2Plot.dataSource = self;
    channel2Plot.identifier = @"channel2";
    [graph addPlot:channel2Plot toPlotSpace:plotSpace];

    CPTScatterPlot *channel3Plot = [[CPTScatterPlot alloc]init];
    channel3Plot.dataSource = self;
    channel3Plot.identifier = @"channel3";
    [graph addPlot:channel3Plot toPlotSpace:plotSpace];

    CPTScatterPlot *channel4Plot = [[CPTScatterPlot alloc]init];
    channel4Plot.dataSource = self;
    channel4Plot.identifier = @"channel4";
    [graph addPlot:channel4Plot toPlotSpace:plotSpace];

    //Set up plot space
    [plotSpace scaleToFitPlots:[NSArray arrayWithObjects:channel1Plot, channel2Plot, channel3Plot, channel4Plot, nil]];
    CPTMutablePlotRange *xRange = [plotSpace.xRange mutableCopy];
    [xRange expandRangeByFactor:CPTDecimalFromCGFloat(1.1f)];
    plotSpace.xRange = xRange;
    CPTMutablePlotRange *yRange = [plotSpace.yRange mutableCopy];
    [yRange expandRangeByFactor:CPTDecimalFromCGFloat(1.2f)];
    plotSpace.yRange = yRange;

    //Create styles and symbols

    CPTMutableLineStyle *channelLineStyle = [channel1Plot.dataLineStyle mutableCopy];
    channelLineStyle.lineWidth = 1.0;
    channelLineStyle.lineColor = [CPTColor redColor];
    channel1Plot.dataLineStyle = channelLineStyle;
    channel2Plot.dataLineStyle = channelLineStyle;
    channel3Plot.dataLineStyle = channelLineStyle;
    channel4Plot.dataLineStyle = channelLineStyle;

}

-(void)configureAxes {

    //Create styles
    CPTMutableTextStyle *axisTitleStyle = [CPTMutableTextStyle textStyle];
    axisTitleStyle.color = [CPTColor whiteColor];
    axisTitleStyle.fontName = @"Helvetica-Bold";
    axisTitleStyle.fontSize = 12.0f;
    CPTMutableLineStyle *axisLineStyle = [CPTMutableLineStyle lineStyle];
    axisLineStyle.lineWidth = 2.0f;
    axisLineStyle.lineColor = [CPTColor whiteColor];
    CPTMutableTextStyle *axisTextStyle = [[CPTMutableTextStyle alloc] init];
    axisTextStyle.color = [CPTColor yellowColor];
    axisTextStyle.fontName = @"Helvetica-Bold";
    axisTextStyle.fontSize = 11.0f;
    CPTMutableLineStyle *tickLineStyle = [CPTMutableLineStyle lineStyle];
    tickLineStyle.lineWidth = 2.0f;
    tickLineStyle.lineColor = [CPTColor yellowColor];
    CPTMutableLineStyle *gridLineStyle = [CPTMutableLineStyle lineStyle];
    tickLineStyle.lineColor = [CPTColor purpleColor];
    tickLineStyle.lineWidth = 1.0f;

    //Get axis set
    CPTXYAxisSet *axisSet = (CPTXYAxisSet *) self.hostView.hostedGraph.axisSet;

    //Configure X-axis
    CPTAxis *x = axisSet.xAxis;
    x.title = @"Time";
    x.titleTextStyle = axisTitleStyle;
    x.titleOffset = 15.0f;
    x.axisLineStyle = axisLineStyle;
    x.labelingPolicy = CPTAxisLabelingPolicyNone;
    x.labelTextStyle = axisTextStyle;
    x.majorTickLineStyle = axisLineStyle;
    x.majorTickLength = 4.0f;
    x.tickDirection = CPTSignNegative;
    CGFloat pointsCount = POINTS_ON_SCREEN;
    NSMutableSet *xLabels = [NSMutableSet setWithCapacity:pointsCount];
    NSMutableSet *xLocations = [NSMutableSet setWithCapacity:pointsCount];
    NSInteger i=0;
    //NSString *loc = [NSString stringWithFormat:@"d",j];
    for (NSInteger j=0; j<POINTS_ON_SCREEN; j++) {
        CPTAxisLabel *label = [[CPTAxisLabel alloc] initWithText:[NSString stringWithFormat:@"%ld", (long)j+1] textStyle:x.labelTextStyle];
        CGFloat location = i++;
        label.tickLocation = CPTDecimalFromCGFloat(location);
        label.offset = x.majorTickLength;
        if (label) {
            [xLabels addObject:label];
            [xLocations addObject:[NSNumber numberWithFloat:location]];
        }
    }
    x.axisLabels = xLabels;
    x.majorTickLocations = xLocations;

    //Configure Y-axis
    axisSet.yAxis.axisConstraints = [CPTConstraints constraintWithLowerOffset:0.0];
    CPTAxis *y = axisSet.yAxis;
    y.title = @"Channel outputs";
    y.titleTextStyle = axisTitleStyle;
    y.titleOffset = -40.0f;
    y.axisLineStyle = axisLineStyle;
    y.majorGridLineStyle = gridLineStyle;
    y.labelingPolicy = CPTAxisLabelingPolicyNone;
    y.labelTextStyle = axisTextStyle;
    y.labelOffset = 16.0f;
    y.majorTickLineStyle = axisLineStyle;
    y.majorTickLength = 4.0f;
    y.minorTickLength = 2.0f;
    y.tickDirection = CPTSignPositive;
    CGFloat majorIncrement = 0.0005;
    CGFloat minorIncrement = 0.0001;
    CGFloat yMax = 0.0040f;
    NSMutableSet *yLabels = [NSMutableSet set];
    NSMutableSet *yMajorLocations = [NSMutableSet set];
    NSMutableSet *yMinorLocations = [NSMutableSet set];
    for (CGFloat j = minorIncrement; j<=yMax; j+=minorIncrement) {
        j = roundf(j*100000)/100000;
        CGFloat mod = j / majorIncrement;
        NSInteger modInt = (NSInteger)mod;
        CGFloat modMantissa = mod - modInt;
        modMantissa = roundf(modMantissa * 100)/100;
        if (modMantissa < 0.1 || modMantissa > 0.9) {
            CPTAxisLabel *label = [[CPTAxisLabel alloc] initWithText:[NSString stringWithFormat:@"%.5f", j] textStyle:y.labelTextStyle];
            NSDecimal location = CPTDecimalFromCGFloat(j);
            //NSNumber *location = [NSNumber numberWithFloat:j];
            label.tickLocation = location;
            label.offset = -y.majorTickLength -y.labelOffset -9;
            //label.offset = 0;
            if (label) {
                [yLabels addObject:label];
            }
            [yMajorLocations addObject:[NSDecimalNumber decimalNumberWithDecimal:location]];
        } else {
            [yMinorLocations addObject:[NSDecimalNumber decimalNumberWithString:[NSString stringWithFormat:@"%f",j]]];
        }
    }
    y.axisLabels = yLabels;
    y.majorTickLocations = yMajorLocations;
    y.minorTickLocations = yMinorLocations;
}

-(void)createTimer {
    NSTimer *dataTimer = [NSTimer timerWithTimeInterval:0.002 target:self selector:@selector(dynamicUpdate:) userInfo:nil repeats:YES];
    [[NSRunLoop mainRunLoop] addTimer:dataTimer forMode:NSDefaultRunLoopMode];
}

-(void)dynamicUpdate: (NSTimer *)dataTimer {
    CPTGraph *graph = self.hostView.hostedGraph;
    CPTPlot *channel1Plot = [graph plotWithIdentifier:@"channel1"];
    CPTPlot *channel2Plot = [graph plotWithIdentifier:@"channel2"];
    CPTPlot *channel3Plot = [graph plotWithIdentifier:@"channel3"];
    CPTPlot *channel4Plot = [graph plotWithIdentifier:@"channel4"];
    CPTXYPlotSpace *plotSpace = (CPTXYPlotSpace *)graph.defaultPlotSpace;


    if (channel1Plot && channel2Plot && channel3Plot && channel4Plot) {
        if ( arrayIndex1 >= POINTS_ON_SCREEN-1
            || arrayIndex2 >= POINTS_ON_SCREEN-1
            || arrayIndex3 >= POINTS_ON_SCREEN-1
            || arrayIndex4 >= POINTS_ON_SCREEN-1) {

            [channel1Array removeObjectAtIndex:0];
            [channel1Plot deleteDataInIndexRange:NSMakeRange(0, 1)];
            [channel2Array removeObjectAtIndex:0];
            [channel2Plot deleteDataInIndexRange:NSMakeRange(0, 1)];
            [channel3Array removeObjectAtIndex:0];
            [channel3Plot deleteDataInIndexRange:NSMakeRange(0, 1)];
            [channel4Array removeObjectAtIndex:0];
            [channel4Plot deleteDataInIndexRange:NSMakeRange(0, 1)];
        }

        plotSpace.xRange = [CPTPlotRange plotRangeWithLocation:CPTDecimalFromUnsignedInteger(currentIndex >= POINTS_ON_SCREEN ? currentIndex-POINTS_ON_SCREEN +1 : 0) length:CPTDecimalFromUnsignedInteger(POINTS_ON_SCREEN-1)];
        currentIndex++;

        [channel1Plot insertDataAtIndex:POINTS_ON_SCREEN-1 numberOfRecords:1];
        [channel2Plot insertDataAtIndex:POINTS_ON_SCREEN-1 numberOfRecords:1];
        [channel3Plot insertDataAtIndex:POINTS_ON_SCREEN-1 numberOfRecords:1];
        [channel4Plot insertDataAtIndex:POINTS_ON_SCREEN-1 numberOfRecords:1];
    }
}


-(NSUInteger)numberOfRecordsForPlot:(CPTPlot *)plot {
    return POINTS_ON_SCREEN;
}

-(NSNumber *)numberForPlot:(CPTPlot *)plot field:(NSUInteger)fieldEnum recordIndex:(NSUInteger)idx {
   // NSLog(@"Plotting point");
    NSNumber *num = nil;
    if ([self.activityIndicator isAnimating] == YES) {
        [self.activityIndicator stopAnimating];
    }
    switch (fieldEnum) {

        case CPTScatterPlotFieldX:
            if (idx < POINTS_ON_SCREEN) {
                return [NSNumber numberWithUnsignedInteger:idx + currentIndex - POINTS_ON_SCREEN];
            };
            break;

        case CPTScatterPlotFieldY:
            if ([plot.identifier isEqual:@"channel1"]) {
                num = [channel1Array objectAtIndex:idx];
                arrayIndex1 = idx;
            } else if ([plot.identifier isEqual:@"channel2"]) {
                num = [channel2Array objectAtIndex:idx];
                arrayIndex2 = idx;
            } else if ([plot.identifier isEqual:@"channel3"]) {
                num = [channel3Array objectAtIndex:idx];
                arrayIndex3 = idx;
            } else if ([plot.identifier isEqual:@"channel4"]) {
                num = [channel4Array objectAtIndex:idx];
                arrayIndex4 = idx;
            } else {
                NSLog(@"data unavailable");
            }
            break;

        default:
            NSLog(@"ERROR: trying to plot on unidentified axis");
            break;
    }
    NSString *numString = [NSString stringWithFormat:@"%@", num];
    dispatch_async(AddToArrayQ, ^{[self writeData:numString];});
    return num;
}

最佳答案

除非我误读了这一点,否则您将从 numberOfRecordsForPlot: 返回一个硬编码值,因此 CorePlot 期望能够填充 x 轴上的所有这些点。您看到的那些行可能是由于将这些数组初始化为常量值(它们必须被初始化,对吧,否则当您尝试访问未初始化的索引时会出错?)

请注意,在 Eric Skroch 的示例中,他从 numberOfRecordsForPlot: 返回 [plotData count],并且 plotData 在初始化时为空。

关于ios - 使用 Core-Plot 的实时图上未说明的水平线,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25733724/

相关文章:

ios - JSQ消息反馈定制

ios - Logo 查找 API?

objective-c - 多语言本地化 Storyboard支持问题

ios - 读取和写入 plist(iPhone 编程)

iphone - iOS 5 中的方法调配?

ios - ObjectiveC mutableCopy 如何在 swift 中工作

ios - Core Plot 的实时线图不更新绘图范围

iphone - 禁用核心图 iPhone 中的滚动

ios - 在表格 View 重新加载期间绘制线条的问题

ios - 如何在 iOS 中注册 GCM