Saturday, 31 August 2013

How To Plot Data From C Using Matplotlib

Following on from my earlier blog entitled "How To Pass A C Array To Python Solution" (http://realgonegeek.blogspot.co.uk/2013/08/how-to-pass-c-array-to-python-solution.html) here is some simple code to plot the same data using Matplotlib.

Note : While this solution worked, I found that it was very slow because of the time required to load Python so I ended up reverting back to GNUPlot, see here for further details : http://realgonegeek.blogspot.co.uk/2014/01/interfacing-cc-to-gnuplot.html.

All you need to do is take the earlier C example, change the Python method from PrintArray to PlotArray and recompile.

def PlotArray (a):
    import matplotlib.pyplot as pp
    from matplotlib.font_manager import FontProperties
    import numpy as np
    
    p1, = pp.plot (a, label = "line 1", color='red')

    ax = pp.subplot (111)
    box = ax.get_position ()
    ax.set_position ([box.x0, box.y0, box.width * 0.85, box.height]) # Shink x axis to fit legend
    fontP = FontProperties ()
    fontP.set_size ('small')

    pp.legend (loc=2, prop = fontP, fancybox = True, bbox_to_anchor=(1, 1.0))
    pp.title ("Title")
    pp.xlabel ("X-Axis")
    pp.ylabel ("Y-Axis")
    pp.ylim (ymin = 0, ymax = 10)
    pp.grid (True)

    pp.show (block=True)

    c = 0
    return c

Finally, if you have found this solution useful then please do hit the Google (+1) button so that others may be able to find it as well.

How To Pass A C Array To Python Solution

While I commonly use C or C++ for processing signals there are not too many options available for displaying the results graphically so I have been looking at using Matplotlib for the display. The first problem I encountered is how to pass an array of floating point data from C to Python.
There are several options and a lot of forum discussions on the subject but I couldn't find a simple solution. So here is one that I developed earlier.
This example works with an Anaconda/Python v3.3 installation with the 64 bit Microsoft compiler.

See here for an introduction to  Anaconda/Python v3.3 installation and calling Python from the 64 bit Microsoft compiler : http://realgonegeek.blogspot.co.uk/2013/08/how-to-embed-python-pylab-into-64bit.html.

Here is the C code :

#include <Python.h>
#include <stdio.h>
#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION
#include "C:\Anaconda\envs\py33\Lib\site-packages\numpy\core\include\numpy\arrayobject.h"

double Array [] = {1.2, 3.4, 5.6, 7.8};

int main (int argc, char *argv[])
{
    PyObject *pName, *pModule, *pDict, *pFunc, *pArgs, *pValue;
    npy_intp dims[1] = { 4 };
    PyObject *py_array;

    Py_Initialize ();
    pName = PyUnicode_FromString ("PrintArray");
    // PyUnicode_FromString error checking here

    pModule = PyImport_Import (pName);                  // Load the module object
    // PyImport_Import error checking here
    Py_DECREF(pName);

    pFunc = PyObject_GetAttrString (pModule, "PrintArray");        // pFunc is a new reference
    // PyObject_GetAttrString error checking here

    import_array ();                                    // Required for the C-API : http://docs.scipy.org/doc/numpy/reference/c-api.array.html#importing-the-api

    py_array = PyArray_SimpleNewFromData (1, dims, NPY_DOUBLE, Array);
    // PyArray_SimpleNewFromData error checking here

    pDict = PyModule_GetDict (pModule);                 // pDict is a borrowed reference

    pArgs = PyTuple_New (1);
    PyTuple_SetItem (pArgs, 0, py_array);

    pFunc = PyDict_GetItemString (pDict, "PrintArray"); // pFunc is also a borrowed reference

    if (PyCallable_Check (pFunc)) 
    {
        PyObject_CallObject (pFunc, pArgs);
    } else 
    {
        printf ("Function not callable !\n");
    }

    Py_DECREF (py_array);                               // Clean up
    Py_DECREF (pModule);
    Py_DECREF (pDict);
    Py_DECREF (pFunc);

    Py_Finalize ();                                     // Finish the Python Interpreter

    return 0;
}

Here is the python script to print the contents of the array :

def PrintArray (a):
    print ("Contents of a :")
    print (a)
    c = 0
    return c

How To Embed Python PyLab Into A 64bit Windows C Application

Here is a quick solution for embedding PyLab into a 64bit Windows C app. It was a bit fiddly to get setup so after a few trips down blind alleys, here is what I did.

The easiest way to get a Python installation that includes PyLab, Matplotlib, Numpy, Scipy etc is to download Anaconda from : http://www.continuum.io/downloads. In my case I wanted to use the Python v3.3 version under 64 bit Windows. The default Anaconda installation is for v2.x but it is very easy to update to Python v3.3 using conda. form C:\Anaconda type the following command :
conda create -n py33 python=3.3 anaconda

In order to use the v3.3 installation, prepend the following to the PATH environment variable :
C:\Anaconda\envs\py33;C:\Anaconda\envs\py33\Scripts;

Although Anaconda works very well from Python scripts I found that I need to set the following PYTHONPATH environment variable :
set PYTHONPATH=C:\Anaconda\envs\py33;C:\Anaconda\envs\py33\Lib;C:\Anaconda\envs\py33\DLLs

To configure the Visual C compiler for 64 bit mode :
call "C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\vcvarsall.bat" amd64
For further details on installing the 64 bit Microsoft compiler, please see here :
http://realgonegeek.blogspot.co.uk/2013/08/microsoft-visual-c-2010-sdk-v71-64-bit.html

To compile the app use the following command line :
cl example.c -IC:\Anaconda\envs\py33\include C:\Anaconda\envs\py33\libs\python33.lib /link /MACHINE:X64

If you want to try it, here is a quick test program :

#include "Python.h"
int main()
{
Py_Initialize ();
PyRun_SimpleString ("import sys");
PyRun_SimpleString ("import pylab");
PyRun_SimpleString ("print(sys.version)");
PyRun_SimpleString ("print()");
PyRun_SimpleString ("pylab.plot(range(10))");
PyRun_SimpleString ("pylab.show()");
Py_Exit(0);
return 0;
}

Tuesday, 27 August 2013

Microsoft Visual C++ 2010 / SDK v7.1 64 bit compiler installation failure - solution

I recently had to install the Microsoft Visual Studio 64 bit compiler on top of my existing Visual C++ 2010 installation, with the service pack SP1.
The 64 bit compiler is included in the Windows SDK 7.1.
If you try to install Windows SDK 7.1 on top of Visual C++ 2010 SP1 the installation process will fail.
Unfortunately the failure dialog that pops up after the installation failure gives no clue as to where the problem lies. You can open the failure log from the dialog but again the error messages do not provide a direct source of the problem.
Performing an internet search for solutions show up a lot of people having the same problem and a lot of other people not quite knowing the solution. One example of erroneous suggestion I came across was to install from the ISO rather than the web install.

Fortunately, those clever people at Mathworks have published a great set of instructions here to explain how to correctly install the 64 bit compiler :
http://www.mathworks.co.uk/support/solutions/en/data/1-ECUGQX/

A quick summary of the procedure is :
Uninstall the Visual C++ 2010 Redistributable packages
Install the SDK 7.1
Apply the compiler patch from Microsoft
Reinstall the Visual C++ 2010 Redistributable packages