Numbers: some first impressions

Just to give it a spin, I started using Numbers today to record some information on transcription factor binding motifs.

Overall, I have to say the experience is very pleasant. First of all, the good points:

  • The ability to just drag PDFs, images, graphs and indeed spreadsheets freely around the canvas is excellent.
  • Adding steppers, sliders, checkboxes and menus to cells is made remarkably easy.
  • The live display of average, sum, maximum, minimum and the count of selected cells is very convenient.
  • The “Sheets” list (like a source list for spreadsheets) is far superior to Excels tabs along the bottom, even showing a collapsable list of the tables and graphs on each sheet:
    Sheets in Numbers
    While this is nice, the highlighting in the sheets list is very odd. In the screenshot, the darkened “Occurrences of mo…” graph is currently selected, but the Table is shown with my default selection colour as its background. I imagine Pierre would have something to say about that.
  • The new format bar makes trips to the Inspector far less frequent. Which is nice.

However, I also have a few reservations already, including the following:

  • Conditional formatting cannot take a “cutoff” value from another cell. For example, in the screenshot below, G2 is invalid. Only a numeric value can be entered when a comparison operator is selected from the menu.
    Conditional formatting limitations in Numbers
    If G2 had been a cell with a slider, one could envisage formatting changing on-the-fly while dragging the slider, which would have been awesome. Sadly it wasn’t to be.
  • No “freeze panes” option. Anyone who has used Excel knows (or can appreciate) how useful it can be to have your own column or row headers visible at all times when scrolling around. While Numbers ably keeps the row and column headings on screen when scrolling, no option equivalent to Excel’s Freeze panes seems to be available. This makes it a real pain to keep track of which column or row is which in a large spreadsheet.
  • Fairly limited graphing. Coming from a scientific background, I’d really like to see the graphs supporting error bars and some linear and polynomial regression (ordinary least squares at the very minimum).
    Numbers charts
    When compared with Excel, Numbers’s graphing options look decidedly sparse.

So overall, I’d say it’s a really nice 1.0 release and I think it hits the target market (“Spreadsheets the Mac way”) extremely well. While the addition of linear and polynomial regression is probably a slight frivolity for the users Apple has in mind (just use R!), I’d say that “freeze panes” is really essential for any spreadsheet package and cell references in conditional formatting would just be a great option to have.

I might post more if I come across any more nifty features or major shortcomings…

Cocoa and MySQL

While Core Data is able to use a SQLite database as its backing store, Cocoa sadly has no native support for full client-server style SQL. Third-party solutions are therefore the answer.

Looking around the web yesterday, I found a number of such solutions including a rather extensive document on OS X ODBC drivers, a rather slick-looking, but wallet-hurting ($700) SQL framework for Cocoa, called MacSQL (it even comes with an Interface Builder palette!) and the open source MySQL-Cocoa project.

ODBC is clearly the compatible, righteous and most open way to access a database, but is also probably the most “heavyweight” solution, which I didn’t really fancy tackling for my humble application. MacSQL looks very nice. The demo movies on their website are a little dated, but show that it really is a very polished solution that allows for a no-code approach to browsing a SQL database. However, it’s also $700 (they do offer a $149 version for hobbyists, but the resulting program can’t be distributed). So, the final option was MySQL-Cocoa.

First impressions of the MySQL-Cocoa project might suggest that it’s dead: the examples disk image link on the homepage is broken, the framework doesn’t compile out of the box on 10.4.10 and the latest news item was posted 18 months ago. However, a little searching reveals that a universal binary version of the framework is linked to from this page, hosted by the different, but similarly-named CocoaMySQL project. Excellent.

To use the framework, first download the bundled version and follow Dave Winter’s excellent guide on adding it to your XCode project.

Once that’s done, I found that the easiest way to actually use the framework was to also download the source for Lorenz Textor’s aforementioned CocoaMySQL program and copy these files into your own project:
Useful files from Cocoa MySQL

If the copying’s all gone well, you’re ready to go, so here’s some sample code to get you started. First of all, don’t forget to import the framework and the header files of Lorenz’s files:
#import <MCPKit_bundled/MCPKit_bundled.h>
#import "CMMCPConnection.h"
#import "CMMCPResult.h"

Once that’s done, you’ll probably want to set up a connection and a query result object, as follows:
CMMCPConnection *mySQLConnection;
CMMCPResult *queryResult;

Finally, you can now establish your connection to the database and start querying it, as demonstrated in the following (and, I think, fairly self-explanatory) code:
mySQLConnection = [[CMMCPConnection alloc] initToHost:@"127.0.0.1"
   withLogin:@"username"
   password:@"password"
   usingPort:3306];
if ([mySQLConnection isConnected])
{
   NSLog(@"Connected.");
   [mySQLConnection setDelegate:self];
   [mySQLConnection selectDB:@"databasename"];
   queryResult = [mySQLConnection queryString:[NSString stringWithFormat:@"SELECT salary FROM table WHERE department = \"%@\" AND age BETWEEN %d AND %d ORDER BY age",departmentName,lowerAge,upperAge]];
   if (queryResult) {
      for (i = 0; i < [queryResult numOfRows]; i++) {          [queryResult dataSeek:i];          NSLog(@"%@",[[queryResult fetchRowAsArray] objectAtIndex:0]);       }    }    [mySQLConnection disconnect]; } else {    NSLog(@"Connection failed."); }

As with my last post, there's no real error checking here, but hopefully the sample code will at least help to get you up and running fairly quickly.

Quick and dirty NSURL request

I started looking at Apple’s NSURL* family of classes today, as I’m about to start interfacing my GFF viewer application with an online BLAT search tool (for in-house purposes only — this isn’t going to be available in the release version) and I was a little shocked to find this line in Apple’s documentation:

In order to download the contents of a URL, an application needs to provide a delegate object that, at a minimum, implements the following delegate methods: connection:didReceiveResponse:, connection:didReceiveData:, connection:didFailWithError: and connectionDidFinishLoading:

In other words, one would have to first establish an NSURLConnection (having already formed an NSURLRequest) and then implement four NSURLConnection delegate methods just to download a single HTML file. This all seems a little excessive for me just downloading a single HTML file.

After a little bit of playing around, I’ve found that the following code works just great for downloading a single HTML file:
NSURL *fileURL;
NSMutableString *fileContents;
fileURL = [NSURL URLWithString:@"http://127.0.0.1/index.html"];
fileContents = [[NSMutableString alloc] initWithContentsOfURL:fileURL];

A quick NSLog(@”%@”,fileContents); reveals that fileContents does indeed contain index.html from localhost. Good stuff.

As a piece of code, this is rather unwholesome on all fronts. There is no error handling anywhere to be seen. Not in the formation of the URL, not in the retrieval of the URL. Zilch. Errors are not handled. Anything could happen. It’s a mini adventure.

Bonus information!
Just out of interest, I checked my Apache access-log after this request to find that NSMutableString’s initWithContentsOfURL: method provides the user agent string: “CFNetwork/129.20” (as of 10.4.10).