Creating a Graph With Quartz 2D: Part 5

This entry is part 5 of 5 in the series Graphing with Quartz 2D

Graphing with Quartz 2D

In this series of articles I am discussing the creation of charts and graphs using nothing more than Quartz 2D, a graphics rendering API created by Apple, which is a part of Core Graphics. You might wish to get up to speed with Part 1, Part 2, Part 3 and Part 4.

Drawing Text

Finally, we are going to write some text on the graph. You might be wondering why I delayed such a simple task for so long. Indeed, it doesn’t take a lot of effort to draw a string in Quartz 2D. Let’s try it: in GraphView, in the end of drawRect add the following snippet (it doesn’t matter which kind of graph you’ll be displaying at this stage):

// Drawing text
CGContextSelectFont(context, "Helvetica", 44, kCGEncodingMacRoman);
CGContextSetTextDrawingMode(context, kCGTextFill);
CGContextSetFillColorWithColor(context, [[UIColor colorWithRed:0 green:0 blue:0 alpha:1.0] CGColor]);
NSString *theText = @"Hi there!";
CGContextShowTextAtPoint(context, 100, 100, [theText cStringUsingEncoding:NSUTF8StringEncoding], [theText length]);

Nothing complex here: we are selecting a font, a color, a drawing mode and then drawing a random string somewhere inside the graph. How do you think the result will look? Let’s see:

Quartz 2D Part V Figure 1

Figure 1

Oops! Not exactly what we wanted: the text is drawn upside down. That’s because in the system of coordinates used in iOS the vertical coordinate goes from top to bottom. Basically, everything is drawn upside down. You might have noticed this already if you were trying to use a more or less complex graphical background.

We can keep this peculiarity in mind when drawing the graph, and adjust the logic accordingly. We could use a different background after all, but when it comes to drawing text, we have to face the problem.

Fortunately, the solution isn’t difficult. All we need to do is transform the system of coordinates in such a way that the vertical axis starts at the bottom of the graph and goes upwards – and there are a few functions that allow us to do exactly that. In fact, we can resolve our problem with a single line of code. Insert it before any text drawing is done:

CGContextSetTextMatrix (context, CGAffineTransformMake(1.0, 0.0, 0.0, -1.0, 0.0, 0.0));

Run the app, and the text should look all right this time:

Quartz 2D Part V Figure 2

Figure 2

Let’s try and understand the incantation that saved the day. The whole magic is in the six parameters, and I will only mention here those that are non-zero. You can read the detailed explanation of the logic in the documentation for CGAffineTransform.

So we are changing the system of coordinates in use, right? The six parameters describe the relationships between the old system and the new system. The very first parameter describes the relationship between the x coordinate of the new system and the x coordinate of the old system. We don’t want any changes here, so the value of the parameter is 1. The fourth parameter describes the relationship between the y coordinate of the new system and the y coordinate of the old system. We only need to reverse the direction, hence the value is –1.

As you can see, everything is very simple in this particular case. However, you are free to define a more complex transformation, to squeeze and shift the coordinates as you wish. For now, let’s better consider another useful transform. Here is the code:

CGContextSetTextMatrix(context, CGAffineTransformRotate(CGAffineTransformMake(1.0, 0.0, 0.0, -1.0, 0.0, 0.0), M_PI / 2));

Can you guess what it does? Replace the previous magical incantation with this one, et voila:

Quartz 2D Part V Figure 3

Figure 3

Well, I had to change the third parameter of CGContextShowTextAtPoint to 200, to make sure that the text remains within the graph boundaries. See, we can draw text vertically – can be quite useful for drawing labels.

To wrap it up, let’s do something for real, let’s number the data points of the line graph. Here is the code, it shouldn’t surprise you:

CGContextSetTextMatrix(context, CGAffineTransformMake(1.0, 0.0, 0.0, -1.0, 0.0, 0.0));
CGContextSelectFont(context, "Helvetica", 18, kCGEncodingMacRoman);
CGContextSetTextDrawingMode(context, kCGTextFill);
CGContextSetFillColorWithColor(context, [[UIColor colorWithRed:0 green:0 blue:0 alpha:1.0] CGColor]);
for (int i = 1; i < sizeof(data); i++) 
{
    NSString *theText = [NSString stringWithFormat:@"%d", i];
    CGContextShowTextAtPoint(context, kOffsetX + i * kStepX, kGraphBottom - 5, [theText cStringUsingEncoding:NSUTF8StringEncoding], [theText length]);
}

And this is the result:

Quartz 2D Part V Figure 4

Figure 4

It looks okay, but it would be much better if the labels were centered under the data points, how do you think? To achieve that, we need to know the width of the label being drawn, and then make a correction to its x coordinate for a half of the label’s width.

Here is the line of code that will give us the size of the label. Obviously, we need to specify the same font that’s being used for drawing text:

CGSize labelSize = [theText sizeWithFont:[UIFont fontWithName:@"Helvetica" size:18]];

Finally, this is the amended line for actually drawing the label:

CGContextShowTextAtPoint(context, kOffsetX + i * kStepX - labelSize.width/2, kGraphBottom - 5, [theText cStringUsingEncoding:NSUTF8StringEncoding], [theText length]);

Run the app again, and now the labels will be nicely aligned under the data points:

Quartz 2D Part V Figure 5

Figure 5

As we said at the beginning of this series, working with Quartz 2D isn’t that hard, you just need to know how to do certain things and once you’ve learnt them, you can move forward quickly. Now you can do everything that is needed to draw a bespoke graph of any complexity using Quartz 2D. The sky is the limit!

Quartz 2D Index

Alexander Kolesnikov’s series on Creating a Graph using Quartz 2D was split into 5 parts. You can refer to the series using the Quartz 2D Tag and access the individual articles using the links below.

Graphing with Quartz 2D

<< Creating a Graph With Quartz 2D: Part 4

Free book: Jump Start HTML5 Basics

Grab a free copy of one our latest ebooks! Packed with hints and tips on HTML5's most powerful new features.

  • http://www.intelgain.com Software Outsourcing Company

    HI, Its Great..find the content useful and it’s well written…keep up the good work..

  • Sam

    Its really awesome!!!
    Can u post/send the source code also?

  • nados

    Excellent tutorial

  • Helmut

    Great Tutorial!

    Thank You

  • steve

    I have just worked through these tutorials and have found them extremely
    helpful.
    The information in them is hard to come by elsewhere and in addition they are extremely well written.
    Well done!

  • Dario

    Excellent Tutorial.

    MANY THANKS !!!

  • Maria

    Excellent Tutorial

    Can you please put the tutorials to draw a bubble graph ?

  • kunal

    Thank You

  • Siva

    This tutorial is really nice. I learnt a lot. Could you please write tutorial on how to make pie chart as well. Then we really don’t need to go to any other third party framework. Eagerly waiting for Pie Chart graph using Quartz 2D.

  • Arun

    Hello Sir,
    i hav gone through all the tutorials all of them are superb and simple but i want implement Pie chart , any help of tutorials from your side is appreciable
    Thanks

  • http://readwithmeapp.com Francisco Nieto Salazar

    Great! I was not digging Core Plot. This tutorial was just what I was looking for. Many thanks.

  • Wang Yandong

    Best Quartz 2D tutorial ever. Thanks.