MatPlotLib running in Cocoa under Xcode

I have always been frustrated that python does not have a nice GUI builder similar to what XCode provides.  Since I am a scientist and engineer, I am really fond of the combination matplotlib/scipy/numpy.  Here I will give an example of how to combine the two using the python cocoa bridge that is build into the python that comes with the operating system (in my case Mountain Lion OS X 10.8).  The only thing that you need to install for this example to work is the SciPySuperpack.

Here is the link to my example: github.com/hstrey/ShowMatPlotLib

Here is how it's done. The basic idea is that the python code creates a png file of the graph and that this graph is sent to the Cocoa program via a NSData object. I then convert NSData into a png image and display it. To show how fast this happens, I added a slider to change the frequency of the sine function that is being displayed. Every time you change the setting a new graph is created and displayed. This technique is not suitable for graphs that need to change dynamically at a high frame rate but for most applications it should work.

First the Cocoa part:
untitled
//
//  SMPLAppDelegate.m
//  ShowMatPlotLib
//
//  Created by Helmut Strey on 4/23/12.
//  Copyright (c) 2012 Stony Brook University. All rights reserved.
//
 
#import "SMPLAppDelegate.h"
#include "Python/Python.h"
 
// Global pointer to app delegate
SMPLAppDelegate* myprogram;
 
// sendGraph function for sending graph through NSData
PyObject* sendGraph(PyObject* self, PyObject* pArgs)
{
    char* GraphStr = NULL;
    int length;
    if (!PyArg_ParseTuple(pArgs, "s#", &GraphStr,&length)) return NULL;
     
    NSLog(@"%i",length);
    [myprogram pythonOut: [NSData dataWithBytes: GraphStr length:length]];
     
    Py_INCREF(Py_None);
    return Py_None;
}
 
static PyMethodDef sendGraphMethods[] = {
    {"SendGraph", sendGraph, METH_VARARGS, "submit string"},
    {NULL, NULL, 0, NULL}
};
 
 
@implementation SMPLAppDelegate
 
@synthesize window = _window;
@synthesize matplotlibView = _matplotlibView;
@synthesize freq=_freq;
 
- (void)setFreq:(double)freq
{
    _freq=freq;
    NSString *mystring = [[NSString alloc] initWithFormat:@"drawplot(%f)\n" , freq];
    PyRun_SimpleString([mystring UTF8String]);
}
 
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
    myprogram=self;
    Py_Initialize();
     
    Py_InitModule("MPL", sendGraphMethods);
    NSString *scriptPath = [[NSBundle mainBundle] pathForResource:@"init" ofType:@"py"];
     
    // load the main script into the python runtime
    FILE *mainFile = fopen([scriptPath UTF8String], "r");
    PyRun_SimpleFile(mainFile, (char *)[[scriptPath lastPathComponent] UTF8String]);
     
    self.freq=50;
     
}
 
- (void)pythonOut: (NSData*)pngimage
{
    NSImage *matplotlibGraph = [[NSImage alloc] initWithData:pngimage];
    [self.matplotlibView setImage:matplotlibGraph];
    [self.matplotlibView setNeedsDisplay:YES];
}
 
@end

And here is the python part (MPL is a module that I inserted from the Cocoa side):

untitled
import MPL
import numpy as np
import StringIO
from pylab import *
 
time=linspace(0,6.3,500)
 
def drawplot(freq):
    f=StringIO.StringIO()
    figure(num=None, figsize=(9,7),dpi=60)
    a=np.sin(freq*time)
    plot(time,a)
    savefig(f,format='png')
    out=f.getvalue()
    f.close()
    MPL.SendGraph(out)