Easily Creating Charts on iOS using Google Image Charts URL API

Google Image Chart

Google Image Chart

In search of the simplest way to put sophisticated charts/graphs into an iPhone app, I surveyed some possible options.  I wanted a non-interactive, freely available, graph that felt polished and native to iOS. This excluded UIWebView javascript options, commercial libraries, and the advanced open-source options. So I settled on Google Charts Image Charts.  

Google Image Charts are wonderful because you can create a URL containing the chart type, data points, and colours, and receive a complete PNG graph of the size you want.  Fair warning though – Google has deprecated the Image Chart service and will discontinue it in 2015.  In any case, given the life of most applications and my requirements, I was willing to update my app when that happens.

So, with that rambling preamble, how do you implement this in IOS.  Well the easiest way is to get the chart you want by using Google’s chart wizard and then rebuilding that URL in your view controller, requesting the URL and then displaying it as a UIImageView. So, as an example.

 

The Chart:

Say you want this chart (note you can create many different chart types):

 

The URL:

The URL used to retrieve this looks like this:

http://chart.apis.google.com/chart?chs=320x160
&cht=p3
   &chco=3072F3
   &chds=-5,100
   &chd=t:70,10,20
   &chdl=Cylons|Humans|Coders
   &chdlp=b
   &chl=Cylons|Humans|Coders
   &chma=0,10,5,25
   &chtt=Cylons+vs+Humans+vs+Coders

The Code:

Assuming you have created a UIViewController (demo code project attached at the bottom of this post), you can then build the URL using your data (assuming it’s in NSArray).  You will need a UIImageView (to display the chart image) and two UIImage‘s to retain the portrait and landscape chart images downloaded from Google. So  your ViewDidLoad() method and synthesized variables would be:

@synthesize chartImgView;
@synthesize chartImgPortrait, chartImgLandscape;

- (void)viewDidLoad
{
    [super viewDidLoad];

    // add image view to mainview
    chartImgView = [[UIImageView alloc] init];
    [chartImgView setContentMode:UIViewContentModeScaleToFill];

    // load the chart image
    [self updateChartImageView];

    // add to view
    [self.view addSubview: chartImgView];    
    self.view.autoresizesSubviews = YES;
}

The updateChartImageView  (Line M above) method call is of interest here. It sets the UIImageView (chartImgView) frame and downloads the correct chart image for the given device orientation, as follows:

// Makes sure image required for current orientations
// is loaded and adjust imageView frame for same.
- (void)updateChartImageView {

    // get the chart image
    [self getChartImg: UIDeviceOrientationIsPortrait(self.interfaceOrientation)];

    // adjust the imageview frame for the orientation 
    // (this should match the sizes specified in the URL &chs parameter above for the
    // orientation, otherwise the image will have aspect problems).
    UIImage *imageName = nil;
    CGRect imageFrame;
    if (UIDeviceOrientationIsPortrait(self.interfaceOrientation)) {
        imageName = self.chartImgPortrait;
        imageFrame = CGRectMake( 0, 0, 320, 200);
    } else {
        imageName = self.chartImgLandscape;
        imageFrame = CGRectMake( 0, 0, 480, 280);
    }

    // set the image view image to the appropriate size and image for the orientation
    self.chartImgView.image = imageName;
    self.chartImgView.frame = imageFrame;

}

The important call here is the getChartImg() method. This builds the URL from your data, downloads the image (one for portrait and one for landscape modes), stores them in a retained property and then the updateChartImageView() method above can set that downloaded image as the UIImageView‘s image to display.

// Build the URL, load and display chart
- (void) getChartImg: (BOOL) isPortrait {

    // build URL
    NSString *chartURL=@"http://chart.apis.google.com/chart?&cht=p3&chco=3072F3&chds=-5,100&chdlp=b&chma=0,10,5,25";

    // Build array of the pie-chart data points
    NSArray *dataPoint = [[NSArray alloc] initWithObjects:@"70",@"10",@"20", nil];    

    // Build array of the pie-chart data point labels 
    NSArray *dataLabel = [[NSArray alloc] initWithObjects:@"Cylons",@"Humans",@"Coders", nil];    

    // Build array of the pie-chart legend 
    NSArray *dataLegend = [[NSArray alloc] initWithObjects:@"Cylons",@"Humans",@"Coders", nil];    

    // append the data points, labels, and legend to the URL
    chartURL = [chartURL stringByAppendingFormat:@"&chd=t:%@", [dataPoint componentsJoinedByString: @","]];
    chartURL = [chartURL stringByAppendingFormat:@"&chdl=%@", [dataLabel componentsJoinedByString: @"|"]];
    chartURL = [chartURL stringByAppendingFormat:@"&chl=%@", [dataLegend componentsJoinedByString: @"|"]];

    // add the title
    chartURL = [chartURL stringByAppendingString:@"&chtt=Cylons+vs+Humans+vs+Coders"];

    // cleanup
    [dataPoint release];
    [dataLabel release];
    [dataLegend release];

    // Load a different sized chart depending on the device orientation
    if (isPortrait) {

        // check if image already exists
        if (self.chartImgPortrait == nil) {

            // append size of graph
            chartURL = [chartURL stringByAppendingString:@"&chs=320x200"];
            NSLog(@"URL %@", chartURL);

            // download the chart and set it in the imageView
            chartURL=[chartURL stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];    
            NSData *chartImageData = [[NSData alloc] initWithContentsOfURL:[NSURL URLWithString:chartURL]];
            self.chartImgPortrait = [[UIImage alloc] initWithData:chartImageData];
            [chartImageData release];
        }

    }else{

        // check if image already exists
        if (self.chartImgLandscape == nil) {

            // append size of graph
            chartURL = [chartURL stringByAppendingString:@"&chs=480x280"];
            NSLog(@"URL %@", chartURL);

            // download the chart and set it in the imageView
            chartURL=[chartURL stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];    
            NSData *chartImageData = [[NSData alloc] initWithContentsOfURL:[NSURL URLWithString:chartURL]];
            self.chartImgLandscape = [[UIImage alloc] initWithData:chartImageData];
            [chartImageData release];

        }

    }

}

The complete XCode (4.3) project:

The complete source code is here: GoogleImageChart Source Code

Notes: 

  • You will want to check for a network connection and notify the user if one’s not available
  • You will probably want to put in an animated ‘loading’ message while the download is happening
  • Again, Google will end this API sometime in 2015.

 

 

Tags: , ,

2 Responses to “Easily Creating Charts on iOS using Google Image Charts URL API”

  1. Arpit Parekh 30. Dec, 2012 at 11:07 pm #

    Hi,

    Your project has helped me lot.
    Thanks for posting such a neat and clean content.
    Big Thanks……..

  2. Bhupendra Rao 30. Jan, 2013 at 1:46 am #

    Thanks !
    your code has helped me.

Leave a Reply