I found it pretty easy to call a Python function from Analytica using COM automation. The Component Object Model (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.
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 Pts
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, linked at the bottom of the page.
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. The article at the bottom 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.