Core Plot : show time in x-axis - core-plot

I am newbie of Core Plot. I have data of time and temperature data. I am using CPTXYGraph to plot Y-axis (temperature) and X-axis (time in minutes). But I have no idea to show the x-axis in format 01:00, 01:15 etc ?
What I'm missing?

All you need to do is to assign a label formatter for the x-axis to print the time values as you want it. Use something like this:
CPTXYAxis *x = axisSet.xAxis;
x.labelTextStyle = textStyle; // a CPTTextStyle you created for color/font etc.
NSDateFormatter *formatter = [NSDateFormatter alloc] initWithDateFormat: #"mm:ss" allowNaturalLanguage: NO];
x.labelFormatter = formatter;

Related

iOS CorePlot numeric formatting of y-axis

I'm working with Core Plot 1.1 to draw a simple scatter plot in iOS6. I am using the following code to properly format my y-axis which then dynamically scales to the plot data.
CPTXYAxis *y = axisSet.yAxis;
y.labelingPolicy = CPTAxisLabelingPolicyAutomatic;
y.minorTicksPerInterval = 3;
y.preferredNumberOfMajorTicks = 6;
y.majorGridLineStyle = majorGridLineStyle;
y.minorGridLineStyle = minorGridLineStyle;
...
NSNumberFormatter * yformatter = [[NSNumberFormatter alloc] init];
[yformatter setUsesSignificantDigits:YES];
[yformatter setMaximumSignificantDigits:4];
[yformatter setMaximumFractionDigits:1];
[yformatter setRoundingMode:NSNumberFormatterRoundCeiling];
y.labelFormatter = yformatter;
Then I dynamically change the range based on the data to be plotted using maxPlotValue but bound it to a minimum.
plotSpace.xRange = [CPTPlotRange
plotRangeWithLocation:CPTDecimalFromFloat(0)
length:CPTDecimalFromFloat(5)];
plotSpace.yRange = [CPTPlotRange
plotRangeWithLocation:CPTDecimalFromFloat(0)
length:CPTDecimalFromFloat(maxPlotValue)];
This works great in most cases but sometimes I get a strange formatting error like in the below fig 1 where 0.6001 is displayed in stead of 0.6. If I manually change the minimum range to 2 the error disappears.
The reason I'm using 4 significant digits is that I can have numbers up to 8000 and then they are displayed without the fraction. If I change the setMaximumSignificantDigits to 3 I get 0.601 which I guess indicates that the problem is with the CPTAxisLabelingPolicyAutomatic.
Any help on this would be greatly appreciated.
Fig 1, Error in formatting:
https://dl.dropbox.com/u/8083213/fig_1.png
Fig 2, No error in formatting:
https://dl.dropbox.com/u/8083213/fig_2.png
This sounds like a rounding error in the labeling calculations. Please report it on the Core Plot issue tracker.

Core Plot axis labels not using my number formatter

I'm using CorePlot and I'm trying to use my number formatter, but the labels on the axes are clearly not using my formatter. This is the code I'm using:
CPTXYGraph *xygraph = [[CPTXYGraph alloc] initWithFrame:fullFrame];
self.graph = xygraph;
self.graph.title = #"Plot of Statistical Data Points";
self.graph.titleDisplacement = CGPointMake(0, -10);
hostingView.hostedGraph = self.graph;
CPTAxisSet *axisSet = xygraph.axisSet;
for (CPTAxis *axis in axisSet.axes) {
NSLog(#"setting axis (%#) label formatter=%# -> %#", axis, axis.labelFormatter, self.formatter.completedValueFormatter);
axis.labelFormatter = self.formatter.completedValueFormatter;
}
I have verified that self.formatter.completedValueFormatter is a good NSNumberFormatter, but the labels on the axes are not using my formatter. What am I doing wrong?
I tested your code in the Plot Gallery example app and changing the label formatter seems to work correctly in the latest code.

Core Plot: should adding a CPTPlotSpaceAnnotation to plot space cause the entire graph to be redrawn?

I am using Core Plot to display a time series of prices. When the user touches the graph, I display a draggable vertical line at that point. Both the time series and the draggable line are CPTScatterPlot objects within a CPTXYGraph. This works pretty well - performance as you drag the line across the time series graph is acceptable.
The next stage is to display the price and date at the point that the user has selected. The Yahoo Stocks App has a nice feature which displays the price in a label that moves as if it is attached to the top of the draggable line. I have tried to replicate this using text displayed in a CPTPlotSpaceAnnotation. This works, but it severely impacts performance. After some digging, I found that CPTLayer drawInContext: is being called multiple times - it looks like the entire graph is being redrawn each time I redraw the text label (in fact my logs imply it's being redrawn twice).
Here is the code which draws the label (work in progress). It is called by plotSpace:shouldHandlePointingDeviceDraggedEvent:atPoint:.
- (void)displayPriceAndDateForIndex:(NSUInteger)index atPoint:(CGPoint)pointInPlotArea
{
NSNumber * theValue = [[self.graphDataSource.timeSeries objectAtIndex:index] observationValue];
// if the annotations already exist, remove them
if ( self.valueTextAnnotation ) {
[self.graph.plotAreaFrame.plotArea removeAnnotation:self.valueTextAnnotation];
self.valueTextAnnotation = nil;
}
// Setup a style for the annotation
CPTMutableTextStyle *annotationTextStyle = [CPTMutableTextStyle textStyle];
annotationTextStyle.color = [CPTColor whiteColor];
annotationTextStyle.fontSize = 14.0f;
annotationTextStyle.fontName = #"Helvetica-Bold";
// Add annotation
// First make a string for the y value
NSNumberFormatter *formatter = [[NSNumberFormatter alloc] init];
[formatter setMaximumFractionDigits:2];
NSString *currentValue = [formatter stringFromNumber:theValue];
NSNumber *x = [NSNumber numberWithDouble:[theDate timeIntervalSince1970]];
NSNumber *y = [NSNumber numberWithFloat:self.graphDataSource.maxValue];
NSArray *anchorPoint = [NSArray arrayWithObjects:x, y, nil];
// Then add the value annotation to the plot area
float valueLayerWidth = 50.0f;
float valueLayerHeight = 20.0f;
CPTTextLayer *valueLayer = [[CPTTextLayer alloc] initWithFrame:CGRectMake(0,0,valueLayerWidth,valueLayerHeight)];
valueLayer.text = currentValue;
valueLayer.textStyle = annotationTextStyle;
valueLayer.backgroundColor = [UIColor blueColor].CGColor;
self.valueTextAnnotation = [[CPTPlotSpaceAnnotation alloc] initWithPlotSpace:self.graph.defaultPlotSpace anchorPlotPoint:anchorPoint];
self.valueTextAnnotation.contentLayer = valueLayer;
// modify the displacement if we are close to either edge
float xDisplacement = 0.0;
...
self.valueTextAnnotation.displacement = CGPointMake(xDisplacement, 8.0f);
[self.graph.plotAreaFrame.plotArea addAnnotation:self.valueTextAnnotation];
// now do the date field
...
}
Is the full redraw expected behaviour? And is there a better way of managing the annotation without destroying it and recreating it each time the method is called?
You shouldn't need to destroy and create the annotation every time. Once it has been created, just update the anchorPoint. Removing and adding the annotation is probably related to the constant redraw.

Sticking Lables in Core-Plot to the Bottom of the GraphView

in the moment im wrestling with core plot, and I´m trying to achieve that the labels of my x-Axis are sticking to the bottom bounds of my graphView. Means:
when I set a range depending on the min/max Values of my PlotData I want to see the Labels everytime on the bottom of the graph.
This is how I set the AutoScaling to make the scaling depending on the min/max values to see only whats needed:
// Auto scale the plot space to fit the plot data
[plotSpace scaleToFitPlots:[NSArray arrayWithObjects:dataSourceLinePlot, nil]];
CPTMutablePlotRange *xRange = [[plotSpace.xRange mutableCopy] autorelease];
CPTMutablePlotRange *yRange = [[plotSpace.yRange mutableCopy] autorelease];
[xRange expandRangeByFactor:CPTDecimalFromDouble(1.0)];
[yRange expandRangeByFactor:CPTDecimalFromDouble(8.15)];
So when I now want to zoom the graph, the labels are staying where they are.
In some cases they´re not visible but they have to be visible all the time. Any tips?
Thanks in Advance
Cheers
// EDIT
I worked with the labelOffset already, but it´s not working when you want to zoom the view or the min/max values are changing.
If you want to have x-axis labels visible all the time even when zooming in, you should set CPTConstraints for the axis. The following code should do the trick:
CPTXYGraph *barchar = <#(create the chart here)#>
CPTXYAxisSet *axisSet = (CPTXYAxisSet *)barChart.axisSet;
CPTXYAxis *xAxis = axisSet.xAxis;
CPTConstraints *axisConstraints = [CPTConstraints constraintWithLowerOffset:0.0f];
xAxis.axisConstraints = axisConstraints;

Force grid lines to update when range changes in Core-Plot scatter plot on iOS

I have a CPTXYGraph with a CPTScatterPlot, which I update with new data using [graph reloadData]. I also set the ranges based on the data. My problem is that though the axes update fine when the range changes, the gridlines do not, so I end up with this http://inky.ws/g/hw (no grid lines at the end of the x-axis).
I set axis.gridLinesRange = nil, and I tried re-setting all the gridline properties when updating ranges, to no avail.
To clarify, the original plot looks fine, but when I update with a bigger data set, the grid lines are missing in the added range.
I've had the same issue and used the following workaround: calculate new bounds of your values and replace the default plot space range with a new one using the plotRangeWithLocation:length: convenience method.
Not very satisfying performance-wise and conceptually (feels a bit like doing the job of the framework) but it worked for me.
CPTXYPlotSpace *plotSpace = (CPTXYPlotSpace *)graph.defaultPlotSpace;
plotSpace.yRange = [CPTPlotRange plotRangeWithLocation:CPTDecimalFromFloat([valuesMin floatValue]) length:CPTDecimalFromFloat([valuesMax floatValue]-[valuesMin floatValue])];
CPTXYAxisSet *axisSet = (CPTXYAxisSet *)graph.axisSet;
CPTXYAxis *y = axisSet.yAxis;
float amplitude = ([valuesMax floatValue]-[valuesMin floatValue]);
NSDecimal intervalLength = CPTDecimalFromFloat(100);
y.majorIntervalLength = intervalLength;

Resources