Plotting Fun with ILNumerics and IronPython

Since the early days of IronPython, I keep shifting one bullet point down on my ToDo list:

* Evaluate options to use ILNumerics from IronPython

Several years ago there has been some attempts from ILNumerics users who successfully utilized ILNumerics from within IronPython. But despite our fascination for these attempts, we were not able to catch up and deeply evaluate all options for joining both projects. Years went by and Microsoft has dropped support for IronPython in the meantime. Nevertheless, a considerably large community seems to be active on IronPython. Finally, today is the day I am going to give this a first quick shot.

Disclaimer: I am not a python developer. My experience with IronPython range from 0 … zero (unfortunatley, since the project deserves much more attention). For CPython it is only slighly better. So please bare with me if I went into some stupid direction or if I have completely missed better options in this article! Corrections and suggestions are always warmly welcome.

Setup

I downloaded and installed IronPython from CodePlex. Also, in Visual Studio 2013 there exists a link in the NEW PROJECT dialog advertising the download of IronPython Tools for Visual Studio. I used that to setup Visual Studio for IronPython projects. All setup went smooth and easy. Nice!

Creating Plots with IronPython

The challenge I was interested in the most was how it is possible to utilize the great plotting capabilities of ILNumerics Visualization Engine from IronPython projects. Since matplotlib seems not to be available for IronPython and other alternatives are also pretty rare (if any at all?) having our visualization engine available to IronPython projects seem to be a big improvement.

The good news first: it works and it does so very easily. The following plot is done purely in IronPython:

I started with a fresh new Iron Python Windows Forms Application from the ‘New Project’ dialog in Visual Studio 2013.

This gives a template python file ‘IronPython_ILPanel.py’ with the following content:

import clr
clr.AddReference('System.Drawing')
clr.AddReference('System.Windows.Forms')

from System.Drawing import *
from System.Windows.Forms import *

class MyForm(Form):
    def __init__(self):
        # Create child controls and initialize form
        pass

Application.EnableVisualStyles()
Application.SetCompatibleTextRenderingDefault(False)

form = MyForm()
Application.Run(form)

If you are familiar with the common setup of Windows Forms you may notice some similarities with the stub provided by a new C# Windows Forms Application project. What is otherwise spread over multiple files, now is done all within the global scope of the one and only *.py file: the form class is defined, the static Application class is configured and the event loop is started with an instance of the formerly defined MyForm class. Straight. This corresponds to the common setup for Windows.Forms from any language, where no Designer support exists for. The same could be done in PowerShell, to name just another example.

In order to integrate support for ILNumerics Visualization Engine, I did the following simple steps:

1) If not done so far, go and install ILNumerics Ultimate VS. We offer 30 days trials which contain all features without limitation.
2) Once installed, ILNumerics is available in the “Add Reference” dialog (right click on References in the Solution Explorer). ILNumerics.dll is added from the .NET tab:

3) Make the ILNumerics namespaces available: I added the following lines to the import section at the very top of IronPython_ILPanel.py:

import clr
clr.AddReference('System.Drawing')
clr.AddReference('System.Windows.Forms')
clr.AddReference('ILNumerics')

from System.Drawing import *
from System.Windows.Forms import *
from ILNumerics import *
from ILNumerics.Drawing import *
from ILNumerics.Drawing.Plotting import *

4) Now we are ready to add a plot to the form. In C# we would simply use the ilPanel1_Load event handler which is easily added by help of the forms designer. Since we do not have designer support here, we simply add the setup to the constructor of MyForm:

class MyForm(Form):
   def __init__(self):
     # Create child controls and initialize form
     ilpanel = ILPanel()
     ilpanel.Dock = DockStyle.Fill
     self.Controls.Add(ilpanel)
     # show some demo: first create a plotcube
     pc = ILPlotCube("pc", 0)
     # it will hold a surface with some sinc data in 3D
     # You can use ILRetArray returned from any ILNumerics Computing
     # Module as input argument here directly. Type conversions seem to happen automatically.
     sf = ILSurface(ILSpecialData.sincf(40,50))
     pc.Add(sf)
     # add the plotcube to the scene
     ilpanel.Scene.Add(pc)
     self.Text = "Plotting Fun with ILNumerics in IronPython"

This is all straightforward. The configuration of the panel and the plots is exactly as it would have been done in C# or Visual Basic. However, we have to add the ILPanel to the self.Controls collection manually. The result, of course is exactly the same: a nice interactive form, utilizing OpenGL, with all manipulation options like rotation, pan and zoom. The full spectrum of the Visualization Engine should work out of the box. This includes several, flexible 3D and 2D plotting types as well as the whole scene graph functionality for building your own interactive visualizations.

This is all what needs to be done in order to create nice professional plots directly within IronPython. Press F5 and start your application, rotate the plot with the mouse and learn about all the options you have.

Computing Fun with IronPython and ILNumerics

ILNumerics not only rely on its own flexible n-dimensional array implementation, it also introduces its very own memory management – for very good reasons. In order for the memory managements to work, individual array types (ILArray, ILInArray, ILOutArray and ILRetArray) are used in ILNumerics algorithms. This makes great use of the strict type safety of .NET languages as C# and Visual Basic and of automatic conversions between those types.

Python on the other side is a dynamic language. It does not know the concept of types to the same extend. A straightforward application of the ILNumerics array types is not possible. IronPython, however offers workarounds (clr.Convert) but they are not able to provide the same syntactical convenience as a pure C# algorithm.

My recommendation for the utilization of ILNumerics Computing Engine therefore is as follows:

ILNumerics Computing Engine can be used without restriction. The utilization of existing algorithms is straightforward. Algorithms leveraging the ILNumerics Function Rules can be called directly without any type conversions. The creation of local variables on the other side requires type conversions from ILRetArray to ILArray. This can be done by help of IronPythons clr.Convert function.

The type conversion issue possibly makes it less feasible to write own ILNumerics Computing Engine algorithms in IronPython. But most the time, one would rather want to use existing python algorithms anyway. In order to actually create a new algorithm, one should rather utilize C# and compile the algorithm into its own .NET module which can than easily be imported into your python project and get interfaced from your python code.

Summary

This blog demonstrated how easy it is to utilize ILNumerics from IronPython. Especially the Visualization Engine is incorporated without any problems and offers the full set of visualization and plotting options out of the box. Algorithms created with ILNumerics Computation Engine can directly be interfaced and used – in parallel with numpy algorithms, if the need arise. The syntax of the Computing Engine however is not as expressive and more clumsy due to the absense of implicit type conversions and operator overloads. Complex algorithms one therefore would rather implement in C# or VisualBasic than in IronPython. For small algorithms, like data preprocessing and the like, ILNumerics Computing Engine serves as a faster alternative to numpy arrays.

  • david tasker

    The issue was due to my opengl driver being too old. Installing the latest drivers for the graphics card resolved the issue.

    OpenGL Version String: 2.1.2

    Vendor: NVIDIA Corporation, GLSL Version: 1.20 NVIDIA via Cg compiler, Renderer: Quadro FX 580/PCI/SSE2

    Extracted version number: 2.1

    Exception in ILOGLControl(): System.NotSupportedException: The OpenGL driver version available is not sufficient. Needed: 3.1. Available: 2.1

    at ILNumerics.Drawing.ILOGLControl..ctor()

    OpenGL Version String: 3.1.0

    Vendor: NVIDIA Corporation, GLSL Version: 1.40 NVIDIA via Cg compiler, Renderer: Quadro FX 580/PCI/SSE2

    Extracted version number: 3.1

  • david tasker

    I create the project as described in your blog. I get a runtime exception as described in the image below. SystemArgument “Parameter is not valid” in the Application.Run(form) method.

    Here is my code..

    import clr

    clr.AddReference(‘System.Drawing’)

    clr.AddReference(‘System.Windows.Forms’)

    clr.AddReference(‘ILNumerics’)

    from System.Drawing import *

    from System.Windows.Forms import *

    from ILNumerics import *

    from ILNumerics.Drawing import *

    from ILNumerics.Drawing.Plotting import *

    class MyForm(Form):

    def __init__(self):

    # Create child controls and initialize form

    # Create child controls and initialize form

    ilpanel = ILPanel()

    ilpanel.Dock = DockStyle.Fill

    self.Controls.Add(ilpanel)

    # show some demo: first create a plotcube

    pc = ILPlotCube(“pc”, 0)

    # it will hold a surface with some sinc data in 3D

    # You can use ILRetArray returned from any ILNumerics Computing

    # Module as input argument here directly. Type conversions seem to happen automatically.

    sf = ILSurface(ILSpecialData.sincf(40,50))

    pc.Add(sf)

    # add the plotcube to the scene

    ilpanel.Scene.Add(pc)

    self.Text = “Plotting Fun with ILNumerics in IronPython”

    pass

    Application.EnableVisualStyles()

    Application.SetCompatibleTextRenderingDefault(False)

    form = MyForm()

    Application.Run(form)