When working with data intensive applications, a developer must often do more than just show lists of data records in a table view. The CorePlot library will allow you to add stunning data visualizations to your applications. Find out how in this Tuts+ Premium series!
Also available in this series:
- Working With CorePlot: Project Setup
- Working with CorePlot: Plot Fundamentals
- Working with CorePlot: Styling and Adding Plots
- Working with CorePlot: Creating a Bar Chart
- Working with CorePlot: Creating a Pie Chart
Where We Left Off
Last time we made the beginnings of our first line graph and allowed the user to navigate there from the list view. We learned about the CPTGraphHostingView, the CPTGraph, CPTXYPlotSpace, CPTScatterPlot and the CPTScatterPlotDataSource methods that provides data for the graph.
Today we will look at how to make the graph more useful to the user by specifying axis increments and how to format the increment labels. We're going to look at different ways we can customize the look and feel of the graph. Finally, we're going to discuss how to work with different plots on a single graph. Let's get started!
Step 1: Setting Axis Increments
To modify the properties of an X and Y axis we work with the 'CPTXYAxisSet' and 'CPTXAxis' objects. Open the STLineGraphViewController.m file and go to the viewDidLoad method. Just below where we work with the plot Space enter the following code:
[[graph plotAreaFrame] setPaddingLeft:20.0f]; [[graph plotAreaFrame] setPaddingTop:10.0f]; [[graph plotAreaFrame] setPaddingBottom:20.0f]; [[graph plotAreaFrame] setPaddingRight:10.0f]; [[graph plotAreaFrame] setBorderLineStyle:nil]; NSNumberFormatter *axisFormatter = [[NSNumberFormatter alloc] init]; [axisFormatter setMinimumIntegerDigits:1]; [axisFormatter setMaximumFractionDigits:0]; CPTMutableTextStyle *textStyle = [CPTMutableTextStyle textStyle]; [textStyle setFontSize:12.0f]; CPTXYAxisSet *axisSet = (CPTXYAxisSet *)[graph axisSet]; CPTXYAxis *xAxis = [axisSet xAxis]; [xAxis setMajorIntervalLength:CPTDecimalFromInt(1)]; [xAxis setMinorTickLineStyle:nil]; [xAxis setLabelingPolicy:CPTAxisLabelingPolicyFixedInterval]; [xAxis setLabelTextStyle:textStyle]; [xAxis setLabelFormatter:axisFormatter]; CPTXYAxis *yAxis = [axisSet yAxis]; [yAxis setMajorIntervalLength:CPTDecimalFromInt(1)]; [yAxis setMinorTickLineStyle:nil]; [yAxis setLabelingPolicy:CPTAxisLabelingPolicyFixedInterval]; [yAxis setLabelTextStyle:textStyle]; [yAxis setLabelFormatter:axisFormatter];
Let's go over everything above. First, we are working with a property of the graph called the 'plotAreaFrame'. With this we are able to set the padding of the area where the graph is actually drawn and it allows us to see the axis labels (which were previously hidden). We then set the Border line style to nil to get rid of the border around the graph.
We then create an NSNumber formatter which we use to format the axis labels. We also create something called a 'CPTMutableTextStyle'. When formatting lines, fill section and text for CorePlot objects we use objects such as CPTMutableTextStyle to do it. For now we only set the font size but we can set the font type and color as well.
We then get a CPTXYAxisSet object from our graph. This axisSet contains an xAxis and a yAxis (both objects of type 'CPTXYAxis'). We then set a variety of properties on each axis. The major interval length sets what the interval at each main tick will be. We also want to get rid of the minor ticks so we set the line style to nil. We set the labellingPolicy to fixed intervals. We then set the text style for the CPTMutableTextStyle object we created earlier and the label formatter to the NSNumberFormatter we created.
Now try going to the student view and adding a student. Afterward you can go back to the graph and you should see it change. However, it still looks a bit bland...
Step 2: Changing the Look
First off, let's change the actual line. Underneath where we have work with the axis enter the following code:
CPTMutableLineStyle *mainPlotLineStyle = [[studentScatterPlot dataLineStyle] mutableCopy]; [mainPlotLineStyle setLineWidth:2.0f]; [mainPlotLineStyle setLineColor:[CPTColor colorWithCGColor:[[UIColor blueColor] CGColor]]]; [studentScatterPlot setDataLineStyle:mainPlotLineStyle];
This will make the line on our graph blue and increase the width. If you're more creative you can make the color a little less stark but it's important to note that it requires a CPTColor value. While we can't get a CPTColor from a UIColor, we can get it from a CGColor.
We can change the line style of the axis as well. Enter the following code below where we set the plot dataLineStyle.
CPTMutableLineStyle *axisLineStyle = [CPTMutableLineStyle lineStyle]; [axisLineStyle setLineWidth:1]; [axisLineStyle setLineColor:[CPTColor colorWithCGColor:[[UIColor grayColor] CGColor]]]; [xAxis setAxisLineStyle:axisLineStyle]; [xAxis setMajorTickLineStyle:axisLineStyle]; [yAxis setAxisLineStyle:axisLineStyle]; [yAxis setMajorTickLineStyle:axisLineStyle];
This sets the line style and the major tick line style for both axis. You can also set the textStyle color as gray if you like (it's your graph, make it look like you want it to!).
You can also add a gradient fill to the line graph to enhance the look further. To do this we create a CPTFill object which we can then assign to the plot:
CPTColor *areaColor = [CPTColor blueColor]; CPTGradient *areaGradient = [CPTGradient gradientWithBeginningColor:areaColor endingColor:[CPTColor clearColor]]; [areaGradient setAngle:-90.0f]; CPTFill *areaGradientFill = [CPTFill fillWithGradient:areaGradient]; [studentScatterPlot setAreaFill:areaGradientFill]; [studentScatterPlot setAreaBaseValue:CPTDecimalFromInt(0)];
This creates an area fill that we put under the line graph that goes from blue to clear. The angle sets the gradient direction and the area base value sets where the gradient starts from on the plot. As we want to start at the bottom of the graph we set it to 0.
Finally, it's sometimes a good idea to have indications where the values are plotted on the line graph. To do this we need to call a CPTScatterPlot datasource method called 'symbolForScatterPlot:recordIndex':
- (CPTPlotSymbol *)symbolForScatterPlot:(CPTScatterPlot *)aPlot recordIndex:(NSUInteger)index { CPTPlotSymbol *plotSymbol = [CPTPlotSymbol ellipsePlotSymbol]; [plotSymbol setSize:CGSizeMake(10, 10)]; [plotSymbol setFill:[CPTFill fillWithColor:[CPTColor blueColor]]]; [plotSymbol setLineStyle:nil]; [aPlot setPlotSymbol:plotSymbol]; return plotSymbol; }
The above code creates and returns a CPTPlotSymbol object. We can make it look like all sorts of things but our graph will use an ellipse (circle) filled with blue with a size of 10 by 10.
After you've implemented the above code, your graph should look something like this:
Step 3: Managing Multiple Plots
We're showing the student enrollment over time, but what if we wanted to see enrollment for a specific subject on the same graph?
CPTGraph objects can render multiple plots. We create a new plot just like we've done in the past, and add it to the graph. In the datasource methods we then get the graph identifier and, based on that, provide the correct data.
Let's go ahead and create a plot that shows enrollment over time for Computer Science. Underneath the code where we create the 'studentScatterPlot' (in the viewDidLoad method), add the following:
CPTScatterPlot *csScatterPlot = [[CPTScatterPlot alloc] initWithFrame:[graph bounds]]; [csScatterPlot setIdentifier:@"csEnrollement"]; [csScatterPlot setDelegate:self]; [csScatterPlot setDataSource:self]; [[self graph] addPlot:studentScatterPlot]; [[self graph] addPlot:csScatterPlot];
While we are in this method we should also style it a little. Let's make it green. Underneath where we set the dataLineStyle for the studentPlot, add the following code:
[studentScatterPlot setDataLineStyle:mainPlotLineStyle]; [mainPlotLineStyle setLineColor:[CPTColor greenColor]]; [csScatterPlot setDataLineStyle:mainPlotLineStyle];
Underneath where we set the fill for the student scatter plot, add the following code:
areaColor = [CPTColor greenColor]; areaGradient = [CPTGradient gradientWithBeginningColor:areaColor endingColor:[CPTColor clearColor]]; [areaGradient setAngle:-90.0f]; areaGradientFill = [CPTFill fillWithGradient:areaGradient]; [csScatterPlot setAreaFill:areaGradientFill]; [csScatterPlot setAreaBaseValue:CPTDecimalFromInt(0)];
We've done all this before so we wont go into what is happening. Now we're going to modify our 'numberForPlot: field: recordIndex:' method. We don't have to change the numberOfRecordsForPlot: method because either way we will have 7 records. In the numberForPlot:field:recordIndex: method, locate where we set the predicate and modify it to have the following:
NSPredicate *predicate = nil; if ([[plot identifier] isEqual:@"studentEnrollment"]) { predicate = [NSPredicate predicateWithFormat:@"dayEnrolled == %d", index]; } else if ([[plot identifier] isEqual:@"csEnrollement"]) { predicate = [NSPredicate predicateWithFormat:@"dayEnrolled == %d AND subjectID == %d", index, 0]; }
This constructs the predicate based on what graph is being plotted and gets the relevant count. Finally, we need to set the symbols for the subject graph to green:
- (CPTPlotSymbol *)symbolForScatterPlot:(CPTScatterPlot *)aPlot recordIndex:(NSUInteger)index { CPTPlotSymbol *plotSymbol = [CPTPlotSymbol ellipsePlotSymbol]; [plotSymbol setSize:CGSizeMake(10, 10)]; if ([[aPlot identifier] isEqual:@"studentEnrollment"]) { [plotSymbol setFill:[CPTFill fillWithColor:[CPTColor blueColor]]]; } else if ([[aPlot identifier] isEqual:@"csEnrollement"]) { [plotSymbol setFill:[CPTFill fillWithColor:[CPTColor greenColor]]]; } [plotSymbol setLineStyle:nil]; [aPlot setPlotSymbol:plotSymbol]; return plotSymbol; }
Again the above should be self-explanatory. We look at the plot identifier and, based off which plot it is, we make the plot symbol either green or blue.
Now save and run the graph and you should have something like the following:
And there you have it! A fully working graph that shows student enrollment over time as well as enrollment for Computer Science. As you can see, it's quite easy to add a second plot once you have the initial graph set up. Try adding more students to the app and Computer Science and see the graph update.
Next Time
We've covered a bit of ground today. We've established how to style our graphs by changing line colors and widths as well as adding gradient fills. We've also outlined how you can add and manage multiple plots on a single graph object.
Next time we're going to focus on how to create and customize a bar graph that shows the total number of students enrolled in each subject (each subject will have an individual bar). Catch you next time!
Comments