I found it pretty easy to call a Python function from Analytica using COM automation. The COM integration functionality comes included with the Analytica Enterprise edition. In this blog posting, I’ll show you the basics for how to do it.

Today’s example calls a Python function that runs a complex algorithm involving NumPy arrays. Next week, I’ll follow this with an example that uses Python to read Shape files into Analytica, thus opening the door for using Python to read all sorts of esoteric data formats. If you are interested in this stuff, be sure to follow Lumina on LinkedIn, Twitter or Facebook, so you’ll see announcements when we do future articles on these and related topics.

To use COM as in this example, you need to have the Analytica Enterprise or Optimizer edition. You can also call Python in this fashion from ADE. (My previous blog posting, Using the Analytica Decision Engine (ADE) from Python, demonstrates the opposite calling direction).

Today I call a Python function, `scipy.spatial.Delaunay( )`

, to compute a Delaunay triangulation of a set of 2-D points. If you don’t already know what that is, for the purposes of this posting you don’t need to. All you need to know is that you pass it a 2-D NumPy array (n x 2, where n=number of data points), and it returns a 2-D array (m x 3, where m=number of triangles). Here is an example of a triangulation that is computed, graphed in Analytica:

On the Analytica side, it looks like this:

Variable py := `COMCreateObject("Lumina.DelaunayCOM")`

Variable TessellationVertices := `py->Tessellation( COMArray( Pts, Pt, Dim ) )`

where P`ts `

is my 2-D array of points, which is indexed by `Pt `

and `Dim`

. I did some further processing of the result, `TessellationVertices`

, in Analytica, which I won’t go into here, but which I describe in the longer version of this article.

The Python-side code is shown here

import numpy as np from scipy.spatial import Delaunay import Analytica_Python import AnalyticaPythonConnector class DelaunayCOM: _reg_clsid_ = "{B524651C-71B2-4521-9E9D-8CC470E51B24}" # Don't re-use this CLSID!!! _reg_desc_ = "COM component that computes a Delaunay tesselation" _reg_progid_ = "Lumina.DelaunayCOM" _reg_class_spec_ = "DelaunayCOM.DelaunayCOM" _public_methods_ = ['Tessellation'] _public_attrs_ = ['softspace', 'noCalls'] _readonly_attrs_ = ['noCalls'] def __init__(self): self.softspace = 1 self.noCalls = 0 def Tessellation(self,pts): tri = Delaunay(np.array(pts)) return tri.simplices.tolist() Analytica_Python.AddCOMClass(DelaunayCOM) if __name__ == "__main__": Analytica_Python.TopLevelServer(__file__)

Highlighted in yellow are the parts you need to customize if you copy this code when you implement your own integration. The function Tesselllation is the actual function called by Analytica. In your own classes, you can add as many functions as you want, just include them in `_public_methods_`

so they can be called by Analytica. When you create your own class, make sure you generate your own _reg_clsid_, which you can do from the Online GUID Generator.

To run this in Python, you’ll need to have the Python for Windows extension installed, which should give you the modules win32com, pythoncom, comtypes, winreg and win32api. Then you’ll also need NumPy and SciPy for my example. And you’ll need by helper library, Analytica_Python.py. My full article also links to the full Analytica model and this python code.

Before using this, you need to register the component, which needs to be done only once. From an admin CMD window, where python points to the installed Python environment with the aforementioned prerequisites, the following command registers the component:

> Python DelaunayCOM.py /regserver

The > is the CMD prompt, which you don’t type. Also make sure you CD to the directory where your the python code (the file DelaunayCOM.py) resides. To unregister it, use <code>Python DelaunayCOM.py /unregserver</code>.

When you evaluate your Analytica model, python is launched automatically. As long as the variable `py `

is cached, the same Python process lives, and can be called multiple times. Once `py `

becomes invalidated (for example, the model closes, or the definition is changed), the python process is released.

I’ve published a more detailed version of this content on the Analytica wiki at: COM Integration/Calling Python code if you want to dive deeper.

Remember to follow to Lumina on LinkedIn, Twitter or Facebook!