I am trying to make a bar graph with core plot. I cannot get the y-axis to scale properly or the tick-marks in the correct places. My biggest issue is that if I set:
CPTXYPlotSpace *plotSpace = (CPTXYPlotSpace *) graph.defaultPlotSpace;
plotSpace.yRange = [CPTPlotRange plotRangeWithLocation:CPTDEcimalFromFloat(0) length:CPTDecimalFromFloat(max_value);
And max_value is anything higher then 10 it takes an unreasonable amount of time for the graph to load. For example I need max_value to be around 1000 to show the tops of all the values but when I set it to 1000 it takes over 15 seconds to load the screen. But if I leave it set to 10 my bar graphs take up the entire screen and you cannot see the top.
This is the rest of the part of the code dealing with this. Any advice would be appreciated.
CPTXYPlotSpace *plotSpace = (CPTXYPlotSpace *) graph.defaultPlotSpace;
plotSpace.yRange = [CPTPlotRange plotRangeWithLocation:CPTDecimalFromFloat(0)
length:CPTDecimalFromFloat(1000)];
[plotSpace scaleToFitPlots:[NSArray arrayWithObjects:_liftOffPlot,_sideLeanPlot,_forwardLeanPlot,_crossLegsPlot,nil]];
graph.plotAreaFrame.borderLineStyle = nil;
axisSet.yAxis.title = #"times completed";
axisSet.yAxis.titleTextStyle = axisTitleStyle;
axisSet.yAxis.titleOffset = -25.0f;
axisSet.yAxis.axisLineStyle = nil;
axisSet.yAxis.labelingPolicy = CPTAxisLabelingPolicyAutomatic;
axisSet.yAxis.preferredNumberOfMajorTicks = 10;
axisSet.yAxis.minorTicksPerInterval = 1;
axisSet.yAxis.minorTickLocations = nil;
axisSet.yAxis.majorTickLocations = nil;
axisSet.yAxis.title = #"times completed";
axisSet.yAxis.titleTextStyle = axisTitleStyle;
axisSet.yAxis.titleOffset = -25.0f;
axisSet.yAxis.axisLineStyle = nil;
axisSet.yAxis.majorIntervalLength = CPTDecimalFromString(#"100");
axisSet.yAxis.orthogonalCoordinateDecimal = CPTDecimalFromString(#"0");
axisSet.yAxis.visibleRange = [CPTPlotRange plotRangeWithLocation:CPTDecimalFromInt(0) length:CPTDecimalFromInt(1000)];
axisSet.yAxis.gridLinesRange = axisSet.yAxis.visibleRange;
As I seem to be finding with most things xcode, it is all about where you put your code. If I have CPTPlotRange:PlotRangeWithLocation:Length before I do my set up it is really slow and buggy. If instead I add it to the end of my code after setting the other values for the axises suddenly there is only a very minor delay. I actually got this code originally from a tutorial and modified it to fit what I needed but I guess the tutorial didn't have the same delay because the length of the data was much lower.
So all I did to fix this problem was put the following code after my axis set up instead of before;
CPTXYPlotSpace *plotSpace = (CPTXYPlotSpace *) graph.defaultPlotSpace;
plotSpace.yRange = [CPTPlotRange plotRangeWithLocation:CPTDecimalFromFloat(0)
length:CPTDecimalFromFloat(1000)];
[plotSpace scaleToFitPlots:[NSArray arrayWithObjects:_liftOffPlot,_sideLeanPlot,_forwardLeanPlot,_crossLegsPlot,nil]];
graph.plotAreaFrame.borderLineStyle = nil;
Related
I have a graph and I need to change its xPlotRange in process adding new elements. How can I do it?
I have tried this:
[self.hostView.hostedGraph.defaultPlotSpace
setAllowsUserInteraction:YES];
long count = [array count];
if (count>100 && count<maxElements)
[self plotSpace:self.hostView.hostedGraph.defaultPlotSpace willChangePlotRangeTo:[CPTMutablePlotRange plotRangeWithLocation:#(0.0) length:[NSNumber numberWithInteger:count+100]] forCoordinate:CPTCoordinateX];
CPTXYPlotSpace *plotSpace = (CPTXYPlotSpace*)self.graph.defaultPlotSpace; plotSpace.allowsUserInteraction=YES; plotSpace.delegate = self;
plotSpace.xRange = [CPTPlotRange plotRangeWithLocationDecimal:CPTDecimalFromInt(xAxisMin)/*minimum x value*/ lengthDecimal:CPTDecimalFromInt()];
plotSpace.yRange = [CPTPlotRange plotRangeWithLocationDecimal:CPTDecimalFromInt(60) lengthDecimal:CPTDecimalFromInt(yAxisRange)];
[plotSpace setGlobalXRange:[CPTPlotRange plotRangeWithLocationDecimal:CPTDecimalFromInt(0) lengthDecimal:CPTDecimalFromInt(xAxisMax - xAxisMin)]];
[plotSpace setGlobalYRange:[CPTPlotRange plotRangeWithLocationDecimal:CPTDecimalFromInt([[_dict1 objectForKey:#"minValue"]intValue ]) lengthDecimal:CPTDecimalFromInt(yAxisRange)]];
I have set the plotspace with X and Y Ranges but still I get to see the negative axes. Thoughts anyone?
// Setup scatter plot space
CPTXYPlotSpace *plotSpace = (CPTXYPlotSpace *)graph.defaultPlotSpace;
plotSpace.allowsUserInteraction = YES;
plotSpace.delegate = self;
plotSpace.xRange = [CPTPlotRange plotRangeWithLocation:[NSNumber numberWithFloat:0.0] length:[NSNumber numberWithInt:2]];
plotSpace.yRange = [CPTPlotRange plotRangeWithLocation:[NSNumber numberWithFloat:0.0] length:[NSNumber numberWithInt:2]];
Please check the image to see how it looks
[![enter image description here][2]][2]
Set the leftPadding and bottomPadding on the graph and/or plot area frame to leave room for the tick marks and axis labels. If you still want to be able to scroll the graph and leave the axes along the edge, set the axisConstraints.
I was able to achieve the solution just by setting the visible ranges for both the axis.
x.visibleRange = [CPTPlotRange plotRangeWithLocation:xMin length:[NSNumber numberWithDouble:([xMax doubleValue] - [xMin doubleValue])]];
y.visibleRange = [CPTPlotRange plotRangeWithLocation:yMin length:[NSNumber numberWithDouble:([yMax doubleValue] - [yMin doubleValue])]];
I'm experiencing some problems with CorePlot. I try to plot multiple scatterPlots into one graph. Which works as expected but when I start scrolling or zooming the graph the whole app increases it's memory usage up to 900MB an crashes. I think I have to do some object releasing but I don't know how. Basically I plot each line with a different plot identifier and put the according data into the datasource.
Here is what I got: (In this example code I just reduced the axe ranges with static values for testing purposes.)
- (void)setupGraph {
// Create graph from theme
self.graph = [[CPTXYGraph alloc] initWithFrame:self.scatterPlotView.bounds];
self.graph.plotAreaFrame.masksToBorder = NO;
self.scatterPlotView.hostedGraph = self.graph;
CPTTheme *theme = [CPTTheme themeNamed:kCPTPlainBlackTheme];
[self.graph applyTheme:theme];
self.graph.paddingLeft = 0.0;
self.graph.paddingTop = 0.0;
self.graph.paddingRight = 0.0;
self.graph.paddingBottom = 0.0;
// Setup plot space
CPTXYPlotSpace *plotSpace = (CPTXYPlotSpace *)self.graph.defaultPlotSpace;
plotSpace.allowsUserInteraction = YES;
plotSpace.delegate = self;
plotSpace.globalXRange = [CPTPlotRange plotRangeWithLocation:CPTDecimalFromDouble(0) length:CPTDecimalFromDouble(30)];
plotSpace.globalYRange = [CPTPlotRange plotRangeWithLocation:CPTDecimalFromDouble(0) length:CPTDecimalFromDouble(15)];
plotSpace.xRange = [CPTPlotRange plotRangeWithLocation:CPTDecimalFromDouble(0) length:CPTDecimalFromDouble(10)];
plotSpace.yRange = [CPTPlotRange plotRangeWithLocation:CPTDecimalFromDouble(0) length:CPTDecimalFromDouble(15)];
CPTXYAxisSet *axisSet = (CPTXYAxisSet *)self.graph.axisSet;
CPTXYAxis *x = axisSet.xAxis;
CPTXYAxis *y = axisSet.yAxis;
x.labelingPolicy = CPTAxisLabelingPolicyNone;
y.labelingPolicy = CPTAxisLabelingPolicyNone;
}
This method loads my data and draws the scatterplots
- (void)loadSignals {
//Data loading logic goes here nothing special just one array for each plot
for (Signal *sig in [signals allValues]) {
[self constructScatterPlot:sig.name];
}
}];
This is where the drawing happens:
- (void)constructScatterPlot:(NSString *)identifier {
CPTScatterPlot *dataSourceLinePlot = [[CPTScatterPlot alloc] init];
CPTMutableLineStyle *lineStyle = [dataSourceLinePlot.dataLineStyle mutableCopy];
CPTScatterPlot *boundLinePlot = [[CPTScatterPlot alloc] init];
boundLinePlot.identifier = identifier;
lineStyle = [boundLinePlot.dataLineStyle mutableCopy];
lineStyle.miterLimit = 1.0;
lineStyle.lineWidth = 1.0;
lineStyle.lineColor = [CPTColor redColor];
boundLinePlot.dataLineStyle = lineStyle;
boundLinePlot.dataSource = self;
boundLinePlot.cachePrecision = CPTPlotCachePrecisionDouble;
boundLinePlot.interpolation = CPTScatterPlotInterpolationStepped;
[self.graph addPlot:boundLinePlot];
}
...and this is where the datasource gets it's values:
-(NSNumber *)numberForPlot:(CPTPlot *)plot field:(NSUInteger)fieldEnum recordIndex:(NSUInteger)index
{
NSString *plotIdent = (NSString *) plot.identifier;
if (![plotIdent isEqualToString:self.currentIdent]) {
self.countPlot++;
self.currentIdent = plotIdent;
}
Signal *newSig = [self.signals objectForKey:plotIdent];
Value * newValue = [newSig valueAtTime:index];
NSNumber *number = [NSNumber numberWithInteger:[newValue.value integerValue]];
if ( fieldEnum == CPTScatterPlotFieldY ) {
return number;
}
if ( fieldEnum == CPTScatterPlotFieldX ) {
return [NSNumber numberWithInteger:index];
}
return nil;
}
So first of all I'd like to know if this is the correct way of drawing multiple plots (up to 40 in my case) into one graph? If so, what could I do to optimize my plot performance?
The output should look like this:
I found this use
"try setting collapsesLayers to YES on the hosting view"
Application get stuck when drawing nearly 40 Scatter Plots using Core Plot in IPad
Each plot is a CALayer that covers the entire plot area of the graph, so with 40 of them you may be using up most of the available video memory. If they all use the same line style, you can plot all of the lines on the same plot and save some memory that way. Insert an extra data point between the line segments and return nil or #(NAN) from the datasource to break the line.
When my scatter plot appears, I see that :
But I would like to se that :
Directly after chart loading, I want that the user see a chart with all data displaying, and not just a small piece like in the first screenshot. How can I define the original "zoom" ?
EDIT : (here's my code)
[...]
CPTGraph *graph = self.hostView.hostedGraph;
CPTXYPlotSpace *plotSpace = (CPTXYPlotSpace *) graph.defaultPlotSpace;
CPTScatterPlot *myPlot = [[CPTScatterPlot alloc] init];
myPlot.dataSource = self;
myPlot.delegate = self;
CPTColor *myColor = [CPTColor greenColor];
[graph addPlot:myPlot toPlotSpace:plotSpace];
myPlot.plotSymbolMarginForHitDetection = 10.0f;
[plotSpace scaleToFitPlots:[NSArray arrayWithObject:myPlot]];
CPTMutablePlotRange *xRange = [plotSpace.xRange mutableCopy];
[xRange expandRangeByFactor:CPTDecimalFromCGFloat(DynamicValue)];
plotSpace.xRange = xRange;
CPTMutablePlotRange *yRange = [plotSpace.yRange mutableCopy];
[yRange expandRangeByFactor:CPTDecimalFromCGFloat(DynamicValue)];
plotSpace.yRange = yRange;
[...]
Many of the Core Plot example apps use -[CPTPlotSpace scaleToFitPlots:] to adjust the plot ranges to the plot data. If you already know the data range, you set the plot space xRange and/or yRange directly when setting up the graph.
I'm trying to come up with a scatter plot whose range depends on the value received. The given variable self.xAxisMinimum takes in the first value of the data received. However when I run my program it reads such that, when self.xAxisMinimum = 4688 the plotspace.range starts from 5000.
Given below is the plotspace settings.
CPTXYPlotSpace *plotSpace = (CPTXYPlotSpace *)self.graph.defaultPlotSpace;
plotSpace.xRange = [CPTPlotRange
plotRangeWithLocation:CPTDecimalFromFloat(self.xAxisMinimum - 100) length:CPTDecimalFromFloat(60*60)];
plotSpace.yRange = [CPTPlotRange plotRangeWithLocation:CPTDecimalFromFloat(yAxisMin) length:CPTDecimalFromFloat(yAxisMax - yAxisMin)];
Is it anything related to the the major interval length? I have major interval length of 180seconds.
Give below is the code for the Xaxis-set's parameters.
axisSet.xAxis.title = #"Time(per sec)";
axisSet.xAxis.titleTextStyle = textStyle;
axisSet.xAxis.axisLineStyle = lineStyle;
axisSet.xAxis.titleOffset = 30.0f;
axisSet.xAxis.majorTickLineStyle = lineStyle;
axisSet.xAxis.minorTickLineStyle = lineStyle;
axisSet.xAxis.majorGridLineStyle = lineStyle;
axisSet.xAxis.minorGridLineStyle=gridStyle;
axisSet.xAxis.labelOffset = 6.0f;
axisSet.xAxis.majorIntervalLength = CPTDecimalFromFloat(180.0f);
axisSet.xAxis.minorTicksPerInterval = 5;
axisSet.xAxis.minorTickLength = 0.50f;
axisSet.xAxis.majorTickLength = 0.50f;
axisSet.xAxis.labelTextStyle = textStyle;
axisSet.xAxis.labelFormatter = formatter;
So for this set up I should have had a x axis starting from (4688-100) instead of 5000. Anyone have any idea why? thanks much in advance
the issue lies in DecimalFromFloat. I gave an integer input to the float value and converted into decimal. Instead I changed to DecimalFromInteger. It works fine. Thanks